末日生存装置(DHT22)

末日生存装置(DHT22)

/ 3评 / 2601次 / 2

upd:2020.3.19

欢迎star https://github.com/jscblack/Survive-in-the-Doomsday

今天所有的东西终于到货了。

来张全家福!

作为所有传感器当中唯一一个以数字信号输出的传感器,DHT22成为了我的计划的第一步。

首先我们来看文档,

可以看到,我们首先需要保持树莓派端引脚处于高电平,当然因为我买的是一个模组,已经自带了上拉电阻,如果你购买的是单个AM2302传感器,你就还需要额外购买一个5.1k电阻,并如下图接线。

步骤二我们就需要唤醒传感器,比较简单就可以实现,将GPIO口设置为OUTPUT并维持低电平,至少1ms,之后施加高电平,经过短暂的2μs之后便可以等待传感器的响应信号了

//host send start signal
    pinMode(dht22, OUTPUT);   //set pin to output
    digitalWrite(dht22, LOW); //set to low at least 1ms
    delay(1);
    digitalWrite(dht22, HIGH); //set to high 20-30us
    delayMicroseconds(25);

这便是一个典型的唤醒代码。

确定之后我们便可以读取数据了,低电平的维持时间是恒定的50μs,我们只需要去测量高电平所维持的时间即可,比较方便的测量方法就是利用循环次数+delay去实现,(这里涉及到相关系统中断的知识,暂且按下不表),通过检测高低电平的转换即可实现这个过程,有点类似我们所熟悉的字符串处理?

cnt = 0; //for recording the lenth of HIGH and LOW
        while (digitalRead(dht22) == las)
        { //read pin state to see if dht responsed. if dht always high for 255 + 1 times, break this while circle
            cnt++;
            delayMicroseconds(1);
            if (cnt == 255)
                break;
        }
        las = digitalRead(dht22); //read current state and store as last state.

利用一个cnt计数器去记录维系时间即可

并利用维系的时间去判断即可,有图示可知,高电平维系超过26μs就为非0了,我们可以将判断阈值设为30μs。

接着我们处理读入的数据即可,根据文档示例,一组数据包含8位,构成一个8位整数,我们按8位一组,读入数组

if (cnt == 255)       //if dht always high for 255 + 1 times, break this for circle
            break;
        // top 3 transistions are ignored, maybe aim to wait for dht finish response signal
        if ((i >= 3) && (i % 2 == 1))
        {
            dht22_val[j / 8] <<= 1;    //write 1 bit to 0 by moving left (auto add 0)
            if (cnt > 30)          //long mean 1(while short is shorter than 28)
                dht22_val[j / 8] |= 1; //write 1 bit to 1
            j++;
        }

最后根据校验位验证数据并加以计算即可

if ((j == 40) && (dht22_val[4] == ((dht22_val[0] + dht22_val[1] + dht22_val[2] + dht22_val[3]) & 0xFF)))
    {
        float f, h;
        h = dht22_val[0] * 256 + dht22_val[1];
        h /= 10.0;
        f = (dht22_val[2] & 0x7F) * 256 + dht22_val[3];
        f /= 10.0;
        if (dht22_val[2] & 0x80)//below zero
            f *= -1;
        printf("Temp =  %.1f *C, Hum = %.1f %% \n", f, h);
        return 1;
    }

最后放出完整代码

/*
 * @Author: Gehrychiang
 * @LastEditTime: 2020-03-19 22:33:29
 * @Website: www.yilantingfeng.site
 * @E-mail: gehrychiang@aliyun.com
 */
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int dht22_val[5] = {0, 0, 0, 0, 0}; //according to the docu 8 bit per group

int dht22_read_val()
{
    int dht22 = 1;
    int max_time = 100;
    uint8_t las = LOW; //last state
    uint8_t cnt = 0;
    uint8_t j = 0, i;
    memset(dht22_val, 0, 40);

    //host send start signal
    pinMode(dht22, OUTPUT);   //set pin to output
    digitalWrite(dht22, LOW); //set to low at least 1ms
    delay(1);
    digitalWrite(dht22, HIGH); //set to high 20-30us
    delayMicroseconds(25);

    //start recieve dht response
    pinMode(dht22, INPUT); //set pin to input
    for (i = 0; i < max_time; i++)
    {
        cnt = 0; //for recording the lenth of HIGH and LOW
        while (digitalRead(dht22) == las)
        { //read pin state to see if dht responsed. if dht always high for 255 + 1 times, break this while circle
            cnt++;
            delayMicroseconds(1);
            if (cnt == 255)
                break;
        }
        las = digitalRead(dht22); //read current state and store as last state.
        if (cnt == 255)           //if dht always high for 255 + 1 times, break this for circle
            break;
        // top 3 transistions are ignored, maybe aim to wait for dht finish response signal
        if ((i >= 3) && (i % 2 == 1))
        {
            dht22_val[j / 8] <<= 1;    //write 1 bit to 0 by moving left (auto add 0)
            if (cnt > 30)              //long mean 1(while short is shorter than 28)
                dht22_val[j / 8] |= 1; //write 1 bit to 1
            j++;
        }
    }
    //printf("i readed successfully\n");
    // verify checksum and print the verified data
    if ((j == 40) && (dht22_val[4] == ((dht22_val[0] + dht22_val[1] + dht22_val[2] + dht22_val[3]) & 0xFF)))
    {
        float f, h;
        h = dht22_val[0] * 256 + dht22_val[1];
        h /= 10.0;
        f = (dht22_val[2] & 0x7F) * 256 + dht22_val[3];
        f /= 10.0;
        if (dht22_val[2] & 0x80) //whether below zero
            f *= -1;
        printf("Temp =  %.1f *C, Hum = %.1f %% \n", f, h);
        return 1;
    }
    else
    {
        //printf("i failed the check\n");
        return 0;
    }
}

int main()
{
    if (wiringPiSetup() == -1)
    {
        exit(1);//fail to initialize, please to check the root
    }

    for (int i = 0; i < 5;)
    {
        int res = dht22_read_val();
        if (res)
        {
            i++;
        }
        delay(2500); //accord to the doc,not recommend to read with an interval less than 2s
    }
    return 0;
}

写在最后:读取数字信号的时候时序很重要,但不必须,也不必苛求,我就遇到了时序上的未知问题,也许是io这边的也许是sensor那边的,但是就出现时序与文档不相符的情况,所以我们这边只是根据大小的转变关系去判断此时状态,以及只有在比较大差距的时候用来判断0和1,其他的时候持续时间都不宜作为一个衡量是否正常工作的指标,就比如我一度尝试去判断来自传感器的response却无果,就是败在了这里,其实只要判断有没有两次转变就行了。

《“末日生存装置(DHT22)”》 有 3 条评论

发表回复

您的电子邮箱地址不会被公开。

你好 No.66803