【STM32随记】—DHT11模块使用
概述:DHT11 是广州奥松有限公司生产的一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一个I/O 口。传感器内部湿度和温度数据 40Bit 的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。DHT11 功耗很低,5V 电源电压下,工作平均最大电流 0.5mA。
性能指标和特性如下:
- 工作电压范围:3.5V-5.5V
- 工作电流 :平均 0.5mA
- 湿度测量范围:20-90%RH
- 温度测量范围:0-50℃
- 湿度分辨率 :1%RH 8 位
- 温度分辨率 :1℃ 8 位
- 采样周期 :1S
- 单总线结构
- 与 TTL 兼容(5V)
DHT11 开始发送数据流程
- 设置IO口为输出,使用MCU向DHT11发送开始信号(拉低总线),主机至少延时等待18ms
- 延时完毕后拉高总线,主机至少延时等待20~40us
- 延时完毕后读取DHT11的回应信号,正常情况下读取到的总线为低电平,并维持40~50us,即DHT11 发送了响应信号;如果读取响应信号为高电平,则 DHT11 没有响应,请检查线路是否连接正常。
- DHT11会再次把总线拉高,并维持40~50us,准备发送数据
- 开始采集数据
DHT11 返回数据结构
DHT11数字湿温度传感器采用单总线数据格式。即单个数据引脚端口完成输入输出双向传输。其数据包由5Byte(40Bit)组成。数据分小数部分和整数部分,具体格式在下面说明。一次完整的数据传输为40bit,高位先出。
数据格式:
8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和
- 校验和数据为前四个字节相加
- 传感器数据输出的是未编码的二进制数据
- 数据(湿度、温度、整数、小数)之间应该分开处理
如果,某次从传感器中读取如下5Byte数据:
由以上数据就可得到湿度和温度的值,计算方法:
humi (湿度)= byte4 . byte3=45.0 (%RH)
temp (温度)= byte2 . byte1=28.0 ( ℃)
jiaoyan(校验)= byte4+ byte3+ byte2+ byte1=73(=humi+temp)(校验正确)
注意:DHT11一次通讯时间最大3ms,主机连续采样间隔建议不小于100ms。
DHT11—0的表示方法:
DHT11—1的表示方法:
程序实现部分
头文件定义
#ifndef __DHT11_H
#define __DHT11_H
#include "sys.h"
//IO方向设置
#define DHT11_SET_IN() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
#define DHT11_SET_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
//IO操作函数
#define DHT11_OUT PGout(11)
#define DHT11_IN PGin(11)
u8 DHT11_Init(void);
u8 DHT11_ReadData(u8 *wendu,u8 *shidu);
u8 DHT11_ReadByte(void);
u8 DHT11_ReadBit(void);
u8 DHT11_CheckResponse(void);
void DHT11_SendReset(void);
#endif
DHT11_SendReset用于实现MCU向DHT11发送指定的起始信号
对应步骤1及步骤2
void DHT11_SendReset(void)
{
DHT11_SET_OUT(); //设置IO为输出
DHT11_OUT=0; //拉低总线
delay_ms(20); //低电平维持至少18ms
DHT11_OUT=1; //拉高总线
delay_us(40); //高电平维持20~40us
}
DHT11_CheckResponse用于检测DHT11是否在MCU发送信号后给予响应
对应步骤3及步骤4
返回0则为正常响应 可以开始采集数据
u8 DHT11_CheckResponse(void)
{
u8 timecount=0;
DHT11_SET_IN(); //设置IO为输入
//正常响应情况下DHT11会拉低总线40~50us
//当IO被拉低或者计时时间到时会跳出while循环
while (DHT11_IN && timecount<100)
{
timecount++;
delay_us(1);
}
//跳出while 超时未检测到DHT11应答 则返回1
//未超时即正常收到低电平信号 继续判断
if(timecount>=100)
return 1;
else
timecount=0;
//DHT11拉低总线后会再次拉高总线40~50us
while (!DHT11_IN && timecount<100)
{
timecount++;
delay_us(1);
}
if(timecount>=100)
return 1;
//正确检测到了高电平且未超时 返回0
return 0;
}
DHT11_ReadBit用于读取DHT11向MCU返回的一个BIT
由手册知0、1的信号都是先低电平再高电平,区别在于高电平的维持时间不同
u8 DHT11_ReadBit(void)
{
u8 timecount=0;
//0、1的信号都是先低电平再高电平
//区别在于高电平的维持时间不同
while(DHT11_IN && timecount<100)
{
timecount++;
delay_us(1);
}
timecount=0;
while(!DHT11_IN && timecount<100)
{
timecount++;
delay_us(1);
}
//根据DATASHEET描述的0与1格式 等待40us再判断总线
delay_us(40);
//若为高电平 则返回了1
if(DHT11_IN)
return 1;
else
return 0;
}
DHT11_ReadBit用于读取DHT11向MCU返回的一个BYTE
u8 DHT11_ReadByte(void)
{
u8 i,dat=0;
for(i=0;i<8;i++)
{
dat<<=1;
dat|=DHT11_ReadBit();
}
return dat;
}
DHT11_ReadData用于读取DHT11向MCU返回的一组完整的数据
DHT11一次性传送40位的数据,即读取40位
数据前16位是与湿度相关的,中间16位是与温度相关的,最后八位是用来校验的
当校验成功后则使用该正确的温湿度值
u8 DHT11_ReadData(u8 *wendu,u8 *shidu)
{
u8 buf[5];
u8 i;
DHT11_SendReset();
if(DHT11_CheckResponse()==0)
{
for(i=0;i<5;i++) //完整读取DHT11返回的40位数据
{
buf[i]=DHT11_ReadByte();
}
//根据DATASHEET提供的校验算法
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
//小数部分其实都为0 因此不取
*shidu=buf[0];
*wendu=buf[2];
}
}
else
return 1;
return 0;
}