目录
一、相关资料
- DHT11数字温湿度传感器是含已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。
- 建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使 用合适的上拉电阻
- 单线制串行接口,即只有一根数据线,用于系统中的数据交换、控制。使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。
相关参数
典型电路
使用3.3V电压供电时连接线尽量短,接线过长会导致传感器供电不足,造成测量偏差。
引脚说明
二、串行通信说明(单线双向)
2.1、数据格式
DHT11每次采集都要由单片机发起开始信号,然后DHT11会向单片机发送响应并开始传输40位数据帧,高位在前。
数据格式为:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位。
以下是示例:
2.2、通讯过程
总时序图
MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据。
2.2.1、采集数据
总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。主机发送开始信号结束后,延时等待20-40us后, 开始读取DHT11的响应信号,切换为输入状态,等待DHT11的80us低电平信号结束,然后判断DHT11是否是否发出 80us 的高电平;如果是,即可开始采集数据。
2.2.2、数据0信号时序
当DHT11输出数字0时, 单片机读取到的信号为50 us
的低电平,之后为26-28 us
的高电平。
2.2.3、数字1信号时序
当DHT11输出数字1时, 单片机读取到的信号为50 us
的低电平,之后为70 us
的高电平。
可见,数字信号1和数字信号0的区别在于高电平时间不同。
可通过设置高电平阈值判断信号种类:单片机可在读取到高电平后,延时30us后,识别此时总线的电平,高电平为数字1,低电平为数字0。
三、代码
3.1、DHT11.c
// 配置为输入
void dth11_input(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //使能PC,D,G端口时钟
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.GPIO_Pin = DTH_IN_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
// GPIO_InitStruct.GPIO_Pull = GPIO_NOPULL;
GPIO_Init(DTH_IN_GPIO_Port, &GPIO_InitStruct);
}
// 配置为输出
void dth11_output(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //使能PC,D,G端口时钟
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.GPIO_Pin = DTH_IN_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DTH_IN_GPIO_Port, &GPIO_InitStruct);
}
// 复位
void dth11_reset(void)
{
dth11_output();
DTH11_Clr();
DelayMs(20);
DTH11_Set();
DelayUs(20);
dth11_input();
}
// 读取一个bit数据
unsigned short dht11_read_bit(void)
{
while(DTH11_IN == Bit_RESET);
DelayUs(40);
if(DTH11_IN == Bit_SET)
{
while(DTH11_IN == Bit_SET);
return 1;
}else {
return 0;
}
}
// 读取一个字节的数据
unsigned short dht11_read_byte(void)
{
unsigned char i;
unsigned short data = 0;
for(i=0;i<8;i++)
{
data <<= 1;
data |= dht11_read_bit();
}
return data;
}
// 读取数据
uint8_t dht11_read_data(DHT11_Data_TypeDef* DTH_Data)
{
uint8_t checksum;
uint16_t data_temp;
dth11_reset(); // 复位
if(DTH11_IN == Bit_RESET)
{
// 监测到DTH11响应
while(DTH11_IN == Bit_RESET);
while(DTH11_IN == Bit_SET);
// 开始读取有效数据,一共五个字节
DTH_Data->humi_high8bit = dht11_read_byte();
DTH_Data->humi_low8bit = dht11_read_byte();
DTH_Data->temp_high8bit = dht11_read_byte();
DTH_Data->temp_low8bit = dht11_read_byte();
DTH_Data->check_sum = dht11_read_byte();
while(DTH11_IN == Bit_RESET);
// 读取完毕,设置为输出
dth11_output();
DTH11_Set();
/* 对数据进行处理 */
data_temp=DTH_Data->humi_high8bit*100+DTH_Data->humi_low8bit;
DTH_Data->humidity =(float)data_temp/100;
data_temp=DTH_Data->temp_high8bit*100+DTH_Data->temp_low8bit;
DTH_Data->temperature=(float)data_temp/100;
// 检验数据
checksum = DTH_Data->humi_high8bit + DTH_Data->humi_low8bit + DTH_Data->temp_high8bit + DTH_Data->temp_low8bit;
if(checksum != DTH_Data->check_sum){
return ERROR;
}else{
return SUCCESS;
}
}else {
return ERROR;
}
}
3.2、DHT11.h
typedef struct
{
uint8_t humi_high8bit; //原始数据:湿度高8位
uint8_t humi_low8bit; //原始数据:湿度低8位
uint8_t temp_high8bit; //原始数据:温度高8位
uint8_t temp_low8bit; //原始数据:温度高8位
uint8_t check_sum; //校验和
float humidity; //实际湿度
float temperature; //实际温度
} DHT11_Data_TypeDef;
#define DTH_IN_Pin GPIO_Pin_6
#define DTH_IN_GPIO_Port GPIOE
#define DTH11_Clr() GPIO_ResetBits(DTH_IN_GPIO_Port, DTH_IN_Pin)
#define DTH11_Set() GPIO_SetBits(DTH_IN_GPIO_Port, DTH_IN_Pin)
#define DTH11_IN GPIO_ReadInputDataBit(DTH_IN_GPIO_Port, DTH_IN_Pin)
3.3、main.c
void Displey_Temp()
{
uint8_t res = dht11_read_data(&dth11_data);
if(res == SUCCESS)
{
printf("humidity = %f \r\n",dth11_data.humidity);
printf("temperature = %f \r\n",dth11_data.temperature);
//LCD_ShowString(85,20,200,200,16,"humi = ");
//LCD_ShowString(80,80,200,200,16,"humi = ");
//LCD_ShowxNum(80,60,dth11_data.temperature,20,16,1);
OLED_ShowString(0,0,"temp=");
OLED_ShowNum(40,0,dth11_data.temp_high8bit/10,1,5) ;
OLED_ShowNum(48,0,dth11_data.temp_high8bit%10,1,5) ;
OLED_ShowString(56,0,".");
OLED_ShowNum(64,0,dth11_data.temp_low8bit/10,1,5) ;
OLED_ShowNum(72,0,dth11_data.temp_low8bit%10,1,5) ;
OLED_ShowString(80,0,"°C");
OLED_ShowString(0,2,"humi=");
OLED_ShowNum(40,2,dth11_data.humi_high8bit/10+'0',1,5) ;
OLED_ShowNum(48,2,dth11_data.humi_high8bit%10+'0',1,5) ;
OLED_ShowString(56,2,".");
OLED_ShowNum(64,2,dth11_data.humi_low8bit/10+'0',1,5) ;
OLED_ShowNum(72,2,dth11_data.humi_low8bit%10+'0',1,5) ;
OLED_ShowString(80,2,"RH");
DelayS(1);
}
else{
printf("read ERROR ! \r\n");
// OLED_Show_String(0,4,"Read Error !!",BIG);
OLED_ShowString(0,5,"Read Error");
}
}
小疑问
还没有想清楚为什么用Displey_Temp()函数时OLED屏幕会显示正常的温湿度但也会显示“Read Error”。
参考自:
1、单片机——DHT11 温湿度传感器
2、dht11 新手原理详解(附代码)