Сегодня рассмотрим подключение датчиков BMP280 и BME280. Описание и подключение уже рассматривалось здесь. Поэтому не будем долго толочь воду в ступе, а просто подключим и измерим.
Датчики, в основном, практически одинаковы, вся разница заключается в точности и пределах измерения и, соответственно, в цене. Может есть ещё отличия, но нам они не принципиальны. Основная фишка этих датчиков состоит в том, что они имеют таблицу корректировки, в которую прописываются данные на заводе-изготовителе. И наша задача - перед измерением считать эти параметры для перерасчёта данных, полученных с АЦП. Подключение будет производиться по I2C:
На картинке подключение по I2C, где вывод 4 - SCL, 3 - SDA. Не забываем подтягивающие резисторы (на схеме не показаны). Комбинируя способ подключения? можно заставить его работать по SPI (3 или 4 линии).
Мы рассмотрим только циклическое измерение. Возможно ещё держать датчик постоянно "спящим", в нужный момент заставить его измерить, и через некоторое время считать готовые данные. Такой режим используется, когда нам не нужно отслеживать параметры постоянно. Но и циклическое измерение имеет своё ограничение. Частота измерения 1 Герц.
Основных функций у нас четыре:
S_BME280(); // Создание объекта в классе BME280 uint8_t Init(I2C *I2C_Ptr); // Инициализация сенсора с адресом по умолчанию 0x76 uint8_t Init(I2C *I2C_Ptr, uint8_t address); // Инициализация сенсора с нестандартным адресом bool isMeasuring(void); // Возвращает 'true' если производится операция измерения float readTemperature(void); // Чтение и вычисление температуры [float , *C] float readPressure(void); // Чтение и вычисление атмосферного давления [float , Pa] float readHumidity(void); // Чтение и вычисление влажности [float , %] void oneMeasurement(void); // Измерение и уход в сон [только в FORCED_MODE]
Конструктор у нас практически ничего не делает, просто создаёт объект. Далее функции инициализации. Первая используется, если адрес датчика стандартный, вторая для нестандартного адреса, чего, в принципе, быть не должно, но пусть будет.
Далее функция isMeasuring(void)
- может использоваться при единичных измерениях для определения окончания преобразования. Три функции для чтения температуры, давления и влажности. И функция единичного измерения oneMeasurement(void)
.
Функция инициализации:
uint8_t S_BME280::Init(I2C* I2C_Ptr, uint8_t address) { _i2c_address = address; _I2C_Ptr = I2C_Ptr; /* === Проверяем, BME280 это или что-то другое === */ if(!_reset()) return false; // Программный сброс и проверка ответа uint8_t ID = _readRegister(0xD0); // Читаем регистр ID if(ID != 0x60 && ID != 0x58) return false; // Если нужный ID (bme/bmp280), то всё в порядке _readCalibrationData(); // Читаем калибровочные данные /* === Загружаем настройки в BME280 === */ _writeRegister(0xF2, _hum_oversampl); _writeRegister(0xF2, _readRegister(0xF2)); _writeRegister(0xF4, ((_temp_oversampl << 5) | (_press_oversampl << 2) | _operating_mode)); _writeRegister(0xF5, ((_standby_time << 5) | (_filter_coef << 2))); return ID; }
В первую очередь, производится программный сброс. Он делается простой записью в регистр 0x0E числа 0xB6, что приводит к сбросу аппаратной части датчика и обнулению всех настроек. Затем из регистра 0xD0 считывается идентификационный код, который для BME280 будет равен 0x60, для BMP280 0x58. Далее считываются калибровочные данные и запоминаются в структуре:
void S_BME280::_readCalibrationData(void) { uint8_t Buff[30] = {0,}; Buff[0] = 0x88; _I2C_Ptr->MasterWrite(_i2c_address, Buff, 1, 12); _I2C_Ptr->MasterRead(_i2c_address, Buff, 25, 12); CalibrationData._T1 = (Buff[0] | (Buff[1] << 8)); CalibrationData._T2 = (Buff[2] | (Buff[3] << 8)); CalibrationData._T3 = (Buff[4] | (Buff[5] << 8)); CalibrationData._P1 = (Buff[6] | (Buff[7] << 8)); CalibrationData._P2 = (Buff[8] | (Buff[9] << 8)); CalibrationData._P3 = (Buff[10] | (Buff[11] << 8)); CalibrationData._P4 = (Buff[12] | (Buff[13] << 8)); CalibrationData._P5 = (Buff[14] | (Buff[15] << 8)); CalibrationData._P6 = (Buff[16] | (Buff[17] << 8)); CalibrationData._P7 = (Buff[18] | (Buff[19] << 8)); CalibrationData._P8 = (Buff[20] | (Buff[21] << 8)); CalibrationData._P9 = (Buff[22] | (Buff[23] << 8)); CalibrationData._H1 = Buff[24]; Buff[0] = 0xE1; _I2C_Ptr->MasterWrite(_i2c_address, Buff, 1, 12); _I2C_Ptr->MasterRead(_i2c_address, Buff, 8, 12); CalibrationData._H2 = (Buff[0] | (Buff[1] << 8)); CalibrationData._H3 = Buff[2]; CalibrationData._H4 = (Buff[3] << 4); uint8_t interVal = Buff[4]; CalibrationData._H4 |= (interVal & 0xF); CalibrationData._H5 = (((interVal & 0xF0) >> 4) | (Buff[5] << 4)); CalibrationData._H6 = Buff[6]; }
После чего пишем в датчик настройки, дающие нужную точность измерения. По умолчанию выставлены максимальные настройки. Если настройки не устраивают, перед вызовом Init()
можно обратиться к функциям, изменяющим настройки по умолчанию:
void setFilter(uint8_t mode); // Настройка фильтра при различных разрешениях в режимах отличных от стандартного [использовать перед Init()] void setStandbyTime(uint8_t mode); // Настройка "сна" перед измерением [только в NORMAL_MODE][использовать перед Init()] void setHumOversampling(uint8_t mode); // Установить разрешение или отключить модуль измерения влажности [использовать перед Init()] void setTempOversampling(uint8_t mode); // Установить разрешение или отключить модуль измерения теипературы [использовать перед Init()] void setPressOversampling(uint8_t mode); // Установить разрешение или отключить модуль измерения давления [использовать перед Init()]
Сами измерения в циклическом режиме. До функции main()
запуливаем конструктор:
S_BME280 myBME;
В функции main()
инициализируем датчик:
/* * Инициализируем BMP или BME */ myUART.println("BMP or BME Init"); Temp = myBME.Init(&myI2C); if(Temp < 0) { FlagBME = 0; sprintf(msg, "BME Read Error \n\r"); } else if(Temp == 0x60) { sprintf(msg, "BME ID - 0x%02X OK \n\r", Temp); FlagBME = 1; } myUART.println(msg);
В цикле делаем замеры:
while(1) { /* * Замеры BME 280 */ if(FlagBME) { myUART.println("--- Measuring BME ---\n\r"); sprintf(msg, "Temperature : %.2f *C\n\r", myBME.readTemperature()); myUART.print(msg); sprintf(msg, "Humidity : %.2f %%\n\r", myBME.readHumidity()); myUART.print(msg); float pressure = myBME.readPressure(); // Читаем давление в [Па] sprintf(msg, "Pressure : %.2f hPa\n\r", pressure / 100.0F); myUART.print(msg); sprintf(msg, "Pressure : %.2f mm Hg\n\r", _pressureToMmHg(pressure)); myUART.println(msg); } }
Как видите, ничего особенного нет. Как всегда весь материал на Яндекс Диске и архивом. Пример в каталоге WorkDevel\Developer\Tests MK\F407\F407_I2C_BMP280.
Тема на форуме - перейти.
Привет. Не получается с датчика BMP180 вывести данные на дисплей ST7735. Где можно примеры подглядеть?
Привет. А код здесь приведённый не подходит?
Он позволяет просканировать шину и узнать, кто нибудь откликается вообще или нет. А потом уже думать. Вывод данных производится в UART.
Да это то сделал, вопрос в том, что данные не могу на экран вывести. Просто строку с текстом получается, а данные нет. По i2c прикрутил, по spi ну ни как.
Тогда проект нужен.
Добрый день,
хочу подключить BMP280, связь по I2C налажена, получаю ID 0х58. А вот дальше не могу разобраться тк в архиве нет заголовочного файла(или не нашел...) и я не могу понять описание класса S_BME280 и его методов, также не понятна и структура I2C. Не могли бы помочь?
Вы пользуетесь чем то своим или что я описывал с самого начала?
Какой МК используется?
Можно код посмотреть?
сначала пытался Вашими примерами воспользоваться, установил соединение, проверил... Но, как и писал ранее, не нашел #include "STM_BME280.h" из main.cpp и на этом остановился.
Теперь пытаюсь самостоятельно портировать библиотеку Gyver-а для STM32 (stm32f411ceu6 у меня)
Сам файл не нашли или в main.cpp его не видно. Если не видно, значит ошибка в прописывании путей.
А на F411 I2C работает? На таком я её не проверял.
Я не могу физически найти хидер файл. Его нет ни в прилагаемом архиве, ни на я-диске. Если сможете, вышлите на емейл.
Что касается f411, то i2c чудесно, как и spi, работает. У меня по spi подключен дисплей tft 240x320 на контроллере st7789v, туда и хочу выводить инфо с датчика.
"MTWorkDevel\STM32Lib\Library\Inc\STM_BME280.h"
Для дисплея драйвер то же есть. Только не знаю с буквой "v" в конце названия чипа подойдёт или нет.
спасибо! не догадался посмотреть в либах... искал стандартно, в "Tests MK\F407\F407_I2C_BMP280\Core\Inc". Для дисплея использовал библиотеку VadRov https://github.com/vadrov/stm32-display-spi-dma
Понравилось, что с DMA и довольно просто и понятно написано и описано. Есть видео на ютуб.
ПС. не реклама)
DMA при работе с дисплеем можно использовать только в двух случаях:
В остальных случаях он бесполезен.
А видосики я не люблю. Их чаще снимают люди, которым нечего сказать.
"Для дисплея использовал библиотеку VadRov "
Я посмотрел библиотеку, много интересного, но драйвер в части DMA построен глупо.
Даже одну точку рисует через DMA. Это только уменьшает скорость работы с дисплеем.
Реально по одному пикселю через DMA?
Это у него в старой версии библиотеки. Одна из первых. Мы с тобой об этом уже разговаривали.
Скачал обновлённую. Он это исправил. Сделал как я говорил. Вывод картинок через DMA или напрямую.
Заполнение экрана одним цветом без предварительного заполнения буфера, т.е. одно и тот же слово из памяти без инкремента.
Нужно как следует пошерстить библиотеку. Сделать её не на один МК, а на все.
Другое дело 👍