Module cảm biến BMP280 giá rẻ có thể dùng để đo nhiệt độ, áp suất khí quyển. Trong phần này chúng ta đi đọc các thông tin này bằng Raspberry Pi Pico với MicroPython.
Bước 1: Đầu tiên chúng ta nối sơ đồ như sau:
![]() |
Sơ đồ kết nối |
Bước 2: Tải thư viện này về và lưu vào bộ nhớ của Pico với tên là bmp280.py
from machine import I2C
import time
# BMP280 default address.
BMP280_I2CADDR = 0x76
# Operating Modes
BMP280_OSAMPLE_1 = 1
BMP280_OSAMPLE_2 = 2
BMP280_OSAMPLE_4 = 3
BMP280_OSAMPLE_8 = 4
BMP280_OSAMPLE_16 = 5
# BMP280 Registers
BMP280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
BMP280_REGISTER_DIG_T2 = 0x8A
BMP280_REGISTER_DIG_T3 = 0x8C
BMP280_REGISTER_DIG_P1 = 0x8E
BMP280_REGISTER_DIG_P2 = 0x90
BMP280_REGISTER_DIG_P3 = 0x92
BMP280_REGISTER_DIG_P4 = 0x94
BMP280_REGISTER_DIG_P5 = 0x96
BMP280_REGISTER_DIG_P6 = 0x98
BMP280_REGISTER_DIG_P7 = 0x9A
BMP280_REGISTER_DIG_P8 = 0x9C
BMP280_REGISTER_DIG_P9 = 0x9E
BMP280_REGISTER_DIG_H1 = 0xA1
BMP280_REGISTER_DIG_H2 = 0xE1
BMP280_REGISTER_DIG_H3 = 0xE3
BMP280_REGISTER_DIG_H4 = 0xE4
BMP280_REGISTER_DIG_H5 = 0xE5
BMP280_REGISTER_DIG_H6 = 0xE6
BMP280_REGISTER_DIG_H7 = 0xE7
BMP280_REGISTER_CHIPID = 0xD0
BMP280_REGISTER_VERSION = 0xD1
BMP280_REGISTER_SOFTRESET = 0xE0
BMP280_REGISTER_CONTROL_HUM = 0xF2
BMP280_REGISTER_CONTROL = 0xF4
BMP280_REGISTER_CONFIG = 0xF5
BMP280_REGISTER_PRESSURE_DATA = 0xF7
BMP280_REGISTER_TEMP_DATA = 0xFA
BMP280_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 BMP280:
def __init__(self, mode=BMP280_OSAMPLE_1, address=BMP280_I2CADDR, i2c=None,
**kwargs):
# Check that mode is valid.
if mode not in [BMP280_OSAMPLE_1, BMP280_OSAMPLE_2, BMP280_OSAMPLE_4,
BMP280_OSAMPLE_8, BMP280_OSAMPLE_16]:
raise ValueError(
'Unexpected mode value {0}. Set mode to one of '
'BMP280_ULTRALOWPOWER, BMP280_STANDARD, BMP280_HIGHRES, or '
'BMP280_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(BMP280_REGISTER_CONTROL, 0x3F)
self.t_fine = 0
def _load_calibration(self):
self.dig_T1 = self._device.readU16LE(BMP280_REGISTER_DIG_T1)
self.dig_T2 = self._device.readS16LE(BMP280_REGISTER_DIG_T2)
self.dig_T3 = self._device.readS16LE(BMP280_REGISTER_DIG_T3)
self.dig_P1 = self._device.readU16LE(BMP280_REGISTER_DIG_P1)
self.dig_P2 = self._device.readS16LE(BMP280_REGISTER_DIG_P2)
self.dig_P3 = self._device.readS16LE(BMP280_REGISTER_DIG_P3)
self.dig_P4 = self._device.readS16LE(BMP280_REGISTER_DIG_P4)
self.dig_P5 = self._device.readS16LE(BMP280_REGISTER_DIG_P5)
self.dig_P6 = self._device.readS16LE(BMP280_REGISTER_DIG_P6)
self.dig_P7 = self._device.readS16LE(BMP280_REGISTER_DIG_P7)
self.dig_P8 = self._device.readS16LE(BMP280_REGISTER_DIG_P8)
self.dig_P9 = self._device.readS16LE(BMP280_REGISTER_DIG_P9)
self.dig_H1 = self._device.readU8(BMP280_REGISTER_DIG_H1)
self.dig_H2 = self._device.readS16LE(BMP280_REGISTER_DIG_H2)
self.dig_H3 = self._device.readU8(BMP280_REGISTER_DIG_H3)
self.dig_H6 = self._device.readS8(BMP280_REGISTER_DIG_H7)
h4 = self._device.readS8(BMP280_REGISTER_DIG_H4)
h4 = (h4 << 24) >> 20
self.dig_H4 = h4 | (self._device.readU8(BMP280_REGISTER_DIG_H5) & 0x0F)
h5 = self._device.readS8(BMP280_REGISTER_DIG_H6)
h5 = (h5 << 24) >> 20
self.dig_H5 = h5 | (
self._device.readU8(BMP280_REGISTER_DIG_H5) >> 4 & 0x0F)
def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
meas = self._mode
self._device.write8(BMP280_REGISTER_CONTROL_HUM, meas)
meas = self._mode << 5 | self._mode << 2 | 1
self._device.write8(BMP280_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(BMP280_REGISTER_TEMP_DATA)
lsb = self._device.readU8(BMP280_REGISTER_TEMP_DATA + 1)
xlsb = self._device.readU8(BMP280_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(BMP280_REGISTER_PRESSURE_DATA)
lsb = self._device.readU8(BMP280_REGISTER_PRESSURE_DATA + 1)
xlsb = self._device.readU8(BMP280_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(BMP280_REGISTER_HUMIDITY_DATA)
lsb = self._device.readU8(BMP280_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)
'''
self._calc_t_fine()
if self._p == 0:
var1 = self._t_fine - 128000
var2 = var1 * var1 * self._P6
var2 = var2 + ((var1 * self._P5) << 17)
var2 = var2 + (self._P4 << 35)
var1 = ((var1 * var1 * self._P3) >> 8) + ((var1 * self._P2) << 12)
var1 = (((1 << 47) + var1) * self._P1) >> 33
if var1 == 0:
return 0
p = 1048576 - self._p_raw
p = int((((p << 31) - var2) * 3125) / var1)
var1 = (self._P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self._P8 * p) >> 19
p = ((p + var1 + var2) >> 8) + (self._P7 << 4)
self._p = p / 256.0
return self._p
'''
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()/100
return t
@property
def pressure(self):
"Return the pressure in Pa."
p = self.read_pressure() / 256
p = p + 1300 #Just for fine exactly!
return p
@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)
Bước 3: Copy đoạn code này về lưu vào Pico và chạy.
from machine import Pin, I2C
from time import sleep
#Nhập thư viện bmp280.py
import bmp280
# ESP32 - Pin assignment
#i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)
# ESP8266 - Pin assignment option1: sda=12(D6), scl=14(D5), option2: sda=12(D6), scl=13(D7)
#i2c = I2C(scl=Pin(14), sda=Pin(12), freq=10_000)
#Raspberry Pico
i2c = I2C(0, scl = Pin(1), sda = Pin(0), freq = 100_000)
#Khai báo địa chỉ thiết bị i2c
addressI2C_Device = 0x76
readSensorOk=True
#Thử kết nối xem có được hay không, nếu không thì báo lỗi
try:
camBienBMP = bmp280.BMP280(i2c=i2c, address=addressI2C_Device)
#hum = bmp.humidity #for module bme280
except OSError as e:
print('Không tìm được cảm biến i2c, xem lại địa chỉ thiết bị, hoặc chân kết nối SDA, SCL')
readSensorOk=False
devices = i2c.scan()
if len(devices)>0:
for x in devices : print(hex(x), end=' ')
def altitude_HYP(Pa , temperatureC):
# Hypsometric Equation (Max Altitude < 11 Km above sea level)
temperatureK = temperatureC+273.15
local_pressure = Pa
sea_level_pressure = 101325 # hPa
pressure_ratio = sea_level_pressure/local_pressure # sea level pressure = 101325 Pa
h = (((pressure_ratio**(1/5.257)) - 1) * temperatureK ) / 0.0065
return h
# altitude from international barometric formula, given in BMP 180 datasheet
def altitude_IBF(pressure_Pa):
local_pressure = pressure_Pa/100 # Unit : hPa
sea_level_pressure = 1013.25 # Unit : hPa
pressure_ratio = local_pressure / sea_level_pressure
altitude = 44330*(1-(pressure_ratio**(1/5.255)))
return altitude
count=0
while readSensorOk==True:
nhietDo = camBienBMP.temperature
apSuatKhiQuyen = camBienBMP.pressure
print("#"+str(count)+"s")
count +=2
print("Nhiệt độ:", nhietDo,chr(186)+"C")
print("Áp suất khí quyển:", apSuatKhiQuyen, "Pa (Pascal) =",apSuatKhiQuyen/101325,"atm")
print("Độ cao so với mực nước biển:",altitude_HYP(apSuatKhiQuyen,nhietDo),"meter (Hypsometric Formula)")
print("Độ cao so với mực nước biển:",altitude_IBF(apSuatKhiQuyen),"meter (International Barometric Formula)\n")
sleep(2)
Không có nhận xét nào:
Đăng nhận xét