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

ESP8266 NodeMCU. I2C. BME280
(на русском языке)

Приклад роботи 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 I2C

Ініціалізація датчика виконується функцією:

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.

Докладніше про функції роботи з датчиком можна прочитати тут:
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 з модулем ESP-12. Плата працює під управлінням Framework NodeMCU. Приклади написані на мові програмування LUA.

Скачати всі файли, використані у цій статті можна за наступним посиланням:
https://github.com/avislab/NodeMCUExamples/tree/master/BME280_BMP280

Бажаю успіхів.

Дивись також:

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

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

 
Translate
Архіви

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