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