tsaiwn 发表于 2015-4-29 03:39:05

【教程】 DHT11 湿度温度传感器 Q & A

本帖最后由 tsaiwn 于 2015-4-29 03:47 编辑

Q: DHT11 的教程何处找 ?
A:
   请看官方网站的关于 DHT11Lib:
      http://playground.arduino.cc/Main/DHT11Lib
   里面就有:
      dht11.h
      dht11.cpp
   以及范例 test_dewpoint.ino

   里面也有教你怎么用:
   (a)在 arduino IDE 的 libraries 目录下建立一个目录 dht11 (其实名称不重要),
      然后用文本编辑器复制贴上该 dht11.h 与 dht11.cpp 存盘到该 dht11 目录内!
   (b)建立新草稿码档案
      把 范例 test_dewpoint.ino 复制贴入即可
   (c)当然要记得把你 DHT11 传感器的 Data pin 连接到 Arduino 的 Pin 2
      ( 因为范例中用 #define DHT11PIN 2)


Q: DHT11 如何连接 ?
A:
   DHT11       Arduino
   VDD -----    5Volt 或 3.3V 也可
   Data -----任何 pin 都可接收信号
   NC   -----不管它
   GND-----   GND

Q: DHT11 要使用库文件吗 ?
A:
   不使用库直接写当然可以, 例如:
   http://www.geek-workshop.com/thread-14544-1-1.html
   但使用库可让你的程序码看起来短短的容易理解!(后面有给超级简单范例)

Q: DHT11 的库在哪 ?
A:
   网络上可以找到很多 DHT11 的库, 最简单的就刚刚最前面说的,
   在官方网站http://playground.arduino.cc/Main/DHT11Lib
   它有教你如何把库放进去(英文的? 我前面不是翻译了吗 !)
   好啦,
   我做成压缩文件放在最后(用我这去解压缩比较好, 用了后在IDE内仔细看我给的简单范例就知道!)


Q: DHT11 的库要如何安装 ?
A:
   刚刚说过了啊, 不然下载这篇内的 Dht11.zip 后,
   存到你的 arduino IDE 内的libraries 目录内, 解压缩即可!
   或是 Sketch>Import Library...>Add Library...
   然后选该下载的压缩文件
   注意这样安装库会跑到你的 sketch 草稿簿目录下的 libraries 目录!

Q: DHT11 的湿度与温度为何小数部分都永远是 0 ?
A:
   DHT11 本来就是湿度与温度都只有整数,
   如果你要有小数, 可改用 DHT22 / DHT33 / DHT44
   但注意 DHT11 的库不能用于 DHT22/33/44 喔, 可以改用这:
      http://playground.arduino.cc/Main/DHTLib

Q: 把 DHT11 与其他传感器合用后为何就湿度与温度都是 0 ?
A:
   DHT11 读取数据时不可以被 ISR( ) 中断太久,
   所以如果你其他会用到中断处理程序 ISR( ) 且会在 ISR( ) 内超过 20 us 那就可能会有问题!
   请注意, 20us 其实很久, 通常在 ISR( ) 内不应该做太多事情 !
   以 16MHz 的 clock 来说, 20us 大约可以执行 80句 C/C++ 语言的指令!
   此时简单的解决方式就是在对 DHT11 做 .read(pin); 之前写 cli( ); 禁止中断 !
   在 .read(pin); 之后立即写 sei( ); 以便允许中断 !

Q: 我只在ISR( ) 内做了 analogRead( ) 并把数据用 Serial.println( ) 共两句怎就出问题了?
   不是说可以用 20us 做 80句左右吗?
A:
   ㄟ, 那句 analogRead( ) 就要大约 108us 喔!
   请注意, analogRead( ) 不是一句, 是调用一个函数, 且该函数要等待硬件做 A to D 转换,
   所以像这要花掉大约 0.11 ms 的句子不太应该在 ISR( ) 内做
   另外, Serial.print( ) 虽然通常不太占用 CPU 时间,
   但是串口输出缓存区只有 64 char, 如果你的中断来得太快,
   导致把串口输出缓存区塞满, 则之后的 .print( ) 就变成要花 CPU 的时间等待,
   在波特率 9600 之下, 打印一个 char 就要大约 1.1ms = 1100us,
   这是非常非常慢的事!
   所以通常建议不可以在中断处理程序内做 Serial.print 输出的事情 !

Q: 为何湿度与温度都不会变 ?
A:
   你可能只有在 setup( ) 内对 dht11 做 .read(pin) 一次,
   然后在 loop( ) { 内都没再去 .read(pin);
   注意, 如果 DHT11 是代表 dht11 的类别对象(对象, Object),
   则 DHT11.read(2); 才是通过 Pin 2 去跟 DHT11 要数据,
   如果你只是写 int temp = DHT11.temperature;
   这样只是拿到上次 .read( ) 拿回内存的温度, 并没有去跟 DHT11 要数据 !!

Q: 官方网站的范例太复杂, 有没有简单些的范例 ?
A:
   好吧, 我就写一个超级短的范例给大家测试:
   (也放入了底下的Dht11.zip压缩文件内)
   (dht11 庫要用我这去解压缩比较好, 至于怎么好, 用了后在IDE内仔细看我给的简单范例就知道!)

//simple dht11 testing example -- by tsaiwn @ cs.nctu.edu.tw
#include <dht11.h>
dht11 ggyy;   // 注意现在 ggyy 代表 DHT11 传感器
const int pin = 2;// 请把 DHT11 的 data pin 连到 arduino Pin 2
void setup( ) {
Serial.begin(9600);
}
void loop( ) {
ggyy.read(pin);// 读取 DHT11 传感器
Serial.print(String("") + "Humidity = "+ ggyy.humidity + " %");
Serial.println(String("")+", temperature = "+ ggyy.temperature +" °C");
delay(2222);// 规定至少要等 2 秒再次读 dht11
}

这样够简短了吧 ?

tsaiwn 发表于 2015-4-29 03:57:15

这也补一张图片方便查看

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

tsaiwn 发表于 2015-4-29 04:01:26

tsaiwn 发表于 2015-4-29 03:57 static/image/common/back.gif
这也补一张图片方便查看

方便查看
Reference
   http://playground.arduino.cc/Main/DHT11Lib

dht11.h//
//    FILE: dht11.h
// VERSION: 0.4.1
// PURPOSE: DHT11 Temperature & Humidity Sensor library for Arduino
// LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
//
// DATASHEET: http://www.micro4you.com/files/sensor/DHT11.pdf
//
//   URL: http://playground.arduino.cc/Main/DHT11Lib
//
// HISTORY:
// George Hadjikyriacou - Original version
// see dht.cpp file
//

#ifndef dht11_h
#define dht11_h

#if defined(ARDUINO) && (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

#define DHT11LIB_VERSION "0.4.1"

#define DHTLIB_OK                                0
#define DHTLIB_ERROR_CHECKSUM        -1
#define DHTLIB_ERROR_TIMEOUT        -2

class dht11
{
public:
    int read(int pin);
        int humidity;
        int temperature;
};
#endif
//
// END OF FILE
//dht11.cpp//
//    FILE: dht11.cpp
// VERSION: 0.4.1
// PURPOSE: DHT11 Temperature & Humidity Sensor library for Arduino
// LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
//
// DATASHEET: http://www.micro4you.com/files/sensor/DHT11.pdf
//
// HISTORY:
// George Hadjikyriacou - Original version (??)
// Mod by SimKard - Version 0.2 (24/11/2010)
// Mod by Rob Tillaart - Version 0.3 (28/03/2011)
// + added comments
// + removed all non DHT11 specific code
// + added references
// Mod by Rob Tillaart - Version 0.4 (17/03/2012)
// + added 1.0 support
// Mod by Rob Tillaart - Version 0.4.1 (19/05/2012)
// + added error codes
//

#include "dht11.h"

// Return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht11::read(int pin)
{
        // BUFFER TO RECEIVE
        uint8_t bits;
        uint8_t cnt = 7;
        uint8_t idx = 0;

        // EMPTY BUFFER
        for (int i=0; i< 5; i++) bits = 0;

        // REQUEST SAMPLE
        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW);
        delay(18);
        digitalWrite(pin, HIGH);
        delayMicroseconds(40);
        pinMode(pin, INPUT);

        // ACKNOWLEDGE or TIMEOUT
        unsigned int loopCnt = 10000;
        while(digitalRead(pin) == LOW)
                if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

        loopCnt = 10000;
        while(digitalRead(pin) == HIGH)
                if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

        // READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
        for (int i=0; i<40; i++)
        {
                loopCnt = 10000;
                while(digitalRead(pin) == LOW)
                        if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

                unsigned long t = micros();

                loopCnt = 10000;
                while(digitalRead(pin) == HIGH)
                        if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

                if ((micros() - t) > 40) bits |= (1 << cnt);
                if (cnt == 0)   // next byte?
                {
                        cnt = 7;    // restart at MSB
                        idx++;      // next byte!
                }
                else cnt--;
        }

        // WRITE TO RIGHT VARS
      // as bits and bits are allways zero they are omitted in formulas.
        humidity    = bits;
        temperature = bits;

        uint8_t sum = bits + bits;

        if (bits != sum) return DHTLIB_ERROR_CHECKSUM;
        return DHTLIB_OK;
}
//
// END OF FILE
//

suoma 发表于 2015-4-29 10:59:42

谢谢分享学习一下

tsaiwn 发表于 2015-4-30 01:23:58

本帖最后由 tsaiwn 于 2015-4-30 01:28 编辑

tsaiwn 发表于 2015-4-29 04:01 static/image/common/back.gif
方便查看
Reference
   http://playground.arduino.cc/Main/DHT11Lib



再补充说明以下这段:

   这时 pin 刚变 LOW 表示 1 bit 正要传送过来
                loopCnt = 10000;
                while(digitalRead(pin) == LOW)
                        if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
   依据图片, dht11 的每个 bit 开始会拉低 50 us
   所以, 如果等了 51 us 还没变 HIGH 就可判定 timeout
   可是保险起见, 通常我们会多等一下, 例如等 80 us
   所以, 其实上述 loopCnt 应该设 300 就够了, 设 10000 是更保守 :)
   如果 time out 就 return 返回了,
   会到这表示此时 pin 变 HIGH,
   立即用 t 记下 micros( )

                unsigned long t = micros();

                loopCnt = 10000;
                while(digitalRead(pin) == HIGH)
                        if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
