【教程】 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
}
这样够简短了吧 ? 这也补一张图片方便查看
http://image.geek-workshop.com/forum/201504/29/014828lw3igene2aeweq6d.jpg 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
// 谢谢分享学习一下 本帖最后由 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( )
为什么DHT11返回的值是乱码的啊 yanglang00 发表于 2015-5-7 19:28 static/image/common/back.gif
为什么DHT11返回的值是乱码的啊
什么叫做返回乱码
DHT11 返回的一定是 int
int 任何数值都是可能的整型,
如果你把它当作一个 char 就有可能是乱码 !
谢谢偶,差不多搞定了,原来是板卡选择错了 能加个QQ吗 我有一些问题想请教你 ....大哥,您太 他 妈 精 辟了!!!!这一篇我断断续续从昨天晚上看到了现在,有些地方反复看了好几次!!谢您了,收获良多!!
哪天,能开个贴介绍一下mpu6050之类的姿态传感器吗? 说的很详细了 高人分享的确实6666 为什么我的DH11湿度会乱跳。 您好,为什么我用的源程序,测试之后温度湿度一直显示零度 问下要用几个dht11该怎么做呢?
页:
[1]