сайт для палких паяльників

Пример работы ESP8266 (NodeMCU) с датчиком атмосферного давления, температуры и влажности BME280. Датчик BME280 работает по шине I2C (IIC). Шину IIC будем использовать для одновременной работы с датчиком BME280 и дисплеем SSD1306. Напомню, что пример использования дисплея SSD1306 с библиотекой UG8 был приведен в статье ESP8266 NodeMCU. SSD1306. U8G.

Датчик BME280 и BMP280

BME280 – это миниатюрный цифровой модуль, который включает в себя датчик атмосферного давления, датчик температуры и гигрометр. Модель другого датчика – BMP280 очень похожа на BME280 и отличается тем, что не имеет гигрометра. Алгоритмы работы с этими датчиками почти идентичны. То есть, можно сказать, что BMP280 + гигрометр = BME280. Мы протестуем оба датчика.

Датчики BME280 и BMEP280 имеют несколько режимов работы (Sleep mode, Forced mode, Normal mode). Наиболее высокая точность достигается при работе в режиме Normal mode. Отдельно для давления, температуры и влажности можно устанавливать oversampling (1,2,4,8,16). Чем больше oversampling тем точнее результаты измерений. Но тратится и больше времени для измерения. Также датчик имеет IIR_filter, который снижает шум в выходных данных.

Подробнее об этих режимах можно прочитать в документации к BME280 и BMP280.

Мы можем не беспокоиться обо всех настройках и режимах. Модуль bme280 NodeMCU по умолчанию настроит датчик для наиболее точной работы.

Полезные ссылки:
http://www.avislab.com/blog/bme280/

Полная документация по модулю NodeMCU bme280:
https://nodemcu.readthedocs.io/en/master/en/modules/bme280/

Функции роботы с BME280

