极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 23820|回复: 14

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

[复制链接]
发表于 2015-4-8 02:30:19 | 显示全部楼层 |阅读模式
本帖最后由 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 有小数, 格式不同)




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

使用道具 举报

发表于 2015-4-8 06:57:30 | 显示全部楼层
充分认识了dhtxxx后才可能写出这么好的帖子,谢谢分享。
回复 支持 反对

使用道具 举报

发表于 2015-4-8 09:00:01 | 显示全部楼层
好帖一定要顶
回复 支持 反对

使用道具 举报

 楼主| 发表于 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 !

回复 支持 反对

使用道具 举报

发表于 2015-4-8 10:39:23 | 显示全部楼层
谢谢分享学习一下
回复 支持 反对

使用道具 举报

发表于 2015-4-26 22:14:42 | 显示全部楼层
求如何不用mpu6050的库读取数据
还有
如何不用sd卡的库,对sd卡进行读写
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-27 00:16:10 | 显示全部楼层
fuwen0202 发表于 2015-4-26 22:14
求如何不用mpu6050的库读取数据
还有
如何不用sd卡的库,对sd卡进行读写

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

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

  http://www.geek-workshop.com/thread-4682-1-1.html
回复 支持 反对

使用道具 举报

 楼主| 发表于 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( ) {  ... } 这函数变可了解 !
好啦, 下次再补充说明这部分 :-)


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2015-4-29 08:58:44 | 显示全部楼层
谢谢分享!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-30 01:38:45 | 显示全部楼层
本帖最后由 tsaiwn 于 2015-4-30 07:44 编辑
tsaiwn 发表于 2015-4-29 01:43
补充说明:
  从图片(由 DHT11 的文件复制来的)得知,
要让 dht11 知道我们想要数据必须把讯号线(单总线)拉 ...



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

byte readData( ) {  // 每次读取 8 bits  ( one byte)
byte data;
// 以下用 for Loop 做八次,  每次读取  1  bits  ( 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(


回复 支持 反对

使用道具 举报

发表于 2015-5-7 15:59:22 | 显示全部楼层
666,大学单片机实验,用ds18b20就是这种逻辑,编程基本一致,没有库自己编真心要知道他的时序图啊,楼主给力!
回复 支持 反对

使用道具 举报

发表于 2015-10-31 17:11:42 | 显示全部楼层
请问下如果我想在1602 上显示,怎么把接收到的数值转换为字符呢?
回复 支持 反对

使用道具 举报

发表于 2018-1-14 18:30:14 | 显示全部楼层
确实是有点看不明白,照接线还没数据,不知道为什么?
回复 支持 反对

使用道具 举报

发表于 2018-1-17 16:15:53 | 显示全部楼层
为什么我的DH11读取的湿度乱跳,一下45,一下25?
回复 支持 反对

使用道具 举报

发表于 2018-1-24 08:04:52 | 显示全部楼层
赞。备案,好文,好人
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-18 19:56 , Processed in 0.054098 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表