Найти в Дзене
Радиотехника

Модуль BMP280 (Arduino)

Модуль BMP280 представляет из себя высокоточный цифровой измеритель атмосферного давления на базе микро-чипа BMP280 от фирмы BOSH. После изготовления каждый датчик проходит индивидуальную калибровку в заводских условиях. Малые размеры, низкое энергопотребление и высокая измерительная способность модуля сделали его популярным среди множества разработчиков Arduino-проектов. Модуль BMP280 был разработан фирмой как более технологичная модель своего предшественника BMP180. BMP280 может подключаться к микроконтроллеру используя шины SPI и I2C. Характеристики На сайте rcl-radio.ru достаточно много проектов в которых используется данный модуль и все они используют уже готовые библиотеки для запуска BMP280. Использование библиотек значительно упрощает разработку Arduino-проектов, поэтому практически любой начинающий радиолюбитель может без особого труда использовать среду программирования Arduino IDE. Но мне было интересно изучить более подробно как управляется данный модуль, какие есть регистр

Модуль BMP280 представляет из себя высокоточный цифровой измеритель атмосферного давления на базе микро-чипа BMP280 от фирмы BOSH. После изготовления каждый датчик проходит индивидуальную калибровку в заводских условиях.

Малые размеры, низкое энергопотребление и высокая измерительная способность модуля сделали его популярным среди множества разработчиков Arduino-проектов.

Модуль BMP280 был разработан фирмой как более технологичная модель своего предшественника BMP180.

BMP280 может подключаться к микроконтроллеру используя шины SPI и I2C.

Характеристики

  • Напряжение питания модуля: 3,3 В
  • Потребляемый ток: до 2 мА во время измерений (зависит от режима точности)
  • Потребляемый ток: до 0,2 мА в режиме ожидания
  • Измеряемое давление: от 30000 до 110000 Па (разрешение 0.16 Па, точность ±12 Па)
  • Измеряемая температура: от 0 до +65 °C (разрешение 0,01°C, точность ±0,5 °C)
  • Время преобразований: до 43,2 мс (зависит от режима точности)
  • Рабочая частота шины I2C: до 3,4 МГц
  • Подготовка к первому запуску после подачи питания: не менее 2 мс
  • Рабочая температура: -40 … +85 °C

На сайте rcl-radio.ru достаточно много проектов в которых используется данный модуль и все они используют уже готовые библиотеки для запуска BMP280. Использование библиотек значительно упрощает разработку Arduino-проектов, поэтому практически любой начинающий радиолюбитель может без особого труда использовать среду программирования Arduino IDE.

Но мне было интересно изучить более подробно как управляется данный модуль, какие есть регистры в модуле и для чего они предназначены. Поэтому статья будет посвящена не очередному проекту на базе модуля BMP280, а изучению регистров и их назначению.

В даташите (BST-BMP280) подробно расписано назначение всех регистров, часть из них управляет работой датчика, другая содержит измеренное значение температуры и давления, есть несколько регистров которые содержать заводские калибровочные коэффициенты.

Таблица регистров

-2

Первые три регистра являются тремя частями 20-и битного байта который содержит информацию (данные) об измеренной температуре. Используя данные этих трех регистров, а так же несколько формул и калибровочные коэффициенты можно получить значение температуры в виде чиcла float (23.25) или long (2325).

Регистры температуры

  • 0xFA temp_msb[7:0]
  • 0xFB temp_lsb[7:0]
  • 0xFC (bit 7, 6, 5, 4) temp_xlsb[3:0]

Как ранее отмечалось, регистры температуры являются тремя частями 20-и битного байта, старший байт temp_msb и младший temp_lsb имеют длину по 8 бит, а так как разрешение измерения температуры может менять от 16 до 20 бит, то используется третий дополнительный регистр temp_xlsb, данные в котором появляются только тогда, когда установленное разрешение измерения температуры превышает 16 бит.

Регистры давления

  • 0xF7 press_msb[7:0]
  • 0xF8 press_lsb[7:0]
  • 0xF9 (bit 7, 6, 5, 4) press_xlsb[3:0]

Регистры давления работают аналогично регистрам температуры, так же для получения значения давления необходимо несколько формул и несколько калибровочных коэффициентов. Так же  для хранения информации о давлении используется байт длиной 20 бит.

Следующий регистр это регистр конфигурации (Register 0xF5 “config”):

-3

Биты t_sb[2:0] отвечает за период перехода модуля в активное состояние с целью выполнения измерений:

-4

Этот параметр отвечает как часто датчик будет проводить измерения.

Биты filter[2:0] отвечает за уровень фильтрации измеренных данных:

-5

Этот параметр дает устранить влияние на измерения резких изменений температуры и давления.

Бит spi3w_en указывает тип шины подключения для SPI нужно указать 1, для I2C 0.

Следующий регистр ctrl_meas определяет режимы измерения и режим работы датчика BMP280.

Биты osrs_t определяют разрешение измерения температуры от 16 до 20 бит