NodeMCU имеет модуль для работы с датчиком BME280. Этот модуль надо включить во время сборки NodeMCU (https://nodemcu-build.com). Поскольку BME280 использует IIC (I2C), также следует включать модуль I2C.

NodeMCU модуль BME280

Инициализация датчика выполняется функцией:

bme280.init (sda, scl [temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter])

sda – SDA pin
scl – SCL pin
(optional) temp_oss – Controls oversampling of temperature data. Default oversampling is 16x.
(optional) press_oss – Controls oversampling of pressure data. Default oversampling is 16x.
(optional) humi_oss – Controls oversampling of humidity data. Default oversampling is 16x
(optional) sensor_mode – Controls the sensor mode of the device. Default sensor more is normal.
(optional) inactive_duration – Controls inactive duration in normal mode. Default inactive duration is 20ms.
(optional) IIR_filter – Controls the time constant of the IIR filter. Default fitler coefficient is 16.
(optional) cold_start – If 0 then the BME280 chip is not initialised. Usefull in a battery operated setup when the ESP deep sleeps and on wakeup needs to initialise the driver (the module) but not the chip itself. The chip was kept powered (sleeping too) and is holding the latest reading that should be fetched quickly before another reading starts (bme280.startreadout()). By default the chip is initialised.

Во время инициализации указываются GPIO, которые будут использованы для линий SDA и SCL шины IIC. Остальные параметры указывать не обязательно. Обратите внимание, что отдельно выполнять инициализацию шины IIC не требуется.

Примечание: bme280.init() описана как deprecated и будет удалена в следующих версиях NodeMCU. В новых версиях надо будет использовать bme280.setup(), а инициализация IIC будет выполняться отдельно.

Для считывания данных с датчика и вычисления данных используют следующие функции:

bme280.baro() – Читает датчик и возвращает давление воздуха в гектопаскалях как целое число, умноженное на 1000 или ноль, когда считывания не удалось.
bme280.dewpoint() – Для заданной температуры и относительной влажности температура росы в виде целого числа, умноженного на 100.
bme280.humi() – Читает датчик и возвращает относительную влажность воздуха в процентах как целое число, умноженное на 100 или ноль, когда считывание не прошло успешно.
bme280.qfe2qnh() – для заданной высоты превращает давление воздуха в давление воздуха на уровне моря.
bme280.startreadout() – начинает считывания (преводит датчик в forced режим).
bme280.temp() – Читает датчик и возвращает температуру в градусах Цельсия как целое число, умноженное на 100.

Подробнее о функциях для работы с датчиком BME280 можно прочитать здесь:
https://nodemcu.readthedocs.io/en/master/en/modules/bme280/

Пример работы с BME280

Схема подключения (для BME280 и BMP280 схема одинакова):

ESP8266 BME280 схема подключения

Пример считывания давления, температуры и влажности с датчика BME280:


-- BME280 Example

bme280.init(5, 6)
local P, T = bme280.baro()
tmr.delay(100000)
 
local P, T = bme280.baro()
local H, t = bme280.humi()
 
T = T/100
H = H/1000
 
print (P, T, H)

Примечание: Сразу после инициализации датчика bme280 я выполняю считывание и задержку на 0.1 секунду. Это необходимо, потому что первое считывание с датчика всегда не удачное (читай доку по датчику). Имеется в виду первое считывание после подачи питания.

Функция bme280.baro() возвращает давление в гектопаскалях и температуру. Перевести гектопаскалях в миллиметра ртутного столба можно следующим образом:

P * 0.000750061683

Примечание: Обратите внимание, что используются расчеты с плавающей запятой. То есть, Вам нужно использовать прошивку NodeMCU float версии.

Как видите, считывать данные с датчика BME280 достаточно просто.

Пример работы с BMP280

Попробуем подключить датчик BMP280. У BMP280 нет гигрометра, поэтому мы будем считывать только давление и температуру:

-- BMP280 Example

bme280.init(5, 6)
local P, T = bme280.baro()
tmr.delay(100000)
 
local P, T = bme280.baro()
 
T = T/100
 
print (P, T)

BME280 + SSD1306

Теперь подключим к плате NodeMCU датчик BME280 и дисплей SSD1306 как показано на схеме (ниже будет объяснение почему так подключать не рекомендуется):

ESP8266 BME280 SSD1306 схема подключения не верная

Обратите внимание, что датчик bme280 и дисплей SSD1306 работают по шине IIC, но мы подключаем их к разным GPIO выводам. NodeMCU позволяет указать какие GPIO будут использоваться как SDA, SCL для линии шины IIC. Но все ли так хорошо как кажется? Сколько отдельных шин IIC мы можем использовать? NodeMCU позволяет использовать только одну шину. И хотя функция i2c.setup имеет параметр id шины, он всегда должен быть 0. Так указано в документации к NodeMCU (https://nodemcu.readthedocs.io/en/master/en/modules/i2c/).

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

-- Don't use this script in real project
-- it's demonstrate wrong IIC using 
-- Please see example4.lua 

function round(num, numDecimalPlaces)
  mult = 10^(numDecimalPlaces or 0)
  return math.floor(num * mult + 0.5) / mult
end
 
--Init BME280
bme280.init(5, 6)
local P, T = bme280.baro()
tmr.delay(100000)
 
function read_and_show()
  --Init BME280
  bme280.init(5, 6)
 
  local P, T = bme280.baro()
  local H, t = bme280.humi()
 
  T = T/100
  H = H/1000
 
  print (P, T, H)
 
  -- IIC init for Display
  local sda = 3
  local scl = 4
  local sla = 0x3c
  i2c.setup(0, sda, scl, i2c.SLOW)
  i2c.setup(0, sda, scl, i2c.SLOW)
  -- Display init
  local disp = u8g.ssd1306_128x64_i2c(sla)
  disp:begin()
 
  -- Set Font
  disp:setFont(u8g.font_10x20)
 
  disp:firstPage()
 
  file.open("t.MONO", "r")
  local xbm_data_t = file.read()
  file.close()
 
  file.open("h.MONO", "r")
  local xbm_data_h = file.read()
  file.close()
 
  file.open("p.MONO", "r")
  local xbm_data_p = file.read()
  file.close()
 
  repeat
    disp:drawXBM( 8, 0, 12, 22, xbm_data_t )
    disp:drawXBM( 7, 24, 15, 22, xbm_data_h )
    disp:drawXBM( 0, 48, 29, 22, xbm_data_p )
    disp:setFont(u8g.font_10x20)
    disp:drawStr( 40, 16, round(T,1)..' C')
    disp:drawStr( 40, 38, round(H)..' %')
    disp:drawStr( 40, 60, round(P* 0.000750061683, 0)..' mmHg')
  until disp:nextPage() == false
 
  xbm_data_t = nil
  xbm_data_h = nil
  xbm_data_p = nil
  collectgarbage()
end
 
read_and_show()
-- Start timer
tmr.register(0, 5000, tmr.ALARM_AUTO, read_and_show)
tmr.start(0)

Вроде бы все работает – данные считаны и на дисплей выведены. Но на самом деле не совсем все в порядке. Дело в том, что сначала выполняется инициализация IIC для работы с датчиком, а когда выполняется инициализация шины IIC для дисплея, связь с датчиком теряется. Чтобы считать данные с датчика в следующий раз, надо снова выполнять переинициализацию шины IIC. А когда надо вывести данные на дисплей выполнять пере-инициализацию дисплея. От этого изображение на дисплее мигает. Выглядит не очень красиво. Вообще, так делать не рекомендую.

Шина IIC предусматривает подключение нескольких устройств (теоретически до 127). Соединим датчик и дисплей как показано на схеме:

 

ESP8266 BME280 SSD1306 схема подключения

Примечание: В модулях дисплея и датчика уже установлены подтягивающие резисторы для линий шины SDA и SCL, поэтому их добавлять не нужно.

При такой схеме выполняется инициализация всех устройств только один раз и дальнейшая работа не требует пере-инициализации IIC. Такое подключение приборов, работающих по шине IIC, является корректным.

Пример работы датчика BME280 с дисплеем SSD1306 под управлением ESP8266:

function round(num, numDecimalPlaces)
  mult = 10^(numDecimalPlaces or 0)
  return math.floor(num * mult + 0.5) / mult
end
 
-- IIC init
local sda = 5
local scl = 6
local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)
 
--Init BME280
bme280.init(sda, scl)
--bme280.setup()
local P, T = bme280.baro()
tmr.delay(100000)
 
-- Display init
local disp = u8g.ssd1306_128x64_i2c(sla)
disp:begin()
 
-- Set Font
disp:setFont(u8g.font_10x20)
 
function read_and_show()
  local P, T = bme280.baro()
  local H, t = bme280.humi()
 
  T = T/100
  H = H/1000
 
  print (P, T, H)
 
  disp:firstPage()
 
  file.open("t.MONO", "r")
  local xbm_data_t = file.read()
  file.close()
 
  file.open("h.MONO", "r")
  local xbm_data_h = file.read()
  file.close()
 
  file.open("p.MONO", "r")
  local xbm_data_p = file.read()
  file.close()
 
  repeat
    disp:drawXBM( 8, 0, 12, 22, xbm_data_t )
    disp:drawXBM( 7, 24, 15, 22, xbm_data_h )
    disp:drawXBM( 0, 48, 29, 22, xbm_data_p )
    disp:setFont(u8g.font_10x20)
    disp:drawStr( 40, 16, round(T,1)..' C')
    disp:drawStr( 40, 38, round(H)..' %')
    disp:drawStr( 40, 60, round(P* 0.000750061683, 0)..' mmHg')
  until disp:nextPage() == false
 
  xbm_data_t = nil
  xbm_data_h = nil
  xbm_data_p = nil
  collectgarbage()
end
 
read_and_show()
-- Start timer
tmr.register(0, 5000, tmr.ALARM_AUTO, read_and_show)
tmr.start(0)

Примечание: bme280.init() описана как deprecated и будет удалена в следующих версиях NodeMCU. В новых версиях надо будет использовать bme280.setup(). bme280.setup() не занимается инициализацией шины IIC, это технически правильно, а занимается лишь настройками датчика. То есть если раньше мы писали:


bme280.init(5, 6)

Теперь нужно:


i2c.setup(0, 5, 6, i2c.SLOW)
bme280.setup()

В этой статье мы рассмотрели пример работы с датчиком атмосферного давления, температуры и влажности BME280 и пример работы с датчиком атмосферного давления и температуры BMP280. Для работы с датчиками использовалась плата NodeMCU c модулем ESP-12E. Плата работает под управлением Framework NodeMCU. Примеры написаны на языке программирования LUA.

Скачать все файлы, использованные этой статье можно по следующей ссылке:
https://github.com/avislab/NodeMCUExamples/tree/master/BME280_BMP280

Желаю успехов.

Смотри также:

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

 
Translate
Архіви

© 2011-2017 Андрій Корягін, Кременчук - Київ, Україна