【51单片机快速入门指南】6.4:DHT11、DHT22单总线温湿度传感器
时间:2022-08-23 11:30:01
目录
- 硬知识
-
- DHT11
- DHT22
- 通信协议
-
- 读取步骤
- 数据解读
-
- DHT11
- DHT22
- 示例程序
-
- DHT11_22.c
- DHT11_22.h
- 测试程序
-
- main.c
- 实验现象
-
- DHT11
- DHT22
STC89C52
Windows 10 20H2
Proteus 8 Frofessional v8.9 SP2
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
硬知识
摘自温湿度模块 DHT11产品手册》、《数字温湿度传感器 DHT22》
- 在典型应用电路中,建议连接线短于5m时用4.7K上拉电阻大于5m上拉电阻的电阻值应根据实际情况降低。
- 使用3.3V电压供电时,连接线尽可能短,导致传感器供电不足,导致测量偏差。
- 每次读取的温度和湿度值是最后一次测量的结果。为了获取实时数据,需要连续读取两次,但不建议连续读取多次传感器次读取传感器间隔大于2秒,以获得准确的数据。
- 如果电源部分波动,会影响温度。如果使用开关电源,温度会跳动。传感器上电后,等待1s在此期间,无需发送任何指令,以跨越不稳定状态。电源引脚(VDD,GND)可以增加1000nF用于去耦滤波的电容器。
引脚说明
- VDD:供电3.3~5.5V DC
- DATA:串行数据,单总线
- NC:空脚
- GND:接地,电源负极
DHT11
DHT数字温湿度传感器是一种含有校准数字信号输出的温湿度复合传感器。采用特殊的数字模块采集技术和温湿度传感技术,保证产品的高可靠性和优异的长期稳定性。传感器包括电容式感湿元件和NTC与高性能8位单片机连接的测温元件。
DHT22
DHT22数字温湿度传感器是一种含有自校准数字信号输出的温湿度复合传感器。采用特殊的数字模块采集技术和温湿度传感技术,保证产品的高可靠性和优异的长期稳定性。传感器包括电容式感湿元件和NTC与高性能8位单片机连接的测温元件。因此,该产品具有品质优良、响应超快、抗干扰能力强、性价比高等优点。每个DHT22传感器在极其精确的湿度校验室中校准。校准系数以程序的形式存储在OTP这些校准系数应调用于传感器内部的检测信号处理。单线串行接口使系统集成简单快捷。超小体积,功耗极低,信号传输距离可达20米以上,成为各种应用甚至最苛刻的应用场合的最佳选择。产品包装4针单排引脚。连接方便,可根据用户需要提供特殊的包装形式。
通信协议
器件采用简化的单总线通信。单总线只有一条数据线,系统中的数据交换和控制由单总线完成。设备(主机或从机)通过漏极开路或三态端口连接到数据线,允许设备在不发送数据的情况下释放总线,并允许其他设备使用总线;单总线通常需要外接约4条.7kΩ这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有在主机呼叫时才能响应,因此主机访问设备必须严格遵循单总线序列。如果序列混乱,设备将不响应主机。
DATA用于微处理器与传感器之间的通讯和同步,采用单总线数据格式,一次传送40位数据,高位先出。
数据格式:
8bit高湿度数据 8bit低湿度数据 8bit高温数据 8bit低温数据 8bit校验位。
校验位数据定义:
校验位等于8bit高湿度数据 8bit低湿度数据 8bit高温数据 8bit低温数据所得结果的末8位。
数据时序图
用户主机(MCU)传感器动信号后,传感器从低功耗模式转换为高速模式。主机启动信号后,传感器发送响应信号40bit的数据,并触发一次信采集。
读取步骤
- 上电后(上电后等1)S通过不稳定状态,在此期间不能发送任何指令),测试环境温湿度数据,记录数据,同时传感器DATA数据线由上拉电阻拉高,保持高电平;此时,传感器DATA引脚处于输入状态,始终检测外部信号。
- 微处理器的I/O设置为输出同时输出低电平,低电平的小于18ms(最大不超过30ms),然后是微处理器I/O由于上拉电阻,微处理器设置为输入状态I/O即传感器的DATA数据线也随之变高,等待传感器发出回答信号。
- 传感器的DATA当引脚检测到外部信号低电时,等待外部信号低电平结束,延迟传感器DATA引脚处于输出状态,输出83微秒的低电平作为响应信号,然后输出87微秒的高电平通知外设准备接收数据,微处理器I/O此时处于输入状态,检测到I/O在低电平(传感器响应信号)后,等待87微秒的高电平数据接收
- 由传感器的DATA微处理器根据引脚输出40位数据I/O电平变化接收40位数据,位数据"0格式为:54微秒的低电平和23-27微秒的高电平"1"格式为:54微秒低电平加68-74微秒高电平。
- 结束信号:传感器DATA引脚输出40位数据后,继续输出低电平54微秒,然后转换为输入状态,因为上拉电阻变为高电平。然而,在传感器部的环境温度和湿度数据,并记录数据,等待外部信号的到来。
数据解读
DHT11
DHT22
示例程序
DHT11_22.c
#include "DHT11_22.h" void delay_ms(int i); void delay_10us(uint8_t n);
DHT_data DHT_Data = {
0};
void DHT_Read(DHT_data *dht_data)
{
uint8_t DHT_timeout_count, i, j;
uint8_t data_temp[6];
uint8_t DHT_Byte;
//主机拉低18~30ms
DHT_IO_L();
delay_ms(20);
DHT_IO_H();
//总线由上拉电阻拉高 主机延时50us
delay_10us(5);
//判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
if(!DHT_IO_read())
{
//判断从机是否发出 80us 的低电平响应信号是否结束
DHT_timeout_count = 0;
while(!DHT_IO_read())
{
delay_10us(1);
if(++DHT_timeout_count >= 10)
return;
}
//判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
DHT_timeout_count = 0;
while(DHT_IO_read())
{
delay_10us(1);
if(++DHT_timeout_count >= 10)
return;
}
for(i = 0; i < 5; ++i)
{
for(j = 0, DHT_Byte = 0; j < 8; ++j)
{
DHT_Byte <<= 1;
DHT_timeout_count = 0;
while(!DHT_IO_read())
{
delay_10us(1);
if(++DHT_timeout_count >= 10)
{
DHT_Byte = 0;
break;
}
}
delay_10us(3); //跳过数据0的时间段,只检测数据为1时的电平
if(DHT_IO_read())
{
++DHT_Byte;
while(DHT_IO_read())
{
delay_10us(1);
if(++DHT_timeout_count >= 10)
{
DHT_Byte = 0;
break;
}
}
}
}
data_temp[i] = DHT_Byte;
}
for(i = 0, data_temp[5] = 0; i < 4; ++i)
data_temp[5] += data_temp[i];
if(data_temp[5] == data_temp[4]) //数据解读
{
#ifdef DHT11
dht_data->RH = data_temp[0] + (data_temp[1] & 0x0f)/10.;
dht_data->Temp = data_temp[2] + (data_temp[3] & 0x0f)/10.;
if(data_temp[3] & 0x80)
dht_data->Temp *= -1;
#endif
#ifdef DHT22
dht_data->RH = ((int16_t)data_temp[0] << 8 | data_temp[1])/10.;
dht_data->Temp = ((int16_t)(data_temp[2] & 0x7f) << 8 | data_temp[3])/10.;
if(data_temp[2] & 0x80)
dht_data->Temp *= -1;
#endif
}
}
}
DHT11_22.h
#ifndef DHT11_22_H
#define DHT11_22_H
#include
#include
#define DHT11
//#define DHT22
typedef struct
{
float RH;
float Temp;
} DHT_data;
#define DHT_IO_H() {
P00=1;}
#define DHT_IO_L() {
P00=0;}
#define DHT_IO_read() P00
extern DHT_data DHT_Data;
void DHT_Read(char *Str);
#endif
测试程序
stdint.h见【51单片机快速入门指南】1:基础知识和工程创建
串口部分见【51单片机快速入门指南】3.3:USART 串口通信
定时器的介绍和配置源码见【51单片机快速入门指南】3.2:定时器/计数器
在头文件中选择使用的型号:
main.c
#include
#include "intrins.h"
#include "stdint.h"
#include "USART.h"
#include "TIM.h"
#include "DHT11_22.h"
void Delay1ms() //@22.1184MHz
{
unsigned char i, j;
_nop_();
i = 4;
j = 146;
do
{
while (--j);
} while (--i);
}
void delay_ms(int i)
{
while(i--)
Delay1ms();
}
uint8_t TIM0_Counter = 0;
void delay_10us(uint8_t n)
{
TL0 = TH0;
TIM0_Counter = n;
while(TIM0_Counter > 1);
}
void main(void)
{
USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 22118400, 115200, DOUBLE_BAUD_ENABLE, USART_TIMER_1);
Timer_Init(TIMER_0, TIMER_MODE_2, GATE_DISABLE, CLK_Internal, 22118400, 10, STC_TIM_Priority_Highest); //定时器配置为10us中断一次,8位重装载
delay_ms(1500);
while(1)
{
DHT_Read(&DHT_Data);
printf("%f %f\r\n", DHT_Data.RH, DHT_Data.Temp);
delay_ms(2000);
}
}