温湿度传感器---DHT11
- 一、DHT11介绍
- 二、DHT11原理图
- 三、DHT11工作原理和时序
-
- [3.1 DHT11工作时序](#3.1 DHT11工作时序)
- 四、DHT11代码
一、DHT11介绍
- DHT11数字温湿度传感器 是一款含有已校准数字信号输出的温湿度复合传感器,传感器内部包括一个8位单片机 控制一个电阻式感湿元件 和一个NTC测温元件
- 类单总线协议传输数据,使用简单便捷
- 测量温度范围在0-50℃,分辨率为1℃,误差在±2℃。湿度的测量范围位20%-95%RH,分辨率为1%RH,误差在±5%RH
- 工作电压:3.3V-5.5V
二、DHT11原理图
- 下图为DHT11和单片机之间的接线图
- DHT11的数据输出口接单片机的IO口,需要上拉一个5K左右的上拉电阻,保证空闲时刻处在高电平
- 下图为DHT11电路原理图
- 如下图中,DHT11一般都是内置上拉电阻的,不需要自行加装
三、DHT11工作原理和时序
- DHT11采用类单总线协议传输数据,与1-Wire协议存在异同之处
- DHT11一次通信时间4ms左右,仪器上电后,要等待1s以越过不稳定状态,在此期间无需发送任何指令
- 数据分为小数部分 和整数部分 ,一次完整的数据传输为40bit ,高位先出
- 数据格式 :8bit湿度整数数据 +8bit湿度小数数据 +8bit温度整数数据 +8bit温度小数数据 +8bit校验
8bit校验 = 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据
校验可以判断数据是否正确发送
3.1 DHT11工作时序
- 主机发送起始信号以后,DHT11发送响应信号,然后发送40bit的数据,高位在前
下图为总时序图
- 起始信号 :总线空闲状态 由DHT11内置上拉电阻拉高 ,主机拉低 总线至少18ms 后释放 总线20-40us
- DHT11响应 :存在的DHT11会及时响应主机,同时拉低 总线80us 后,释放 总线80us ,然后拉低 总线,表示开始传送数据
- 发送数据 :当总线是低电平 是表示开始发送数据,同时存在50us低电平时隙 ,之后拉高 总线,高电平的持续时间 表示发送0或者1,当高电平持续时间为26us-28us 表示发送0 ,高电平持续时间为70us 时,表示发送1
- 数据发送完毕,由上拉电阻拉高,置回空闲高电平状态
四、DHT11代码
DHT11与STM32单片机连接使用时,需要将VCC接3.3V,GND接地,DAT接IO口,由于DHT11内置上拉电阻,可以将IO口配置成开漏输出模式,这样就不需要切换输入输出模式
如果配置成推挽输出模式,只能输出,不能输入,还需要在STM32接收数据时,配置成输入模式,比较麻烦
下面为DHT11代码
其中包括时序部分,起始信号、DHT11响应、DHT11发送数据
DHT11_ReadData()函数中,需要校验STM32接收的数据是否正确
c
/*
@brief:DHT11初始化
@param:无
@retval:无
*/
void DHT11_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启GPIOA时钟
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure); //初始化GPIOPA7
GPIO_SetBits(GPIOA,GPIO_Pin_7); //默认高电平
}
/*
@brief:置PA7高低电平
@param:BitValue:1|0
@retval:无
*/
void WriteIO(uint8_t BitValue)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)BitValue);
}
/*
@brief:DHT11起始信号
@param:无
@retval:无
*/
void DHT11_Start()
{
WriteIO(0); //主机拉低总线
Delay_ms(20); //至少拉低18ms
WriteIO(1); //释放总线
Delay_us(30); //释放总线20~40us
}
/*
@brief:起始信号以后检测DHT11的响应信号
@param:无
@retval:stateData,1表示DHT11响应,-1表示DHT11无响应
*/
uint8_t DHT11_Check()
{
uint8_t stateData = 0;
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == RESET)//DHT11收到起始信号后会把总线拉低
{
Delay_us(80);//等待80us
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == SET)//DHT11拉高表示响应信号有用
{
stateData = 1;
}
else
{
stateData = 2;
}
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == SET);//引脚恢复低电平则表示传感器准备发数据
}
return stateData;
}
/*
@brief:接收DHT11传感器的一个字节数据
@param:无
@retval:Byte:接收的数据
*/
uint8_t DHT11_ReadByte()
{
uint8_t i,Byte = 0x00;
for(i=0;i<8;i++)
{
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == RESET);//DHT11每发一位数据之前,都先拉低,所以等待总线拉高
Delay_us(40);//等待40us
//高电平持续时间26-28us为0,70us为1
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7))
{
Byte |= (0x80>>i);//高位在前
}
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == SET);//等待高电平结束,为下一次接收数据做准备
}
return Byte;
}
/*
@brief:接收DHT11传感器的温度和湿度
@param1:
@param1:
@retval:Byte:接收的数据
*/
uint8_t DHT11_ReadData(uint8_t *Hum,uint8_t *FHum,uint8_t *Temp,uint8_t *FTemp)
{
uint8_t Buf[5];
uint8_t i,Flag = 0;
DHT11_Start();//起始信号
if(DHT11_Check() == 1)//DHT11正确响应
{
for(i=0;i<5;i++)
{
Buf[i] = DHT11_ReadByte();//读取5个字节存在数组中
}
Delay_us(60);//保证完整读取
if(Buf[0] + Buf[1] + Buf[2] + Buf[3] == Buf[4])//校验数据是否有效,如果有效
{
*Hum = Buf[0]; //湿度整数部分
*FHum = Buf[1]; //湿度小数部分
*Temp = Buf[2]; //温度整数部分
*FTemp = Buf[3]; //温度小数部分
Flag = 2; //验证读取数据是否正确
return Flag;
}
else//校验失败
{
*Hum = 0xFF;
*FHum = 0xFF;
*Temp = 0xFF;
*FTemp = 0xFF;
}
}
else//DHT11无响应
{
*Hum = 0xFF;
*FHum = 0xFF;
*Temp = 0xFF;
*FTemp = 0xFF;
}
}
主函数中调用函数,即可显示温湿度,湿度无小数位
c
DHT11_ReadData(&Hum_int,&Hum_dec,&Temp_int,&Temp_dec); //读取DHT11的值,湿度整数,湿度小数,温度整数,湿度小数
OLED_ShowNum(40,25,Temp_int,2,OLED_8X16); //温度整数部分
OLED_ShowChar(56,25,'.',OLED_8X16);
OLED_ShowNum(60,25,Temp_dec,1,OLED_8X16); //温度小数部分
OLED_ShowNum(95,25,Hum_int,2,OLED_8X16); //湿度整数部分