ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树莓派从DHT11读取温湿度

2021-02-01 13:01:36  阅读:174  来源: 互联网

标签:树莓 code 读取 温湿度 self ._ DHT DHT11


树莓派之DHT11传感器

硬件DHT11

主要看其原理,具体的详细原理大家就搜索引擎都能搜到。

也是为了好奇心,入手一台便宜的示波器,看看具体波形,下面是我所测:

IMG_5297

这张显示首次触发,主机至少下拉18ms。图中可以看到主机下拉快近30ms,其实代码实现中我也是用的是18ms。具体原因为什么会测出是快30ms下面谈到代码实现再解释。

IMG_2569

这张图显示的是主机拉高20~40us,但实际代码中并不需要主动拉高。

IMG_1418

这张图显示的是DHT11开始响应的信号80us低电平80us高电平,表示下面即将开始40位的数据输出。

IMG_6766

这张图显示的是一位数据0的表示即:50us的低电平26~28us的高电平。

IMG_4592

这张图显示的是一位数据1的表示:50us低电平70us高电平。

代码实现

之前有看到一个博客说是要修改/boot/config.txt,于是查看/boot/overlays/README的确有这么一段:

Name:   dht11
Info:   Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
        Also sometimes found with the part number(s) AM230x.
Load:   dtoverlay=dht11,<param>=<val>
Params: gpiopin                 GPIO connected to the sensor's DATA output.
                                (default 4)

但我实际测试时,开启和不开启都能测出同样的温湿度。我不知道这是什么原因,我的树莓派装的是64位的。如果有对这个了解的请给我科普一下。我觉得官方既然有这段话,肯定是有原因的。

现在补充下,开启dtoverlay=dht11就可以直接读取温湿度,不需要自己实现了:

$ sudo cat /sys/devices/platform/dht11@0/iio\:device0/in_temp_input             #读取温度
$ sudo cat /sys/devices/platform/dht11@0/iio\:device0/in_humidityrelative_input #读取湿度

但我实际使用过程中发现很多时候是读不出来,读出来的也都是0。网上查询了下,说是比较不稳定,遇到系统采样就读取错误。

下面是我读出的各种错误:

image-20210130133758253

这是湿度读取,有读取错误,也有读到0,反正大多数情况是读取错误,很少读取到0,没有一次读取到正确湿度。

image-20210130134049404

这是温度读取,有读到0,有读到错误,更有连接超时,也是大多数情况读取错误,很少情况读出0和连接超时,也是没有一次读到正确温度。

也在网上找了很多博客以及github上面对读DHT11数据的实现,发现很多都是使用计数器加死循环来读取数据的。感觉这样读是很不准确的,因为对树莓派我使用的都是远程连接库,这涉及到网络的延迟,毕竟你使用的计数器在本机并不在树莓派机器上。所以我采用了pigpio库的示例稍做修改,但也并不能完全排除网络延迟(触发时)。下面可以创建dht.py文件,将下面的代码复制进去:

import time
import pigpio

# 有效状态
DHT_GOOD = 0
# 校验不一致
DHT_BAD_CHECKSUM = 1
# 超出量程
DHT_BAD_DATA = 2
# 超时
DHT_TIMEOUT = 3


