本章学习温湿度传感器DHT11的使用,利用DHT11采集环境的温湿度,DHT11和DS18B20一样,也是单线通信。
DHT11数字温湿度传感器是一种含有已校准数字信号传输的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术。确保产品具有很高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接,DHT11与单片机之间能采用简单的单总线进行通信,仅需要一个I/O口,传感器内部温度和温度数据40Bit的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。DHT11功耗很低,5V电源电压,工作平均最大电流0.5mA
DHT11 的技术参数如下:
工作电压范围:3.3V-5.5V;
平均电流:平均0.5mA。
输出:单总线数字信号
测量范围:湿度 20~90%RH,温度 0~50°C。
精度:湿度 ±5%,温度±2°C。
分辨率:湿度 1% 温度 1°C。
DHT11和MCU之间一次通信大约4ms,一次完整的数据包由40Bit组成,高位先出,数据分为整数部分和小数部分,当前小数部分用于以后扩展,现读出为0,数据格式如下:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据和8bit校验和,其中校验和数据为前四字节相加。
MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40Bit数据并触发一次采集,采集完成转到低功耗模式下,DHT11通信过程如下:
**DHT11开始信号:**总线空闲状态位高电平,主机把总线拉低必须大于18ms,,然后再拉高总线20-40us后,读取DHT11的响应,如果DHT11存在,会拉低总线80us后,再拉高总线80us,接着才会开始输出数据,开始信号时序图如下:
DHT11和DS18B20一样,不过DHT11有4个引脚,注意:DS18B20读写都是低位在前,而DHT11读是高位在前
#include "MyIncludes.h"
u16 sys_cnt = 0;
void systick_isr(void)
{
if(sys_cnt < 1000) sys_cnt++;
else
{
sys_cnt = 0;
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_4|GPIO_PIN_5);
}
}
DHT11_Data_TypeDef DHT11_Measure;
char measure[40];
//用来存储温湿度
int main(void)
{
System_Init();
LED_Init();
SysTick_Init(systick_isr);
USART1_Init(115200,NULL,NULL);
while(DHT11_Init())
//器件不存在
{
printf("DHT11 Init ERROR");
}
delay_ms(1000);
while(1)
{
if(DHT11_Get_TemperAndHumi(&DHT11_Measure) == 1)
//测量温度
{
sprintf((char*)measure,"DHT11: 温度 %d",DHT11_Measure.temp_int,DHT11_Measure.humi_int);
printf(measure);
printf("%%\r\n");
}
else printf("DHT11 Error!!!\r\n");
delay_ms(1000);
}
}
DHT11.h
#ifndef __DHT11_H_
#define __DHT11_H_
#include "stm32f1xx.h"
#include "stm32_types.h"
#include "stm32f1xx_hal.h"
#define DHT_DQ_PORT GPIOC
#define DHT_DQ_PIN GPIO_PIN_7
#define DHT_DQ_PORT_CLK_ENABLE() __GPIOC_CLK_ENABLE()
#define DHT_BIT_HIGH() HAL_GPIO_WritePin(DHT_DQ_PORT, DHT_DQ_PIN, GPIO_PIN_SET)
//高位
#define DHT_BIT_LOW() HAL_GPIO_WritePin(DHT_DQ_PORT, DHT_DQ_PIN, GPIO_PIN_RESET)
//低位
#define DHT_BIT_IN() HAL_GPIO_ReadPin(DHT_DQ_PORT, DHT_DQ_PIN)
//读
typedef struct
{
u8 humi_int;
//湿度的整数部分
u8 humi_deci;
//湿度的小数部分
u8 temp_int;
//温度的整数部分
u8 temp_deci;
//温度的小数部分
u8 check_sum;
//校验和
}DHT11_Data_TypeDef;
u8 DHT11_Get_TemperAndHumi(DHT11_Data_TypeDef *DHT11_Data);
//获得温湿度
u8 DHT11_Init(void);
#endif
DHT11.c
#include "DHT11.h"
#include "delay.h"
//DQ配置为输出
void DHT_DIR_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//GPIOC7初始化设置
GPIO_InitStruct.Pin = DHT_DQ_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
//普通推挽输出模式
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//高速
GPIO_InitStruct.Pull = GPIO_PULLUP;
//上拉
HAL_GPIO_Init(DHT_DQ_PORT, &GPIO_InitStruct);
//初始化GPIO
}
//DQ配置为输入
void DHT_DIR_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//配置为输入
GPIO_InitStruct.Pin = DHT_DQ_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//输入
GPIO_InitStruct.Pull = GPIO_PULLUP;
//上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//高速
HAL_GPIO_Init(DHT_DQ_PORT, &GPIO_InitStruct);
}
u8 DHT11_Reset(void)
{
u16 timeout=0;
DHT_DIR_OUT();
//数据线配置为输出
DHT_BIT_LOW();
//数据线拉低
delay_ms(20);
//延时20ms 最低18ms
DHT_BIT_HIGH();
//拉高 ,释放总线
delay_us(30);
//延时30ms 20-40ms
DHT_DIR_IN();
//数据线配置为输入,等待从机相应(低电平)
//这时DHT11已经做出响应,数据线变为低电平
while(DHT_BIT_IN())
//等待变为低电平 80ms
{
delay_us(1);
if(++timeout > 200) goto Exit;
}
timeout = 0;
//变为高电平,持续80ms
while(!DHT_BIT_IN())
//等待变为高电平
{
delay_us(1);
if(++timeout > 200) goto Exit;
}
return 0;
Exit:
return 0xFF;
}
u8 DHT11_RD_Bit(void)
//读一个位
{
u8 timeout=0;
DHT_DIR_IN();
//数据配置为输入
while(DHT_BIT_IN())
//等待变为低电平,每位以50us低电平开始
{
delay_us(1);
if(++timeout > 200) goto Exit;
}
timeout = 0;
//变为高电平,持续80ms
while(!DHT_BIT_IN())
//等待变为高电平
{
delay_us(1);
if(++timeout > 200) goto Exit;
}
delay_us(80);
//延时80ms
if(DHT_BIT_IN())
return 1;
else
return 0;
Exit:
return 0xFF;
}
u8 DHT11_RD_Byte(void)
//读一个字节,高位在前
{
u8 i,dat=0;
for(i = 0; i < 8; i++)
{
dat |= (DHT11_RD_Bit()<<(7-i));
}
return dat;
}
u8 DHT11_Get_TemperAndHumi(DHT11_Data_TypeDef *DHT11_Data)
//获取温湿度
{
if(DHT11_Reset() == 0)
//复位DHT11总线完成
{
//开始接收数据
DHT11_Data->humi_int = DHT11_RD_Byte();
DHT11_Data->humi_deci = DHT11_RD_Byte();
DHT11_Data->temp_int = DHT11_RD_Byte();
DHT11_Data->temp_deci = DHT11_RD_Byte();
DHT11_Data->check_sum = DHT11_RD_Byte();
if(DHT11_Data->check_sum == DHT11_Data->humi_int+DHT11_Data->humi_deci+DHT11_Data->temp_int+DHT11_Data->temp_deci)
//如果校检和等于温度整数部分+温度小数部分
//+湿度整数部分+湿度小数部分
return 1;
//读取成功
else
return 0;
//读取失败
}
else
return 0xFF;
//校验失败
}
u8 DHT11_Init(void)
{
DHT_DQ_PORT_CLK_ENABLE();
//使能端口时钟,也就是GPIOC时钟
return DHT11_Reset();
//复位DHT11总线
}