依据图片, 如果这 bit 是 0,
则 dht11 会在 28 us 后拉低 pin,
如果这 bit 是 1, 则会让 pin 在 HIGH 维持 70 us 才拉低电平;
因此, 只要超过 90 us ( 保守一点啦)没变 LOW 就可判定 timeout
不过这 loopCnt = 10000; 相当于至少 250 us是超级保守啰!
                if ((micros() - t) > 40) bits |= (1 << cnt);
    这句 if 是说如果收到的是 1 就把 1 塞入该 Byte 该有的位置
为何用 micros( ) -t > 40 作条件呢?
因为刚说了, 依据图片如果 bit 是 0, 则 HIGH 应维持约 28us,
      如果 bit 是 1, 则 HIGH 应维持 70 us;
      假如你用 micros( ) -t > 30 当然也可以,
      可是 28 和 30 太近, 万一 dht 自己时序不准确呢 !?
      所以保守一点, 用 40 us 当作门坎 !
      假如用 70 us 当门坎则也很危险,
      因万一 dht11 不准确在 68 us 就拉低, 那 1 就被判为 0 了,
      所以, 最好的门坎应该在 40 到 55 之间 !
还有,
从这就可看出万一你在 ISR( ) 内做太多事会影响 dht11 读取!
你看, 假如你刚做了 unsigned long t = micros();
然后就被 ISR( ) 抢走 CPU 执行权,
只要在 ISR( )内做超过 70 us 就铁定出问题 !
Why ?
因为这时 pin 一定已经变 LOW,
然而在 ISR( ) 内因为中断禁止会导致 micros( ) 几乎不变!
   (注意, 中断禁止是 millis( ) 不会变, 但 micros( )略为会变!)
