在前一教程,我们学习了如何将LM35温度传感器与Arduino连接。LM35是一个模拟传感器,可以与Arduino的模拟输入引脚接口。
在本教程中,我们将介绍如何将DHT-11传感器与Arduino连接。DHT-11是一种数字式温湿度传感器。它输出比模拟传感器更精确的温度读数。DHT-11的输出是一个数字信号,可以通过Arduino的数字I/O引脚读取。
然而,传感器的数字输出不符合常见的串行数据协议,如UART、SPI或I2C。相反,DHT-11通过一种单线协议进行传感器数据的数字通信。
在本教程中,我们将连接DHT-11传感器与Arduino,从它读取传感器数据,而不需要外部库的帮助。传感器的读数在Arduino的串行监视器上观察,在那里Arduino和桌面计算机之间建立串行(UART)通信。让我们开始吧。
DHT-11传感器
DHT-11是一种基本的数字温湿度传感器。该传感器预先校准,不需要外部电路来测量温度或湿度。
对于感应湿度,DHT-11具有一个电阻元件,该元件具有两个电极,电极之间有一个保持湿度的衬底。当基底吸收水蒸气时,它会释放离子,增加电极之间的电导率。
当相对湿度较高时,电极之间的电阻减小,当相对湿度较低时,电极之间的电阻增大。这种电阻的变化与相对湿度成正比。
对于感知温度,DHT-11有一个NTC热敏电阻,这是一个热电阻。DHT11中的热敏电阻具有负的温度系数,因此其电阻随温度的升高而减小。
该传感器包含一个14针8位微控制器IC:
- 感应来自防潮元件和热敏电阻的模拟信号
- 根据存储的校准系数,将模拟电压转换为数字值
- 输出一个数字信号,包含湿度、温度和校验和字节的值
DHT-11传感器读取相对湿度值的百分比范围为20 ~ 90% RH。它能感知摄氏温度,范围从0˚C到50˚C。
DHT11传感器有这样的引脚图:
DHT11传感器有这样的引脚配置:
湿度、温度传感器功耗为0.3 mA,待机功耗为60ua。湿度精度为+/- 1%,温度为+/- 1˚C。该传感器能以1hz(即每秒一次)的最大采样率输出数据。然而,两次阅读之间需要更多的时间。
数据输出信号的电压水平取决于对DHT11传感器的电源。如果是5V供电,那么5V是来自TON传感器的数字信号的电平(来自传感器的数字脉冲是ON的时间)。0V为TOFF(来自传感器的数字脉冲为OFF时)的数字信号电平。
在5V电源的情况下,DATA引脚可以有20米的最大电缆连接到控制器引脚。如果传感器在3V3中提供,那么3.3V是来自传感器的数字信号的级别,对于TON,而0V是数字信号的级别,对于TOFF。使用3V3电源,DATA引脚可以有1米的最大电缆到控制器引脚。
DHT11传感器模块
DHT11传感器模块也可选。该模块有一个内置的支持电路,这意味着传感器可以在没有额外电路的情况下进行接口。该模块在VCC和DATA引脚之间有一个10 KΩ上拉电阻,电源上有一个去耦电容,用于滤波噪声。
该模块只有三个引脚:VCC、DATA和Ground。
为了支持该电路,传感器模块必须确保与控制器进行适当的通信。如果使用传感器,可以使用外部上拉电阻。微控制器板的GPIO有内置的上拉和下拉电阻。这确保了DHT11传感器的DATA引脚可以直接与配置为使用内部拉起的微控制器引脚连接。
DHT11 vs DHT22
DHT22是同一家族的传感器。它与DHT11传感器保持相同的引脚配置、电源电压和电流消耗。然而,DHT22测量的湿度范围为0 ~ 100% RH,精度为2 ~ 5%。它还可以测量温度范围从-40˚到125˚C,精度为+/- 0.5˚C。
DHT22的最大采样率是0.5 Hz(即每2秒一次)。DHT11和DHT22传感器都用于环境监测、当地气象站和自动气候控制等应用。
DHT-11与Arduino接口
DHT-11传感器可以直接与Arduino对接。它可以从Arduino提供5V DC和接地。传感器的数据引脚也可以直接连接到Arduino的任何数字I/O引脚。但是它所连接的数字I/O引脚必须配置为使用内部上拉。否则,VCC和DHT-11的DATA引脚之间必须连接一个10K的外部上拉电阻。另外,也可以使用DHT-11传感器模块。
DHT11是如何工作的
DHT-11传感器使用一种单线协议来通信湿度和温度值。传感器充当主控制器的从控制器。
DHT11与主控制器(如Arduino)之间的数字通信可分为四个步骤:
1.开始信号.主机(Arduino)需要向DHT11传感器的DATA引脚发送启动信号,才能与DHT11传感器进行通信。DATA引脚在默认情况下被拉高。开始信号是一个持续18毫秒的逻辑LOW,随后是一个LOW-to- high转换(上升边)。
2.响应。从主机接收到启动信号后,DHT-11发送响应信号,表示它已经准备好传输传感器数据。响应脉冲是54微秒的逻辑LOW,然后是80微秒的逻辑HIGH。
3.数据。在发送响应脉冲后,DHT11将开始传输包含湿度、温度和校验和字节值的传感器数据。数据包由40位组成,包含5个8位段或字节。
前两个字节包含相对湿度值,其中第一个字节是湿度值的整数部分,第二个字节是湿度值的小数部分。接下来的两个字节包含温度值,其中第三个字节是温度值的整数部分,第四个字节是温度值的小数部分。
最后一个字节是校验和字节,它必须等于前四个字节的二进制和。如果校验和字节不等于湿度和温度值的二进制和,则值中有错误。
比特作为定时信号传输,其中数字信号的脉冲宽度决定了它是位1还是位0。位0从一个逻辑LOW信号(Ground)开始,持续54微秒,然后是一个逻辑HIGH信号(VCC),持续24微秒。
第1位从一个逻辑低信号(接地)开始,持续54微秒,然后是一个逻辑高信号(VCC),持续70微秒。
4.帧的结束。传输40位数据包后,传感器发送一个逻辑低54微秒,然后将拉高的数据引脚。在此之后,传感器进入低功耗睡眠模式。来自传感器的数据可以以1hz或每秒一次的速率采样。
从DHT11读取传感器数据
为了从DHT11传感器读取传感器数据,Arduino必须首先向它发送启动信号。为此,DHT11的DATA引脚必须设置为数字输出。一个18毫秒的数字脉冲必须传递到DATA引脚,然后是一个上升的边缘。随后,必须将Arduino引脚设置为具有内部上拉功能的数字输入。
现在,在Arduino引脚上读取来自DHT11的响应信号。如果在90微秒内检测到下降边缘,这意味着DHT11成功地发送了响应脉冲。
从DHT11传感器接收的数据可以通过轮询数字脉冲的逻辑电平采样,同时跟踪脉冲宽度。在轮询逻辑HIGH或LOW的同时,可以通过测量从特定时刻开始所经过的时间来跟踪脉冲宽度。
有millis()和micros()函数可用于跟踪从Arduino启动以来所经过的时间。millis()函数提供从启动开始的时间,以毫秒为单位,micros()函数提供从启动开始的时间,以微秒为单位。
Arduino USART
Arduino有一个内置的USART,用于与其他设备进行串行通信。在Arduino UNO上,这个USART在数字I/O引脚0和1处可用。
这个USART也可以在Arduino的USB端口上使用,该端口用于从Arduino IDE对其进行编程。同一USB端口可用于与桌面计算机或任何具有USB接口的计算设备进行串行UART通信。要了解更多关于UART协议的信息,请查看这个树莓派的UART教程.
Arduino连续监控
Arduino IDE有一个集成的串行监视器,可以通过桌面的USB端口接收和发送串行数据。通过导航到“Tools-> serial monitor”可以打开串口监视器。
还可以通过单击IDE右上角的Serial Monitor图标来访问它。
在启动Serial Monitor时,将打开一个窗口,在该窗口中可以将串行数据发送到连接的串行设备。这也是从设备接收到的串行数据可以被查看的地方。波特率和编码可以从这个窗口设置。
串行通信:Arduino和一台台式电脑
在本教程中,我们将通过Arduino UNO将从DHT11传感器读取的传感器数据发送到桌面计算机。在这种情况下,DHT11将与Arduino接口,Arduino将通过USB线连接到桌面计算机。
对Arduino进行编程,以便在Arduino IDE的串行监视器上观察传感器数据。
Arduino串行图书馆
要建立Arduino和PC之间的串行通信,串行库是有用的。
串行库包含以下方法:
- Serial.begin ()- - - - - -初始化Arduino进行串行通信,用于设置波特率和UART数据编码
- 并同时()- - - - - -将串行数据转换为ASCII字符并通过串口发送
- 以()- - - - - -通过串口以ASCII字符的形式发送串行数据,后面跟着一个回车符
- Serial.write ()- - - - - -发送二进制数据到串口,并返回写入串口的字节数
- Serial.available ()- - - - - -检查是否有任何数据可从串口读取
- Serial.read ()- - - - - -从串口读取可用的数据
- Serial.readString ()- - - - - -从串口读取可用的数据字符串
- Serial.end ()- - - - - -用于关闭串行通信
使用外部库读取传感器数据
DHT传感器有许多可用的库。它们可以通过导航到:Tools->管理库找到。
在其中一个库中搜索DHT11并安装其最新版本。然后,您可以通过导航到Sketch-> Include library来导入这个库。
导入库后,可以使用库中的函数从DHT11读取传感器数据。但是什么功能?这取决于您安装和导入的库。
从Arduino中删除库
您可以尝试DHT11传感器的一个库,然后再尝试另一个库。事实上,很有可能许多第三方库具有相同的名称。这可能会导致一个问题。因此,如果不打算使用外部库,最好删除它。外部库可能与将来可能导入的任何库存在名称冲突或函数名冲突。
要删除外部库,首先需要找到它的文件夹。
- 在macOS和Linux上,外部库存储在Documents/Arduino/libraries/
中 - 在Windows上,外部库存储在My Documents/Arduino/libraries/
中
要删除一个库,请从libraries文件夹中删除它的文件夹,并重新启动Arduino IDE。现在,删除的库将从Sketch->包含库中消失。删除外部库后,不能再导入它或使用该库编译Arduino草图。如果您打算再次使用该库,您可以将其备份为存档文件。
从DHT-11读取传感器数据(没有库)
我们可以编写自己的函数从DHT11读取传感器数据。
以下函数可以用来编写我们自己的DHT11函数或库:
- pinMode()函数- - - - - -将引脚设为数字输入或输出
- digitalWrite()函数- - - - - -在引脚上写入数字信号
- digitalRead()函数- - - - - -在引脚上读取数字信号
- 延迟()函数- - - - - -以毫秒为单位提供延迟
- delayMicroseconds()函数- - - - - -以微秒为单位提供延迟
- 米尔斯()函数- - - - - -以毫秒为单位测量时间推移
- 微指令()函数- - - - - -以微秒为单位测量时间推移
看看下面的Arduino食谱。利用Arduino草图中的上述函数,编写读取DHT11传感器数据的函数。
方法:不使用外部库从DHT-11读取传感器数据
在这个菜谱中,我们编写了自己的函数,从Arduino上的DHT11读取传感器数据。这些函数是用来将传感器数据传递到串口的。
组件的要求
1.Arduino UNO x1
2.DHT11传感器x1
3.Arduino x1的USB连接线
4.台式电脑x1
5.公对公跳线或连接线
电路的连接
- 用USB线连接Arduino和PC
- 分别从Arduino的接地和5V引脚向DHT11传感器提供接地和VCC
- 将DHT11传感器的数据引脚与Arduino UNO的引脚2连接
Arduino草图
项目如何运作
DHT11的数据引脚与Arduino UNO的引脚2相连。Arduino通过编程向DHT11传感器发送启动信号,然后从传感器读取响应脉冲和串行数据。
为了检测响应信号并从DHT11读取串行数据,对Arduino引脚上的输入数字信号进行轮询,并确定TON和TOFF的脉冲宽度。这是通过比较在信号上升边缘之后的逻辑HIGH输入和在Arduino引脚上信号下降边缘之后的逻辑LOW输入所花费的时间来实现的。
通过测量响应信号的TON信号的脉宽,它确定启动脉冲是否已成功应用到DHT11的数据引脚上。如果响应信号上升边缘后的TON脉冲宽度不超过90微秒,这意味着启动信号已经成功应用到DHT11的DATA引脚上。否则,在将启动信号应用到DHT11的数据引脚时将会出现TIMEOUT_ERROR。
接收到DHT11的响应脉冲后,在Arduino引脚上读取来自DHT11的串行数据。通过测量信号上升边缘后的脉冲宽度来检测位0和位1。如果脉冲宽度超过30微秒,它就是位1。否则,它就是位0。
这些位存储在一个16位的变量中,并将湿度和温度值传递给其他16位的变量,将校验和字节传递给8位的变量。
读取位——包括湿度和温度值、校验和字节和错误码——以这种格式发送到串口。
如果在应用启动信号时出现超时错误,将此发送到串口:
湿度:
温度摄氏度:
校验和字节:
< bit32-39从DHT11 >
<二进制湿度和温度值的和>
CHECKSUM_OK{如果bit32-39和湿度和温度的二进制和相同}/CHECKSUM_ERROR{如果bit32-39和湿度和温度的二进制和不相同}
结果
编程指南
Arduino草图从setup()函数开始,在这里串行通信的波特率被设置为9600 bps。
然后,编写以下自定义函数:
dec2bin (int n)- - - - - -将16位整数转换为其二进制表示。它逐位遍历16位整数值,每次移动一位并用1(使用&操作符)屏蔽它,以确定整数值中的特定位是1还是0。这个函数不返回任何东西,只是串行输出传递给它的参数的二进制表示。它用于将读取的湿度和温度值转换为它们的二进制表示形式。
dec2bin8 (int n)- - - - - -将8位整数转换为其二进制表示。它逐位遍历8位整数值,每次移动一位并用1(使用&操作符)屏蔽它,以确定整数值中的特定位是1还是0。该函数不返回任何东西,而是连续输出传递给它的参数的二进制表示。它用于将读取的校验和值、湿度值的整数和小数部分以及温度值的整数和小数部分转换为它们的二进制表示。
wait_for_dht11 ()- - - - - -提供2秒的延迟。这需要在DHT11的主机(Arduino)引导后准备好数据传输。如果没有提供这个延迟,DHT11传感器将不会响应主控制器,并且在从DHT11读取传感器数据的初始尝试中,将会出现超时错误。
空白wait_for_dht11 ()
{
延迟(2000);
}
start_signal (uint8_t dht11_pin)- - - - - -为DHT11传感器生成启动信号。这个函数将DHT11的DATA引脚作为参数。首先使用pinMode()函数将引脚设置为数字输出。使用digitalWrite()和delay()函数在18毫秒内清除(LOW)。然后,设置(HIGH)以提供数字信号的上升边缘。随后,引脚被设置为数字输入,并被拉高。
空白start_signal (uint8_t dht11_pin)
{
pinMode (dht11_pin、输出);
digitalWrite (dht11_pin、低);
延迟(18);
digitalWrite (dht11_pin、高);
pinMode (dht11_pin、输入);
digitalWrite (dht11_pin、高);
}
read_dht11 (uint8_t dht11_pin)用于从DHT11读取传感器数据。它将连接DHT11的DATA引脚的引脚作为参数。首先,定义变量来存储:
- 原始湿度值(包含整数部分和小数部分)
- 原始温度值(包含整数部分和小数部分)
- 校验和字节
- 来自DHT11传感器的位流(变量“数据”)
- 湿度值的积分部分
- 湿度值的小数部分
- 温度值的积分部分
- 温度值的小数部分
- 变量以存储信号上升或下降边缘处的时间瞬间
空白read_dht11 (uint8_t dht11_pin)
{
uint16_t rawHumidity = 0;
uint16_t rawTemperature = 0;
uint8_t checkSum = 0;
Uint16_t data = 0;
uint8_t humi;
uint8_t humd;
uint8_t拍子;
uint8_t tempd;
无符号长开始时间;
运行for循环检测DHT11的响应信号和位流。声明一个变量' live '来存储TON时间,而当前时刻的时间存储在变量' startTime '中。
For (int8_t I = -3;我< 80;我+ +){
字节生活;
开始时间=微指令();
在do-while循环中,将检测到响应信号。确定Arduino引脚上的数字信号是否为HIGH作为循环的条件。当信号保持HIGH时,从最后测量的时间瞬间开始的经过时间将被轮询。
如果它大于90微秒,则启动信号没有正确应用到DHT11 DATA引脚。否则,如果有下降边导致while循环在90微秒前退出,则从DHT11成功接收到响应信号。
现在,我们准备检测来自DHT11的位流。
{做
live = (unsigned long)(micros() - startTime);
If (live > 90) {
以“ERROR_TIMEOUT”);
返回;
}
}
while (digitalRead(dht11_pin) == (i & 1) ?高:低);
for循环已经运行了四次,试图检测响应信号。由于下降边缘退出前一个do-while循环后,Arduino引脚被读取为LOW。现在我们可以开始读取位流了。当循环计数器大于或等于0并且当它被1(&操作)屏蔽时为偶数(如0、2、4、6、8等)时,如果条件为false,则执行以下操作。所以,什么都不做时,有TOFF的数字脉冲。
If (I >= 0 && (I & 1)) {
当循环计数器为奇数时,if条件为真。检查时间(对于数字脉冲的TON)是否大于30微秒。如果是,左移存储位流的变量并追加1。否则,只需将存储位0的变量左移。
数据< < = 1;
//吨位0的最大30个使用秒,位1的至少68个使用秒。
If (live > 30) {
数据| = 1;//我们得到一个1
}
}
当循环计数器在检测到位流后运行了31次,这意味着已经读取了16位,将位流存储为原始湿度值。当循环计数器在检测到位流后运行了63次,因此已经读取了下16位,将位流存储为原始温度值。
当循环计数器在检测到一个位流后运行了79次,并且已经读取了8位,将该位流存储到校验和字节中。
开关(I) {
例31:
rawHumidity =数据;
打破;
63年情况:
rawTemperature =数据;
79年情况:
校验和=数据;
数据= 0;
打破;
}
}
现在我们已经有了湿度值、温度值和校验和字节,将它们按上面所述的格式传输到串口。
系列。println(“湿度:”);
dec2bin (rawHumidity);
并同时“t \”);
humi = rawHumidity >> 8;
dec2bin8 (humi);
并同时“t \”);
rawHumidity = rawHumidity << 8;
humd = rawHumidity >> 8;
dec2bin8 (humd);
并同时“t \”);
并同时humi);
并同时(“。”);
并同时humd);
并同时(“%”);
以(" ");
系列。println("温度摄氏度:");
dec2bin (rawTemperature);
并同时“t \”);
tempi = rawTemperature >> 8;
dec2bin8(速率);
并同时“t \”);
rawTemperature = rawTemperature << 8;
tempd = rawTemperature >> 8;
/ / tempd =(字节)rawTemperature;
dec2bin8 (tempd);
并同时“t \”);
并同时(速率);
并同时(“。”);
并同时tempd);
并同时“C”);
以(" ");
系列。println(“校验和字节:”);
dec2bin8(校验和);
以(" ");
Dec2bin8 (tempi + tempd + humi + humd);
以(" ");
if((byte)checkSum == (byte)(tempi + tempd + humi + humd)){Serial.print(" CHECKSUM_OK ");}
其他{并(“CHECKSUM_ERROR”);}
以(" ");
以(" ");
以(" ");
}
在loop()函数中,wait_for_dht11()、start_signal()和read_dht11()函数以相同的顺序执行5次。因此,传感器数据从DHT11传感器读取5次。然后使用serial .end()方法关闭串行通信。
注意:以上代码将只与DHT11传感器工作。它将不能与DHT家族中的其他传感器一起工作。
在下一个教程,我们将介绍使用Arduino的串行(USART)通信。
了下:Arduino