以前在其他社区的活动中见到一款称为DFRobot 云雀气象仪的组件,见图1所示。

图1 云雀气象仪
当然,这家伙可不便宜约要千元左右。既然买不起它,但要测量温度、湿度及大气压还是无需这么高的代价的,一款 BME280模块就可搞定。
稍感遗憾的是无良的商家在推销时,将BME280和BMP280混淆着一起卖,稍不留神就会中道。
其实这两种是有较大区别的,其中BME280是可以检测温度、湿度及大气压的,而BMP280却没有湿度检测功能。
但BME280和BMP280在程序上是可以共用的,且均采用I2C接口来工作。
为此,可使用I2C2来与传感器模块来连接,见图3所示。

图2 I2C2引脚位置

图3 连接形式
对所用引脚的配置及初始化处理的内容为:
from machine import I2C, Pin
import time
from struct import unpack
from machine import FPIOA
fpioa = FPIOA()
fpioa.set_function(11, FPIOA.IIC2_SCL)
fpioa.set_function(12, FPIOA.IIC2_SDA)
temperature=0.0
pressure=0.0
humidity=0.0
BME280进行检测的函数定义为:
class BME280:
def __init__(self, i2c, address=0x76):
self.i2c = i2c
self.address = address
self.t_fine = 0
self._read_calibration_data()
self._configure_sensor()
def _read_calibration_data(self):
calib = self.i2c.readfrom_mem(self.address, 0x88, 26)
self.dig_T1 = unpack('<H', calib[0:2])[0]
self.dig_T2 = unpack('<h', calib[2:4])[0]
self.dig_T3 = unpack('<h', calib[4:6])[0]
self.dig_P1 = unpack('<H', calib[6:8])[0]
self.dig_P2 = unpack('<h', calib[8:10])[0]
self.dig_P3 = unpack('<h', calib[10:12])[0]
self.dig_P4 = unpack('<h', calib[12:14])[0]
self.dig_P5 = unpack('<h', calib[14:16])[0]
self.dig_P6 = unpack('<h', calib[16:18])[0]
self.dig_P7 = unpack('<h', calib[18:20])[0]
self.dig_P8 = unpack('<h', calib[20:22])[0]
self.dig_P9 = unpack('<h', calib[22:24])[0]
self.dig_H1 = self.i2c.readfrom_mem(self.address, 0xA1, 1)[0]
calib_h = self.i2c.readfrom_mem(self.address, 0xE1, 7)
self.dig_H2 = unpack('<h', calib_h[0:2])[0]
self.dig_H3 = calib_h[2]
e4 = calib_h[3]
e5 = calib_h[4]
e6 = calib_h[5]
self.dig_H4 = (e4 << 4) | (e5 & 0x0F)
self.dig_H5 = (e6 << 4) | (e5 >> 4)
self.dig_H6 = self._to_signed(calib_h[6])
def _configure_sensor(self):
self.i2c.writeto_mem(self.address, 0xF2, b'\\x01')
self.i2c.writeto_mem(self.address, 0xF4, b'\\x27')
self.i2c.writeto_mem(self.address, 0xF5, b'\\xA0')
def _to_signed(self, n):
return n - 256 if n > 127 else n
def read_raw_data(self):
data = self.i2c.readfrom_mem(self.address, 0xF7, 8)
adc_p = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
adc_t = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
adc_h = (data[6] << 8) | data[7]
return adc_t, adc_p, adc_h
def compensate_temperature(self, adc_T):
var1 = ((adc_T / 16384.0) - (self.dig_T1 / 1024.0)) * self.dig_T2
var2 = (((adc_T / 131072.0) - (self.dig_T1 / 8192.0)) ** 2) * self.dig_T3
self.t_fine = int(var1 + var2)
T = (var1 + var2) / 5120.0
return T
def compensate_pressure(self, adc_P):
var1 = self.t_fine / 2.0 - 64000.0
var2 = var1 * var1 * self.dig_P6 / 32768.0
var2 += var1 * self.dig_P5 * 2.0
var2 = var2 / 4.0 + self.dig_P4 * 65536.0
var1 = (self.dig_P3 * var1 * var1 / 524288.0 + self.dig_P2 * var1) / 524288.0
var1 = (1.0 + var1 / 32768.0) * self.dig_P1
if var1 == 0:
return 0
p = 1048576.0 - adc_P
p = ((p - (var2 / 4096.0)) * 6250.0) / var1
var1 = self.dig_P9 * p * p / 2147483648.0
var2 = p * self.dig_P8 / 32768.0
p += (var1 + var2 + self.dig_P7) / 16.0
return p
def compensate_humidity(self, adc_H):
var_H = self.t_fine - 76800.0
var_H = (adc_H - (self.dig_H4 * 64.0 + self.dig_H5 / 16384.0 * var_H)) * \\
(self.dig_H2 / 65536.0 * (1.0 + self.dig_H6 / 67108864.0 * var_H *
(1.0 + self.dig_H3 / 67108864.0 * var_H)))
var_H *= (1.0 - self.dig_H1 * var_H / 524288.0)
if var_H > 100.0:
var_H = 100.0
elif var_H < 0.0:
var_H = 0.0
return var_H
def read_compensated_data(self):
adc_T, adc_P, adc_H = self.read_raw_data()
temperature = self.compensate_temperature(adc_T)
pressure = self.compensate_pressure(adc_P)
humidity = self.compensate_humidity(adc_H)
return temperature, pressure / 100.0, humidity
实现检测数据打印输出的主程序为:
if __name__ == "__main__":
i2c = I2C(2)
sensor = BME280(i2c)
while True:
temperature, pressure, humidity = sensor.read_compensated_data()
print("温度: {:.2f}°C".format(temperature))
print("气压: {:.2f} hPa".format(pressure))
print("湿度: {:.2f}%".format(humidity))
print("----------------------------")
time.sleep(0.5)
经程序的运行,其检测结果如图4所示。

图4 检测结果
此时,所购模块的真面目现行了,原来给的是BMP280而非BME280,故而检测的只是温度和大气压。哎,花钱买了个见识。
后来又重新购买了真正的BME280模块,在连接测试后其结果如图5所示,这次终于实现了预期的目标。

图5 检测结果