树莓派控制DHT11温湿度传感器

基本说明:

       DHT11数字温度传感器是一款含有已校准数字信号输出的温湿度复合传感器。其湿度测量范围在20-90%RH间,误差±5%RH,温度测量范围在0-50℃间,误差±2℃。

图1 实物图

接口说明:

图2 接口说明

串口通信:

       DHT11通信采用单总线数据格式,数据部分分为小数和整数部分,通信时间约为4ms。DHT11完整的数据共40bit,高位先出。其数据格式为8位湿度整数数据+8位湿度小数数据+8位温度整数数据+8位温度小数数据+8位校验和。校验和等于前4项8位数据之和。

通信过程:

图3 通信过程

       总线空闲状态为高电平,总线输出低电平大于18ms,保证DHT11成功检测到起始信号,拉高并延时等待。等待主机发送信号结束(拉高)并切换到输入模式,DHT11发送80us低电平响应信号。发送响应信号后再拉高80us,开始发送数据。

图4 数据“0”

图5 数据“1”

        每一bit数据均以50us的低电平时隙开始,高电平持续26us-28us表示数据0,高电平持续70us表示数据1,编程时通过选取数据0和1时隙中间值,可以判断数据为0或1。

       (注意:本段内容末尾补充已解决问题)在实际测试中,我参考了网上大部分代码,也不知道是树莓派时钟的问题还是我自己的DHT11模块问题,还是说是个普遍的问题,发现读取成功率很低。为了解决这个问题,只能够牺牲读取速度,设定限定的retry次数,当读取数据检验失败时,延时2s(最小采样时间1s)重新采集数据,直到成功读取数据后返回正确的数据。

代码展示:

!!!注意:本段代码的 检测响应信号的DHT11_Check()方法,有问题,需要修改为文章末尾补充的部分

import RPi.GPIO as GPIO   #引入RPi.GPIO模块,并实例化为GPIO,简化后面的模块调用
import time               #引入time模块

GPIO.setmode(GPIO.BOARD)    #定义GPIO编码方式
time.sleep(2)
Pin=12                      #设置引脚为12(BOARD方式)

#重置DHT11,发送主机信号
def DHT11_rst():
    GPIO.setup(Pin,GPIO.OUT)    #将GPIO设置为输出模式
    GPIO.output(Pin,1)          #发送前先保证电平拉高
    time.sleep(0.002)
    GPIO.output(Pin,0)          #向DHT11发送低电平(开始信号)
    time.sleep(0.025)           #拉低电平,持续时间保证大于18ms且小于30ms
    GPIO.output(Pin,1)          #向DHT11发送高电平(确保重新发送时开始为高电平)
    GPIO.setup(Pin,GPIO.IN)
#检验DHT11响应信号
def DHT11_Check():
    while GPIO.input(Pin)==0:   #轮询检测低电平信号
        continue
    while GPIO.input(Pin)==1:   #轮询检测高电平信号
        continue
    return 0
#读取位数据
def DHT11_Read_Bit():
    k=0
    while GPIO.input(Pin)==0:   #轮询检测50us位起始低电平
        continue
    while GPIO.input(Pin)==1:   #计算高电平持续时间
        k+=1
        continue
    if k>20:                    #这里循环检测20的时间差不多处于28us和70us间,从而可以判断具体数据,可自行根据实际情况测试判断,稍加增减
        return 1                #大于20次,判断为1
    else:
        return 0                #小于20次,判断为0
    
#读取数据
def DHT11_Read_Data():
    humi1=0
    humi2=0
    temp1=0
    temp2=0
    check=0
    data=[]

    DHT11_rst()                 #主机发送信号
    
    if DHT11_Check()==0:        #如果成功接收响应信号则开始读取位数据
        for i in range(40):
            data.append(DHT11_Read_Bit())

        hum1=data[0:8]
        hum2=data[8:16]
        tem1=data[16:24]
        tem2=data[24:32]
        checkbit=data[32:40]
        
        for i in range(8):         #循环8次,将二进制数转换为十进制数
            humi1+=hum1[i]*(2**(7-i))
            humi2+=hum2[i]*(2**(7-1))
            temp1+=tem1[i]*(2**(7-i))
            temp2+=tem2[i]*(2**(7-i))
            check+=checkbit[i]*(2**(7-i))

        temperature=temp1+temp2*0.1 #获取温度值
        humidity=humi1+humi2*0.1    #获取湿度值
        checknum=temp1+humi1+temp2+humi2 #计算前32位数的值
        
        if checknum==check:              #检查前32位的值是否与校验位相等
            if humidity>100:             #个人测试偶尔会有湿度大于100但校验成功的个例,故这里排除
                return 0                 #返回0,表示读取错误
            print("temp:%s,hum:%s"%(temperature,humidity))   #相等输出温度和湿度
            return 1                     #返回1表示读取成功
        else:
            return 0                     #返回0,表示读取错误
#运行
def DHT11_Working():
    retry=0
    while DHT11_Read_Data()==0:          #如果返回0表示读取错误,retry+1,重新读取
        retry+=1
        print ("Data error!Retrying!Times:%d"%retry)
        if retry>10:                     #设置重新读取次数不大于10次
            print ("Fail to read data! Please retry!")
            break
        time.sleep(2)                    #保证采样间隔2s
        continue
    
DHT11_Working()                          #运行程序,读取数值
print ("Finished!")                      #运行完毕
GPIO.cleanup()
    

 有的例子采用调用两次time.time()读取数据部分高电平持续时间,代码如下:

def DHT11_Read_Bit():
    while GPIO.input(Pin)==0:   #轮询检测50us位起始低电平
        continue
    begin=time.time()           #高电平上升时的时间点
    while GPIO.input(Pin)==1:   #计算高电平持续时间
        continue
    end=time.time()             #高电平下降时的时间点
    if (end-begin>0.000035):    #高电平持续时间大于35us为数据“1”,具体时间可以自己测试
        return 1                #大于35us,判断为1
    else:
        return 0                #小于35us,判断为0

结语

代码还有一些问题,比如运行时偶尔程序会卡住,等后续解决了,会第一时间修改

补充(2022.5)

解决运行卡住或者正确率低的问题,需要将检验DHT11响应信号DHT11_Check()方法改为下面的方法。原来的问题出在一开始可能有一段极短的高电平被略掉,导致卡住

#需要将原文这个方法的内容改为下面没有注释掉的代码
#检验DHT11响应信号
#def DHT11_Check():
#    while GPIO.input(Pin)==0:   #轮询检测低电平信号
#        continue
#    while GPIO.input(Pin)==1:   #轮询检测高电平信号
#        continue
#    return 0


#改为如下代码
def DHT11_Check():
    if(GPIO.input(Pin_dht11)==1):         #这里是新加的,为了检测原先代码被忽略的的高电平部分
        while GPIO.input(Pin_dht11)==1:
            continue
    if(GPIO.input(Pin_dht11)==0):
        while GPIO.input(Pin_dht11)==0:
            continue
        while GPIO.input(Pin_dht11)==1:   #采用轮训检测dht的响应信号
            continue

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值