美文网首页张国平玩树莓派树莓派玩转树莓派
树莓派基础实验27:温湿度传感器DHT11 实验

树莓派基础实验27:温湿度传感器DHT11 实验

作者: Maker张 | 来源:发表于2020-04-16 00:12 被阅读0次

    一、介绍

       数字温湿度传感器DHT11是一种复合传感器,包含温度和湿度的校准数字信号输出。采用专用数字模块采集技术和温湿度传感技术,确保产品具有高可靠性和优异的长期稳定性。
       该传感器包含一个电阻湿感元件和一个NTC温度测量设备,并与一个高性能8位微控制器连接。其精度:湿度+-5%RH, 温度+-2℃。量程:湿度20-90%RH, 温度0~50℃。采样周期:大于等于1秒/次。
       在我们刚开始练习写传感器的时序时,DHT11非常适合新手入门练习如何写时序。


    二、组件

    ★Raspberry Pi主板*1

    ★树莓派电源*1

    ★40P软排线*1

    ★湿度传感器DHT11模块*1

    ★面包板*1

    ★跳线若干

    三、实验原理

    温湿度传感器 温湿度传感器模块原理图

       DHT11是一款价格便宜,易于使用的温度湿度测量二合一传感器。它具有超小体积、极低功耗的特点。它使用单根总线与单片机进行双向的串行数据传输,信号传输距离可达20米以上。非常适用于对精度和实时性要求不高的温湿度测量场合。

    DHT11硬件原理图

       数据总线DATA使用上拉电阻拉高,因此总线空闲时为高电平。上拉电阻阻值推荐范围:4.7K~5.1K。必要时在VDD和GND之间并一个100nF的去耦电容。

    1. DHT11的数据格式:

      DATA 用于树莓派与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,操作流程如下:

       DHT11用的是单总线协议,一次传送40位的数据。 注意了,看到这一句话,也就是说我们每次读取DHT11的数据时,都要一次性读取40次,也就是读取40位。并且数据前16位是与湿度相关的,中间16位是与温度相关的,最后八位是用来校验的,当我们校验成功后,证明这一次的温湿度结果正确的,我们的树莓派就可以使用这个温湿度值;如果校验不通过,那么就代表我们这次读取出来的温湿度值,是错误的(也许是我们的时序错误了,也许是传感器的问题),我们不进行采样。

    DHT11数据格式示例

    2. DHT11的工作原理:

    数据时序图

    DHT11的总体通信流程:
    第一步:主机(树莓派)先发送开始信号,从机(DHT11)会返回一个相应信号进行应答。
    第二步:主机信号线拉高准备接收数据。
    第三步:开始接收数据(一次接收40位)。

       DHT11使用单一总线通信,即DATA引脚和单片机连接的线。总线总是处于空闲状态和通信状态这个2个状态之间。当树莓派没有与DHT11交互时,总线处于空闲状态,在上拉电阻的作用下,处于高电平状态。

       当单片机和DHT11正在通信时,总线处于通信状态,一次完整的通信过程如下:

       第一步:DHT11 上电后(DHT11 上电后要等待 1秒以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,幵记录数据,同时 DHT11 的 DATA 数据线由上拉电阻拉高一直保持高电;此时 DHT11 的DATA 引脚处于输入状态,时刻检测外部信号。

       第二步:微处理器的 I/O 设置为输出,同时输出低电平,且低电平保持时间不能小于 18ms,然后输出高电平20~40us,再树莓派的 I/O设置为输入状态,等待 DHT11 作出回答信号,发送信号如图所示:

    主机发送起始信号

       第三步:DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,树莓派的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 80 微秒的高电平后的数据接收,发送信号如图所示:

    DHT11应答信号

       第四步:由 DHT11 的 DATA 引脚输出 40 位数据,树莓派根据 I/O 电平的变化接收 40 位数据,位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平;位数据“1”的格式为: 50 微秒的低电平加 70微秒的高电平。位数据“0”、“1”格式信号如图所示:

    位数据“0”、“1”的格式

       我们可以把这一段的时序理解为,DHT11先把数据线拉低50us,然后我们再去对比高电平持续的时间,如果持续时间较短,则为位“0”;如果持续时间较长,则为位“1”。

       结束信号:DHT11 的 DATA 引脚输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态,由于上拉电阻随之变为高电平。但 DHT11 内部重测环境温湿度数据,幵记录数据,等待外部信号的到来。

    注意事项:

    1、DHT11上电后,要等待 1秒 以越过不稳定状态,在此期间不能发送任何指令。

    2、DHT11属于低速传感器,两次通信请求之间的间隔时间不能太短,一般来说要不能低于1秒。

    对DHT11的时序做一个总结:
    一. 主机(单片机)发送起始信号:
      1.主机先拉高data。
      2.拉低data延迟18ms。
      3.拉高data(单片机引脚设置为输入)。

    二. 从机(DHT11)收到起始信号后进行应答:
      从机拉低data,主机读取到data线被拉低持续80us后从机拉高data线, 持续80us,直到高电平结束,意味着主机可以开始接受数据。

    三. 主机开始接收数据:
      1.主机先把data线拉高(io设置为输入)。
      2.从机把data线拉低,主机读取data线电平,直到低电平结束(大约50us)从机拉高data线后,对比高电平持续的时间,如果持续时间较短,则为位“0”;如果持续时间较长时,则为位“1”。
      3.继续重复上述1,2步骤累计40次。

    四. data线拉低50us代表读取结束

    五. 校验数据

    更多资料请参考DHT11 官方手册:
    https://www.dfrobot.com.cn/image/data/DFR0067/DFR0067_DS_10.pdf

    四、实验步骤

      第1步:连接电路。

    树莓派 T型转接板 超声波测距模块
    GPIO0 G17 OUT(DATA)
    5V 5V VCC
    GND GND GND
    温湿度传感器DHT11 实验电路图 温湿度传感器DHT11 实验实物接线图

      第2步:编写控制程序。将提取的二进制数据转化为十进制数据,校验后打印出来。
      本次编程中将用到NumPy(Numerical Python)扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。详情参考NumPy 教程:
      https://www.runoob.com/numpy/numpy-tutorial.html

      为便于对比DHT11高电平持续的时间,我们设置了一个计数器参数k,如果持续时间较短,则k值较小;如果持续时间较长时,则k值较大。当然,也可以使用时间函数直接对比时间长短,但是程序相对要复杂一些

    执行结果截图

      从上面的截图中可以看出,高电平持续的时间较短,26-28 微秒时,参数k等于5或6;高电平持续的时间较长,70 微秒时,参数k等于17或18。

    #!/usr/bin/env python
    import RPi.GPIO as GPIO
    import numpy as np
    import time
     
    DHTPIN = 17         #引脚号17
    
    GPIO.setmode(GPIO.BCM)      #以BCM编码格式
    
    def read_dht11_dat():
        
        GPIO.setup(DHTPIN, GPIO.OUT)
        GPIO.output(DHTPIN, GPIO.LOW)
        #给信号提示传感器开始工作,并保持低电平18ms以上
        time.sleep(0.02)                #这里保持20ms   
        GPIO.output(DHTPIN, GPIO.HIGH)  #然后输出高电平
        
        GPIO.setup(DHTPIN, GPIO.IN)    
        # 发送完开始信号后得把输出模式换成输入模式,不然信号线上电平始终被拉高
     
        while GPIO.input(DHTPIN) == GPIO.LOW:
            continue
        #DHT11发出应答信号,输出 80 微秒的低电平
        
        while GPIO.input(DHTPIN) == GPIO.HIGH:
            continue
        #紧接着输出 80 微秒的高电平通知外设准备接收数据
        
        
        #开始接收数据
        j = 0               #计数器
        data = []           #收到的二进制数据
        kk=[]               #存放每次高电平结束后的k值的列表
        while j < 40:
            k = 0
            while GPIO.input(DHTPIN) == GPIO.LOW:  # 先是 50 微秒的低电平
                continue
            
            while GPIO.input(DHTPIN) == GPIO.HIGH: # 接着是26-28微秒的高电平,或者 70 微秒的高电平
                k += 1
                if k > 100:
                    break
            kk.append(k)
            if k < 8:       #26-28 微秒时高电平时通常k等于5或6
                data.append(0)      #在数据列表后面添加一位新的二进制数据“0”
            else:           #70 微秒时高电平时通常k等于17或18
                data.append(1)      #在数据列表后面添加一位新的二进制数据“1”
     
            j += 1
     
        print("sensor is working.")
        print '初始数据高低电平:\n',data    #输出初始数据高低电平
        print '参数k的列表内容:\n',kk      #输出高电平结束后的k值
        
        m = np.logspace(7,0,8,base=2,dtype=int) #logspace()函数用于创建一个于等比数列的数组
        #即[128 64 32 16 8 4 2 1],8位二进制数各位的权值
        data_array = np.array(data) #将data列表转换为数组
    
        #dot()函数对于两个一维的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积)
        humidity = m.dot(data_array[0:8])           #用前8位二进制数据计算湿度的十进制值
        humidity_point = m.dot(data_array[8:16])
        temperature = m.dot(data_array[16:24])
        temperature_point = m.dot(data_array[24:32])
        check = m.dot(data_array[32:40])
        
        print humidity,humidity_point,temperature,temperature_point,check
        
        tmp = humidity + humidity_point + temperature + temperature_point
        #十进制的数据相加
     
        if check == tmp:    #数据校验,相等则输出
            return humidity, temperature
        else:               #错误输出错误信息
            return False
     
    def main():
        print "Raspberry Pi DHT11 Temperature test program\n"
        time.sleep(1)           #通电后前一秒状态不稳定,时延一秒
        while True:
            result = read_dht11_dat()
            if result:
                humidity, temperature = result
                print "humidity: %s %%,  Temperature: %s  ℃" % \
                      (humidity, temperature)
                print '\n' 
                time.sleep(1)
    
            if result == False:
                print "Data are wrong,skip\n"
                time.sleep(1)
                
    def destroy():
        GPIO.cleanup()
    
    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            destroy() 
    
    
    
    

      

    树莓派套装
    点击购买:
    https://s.click.taobao.com/B1N2Ynv
    扫描二维码购买:
    树莓派套装购买二维码

    相关文章

      网友评论

        本文标题:树莓派基础实验27:温湿度传感器DHT11 实验

        本文链接:https://www.haomeiwen.com/subject/vqygmhtx.html