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却无果,就是败在了这里,其实只要判断有没有两次转变就行了。


你好
你好1
你好1