温湿度传感器---DHT11
- 一、DHT11介绍
- 二、DHT11原理图
- 三、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接收的数据是否正确
/*
@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;
}
}
主函数中调用函数,即可显示温湿度,湿度无小数位
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); //湿度整数部分