Raspberry Pi Pico: BME280 – получение температуры, влажности и давления (MicroPython)
Узнайте, как использовать модуль датчика BME280 с платой Raspberry Pi Pico на MicroPython для получения показаний температуры, влажности и давления. Это краткое руководство, которое поможет вам быстро начать работу с датчиком BME280 и платой Raspberry Pi Pico.
Примечание
Впервые работаете с Raspberry Pi Pico? Начните знакомство с Raspberry Pi Pico с вводного руководства.
Содержание:
Предпочитаете программировать Raspberry Pi Pico в Arduino IDE? Тогда ознакомьтесь с этим руководством: Raspberry Pi Pico – BME280: получение температуры, влажности и давления (Arduino IDE).
Прошивка MicroPython
Для выполнения этого руководства вам необходима прошивка MicroPython, установленная на вашу плату Raspberry Pi Pico. Также вам понадобится IDE для написания и загрузки кода на плату.
Рекомендуемая IDE для работы с MicroPython на Raspberry Pi Pico – это Thonny IDE. Следуйте приведенному ниже руководству, чтобы узнать, как установить Thonny IDE, прошить firmware MicroPython и загрузить код на плату.
Знакомство с модулем датчика BME280
Модуль датчика BME280 измеряет барометрическое давление, температуру и влажность. Поскольку давление изменяется с высотой, вы также можете оценить высоту над уровнем моря. Существует несколько версий этого модуля датчика, но мы будем использовать версию, показанную на рисунке ниже.
Этот датчик использует протокол связи I2C, поэтому подключение очень простое. Вы можете использовать любые выводы I2C на Raspberry Pi Pico для подключения датчика BME280. Мы будем использовать GPIO 4 (SDA) и GPIO 5 (SCL) – подробнее о GPIO Raspberry Pi Pico.
BME280 |
Raspberry Pi Pico |
|---|---|
Vin |
3.3V (OUT) |
GND |
GND |
SCL |
GPIO 5 |
SDA |
GPIO 4 |
Необходимые компоненты
Для этого проекта вам нужно подключить модуль датчика BME280 к выводам I2C Raspberry Pi Pico. Вот список компонентов, необходимых для этого руководства:
Модуль датчика BME280
Плата Raspberry Pi Pico
Макетная плата (breadboard)
Соединительные провода (jumper wires)
Подключение BME280 к Raspberry Pi Pico
Подключите BME280 к любой комбинации выводов I2C на Pico – мы будем использовать GPIO 4 (SDA) и GPIO 5 (SCL).
Примечание
Рекомендуем прочитать: Raspberry Pi Pico и Pico W: распиновка и описание GPIO
Библиотека BME280 для MicroPython
Библиотека для чтения данных с датчика BME280 не входит в стандартную библиотеку MicroPython по умолчанию. Существуют различные модули/библиотеки, которые можно использовать для чтения данных с датчика BME280. Мы будем использовать следующую (адаптированную из библиотеки Adafruit BME280).
from machine import I2C
import time
# BME280 default address.
BME280_I2CADDR = 0x76
# Operating Modes
BME280_OSAMPLE_1 = 1
BME280_OSAMPLE_2 = 2
BME280_OSAMPLE_4 = 3
BME280_OSAMPLE_8 = 4
BME280_OSAMPLE_16 = 5
# BME280 Registers
BME280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
BME280_REGISTER_DIG_T2 = 0x8A
BME280_REGISTER_DIG_T3 = 0x8C
BME280_REGISTER_DIG_P1 = 0x8E
BME280_REGISTER_DIG_P2 = 0x90
BME280_REGISTER_DIG_P3 = 0x92
BME280_REGISTER_DIG_P4 = 0x94
BME280_REGISTER_DIG_P5 = 0x96
BME280_REGISTER_DIG_P6 = 0x98
BME280_REGISTER_DIG_P7 = 0x9A
BME280_REGISTER_DIG_P8 = 0x9C
BME280_REGISTER_DIG_P9 = 0x9E
BME280_REGISTER_DIG_H1 = 0xA1
BME280_REGISTER_DIG_H2 = 0xE1
BME280_REGISTER_DIG_H3 = 0xE3
BME280_REGISTER_DIG_H4 = 0xE4
BME280_REGISTER_DIG_H5 = 0xE5
BME280_REGISTER_DIG_H6 = 0xE6
BME280_REGISTER_DIG_H7 = 0xE7
BME280_REGISTER_CHIPID = 0xD0
BME280_REGISTER_VERSION = 0xD1
BME280_REGISTER_SOFTRESET = 0xE0
BME280_REGISTER_CONTROL_HUM = 0xF2
BME280_REGISTER_CONTROL = 0xF4
BME280_REGISTER_CONFIG = 0xF5
BME280_REGISTER_PRESSURE_DATA = 0xF7
BME280_REGISTER_TEMP_DATA = 0xFA
BME280_REGISTER_HUMIDITY_DATA = 0xFD
class Device:
"""Class for communicating with an I2C device.
Allows reading and writing 8-bit, 16-bit, and byte array values to
registers on the device."""
def __init__(self, address, i2c):
"""Create an instance of the I2C device at the specified address using
the specified I2C interface object."""
self._address = address
self._i2c = i2c
def writeRaw8(self, value):
"""Write an 8-bit value on the bus (without register)."""
value = value & 0xFF
self._i2c.writeto(self._address, value)
def write8(self, register, value):
"""Write an 8-bit value to the specified register."""
b=bytearray(1)
b[0]=value & 0xFF
self._i2c.writeto_mem(self._address, register, b)
def write16(self, register, value):
"""Write a 16-bit value to the specified register."""
value = value & 0xFFFF
b=bytearray(2)
b[0]= value & 0xFF
b[1]= (value>>8) & 0xFF
self.i2c.writeto_mem(self._address, register, value)
def readRaw8(self):
"""Read an 8-bit value on the bus (without register)."""
return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF
def readU8(self, register):
"""Read an unsigned byte from the specified register."""
return int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF
def readS8(self, register):
"""Read a signed byte from the specified register."""
result = self.readU8(register)
if result > 127:
result -= 256
return result
def readU16(self, register, little_endian=True):
"""Read an unsigned 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
if not little_endian:
result = ((result << 8) & 0xFF00) + (result >> 8)
return result
def readS16(self, register, little_endian=True):
"""Read a signed 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = self.readU16(register, little_endian)
if result > 32767:
result -= 65536
return result
def readU16LE(self, register):
"""Read an unsigned 16-bit value from the specified register, in little
endian byte order."""
return self.readU16(register, little_endian=True)
def readU16BE(self, register):
"""Read an unsigned 16-bit value from the specified register, in big
endian byte order."""
return self.readU16(register, little_endian=False)
def readS16LE(self, register):
"""Read a signed 16-bit value from the specified register, in little
endian byte order."""
return self.readS16(register, little_endian=True)
def readS16BE(self, register):
"""Read a signed 16-bit value from the specified register, in big
endian byte order."""
return self.readS16(register, little_endian=False)
class BME280:
def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
**kwargs):
# Check that mode is valid.
if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,\
BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
raise ValueError(
'Unexpected mode value {0}. Set mode to one of '
'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
'BME280_ULTRAHIGHRES'.format(mode))
self._mode = mode
# Create I2C device.
if i2c is None:
raise ValueError('An I2C object is required.')
self._device = Device(address, i2c)
# Load calibration values.
self._load_calibration()
self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
self.t_fine = 0
def _load_calibration(self):
self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)
self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)
self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)
h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
h4 = (h4 << 24) >> 20
self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)
h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
h5 = (h5 << 24) >> 20
self.dig_H5 = h5 | (
self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)
def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
meas = self._mode
self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
meas = self._mode << 5 | self._mode << 2 | 1
self._device.write8(BME280_REGISTER_CONTROL, meas)
sleep_time = 1250 + 2300 * (1 << self._mode)
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
time.sleep_us(sleep_time) # Wait the required time
msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_pressure(self):
"""Reads the raw (uncompensated) pressure level from the sensor."""
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_humidity(self):
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
raw = (msb << 8) | lsb
return raw
def read_temperature(self):
"""Get the compensated temperature in 0.01 of a degree celsius."""
adc = self.read_raw_temp()
var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
var2 = ((
(((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
self.dig_T3) >> 14
self.t_fine = var1 + var2
return (self.t_fine * 5 + 128) >> 8
def read_pressure(self):
"""Gets the compensated pressure in Pascals."""
adc = self.read_raw_pressure()
var1 = self.t_fine - 128000
var2 = var1 * var1 * self.dig_P6
var2 = var2 + ((var1 * self.dig_P5) << 17)
var2 = var2 + (self.dig_P4 << 35)
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
((var1 * self.dig_P2) >> 12))
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
if var1 == 0:
return 0
p = 1048576 - adc
p = (((p << 31) - var2) * 3125) // var1
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self.dig_P8 * p) >> 19
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
def read_humidity(self):
adc = self.read_raw_humidity()
# print 'Raw humidity = {0:d}'.format (adc)
h = self.t_fine - 76800
h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
self.dig_H2 + 8192) >> 14))
h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
h = 0 if h < 0 else h
h = 419430400 if h > 419430400 else h
return h >> 12
@property
def temperature(self):
"Return the temperature in degrees."
t = self.read_temperature()
ti = t // 100
td = t - ti * 100
return "{}.{:02d}C".format(ti, td)
@property
def pressure(self):
"Return the temperature in hPa."
p = self.read_pressure() // 256
pi = p // 100
pd = p - pi * 100
return "{}.{:02d}hPa".format(pi, pd)
@property
def humidity(self):
"Return the humidity in percent."
h = self.read_humidity()
hi = h // 1024
hd = h * 100 // 1024 - hi * 100
return "{}.{:02d}%".format(hi, hd)
Загрузите приведенную выше библиотеку на вашу плату Raspberry Pi Pico (сохраните файл с именем BME280.py). Следуйте инструкциям ниже, чтобы узнать, как загрузить библиотеку с помощью Thonny IDE.
Если вы используете Thonny IDE, выполните следующие шаги:
1. Скопируйте код библиотеки в новый файл. Код библиотеки BME280 можно найти здесь.
2. Перейдите в File > Save as…
3. Выберите сохранение на «Raspberry Pi Pico»:
4. Назовите файл BME280.py и нажмите кнопку OK:
Вот и все. Библиотека загружена на вашу плату. Чтобы убедиться, что загрузка прошла успешно, перейдите в File > Save as… и выберите устройство MicroPython. Ваш файл должен быть в списке:
После загрузки библиотеки на плату вы можете использовать функции библиотеки в своем коде, импортировав ее.
BME280: давление, температура и влажность – код MicroPython
После загрузки библиотеки на Raspberry Pi Pico создайте новый файл с именем main.py и вставьте следующий код. Он просто выводит температуру, влажность и давление в консоль каждые 5 секунд.
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-bme280-micropython/
from machine import Pin, I2C
from time import sleep
import BME280
# Initialize I2C communication
i2c = I2C(id=0, scl=Pin(5), sda=Pin(4), freq=10000)
while True:
try:
# Initialize BME280 sensor
bme = BME280.BME280(i2c=i2c)
# Read sensor data
tempC = bme.temperature
hum = bme.humidity
pres = bme.pressure
# Convert temperature to fahrenheit
tempF = (bme.read_temperature()/100) * (9/5) + 32
tempF = str(round(tempF, 2)) + 'F'
# Print sensor readings
print('Temperature: ', tempC)
print('Temperature: ', tempF)
print('Humidity: ', hum)
print('Pressure: ', pres)
except Exception as e:
# Handle any exceptions during sensor reading
print('An error occurred:', e)
sleep(5)
Как работает код
Сначала необходимо импортировать нужные библиотеки, включая модуль BME280, который вы загрузили ранее.
from machine import Pin, I2C
from time import sleep
import BME280
Задайте идентификатор I2C, выводы и частоту. Мы используем GPIO 5 и 4, но любые другие выводы I2C тоже должны работать.
i2c = I2C(id=0, scl=Pin(5), sda=Pin(4), freq=10000)
Примечание
GPIO 5 и 4 относятся к I2C id=0 – проверьте другие комбинации и их идентификаторы в руководстве по распиновке.
В цикле while создайте объект BME280 с именем bme с определенными ранее выводами I2C:
bme = BME280.BME280(i2c=i2c)
По умолчанию библиотека предполагает, что ваш датчик BME280 имеет стандартный I2C-адрес 0x76 (если вы откроете код библиотеки, вы увидите адрес, определенный в строке 5: BME280_I2CADDR = 0x76).
Если ваш датчик не работает, возможно, он имеет другой I2C-адрес. Чтобы проверить I2C-адрес, ознакомьтесь со следующим руководством.
Если после запуска I2C-сканера, который мы предоставили ранее, ваш датчик имеет другой I2C-адрес, измените эту строку:
bme = BME280.BME280(i2c=i2c)
На:
bme = BME280.BME280(i2c=i2c, addr=YOUR_I2C_ADDRESS)
Например, если ваш I2C-адрес 0x78, это будет выглядеть так:
bme = BME280.BME280(i2c=i2c, addr=0x78)
Чтение температуры, влажности и давления так же просто, как использование методов temperature, humidity и pressure объекта bme.
temp = bme.temperature
hum = bme.humidity
pres = bme.pressure
Если вы хотите отображать температуру в градусах Фаренгейта, просто раскомментируйте (удалите #) следующие две строки:
# temp = (bme.read_temperature()/100) * (9/5) + 32
# temp = str(round(temp, 2)) + 'F'
Наконец, выведите показания в оболочку:
print('Temperature: ', temp)
print('Humidity: ', hum)
print('Pressure: ', pres)
В конце мы добавляем задержку в 5 секунд:
sleep(5)
Мы используем try и except для перехвата любых непредвиденных ошибок, которые могут возникнуть при попытке чтения данных с датчика.
except Exception as e:
print('An error occurred:', e)
Демонстрация
Сохраните код на плату Raspberry Pi Pico с помощью Thonny IDE или любой другой MicroPython IDE по вашему выбору.
Скопируйте предоставленный код MicroPython в новый файл в Thonny IDE.
После копирования кода в файл нажмите на значок Save. Затем выберите Raspberry Pi Pico.
Сохраните файл с именем: main.py.
Примечание
Когда вы называете файл main.py, Raspberry Pi Pico будет автоматически запускать этот файл при загрузке. Если вы дадите ему другое имя, он все равно будет сохранен в файловой системе платы, но не будет запускаться автоматически при загрузке.
Нажмите маленькую зеленую кнопку «Run Current Script» или клавишу F5.
Новые показания температуры и влажности будут выводиться в оболочку приблизительно каждые пять секунд.
Устранение неполадок
Ваш BME280 не работает? Возможные причины: неправильное подключение, неверный I2C-адрес, сломанный датчик или поддельный датчик BME280. Ознакомьтесь с руководством по устранению неполадок BME280, чтобы найти причину и решение вашей проблемы.
Заключение
В этом руководстве вы узнали, как подключить датчик температуры, влажности и давления BME280 к Raspberry Pi Pico и как написать программу на MicroPython для получения и отображения показаний в консоли MicroPython. Это один из самых простых примеров для начала работы с датчиком BME280.
Надеемся, что это руководство было для вас полезным. У нас есть руководства для других популярных датчиков окружающей среды: