tsaiwn 发表于 2015-4-8 02:30:19

【教程】不使用 DHTxx 庫, 如何自己读取 DHT11 湿度温度 ?

本帖最后由 tsaiwn 于 2015-4-29 01:49 编辑

其实读取 DHTxx 没啥学问, 可以不使用DHTxx 庫 !
    Arduino 每次与 DHT11 沟通可读取 40 bits == 也就是 5 bytes,
其中 2 bytes 是湿度, 2 bytes 是温度,
然后这 4 bytes 加起来除以 256取余数(称 checkSum)必须等於第 5 bytes
否则表示接收资讯错误 !
可忽略第 5 byte,
仍然拿湿度温度来用!
不过大部分的DHTxx 库是如果发现 第 5 byte 不等於4 bytes的 checksum ,
那就不使用收到的湿度温度资讯!
至於只有一条信號线要如何读取呢:
看看以下这我从淘宝网抄来, 我修改过並加入注释的 DHT11 范例:
(不能用於 DHT22, 因为DHT11 只有整数, DHT22 有小数, 格式不同)

http://image.geek-workshop.com/forum/201504/29/014828lw3igene2aeweq6d.jpg


//Test the DHT11 -- Modified by [email protected]
int dhPin = 8;// 温溼度讯號接脚连入 Arduino 的 Pin 8
byte dat;   // 存放湿度2byte, 温度 2 byte, checksum 1 byte
byte readData( ) {// 每次读取 8 bits( one byte)
byte data;
for(int i=0; i<8; i++) {
if(digitalRead(dhPin) == LOW) {   // 一开始要 LOW 才表示要传过来
    while(digitalRead(dhPin) == LOW); //等待 50us;
    // 现在已经变成 HIGH 了
    delayMicroseconds(30); //判断高电平持续时间,以判定资料是‘0’还是‘1’;
    if(digitalRead(dhPin) == HIGH)// 持续了 30 us 以上就是 1
      data |= (1<<(7-i)); //高位在前,低位元在后;
    //如果这时已经是 LOW, 表示这 bit 是 0, 不必塞入 data
    //..而且以下的 while 也会立即结束(因为 LOW), 准备接收下一个 bit
    while(digitalRead(dhPin) == HIGH); // 等待下一bit的接收;
    //这时一定已经变成 LOW 了
}// if
}// for(
return data;   // 收完 8 bit = one byte = one char
} // readData(
void start_test() {// 每次要与 DHT11 沟通
digitalWrite(dhPin,LOW); //拉低到 LOW,发表示要开始沟通的信號;
delay(30); //延时要大於 18ms,以便 DHT11 能检测到开始信號;我们用30ms
digitalWrite(dhPin,HIGH);   // 拉高HIGH, 让 DHT11 拉低到 LOW 告诉我们要传送
delayMicroseconds(40);// 给40us等待 DHT11 响应;
pinMode(dhPin,INPUT);// 改为输入 mode 准备 digitalRead( )
while(digitalRead(dhPin) == HIGH);   // 必须等到 LOW
delayMicroseconds(80); //DHT11 发出响应,会拉低 80us;所以至少等80us
while(digitalRead(dhPin) == LOW);// 继续等到变 HIGH
delayMicroseconds(80); //DHT11 会拉高到HIGH 80us 后开始发送资料;
/// 以下连续读入 5 bytes (40 bits), 最后的 byte 是 checksum 校验值
for(int i=0;i < 5;i++) dat = readData( ); //接收温湿度资料,校验位元;
pinMode(dhPin,OUTPUT);// 改为 Output mode, 准备拉高HIGH
digitalWrite(dhPin,HIGH); //发送完一次资料后释放bus,等待下一次开始信號;
}
void setup() {Serial.begin(9600);pinMode(dhPin, OUTPUT); }
void loop() {
start_test( );// 读取湿度温度和检核位到 dat[ ]; 其中dat是checkSum
// 根据datasheet规定, dat 要 == (dat+dat+dat+dat) %256
// 否则表示沟通有错误 !!
Serial.print("Current humdity = ");
Serial.print(dat, DEC); //显示湿度的整数部分;
Serial.print('.');
Serial.print(dat,DEC); //显示湿度的小数位;(其实是 0)
Serial.println(" %");// 注意有空格要用 " %"不可用 ' %'
Serial.print("Current temperature = ");
Serial.print(dat, DEC); //显示温度的整数部分;
Serial.print('.');
Serial.print(dat,DEC); //显示温度的小数位;(其实是 0)
Serial.println(" C");
delay(1985);
} /// http://keyes-arduino.taobao.com
// Also seehttp://playground.arduino.cc/main/DHT11Lib

topdog 发表于 2015-4-8 06:57:30

充分认识了dhtxxx后才可能写出这么好的帖子,谢谢分享。

huan 发表于 2015-4-8 09:00:01

好帖一定要顶

tsaiwn 发表于 2015-4-8 09:18:49


补充说明:
    这程序的写法没考虑到 time out, 里面类似以下的 while Loop 一直等待变 LOW (或相反):
      while(digitalRead(dhPin) == HIGH); // 收完资料‘1’,等待下一bit的接收;
      // 如果有到这, 这时一定已经变成 LOW 了
这样很可能陷入无尽的循环而不结束 !
更好的写法是要考虑 Time out,
         例如, 很多 DHTxx 库都是直接用一个 for Loop 做相当多次 digitalRead(dhtPin);
如果 for Loop 做完都没变化就是 Time out !

suoma 发表于 2015-4-8 10:39:23

谢谢分享学习一下

fuwen0202 发表于 2015-4-26 22:14:42

求如何不用mpu6050的库读取数据
还有
如何不用sd卡的库,对sd卡进行读写

tsaiwn 发表于 2015-4-27 00:16:10

fuwen0202 发表于 2015-4-26 22:14 static/image/common/back.gif
求如何不用mpu6050的库读取数据
还有
如何不用sd卡的库,对sd卡进行读写

这比较麻烦, 你要先大略看看 IIC 通信
然后看看弘毅大神的这两篇:

http://www.geek-workshop.com/thread-4502-1-1.html

http://www.geek-workshop.com/thread-4682-1-1.html

tsaiwn 发表于 2015-4-29 01:43:00

本帖最后由 tsaiwn 于 2015-4-29 01:49 编辑

补充说明:
从图片(由 DHT11 的文件复制来的)得知,
要让 dht11 知道我们想要数据必须把讯号线(单总线)拉低超过 18ms
于是:
digitalWrite(dhPin,LOW); //拉低到 LOW,发表示要开始沟通的信号;
delay(30); //延时要大于 18ms,以便 DHT11 能检测到开始信号;我们用30ms

接着, 我们(主机, Arduino)必须拉高持续 20-40us 等着 DHT11 拉低,
于是:
digitalWrite(dhPin,HIGH);   // 拉高HIGH, 让 DHT11 拉低到 LOW 告诉我们要传送
delayMicroseconds(40);// 给40us等待 DHT11 响应;
pinMode(dhPin,INPUT);// 改为输入 mode 准备 digitalRead( )
while(digitalRead(dhPin) == HIGH);   // 必须等到 LOW
注意,
当我们拉高 40 us 后,
因为要等 DHT11 拉低, 所以我们先把 dhPin 改为 INPUT mode,
然后用 while 配合读取 dhPin, 会一直 Loop 到 dhPin 变 Low
当然, 如果 while 一开始就发现 dhPin 是 LOW 则会立即结束 while;
接着, 根据图片我们必须等 80 us 让 DHT11 有时间准备 !
于是:
delayMicroseconds(80); //DHT11 发出响应,会拉低 80us;所以至少等80us

接着, 依据图片, DHT11 会拉高电平持续 80 us,
然后就会又拉低做为要传送 1 bit 的开始,
于是要这样:
while(digitalRead(dhPin) == LOW);// 继续等到变 HIGH
delayMicroseconds(80); //DHT11 会拉高到HIGH 80us 后开始发送资料;
再来,
就是 DHT11 要连续发送 40 bits 给我们(主机, Arduino)了,
为了方便, DHT11 会把 40 bits 切开为五次, 每次是 一个 byte 也就是 8 bits,
于是我们这样:
for(int i=0;i < 5;i++) dat[ i ] = readData( ); //接收温湿度资料,校验位;
把每次收到的 8 bits 存入 dat[ i ] 内
至于每次 8 bits 要如何接收呢?
可以自己看看图片对照byte readData( ) {... } 这函数变可了解 !
好啦, 下次再补充说明这部分 :-)


hardstudy12345 发表于 2015-4-29 08:58:44

谢谢分享!

tsaiwn 发表于 2015-4-30 01:38:45

本帖最后由 tsaiwn 于 2015-4-30 07:44 编辑

tsaiwn 发表于 2015-4-29 01:43 static/image/common/back.gif
补充说明:
从图片(由 DHT11 的文件复制来的)得知,
要让 dht11 知道我们想要数据必须把讯号线(单总线)拉 ...


再补充..
每次到底如何接收 8 bits 呢 ?
就是由以下函数负责..

byte readData( ) {// 每次读取 8 bits( one byte)
byte data;
// 以下用 for Loop 做八次,每次读取1bits( 0 或 1 )
for(int i=0; i<8; i++) {
// 以下的 if 只是防止万一, 其实是多余的 !
// 因到这 dhPin 一定是 LOW
if(digitalRead(dhPin) == LOW) {   // 一开始要 LOW 才表示要传过来
    while(digitalRead(dhPin) == LOW); //等待 50us;
    // 依据图片, 应该 50us 后会被 dht11 拉高,
    // 现在这样写就是一直等到变 HIGH, 没检查 timeout, 很可能髂在这 !!
    // 如果到这, 现在已经变成 HIGH 了
    delayMicroseconds(30); //判断高电平持续时间,以判定资料是‘0’还是‘1’;
    // 依据图片, 若 bit是 0 则 HIGH 会维持 26us-28us
    // 这里用 30 us 当作检查门坎 (其实最好该用 35 ~ 55 之间)

    if(digitalRead(dhPin) == HIGH)// 持续了 30 us 以上就是 1
      data |= (1<<(7-i)); //高位在前,低位在后;
    //如果这时已经是 LOW, 表示这 bit 是 0, 不必塞入 data
    //..而且以下的 while 也会立即结束(因为 LOW), 准备接收下一个 bit
    while(digitalRead(dhPin) == HIGH); // 等待下一bit的接收;
    //这时一定已经变成 LOW 了, 表示下一个 bit 即将开始
}// if
// 一个 for LOOP 做完是收取了 8 bits
}// for(
return data;   // 收完 8 bit = one byte = one char
} // readData(


Huanjl 发表于 2015-5-7 15:59:22

666,大学单片机实验,用ds18b20就是这种逻辑,编程基本一致,没有库自己编真心要知道他的时序图啊,楼主给力!

213菜鸟 发表于 2015-10-31 17:11:42

请问下如果我想在1602 上显示,怎么把接收到的数值转换为字符呢?

方恨少 发表于 2018-1-14 18:30:14

确实是有点看不明白,照接线还没数据,不知道为什么?

wulisys 发表于 2018-1-17 16:15:53

为什么我的DH11读取的湿度乱跳,一下45,一下25?

chaqing 发表于 2018-1-24 08:04:52

赞。备案,好文,好人
页: [1]
查看完整版本: 【教程】不使用 DHTxx 庫, 如何自己读取 DHT11 湿度温度 ?