MicroPython-On-ESP8266——获取温湿度传感器数据(DHT11 / AHT10)
0. [外话] 后期基于nodemuc做开发学习与测试
之前用的青蛙创客的europa开发板,接口封装得太好,以致于想自由接线的时候很是头大。从淘宝上又买了块nodemcu开发板,不到十块钱,用起来不心疼,真的是买不了吃亏买不了上当。
两块板一主一从,后面有需要主从通讯什么的,也可以实验了。nodemcu刷micropython固件方法跟前面提到刷europa是一样的,不过这么会儿功夫,官方固件已经更新到 1.16了。 哎,咱这学习进度又拉下了。。。
强调一下 nodemcu板子上的管脚字符标注跟实际GPIO管脚号是有区别的,需要按网上提供的接线图做对照使用。
比如要使用GPIO0控制或读取信号时,不能接到板子上标注D0的针脚处,需要按对照图接到D3(GPIO 00)上。这个一定要注意。
1. 获取DHT11数据
1.1. 接线
手上有N年时买Arduino开发板时送的DHT11模块。DHT11模块有4根针脚,有3根是有用的,见图示。
我们把数据脚接入到D5(GPIO 14),旁边就有正负极脚,走线整齐。
1.2. 读取数据
micropython标准库已经对DHT驱动进行了封装,咱们直接用就可以了
import dht
import machine
d = dht.DHT11(machine.Pin(14))
d.measure() # 先调用测量函数
d.temperature() # 然后可以查湿度
d.humidity() # 和湿度了
广东的天气吓死人,房间里面都32度。空调开起来~~
DHT11精度只到整数,这就不要谈什么误差了吧,真的是仅限学习使用了。
2. 获取AHT10数据
2.1. AHT10模块说明
买nodemcu时,顺手也买了个AHT10模块,这个模块精度要高于DHT11,网上找了下读取数据的资料。
在厂商奥松官网产品页,赫然看到该模块已停产。流年不利,且行且珍惜吧。不过产品说明书还是能下载。
产品手册前面啰里吧嗦的那些就先不管了,直接在第8页看到有对使用方法和解析数据的说明。干脆也贴下图吧
“传感器读取流程”的意思来看,模块接线并上电后,需要先从主机给它发送初始化指令,然后就跟DHT11的measure一样测量一下,就可以读取温湿度数据了。中间要注意的就是返回的数据可能因为传感器状态忙而无效。
咱们学习时候就先不管状态的事儿了,按正常流程手动指令去执行,芯片怎么地都忙完了。
2.2. 接线
AHT10购买时介绍中说的数据走的I2C总线,官方手册前面也提到这一点了。I2C总线需要4条线来连接,模块背后也标注了。nodemcu上需要用正负极加两个GPIO接口来与之对应。我这里的接线方式为(AHT10 – nodemcu) vin – 3v, GND – G, SCL – GPIO 05 (D1), SDA – GPIO 04 (D2)
如图:
另外还要注意一点,AHT10手册上有说VIN输入的电压范围是1.8V到3.6V之间,所以咱们接线时只能接到3.3V针脚上,不要接到5V了,烧穿就没得玩了。
2.3. micropython读取数据
引入基础库,并定义I2C总结协议使用的引脚
from machine import Pin, I2C
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)
官方手册里面写了AHT10模块的从机地址是0x38,如果不放心,可以自己扫找描去拿地址:
addr=i2c.scan()[0] # 56
扫描到的地址是56(十进制),跟官方写的0x38(十六进制)是一致的。
线已经接好了,咱们就直接先初始化设备,然后就可以测量了
i2c.writeto(addr, b'\xE1\x08\x00') # 初始化
i2c.writeto(addr, b'\xAC\x33\x00') # 测量
测量完按手册说的,要先查状态再决定要不要读取结果,这里先直接读结果到中间变量,方便后面计算
data = i2c.readfrom(addr, 6)
读取到6个字节的数据,其中第1个字节是状态位,后面5个字节分两半存储了湿度和温度数据
rst0 = data[1]<<12 | data[2]<<4 | data[3]>>4
rst1 = (data[3]&0x0f)<<16 | data[4]<<8 | data[5]
这里涉及到位运算和位移的操作,目的是把红框和绿框两个数拆分开。
基本方法是把高位数向左移位后,与后面的低位数按位或运算,就得到各自的二进制完整数值。绿框最高位因为只有一半,所以先跟0x0F做与运算,把该字节的前4位置为0而保留后4位的原始值。
另外手册第9页有转换数据的公式,按图索骥
from math import pow
# 湿度转换公式
humidity = rst0 / pow(2, 20) * 100
# 温度转换公式
temperature = rst1 * 200 / pow(2, 20) - 50
REPL实测效果:
开了空调果然不一样,温度下来不说,湿度变低就没那么躁了。
2.4. AHT10三方驱动库
淘宝购买AHT10模块时,产品介绍页资料中有C++版本的驱动库文件。(前面按位操作取值也是参考该库来着)
网上搜索到有大神已经对mpy版本进行封装和开源了,见 Gitee库AHT10
有了这个库其实直接拿来用就好了,省去翻看官方手册的时间了。相见恨晚呐~~
2.5. 自用驱动库
上面大神库加入了温度取摄氏度还是华氏度模式,也跟官方驱动一样实现了露/霜点的计算,这些咱用不到,就按DHT11的模式做个近似的封装。
按官方手机的说明来看,加入了状态位的判断,空闲时取到的温湿度才有效
import utime
class AHT10:
def __init__(self, i2c, address=0x38):
if i2c is None:
raise ValueError('I2C object required.')
self.i2c = i2c
self.address = address
self.i2c.writeto(self.address, b'\xE1\x08\x00') # 初始化模块
self._h, self._t = 0, 0 # 湿度,温度
def status(self, data=None):
'检查忙闲状态'
if not data:
self.i2c.writeto(self.address, b'\x71')
data = self.i2c.readfrom(self.address, 1)
return data & 0x40 # 最高位为1是忙(测量中)
def measure(self):
'测量'
self._h, self._t = 0, 0
for _ in range(3): # 最多重试3次
self.i2c.writeto(self.address, b'\xAC\x33\x00')
utime.sleep_ms(100) # 模块需要80ms以上的测量时间
raw = self.i2c.readfrom(self.address, 6)
if self.status(raw[0]):
utime.sleep_ms(20) # 忙就稍等再测
else:
data_h = raw[1] << 12 | raw[2] << 4 | raw[3] >> 4
data_t = (raw[3] & 0x0F) << 16 | raw[4] << 8 | raw[5]
self._h, self._t = data_h * 100 / 1048576, ((200 * data_t) / 1048576) - 50
break
def humidity(self):
'返回测量到的湿度 %RH'
return self._h
def temperature(self):
'返回测量到的温度 C'
return self._t
def reset(self):
'软复位'
self.i2c.writeto(self.address, b'\xBA')
utime.sleep_ms(20)