这样相当于 Arduino 这边时间静止, 但其实 dht11 已经过了 70us,
于是到底是 0 还是 1 我们会搞错!
如果 ISR( ) 做事超过 78us, 甚至可能影响下一个 bit 的接收!
这里的 78us 是因为万一这 bit 是 0, 会在 28 us 后拉低电平,
表示另一个 bit 即将开始, 依据图片, 开始是拉低持续 50us,
所以, 78 us 之后我们就又拉高, 这样我们没看到拉低,
相当于错过了一个 bit 啰 !

注意喔,
一个 analogRead( ) 就要大约 108us =大约0.11 ms
所以, 尽量不要在 ISR( ) 内做analogRead( )

yanglang00 发表于 2015-5-7 19:28:00

为什么DHT11返回的值是乱码的啊

tsaiwn 发表于 2015-5-7 20:52:42

yanglang00 发表于 2015-5-7 19:28 static/image/common/back.gif
为什么DHT11返回的值是乱码的啊

什么叫做返回乱码
DHT11 返回的一定是 int
int 任何数值都是可能的整型,
如果你把它当作一个 char 就有可能是乱码 !

yanglang00 发表于 2015-5-8 14:26:29

谢谢偶,差不多搞定了,原来是板卡选择错了

hyshen 发表于 2015-10-29 19:00:22

能加个QQ吗 我有一些问题想请教你

13543016677 发表于 2015-11-13 12:12:05

....大哥,您太 他 妈 精 辟了!!!!这一篇我断断续续从昨天晚上看到了现在,有些地方反复看了好几次!!谢您了,收获良多!!

哪天,能开个贴介绍一下mpu6050之类的姿态传感器吗?

keneng 发表于 2015-11-13 22:14:27

说的很详细了

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

高人分享的确实6666

wulisys 发表于 2018-1-16 15:00:56

为什么我的DH11湿度会乱跳。

amiao 发表于 2018-4-19 19:27:57

您好,为什么我用的源程序,测试之后温度湿度一直显示零度

zjbhm 发表于 2020-2-6 17:49:30

问下要用几个dht11该怎么做呢?
页: [1]
查看完整版本: 【教程】 DHT11 湿度温度传感器 Q & A