esp8266连接AHT20和BMP280
esp8266 micropython 控制AHT20和BMP280
AHT20手册百度一搜就有,还是免费中文的,BMP280的手册官网上有,是英文的,链接在我后面的代码部分里面有
测试效果
一句话:误差很大
AHT20和BMP280测出来的温度差0.6°左右
AHT20之间测出的温度误差在0.4°左右
BMP280之间温度误差在0.5°左右
我发现一个问题,这些传感器尤其是bmp280,一段时间不测量或者刚开机的时候,得到的温度就会很高,然后会慢慢下降,最好是一直让它测量,这样得出来的结果才能尽可能的可靠
首先看接线
我买的是AHT20和BMP280放在一个板子上的,用I2C通信
vdd接3.3V
GND接GND
SCL接esp8266上的D1(gpio5)
SDA接esp8266上的D2(gpio4)
由于只是学习并不是做产品,这里就只是用杜邦线连接的,没有直接焊上去
代码部分
先是传感器控制部分,这里是用类进行了封装,两个设备共用一个i2c总线
from machine import Pin,I2C
import utime
from ustruct import unpack
#共用的i2c设备,由于我买的bmp280和AHT20是在一张板子上,共用接口,故用一个i2c就行了
i2c=I2C(scl=Pin(5),sda=Pin(4),freq=100000)
#写寄存器,给BMP280使用的
def writeRegister(addr,rAddr,buf):
if type(buf) !=bytearray:
buf=bytearray([buf])
i2c.writeto_mem(addr,rAddr,buf) #esp8266没有size参数
#读寄存器,给BMP280使用的
def readRegister(addr,rAddr,size=1):
return i2c.readfrom_mem(addr,rAddr,size) #size表示读几个字节,也就是地址偏移量
class AHT20:
'''可控制ATH20,21,使用getData读取温度和湿度,返回一个元组.'''
def __init__(self):
self.addr=0x38
self.sig_getStatus=bytearray(1)
self.sig_getStatus[0]=0x71
#读取的状态字的最后一位如果是0表示测量完成,第四位如果为0表示未校准
self.sig_init=bytearray(3)
self.sig_init[0]=0xe1
self.sig_init[1]=0x08
self.sig_init[2]=0x00
self.sig_measure=bytearray(3)
self.sig_measure[0]=0xac
self.sig_measure[1]=0x33
self.sig_measure[2]=0x00
#测量后,可以连续读取7字节数据,按需要读取,读取的数据第一个字节和发送0x71一样获得的是状态字
#第2,3,字节和第四字节的高四位是湿度数据,第四字节底四位和第5,6字节是温度数据,第七字节是crc校验值
self.checkDevice()
self.initDevice()
#检查是否有设备连接,如果未连接会一直卡在这里
def checkDevice(self):
devList=i2c.scan()
while self.addr not in devList:
print("not found devices!")
utime.sleep_ms(1000)
#检查设备是否就绪,如果未就绪则进行初始化
def initDevice(self):
i2c.writeto(self.addr,self.sig_getStatus)
while not (int.from_bytes(i2c.readfrom(self.addr,1),'big') & 0x18):
i2c.writeto(self.addr,self.sig_init)
utime.sleep_ms(100)
#读取并计算温度和湿度
def getData(self):
flag=1
i2c.writeto(self.addr,self.sig_measure) #发送测量信号
d=0
while flag:
utime.sleep_ms(100)
d=i2c.readfrom(self.addr,6)
flag=d[0]&0x01 #检查是否测量完成
humidity=int.from_bytes(bytes.fromhex('0'+d.hex()[2:7]),'big')*100.0/0x100000
temperature=int.from_bytes(bytes.fromhex('0'+d.hex()[7:12]),'big')*200.0/0x100000 - 50
return round(temperature,2),round(humidity,2) #摄氏度,RH%
class BMP280:
'''可控制BMP280,使用getData读取温度和压强,返回一个元组.
请注意查看自己的设备地址是0x76还是0x77'''
def __init__(self):
self.addr=0x77
self.sig_measure=bytes.fromhex('f456')
self.sig_softReset=bytes.fromhex('e0b6')
#这两个参数是从别人的地方看到的,具体作用不详
self.sig_setMode=bytes.fromhex('f455')
self.sig_setConfig=bytes.fromhex('f510')
self.checkDevice()
self.initDevice()
self.getConfig()
#检查设备是否已经连接
def checkDevice(self):
devList=i2c.scan()
while self.addr not in devList:
print("not found devices!")
utime.sleep_ms(1000)
#初始化设备,设置一些参数
def initDevice(self):
writeRegister(self.addr,self.sig_setMode[0],self.sig_setMode[1])
writeRegister(self.addr,self.sig_setConfig[0],self.sig_setConfig[1])
#读取设备寄存器中的数据,后面计算要用到,每个芯片好像这些值不一样,大概相当于出厂时的校准参数
def getConfig(self):
self.T1 = unpack('<H', readRegister(self.addr,0x88, 2))[0]
self.T2 = unpack('<h', readRegister(self.addr,0x8A, 2))[0]
self.T3 = unpack('<h', readRegister(self.addr,0x8C, 2))[0]
self.P1 = unpack('<H', readRegister(self.addr,0x8E, 2))[0]
self.P2 = unpack('<h', readRegister(self.addr,0x90, 2))[0]
self.P3 = unpack('<h', readRegister(self.addr,0x92, 2))[0]
self.P4 = unpack('<h', readRegister(self.addr,0x94, 2))[0]
self.P5 = unpack('<h', readRegister(self.addr,0x96, 2))[0]
self.P6 = unpack('<h', readRegister(self.addr,0x98, 2))[0]
self.P7 = unpack('<h', readRegister(self.addr,0x9A, 2))[0]
self.P8 = unpack('<h', readRegister(self.addr,0x9C, 2))[0]
self.P9 = unpack('<h', readRegister(self.addr,0x9E, 2))[0]
#读取数据并计算压强和温度,计算公式参考手册第22页的代码
#参考手册下载地址:https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
def getData(self):
writeRegister(self.addr,self.sig_measure[0],self.sig_measure[1])
utime.sleep_ms(100)
d=readRegister(self.addr,0xf7,6) #根据手册第23页,从这个寄存器中读取压强和温度数据,地址偏移6,也就是连续读取6个字节,读取0xf7-0xfc
#0xf7,0xf8,0xf9的高4位是压强数据
#0xfa,0xfb,0xfc的高4位是温度数据
#温度和压强都占20位,两个半字节
raw_p=int.from_bytes(bytes.fromhex('0'+d.hex()[0:5]),'big')
raw_t=int.from_bytes(bytes.fromhex('0'+d.hex()[6:11]),'big')
t1 = (((raw_t>>3) - (self.T1<<1))*self.T2) >> 11
t2=(((((raw_t>>4) - self.T1) * ((raw_t>>4) - self.T1)) >> 12)* self.T3) >> 14
t=(((t1+t2)*5+128)/256.0)/100.0 #摄氏度
p1=t1+t2-128000
p2=p1*p1*self.P6
p2=p2+((p1*self.P5)<<17)
p2=p2+(self.P4<<35)
p1=((p1*p1*self.P3)>>8)+((p1*self.P2)<<12)
p1=(((1<<47)+p1)*self.P1)>>33
if p1==0:
return t,0
p=1048576-raw_p
p=(((p<<31)-p2)*3125)/p1
p=int(p)
p1=(self.P9*(p>>13)*(p>>13))>>25
p2=(self.P8*p)>>19
p=((p+p1+p2)>>8)+((self.P7)<<4)
p=p/256000.0 #KPa
return round(t,2),round(p,4) #摄氏度,KPa
#设备软重置
def softReset(self):
writeRegister(self.addr,self.sig_softReset[0],self.sig_softReset[1])
def test()
aht=AHT20()
for i in range(10):
print(aht.getData())
bmp=BMP280()
for i in range(10):
print(bmp.getData())
for i in range(10):
print(aht.getData(),'\t',bmp.getData())
utime.sleep(1)
简单的HTTP示例,基于select
import socket
import select
from sensors import BMP280,AHT20,i2c
serverAddress=('0.0.0.0',80)
sockfd=socket.socket()
sockfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
sockfd.bind(serverAddress)
sockfd.listen(6)
sockfd.setblocking(False)
bmp=BMP280()
aht=AHT20()
def handle(connfd,data):
requests=data.decode('utf-8').split("\r\n")
request=''
for i in requests:
if 'GET' in i:
request=i.split(' ')[1]
break
print(request)
Head='''HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n'''
if request.lower() == '/getdata':
d1=aht.getData()
d2=bmp.getData()
Page='''AHT20: 温度: {} ℃ 湿度: {} %
\r\n BMP280: 温度: {} ℃ 压强: {} KPa'''.format(d1[0],d1[1],d2[0],d2[1])
else:
Page='''<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<p>传感器:</br></p>
<p id="info" name="info"></p>
</body>
<script>
setInterval(function(){
$.get("/getdata",function(result){
document.getElementById("info").innerText=result;
console.log("success")
})
},1000);
</script>
</html>
'''
connfd.send(Head.encode())
connfd.send(Page.encode())
connfd.close()
inputs=[sockfd]
outputs=[]
while 1:
readable,writeables,exceptional=select.select(inputs, outputs, inputs)
print(readable,writeables,exceptional)
#检查可读列表,查看是否有外部连接
for i in readable:
#来连接了,进行连接
if i is sockfd:
coonfd,addr=sockfd.accept()
print(addr)
inputs.append(coonfd)
#来数据了,进行接收
else:
data=i.recv(4096)
if data:
handle(i,data)
else:
#数据为空,断开连接,清理连接
if i in inputs:
inputs.remove(i)
i.close()
#检查错误列表,处理错误,清理错误的连接
for e in exceptional:
print(e)
if e in outputs:
outputs.remove(e)
if e in inputs:
inputs.remove(e)