-6

Биты osrs_p определяют разрешение измерения давления от 16 до 20 бит

-7

Биты mode определяют основной режим работы:

-8
  • NORMAL – в данном режиме модуль просыпается с определённой периодичностью, выполняет необходимые измерения и снова засыпает. Частота измерений задаётся программным путём, а результат считывается при необходимости.
  • SLEEP – режим максимально пониженного энергопотребления.
  • FORCED – этот режим позволяет будить модуль подачей внешнего управляющего сигнала. После выполнения измерений, модуль автоматически переходит в режим пониженного энергопотребления.

Регистр status:

  • бит measuring автоматически устанавливается на «1« всякий раз, когда выполняется преобразование , и возвращается на «0«, когда результаты передаются в регистры данных.
  • Бит im_update автоматически устанавливается в значение «1«, когда происходит копирование данных из энергонезависимой памяти (считывание коэффициентов) и устанавливается на «0», когда копирование завершено.

Регистр reset — запись в него значения 0xB6 приводит к перезагрузке датчика.

Регистр id содержит номер ID датчика, по даташиту это 0х58.

Последние регистры 0xA1…0x88 это регистры калибровочных коэффициентов:

-9

Каждое значение коэффициента состоит из 2-х байт.

Вот примерные значение коэффициентов указанные в даташите и данные регистров измерения температуры и давления:

-10

Вот значения полученные из моего датчика

-11

В даташите приводится пример кода расчетов температуры и давления:

-12

Примеры кода расчетов имеют по два примера, первый пример для получения данных от температуре и давлении в виде чисел float (число с плавающей точкой), как пример выводит значение температуры 25.56. Этот метод расчета более точен, но подходит для микроконтроллеров не имеющих дефицита памяти. Второй метод расчета позволяет получить значения измерения температуры и давления в виде числа long, как пример выводит значение температуры 2556, подходит для микроконтроллеров с небольшим объемом памяти.

Ниже показан пример считывания данных в датчика BMP280, для подключения используется шина I2C. Информация об измерениях выводится в монитор порта.

Скетч для Arduino Nano (Uno), LGT8F328:

#include <Wire.h>
#define ADDR 0b1110110
#define OSRS_T 0b101
// 000 Skipped (output set to 0x80000) –
// 001 ×1 16 bit / 0.0050 °C
// 010 ×2 17 bit / 0.0025 °C
// 011 ×4 18 bit / 0.0012 °C
// 100 ×8 19 bit / 0.0006 °C
// 101, 110, 111 ×16 20 bit / 0.0003 °C
#define OSRS_P 0b110
// 000 Skipped (output set to 0x80000) –
// 001 ×1 16 bit / 2.62 Pa
// 010 ×2 17 bit / 1.31 Pa
// 011 ×4 18 bit / 0.66 Pa
// 100 ×8 19 bit / 0.33 Pa
// 101, 110, 111 ×16 20 bit / 0.16 Pa
#define MODE 0b11
// 00 Sleep mode
// 01 and 10 Forced mode
// 11 Normal mode
#define FILTER 0b001
// 000 Filter off Full
// 001 2 0.223 × ODR
// 010 4 0.092 × ODR
// 011 8 0.042 × ODR
// 100, others 16 0.021 × ODR
#define STANDBY 0b110
// 000 0.5 ms
// 001 62.5 ms
// 010 125 ms
// 011 250 ms
// 100 500 ms
// 101 1000 ms
// 110 2000 ms
// 111 4000 ms
uint32_t t1,p1, temp_dig,press_dig;
int32_t t2,t3,p2,p3,p4,p5,p6,p7,p8,p9;
void setup() {
Serial.begin(9600);
Wire.begin();
I2C_write(0xE0, 0xB6);// reset
I2C_write(0xF5, (STANDBY<<5) | (FILTER<<2));
I2C_write(0xF4, (OSRS_T<<5)|(OSRS_P<<2)|MODE); // osrs_t settings
delay(200);
t1 = (int32_t)I2C_read(0x89) << 8 | I2C_read(0x88);
t2 = I2C_read(0x8B) << 8 | I2C_read(0x8A);
t3 = I2C_read(0x8D) << 8 | I2C_read(0x8C);
p1 = (int32_t)I2C_read(0x8F) << 8 | I2C_read(0x8E);
p2 = I2C_read(0x91) << 8 | I2C_read(0x90);
p3 = I2C_read(0x93) << 8 | I2C_read(0x92);
p4 = I2C_read(0x95) << 8 | I2C_read(0x94);
p5 = I2C_read(0x97) << 8 | I2C_read(0x96);
p6 = I2C_read(0x99) << 8 | I2C_read(0x98);
p7 = I2C_read(0x9B) << 8 | I2C_read(0x9A);
p8 = I2C_read(0x9D) << 8 | I2C_read(0x9C);
p9 = I2C_read(0x9F) << 8 | I2C_read(0x9E);
Serial.print("ID = 0x");Serial.println(I2C_read(0xD0), HEX); // ID 58
Serial.print("t1 = ");Serial.println(t1);
Serial.print("t2 = ");Serial.println(t2);
Serial.print("t3 = ");Serial.println(t3);
Serial.print("p1 = ");Serial.println(p1);
Serial.print("p2 = ");Serial.println(p2);
Serial.print("p3 = ");Serial.println(p3);
Serial.print("p4 = ");Serial.println(p4);
Serial.print("p5 = ");Serial.println(p5);
Serial.print("p6 = ");Serial.println(p6);
Serial.print("p7 = ");Serial.println(p7);
Serial.print("p8 = ");Serial.println(p8);
Serial.print("p9 = ");Serial.println(p9);
Serial.println();
}
void loop() {
temp_dig = (int32_t)I2C_read(0xFA)<<12 | (int32_t)I2C_read(0xFB)<<4 | (I2C_read(0xFC) & 0xF0)>>4;
double var1, var2, T;
var1 = (((double)temp_dig)/16384.0 - ((double)t1)/1024.0) * ((double)t2);
var2 = ((((double)temp_dig)/131072.0 - ((double)t1)/8192.0) *(((double)temp_dig)/131072.0 - ((double) t1)/8192.0)) * ((double)t3);
int32_t t_fine = (int32_t)(var1 + var2);
T = (var1 + var2) / 5120.0;
int32_t qT;
var1 = ((((temp_dig>>3) - ((uint32_t)t1<<1))) * ((uint32_t)t2)) >> 11;
var2 = (((((temp_dig>>4) - ((uint32_t)t1)) * ((temp_dig>>4) - ((uint32_t)t1))) >> 12) *((int32_t)abs(t3))) >> 14;
uint32_t qt_fine = var1 + var2;
qT = (qt_fine * 5 + 128) >> 8;
press_dig = (int32_t)I2C_read(0xF7)<<12 | (int32_t)I2C_read(0xF8)<<4 | (I2C_read(0xF9)&0xF0)>>4;
double p;
var1 = ((double)t_fine/2.0) - 64000.0;
var2 = var1 * var1 * ((double)p6) / 32768.0;
var2 = var2 + var1 * ((double)p5) * 2.0;
var2 = (var2/4.0)+(((double)p4) * 65536.0);
var1 = (((double)p3) * var1 * var1 / 524288.0 + ((double)p2) * var1) / 524288.0;
var1 = (1.0 + var1 / 32768.0)*((double)p1);
if (var1 == 0.0){return 0;}
p = 1048576.0 - (double)press_dig;
p = (p - (var2 / 4096.0)) * 6250.0 / var1;
var1 = ((double)p9) * p * p / 2147483648.0;
var2 = p * ((double)p8) / 32768.0;
p = p + (var1 + var2 + ((double)p7)) / 16.0;
int32_t zvar1, zvar2;
uint32_t zp;
zvar1 = (((int32_t)t_fine)>>1)-(int32_t)64000;
zvar2 = (((zvar1>>2) * (zvar1>>2)) >> 11 ) * ((int32_t)p6);
zvar2 = zvar2 + ((zvar1*((int32_t)p5))<<1);
zvar2 = (zvar2>>2)+(((int32_t)p4)<<16);
zvar1 = (((p3 * (((zvar1>>2) * (zvar1>>2)) >> 13 )) >> 3) + ((((int32_t)p2) * zvar1)>>1))>>18;
zvar1 =((((32768+zvar1))*((int32_t)p1))>>15);
if (zvar1 == 0){return 0; }
zp = (((uint32_t)(((int32_t)1048576)-press_dig)-(zvar2>>12)))*3125;
if (zp < 0x80000000){zp = (zp << 1) / ((uint32_t)zvar1);}
else{zp = (zp / (uint32_t)zvar1) * 2;}
zvar1 = (((int32_t)p9) * ((int32_t)(((zp>>3) * (zp>>3))>>13)))>>12;
zvar2 = (((int32_t)(zp>>2)) * ((int32_t)p8))>>13;
zp = (uint32_t)((int32_t)zp + ((zvar1 + zvar2 + p7) >> 4));
Serial.print("T(float) = ");Serial.print(T,2);Serial.println(" °C");
Serial.print("T(int32_t) = ");Serial.println(qT);
Serial.print("P(float) = ");Serial.print(p,2); Serial.println(" Pa");
Serial.print("P(int32_t) = ");Serial.print(zp); Serial.println(" Pa");
Serial.print("P = ");Serial.print(p/133.3224,2); Serial.println(" mmHg");
Serial.println();
delay(2000);
}
byte I2C_read(byte reg){
Wire.beginTransmission(ADDR);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(ADDR,1);
while(Wire.available()<1);
byte value = Wire.read();
return value;
}
void I2C_write(byte reg, byte data){
Wire.beginTransmission(ADDR);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission();
}

Читать дальше - http://rcl-radio.ru/?p=132560