树莓派实践系列1-DHT11传感器获取当前温湿度

 

绪:

树莓派买了有一段时间了,也折腾了几次,总想着做些分享,却又多次耽搁,今日立下Flag:两周更新一次折腾日志。

 简介:

树莓派最初发布于2012年,当前已经发布了8个版本,如下图,详情参见官网链接:https://www.raspberrypi.org/products/。引用树莓派实验室的一句话来介绍树莓派:树莓派虽小,五脏俱全,它给爱折腾的极客们提供了一种新的玩具。本次将分享树莓派基于DHT11温湿度传感器的实践。

DHT11温湿度传感器原理

DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃,参考百度百科。它的工作原理为:主机给DHT11传感器发送一个启动信号,进行一系列交互后,传感器发送40位二进制数字,其中前8位表示湿度整数部分humidity_int,9-16位表示湿度小数部分humidity_decimal,17-24表示温度整数部分temperature_int,25-32位表示温度小数部分temperature_decimal;最后8位为检验数字check_num,当check_num=(humidity_int+humidity_decimal+temperature_int+temperature_decimal)时,本次数据传输有效,否则无效。

DHT11传感器初始化

  1. 树莓派通过GPIO针脚输出一个低电平,持续至少18ms,然后输出一个高电平,此为触发DHT11传感器工作的信号;
  2. DHT11被成功初始化后,会通过GPIO针脚输出80us的低电平,然后拉高80us,此信号表示告诉树莓派:我已被成功初始化,即将开始传送数据;
  3. 随后,DHT11开始向树莓派发送40位二进制数字,其中"0"对应50us的低电平加上26~28us的高电平,"1"对应50us的低电平加上70us的高电平。

上述过程用数据时序图表示如下:

DHT11工作时序图
DHT11工作数据时序图

 

树莓派与DHT11的交互

树莓派与DHT11交互就是基于DHT11传感器原理模拟上述过程来获取数据,首先通过树莓派的针脚与DHT11联接。我的设备为树莓派B+,为40针脚,其排列及不同编码下的映射如下面两张图,左图来源于树莓派实验室http://shumeipai.nxez.com/,右图可在树莓派终端通过gpio readall命令获取,在下面程序中我将演示基于BCM编码获取温湿度数据:

而DHT11有三个引脚,分分别为:VCC(供电5V),GND(接地引脚)及DATA(数据引脚),根据树莓派的针脚设定,一种连接方式为:

DHT11针脚树莓派针脚
VCC2
DATA12 (BCM编码下,GPIO18号)
GND6

实际连接图如下:

编程实现从DHT11获取温湿度

import RPi.GPIO as GPIO
import time


class RaspiTemperature(object):
    def __init__(self):
        self.channel = 18
        self.mode = GPIO.BCM

    def initial_dht11(self):
        """
        初始化dht11传感器,请参考dht11工作原理:
        1. 将18(BCM编码下,原始为12号)GPIO针脚置为输出模式,拉低电平,并保持18ms,然后拉高,初始化dht11;
        2. 然后将18号GPIO针脚置为输入模式,接受dht11传感器的反馈;
        :return: 
        """
        GPIO.setmode(self.mode)
        time.sleep(1)
        GPIO.setup(self.channel, GPIO.OUT)
        GPIO.output(self.channel, GPIO.LOW)
        time.sleep(0.018)
        GPIO.output(self.channel, GPIO.HIGH)
        GPIO.setup(self.channel, GPIO.IN)

    def get_data(self):
        """
        数据获取,请参考dht11工作原理:
        1. dht11会先拉低电平80us,然后拉高80us,告诉树莓派,我已初始化完毕,即将开始传输数据,因此这部分在python
        代码中利用while...continue处理即可
        2. 获取数据:这部分为最易混淆的地方,实际这也是核心代码部分
            # 数据0或1前面都有50us的低电平
            while GPIO.input(self.channel) == GPIO.LOW:
                continue
            # 由于程序无法精确控制us级别的sleep,因此采用如下方式计算高电平的计数,这里和CPU时钟及处理速度有关系,我不懂内部原理,期待大佬分享
            while GPIO.input(self.channel) == GPIO.HIGH:
                k += 1
                if k > 100:
                    break
            # 如果高电平计数小于8,则为0,否则为1
            if k < 8:
                data.append(0)
            else:
                data.append(1)
        
        :return: 
        """
        data = []
        count = 0

        # dht11拉低电平80us
        while GPIO.input(self.channel) == GPIO.LOW:
            continue
        # dht11拉高电平80us
        while GPIO.input(self.channel) == GPIO.HIGH:
            continue
        
        # 获取数据
        while count < 40:
            k = 0
            while GPIO.input(self.channel) == GPIO.LOW:
                continue
            while GPIO.input(self.channel) == GPIO.HIGH:
                k += 1
                if k > 100:
                    break
            if k < 8:
                data.append(0)
            else:
                data.append(1)
            count += 1
        return data

    def normalize_data(self, data):
        """
        数据规整,这里的知识点就一个:二进制数据转为十进制数,参见方法transform_binary
        :param data: 
        :return: 
        """
        humidity_int = self.transform_binary(data[0:8])
        humidity_decimal = self.transform_binary(data[8:16])
        temperature_int = self.transform_binary(data[16:24])
        temperature_decimal = self.transform_binary(data[24:32])
        check_int = self.transform_binary(data[32:40])
        tmp = humidity + humidity_point + temperature + temperature_point
        if check_int == tmp:
            print "temperature: {}.{}*c".format(temperature_int, temperature_decimal),\
                  "humidity: {}.{}%".format(humidity_int, humidity_decimal)
        else:
            print "failed to get data from dht11"
        GPIO.cleanup()

    @staticmethod
    def transform_binary(self, num_binary):
        num = 0
        for i in range(8):
            num += num[i] * 2 ** (7 - i)
        return num


if __name__ == '__main__':
    dht11 = RaspiTemperature()
    dht11.initial_dht11()
    data = dht11.get_data()
    dht11.normalize_data(data)

则执行脚本python *.py即可获取读数,有了这个脚本,可以把DHT11用到更多有趣的地方,如自动监控室内温度等。

注:在连接树莓派和DHT11传感器时,一定要注意连接针脚,以免烧掉传感器,我只能说:这后面有个悲伤的故事!因此这里不能贴上获取温湿度的图了。

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值