Сегодня рассмотрим подключение датчиков 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.
Тема на форуме - перейти.