class sensor:
    """
    A class to read the DHT11 temperature/humidity sensors.
    """

    def __init__(self, pi, gpio, callback=None):
        """
        Instantiate with the Pi and the GPIO connected to the
        DHT temperature and humidity sensor.

        Optionally a callback may be specified.  If specified the
        callback will be called whenever a new reading is available.

        The callback receives a dictionary of GPIO, status,
        temperature, and humidity.

        The status will be one of:
        0 DHT_GOOD (a good reading)
        1 DHT_BAD_CHECKSUM (receieved data failed checksum check)
        2 DHT_BAD_DATA (data receieved had one or more invalid values)
        3 DHT_TIMEOUT (no response from sensor)
        """
        self._pi = pi
        self._gpio = gpio
        self._callback = callback

        # 标记数据是否解码完成
        self._new_data = False
        self._in_code = False

        # DHT11计数读取的bit位
        self._bits = 0
        # DHT11读取的数据
        self._code = 0

        # 标记数据的状态
        self._status = DHT_TIMEOUT
        self._temperature = 0.0
        self._humidity = 0.0

        pi.set_mode(gpio, pigpio.INPUT)
        self._last_edge_tick = pi.get_current_tick() - 10000
        # 上升沿触发,这是读取DHT11数据的方法,也是这段代码的核心
        self._cb_id = pi.callback(gpio, pigpio.RISING_EDGE, self._rising_edge)

    def _datum(self):
        return {'gpio': self._gpio, 'status': self._status,
                 'temperature': self._temperature, 'humidity': self._humidity}

    def _validate_DHT11(self, b1, b2, b3, b4):
        t = b2
        h = b4
        # 判断读取的温湿度是否超过DHT11的量程
        # 只要有一项在量程范围内即认为数据有效
        if ((t >= 0) and (t <= 50)) or ((h >= 20) and (h <= 90)):
            valid = True
        else:
            valid = False
        return (valid, t + b1 / 100, h + b3 / 100)

    def _decode_dht11(self):
        """
              +-------+
              | DHT11 |
              +-------+
        Temp C| 0-50  |
              +-------+
        RH%   | 20-80 |
              +-------+

                 0      1      2      3      4
              +------+------+------+------+------+
        DHT11 |check-| temp | temp | RH%  | RH%  |
              |sum   |      |      |      |      |
              +------+------+------+------+------+
        """
        b0 = self._code & 0xff
        b1 = (self._code >> 8) & 0xff
        b2 = (self._code >> 16) & 0xff
        b3 = (self._code >> 24) & 0xff
        b4 = (self._code >> 32) & 0xff

        chksum = (b1 + b2 + b3 + b4) & 0xFF

        if chksum == b0:
            valid, t, h = self._validate_DHT11(b1, b2, b3, b4)
            if valid:
                self._temperature = t
                self._humidity = h
                self._status = DHT_GOOD
            else:
                self._status = DHT_BAD_DATA
        else:
            self._status = DHT_BAD_CHECKSUM
        self._new_data = True

    def _rising_edge(self, gpio, level, tick):
        edge_len = pigpio.tickDiff(self._last_edge_tick, tick)
        self._last_edge_tick = tick
        if edge_len > 10000:
            self._in_code = True
            self._bits = -2
            self._code = 0
        elif self._in_code:
            self._bits += 1
            if self._bits >= 1:
                self._code <<= 1
                if (edge_len >= 60) and (edge_len <= 150):
                    if edge_len > 100:
                        # 1 bit
                        self._code += 1
                else:
                    # invalid bit
                    self._in_code = False
            if self._in_code:
                if self._bits == 40:
                    self._decode_dht11()
                    self._in_code = False

    def _trigger(self, ajust):
        self._new_data = False
        self._status = DHT_TIMEOUT
        self._pi.write(self._gpio, 0)
        time.sleep((18 + ajust) / 1000)
        self._pi.set_mode(self._gpio, pigpio.INPUT)

    def cancel(self):
        """
        """
        if self._cb_id is not None:
            self._cb_id.cancel()
            self._cb_id = None

    # 参数ajust用于远程连接时的微调可以为负数
    def read(self, ajust=0):
        """
        This triggers a read of the sensor.

        The returned data is a dictionary of GPIO, status,
        temperature, and humidity.

        The status will be one of:
        0 DHT_GOOD (a good reading)
        1 DHT_BAD_CHECKSUM (receieved data failed checksum check)
        2 DHT_BAD_DATA (data receieved had one or more invalid values)
        3 DHT_TIMEOUT (no response from sensor)
        """
        self._trigger(ajust)
        for i in range(5):  # timeout after 0.25 seconds.
            time.sleep(0.05)
            if self._new_data:
                break
        datum = self._datum()
        if self._callback is not None:
            self._callback(datum)
        return datum

这里使用的是上升沿触发,并且调用树莓派的tick这样避免了在本机使用计数器来读取数据的不准确性。但其中触发DHT11时使用的是本机的time.sleep,还记得上面图片主机下拉接近30ms吗?这就是因为调用的是本机线程的sleep。

标签:树莓,code,读取,温湿度,self,._,DHT,DHT11
来源: https://www.cnblogs.com/goalidea/p/14356046.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有