STM32单片机学习:DHT11温湿度传感器使用详解
STM32单片机学习:DHT11温湿度传感器使用详解
DHT11温湿度传感器是一款常见的数字温湿度传感器,广泛应用于各种环境监测场景。本文将详细介绍DHT11传感器的功能、接线方式、通信协议以及在STM32单片机上的具体使用方法,帮助读者快速掌握其使用技巧。
DHT11传感器简介
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它采用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器内部集成了电容式感湿元件和NTC测温元件。
图1:DHT11传感器实物图(图片来源于网络)
DHT11传感器接线
DHT11传感器的典型电路应用中,产品手册建议连接线长度短于5m时使用4.7K上拉电阻,大于5m时根据实际情况降低上拉电阻的阻值。另外,使用3.3V电压供电时,连接线应尽量短,过长的接线可能导致传感器供电不足,造成测量偏差。
市面上很多产品将电路部分和传感器本身集成为一个模块,这种情况下上拉电阻通常是不需要使用者外接的,直接将DATA与单片机连接即可。
传感器引脚定义如下:
- 引脚1:VCC(电源)
- 引脚2:IO口(数据)
- 引脚3:NC(悬空)
- 引脚4:GND(地)
DHT11传感器通信协议
DHT11传感器采用半双工的简化单总线通信方式。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。单总线通常要求外接一个约4.7kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。
传感器与控制器的数据通信格式为40位数据,高位先出。数据格式具体如下:
- 8bit湿度整数数据
- 8bit湿度小数数据
- 8bit温度整数数据
- 8bit温度小数数据
- 8bit校验位
数据校验规则:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据 = 8bit校验位。如果不满足上述等式,则数据无效,需要舍弃。
DHT11传感器通信时序
上电初始化:DHT11上电后需要等待1S以越过不稳定状态,在此期间不能发送任何指令。此时DHT11的DATA数据线由上拉电阻拉高一直保持高电平。
主机发送读取指令:控制器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后控制器的I/O设置为输入状态,由于上拉电阻,控制器的I/O即DHT11的 DATA数据线也随之变高,等待DHT11作出回答信号。
传感器回应信号:DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知外设准备接收数据。
数据传输:由DHT11的DATA引脚输出40位数据,控制器根据I/O电平的变化接收40位数据。位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平;位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。
结束信号:DHT11的DATA引脚输出40位数据后,继续输出低电平54微秒后转为输入状态,由于上拉电阻随之变为高电平。但DHT11内部重测环境温湿度数据,并记录数据,等待外部信号的到来。
STM32单片机使用DHT11传感器代码示例
以下是基于STM32F10x的DHT11传感器读取代码示例,包含了初始化、读取数据等关键函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
uint8_t DHTData[5] = {0,0,0,0,0}; //数据容器,外部使用时记得声明
// 初始化IO口为推挽输出,用于主机发送读取指令
void DHT11_Out_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
// 初始化IO口为浮空输入,用于DHT11传输数据和响应读取信号
void DHT11_In_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
// 初始化DHT11,DHT11温湿度模块上电需要后需要1s的启动时间
void DHT11_Init()
{
DHT11_Out_Init();
Delay_ms(1000);
}
// 读取DHT11一个字节的数据
uint8_t DHT11_ReadByte()
{
uint8_t Data = 0;
uint8_t i = 0;
for(i = 0;i<8;i++)
{
uint8_t tmp = 0;//定义临时变量存放Data里面的每一位
uint8_t timeOut_Count = 0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}
timeOut_Count = 0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 0 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}
timeOut_Count = 0;
Delay_us(30);//延时30us - 表示0的区间在26-28us,如果延时超过28s还没有跳变为低电平,说明表示的是1
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1)
tmp = 1;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1 && timeOut_Count < 100)//等待1剩余的时间
{
Delay_us(1);
timeOut_Count++;
}
Data <<= 1;
Data |= tmp;
}
return Data;
}
// 读取DHT11温湿度模块一轮的数据
uint8_t DHT11_ReadData()
{
uint8_t i = 0;
uint8_t timeOut_Count = 0;
DHT11_Out_Init();//主机掌控总线控制权
GPIO_SetBits(GPIOA,GPIO_Pin_9);
Delay_us(30);
GPIO_ResetBits(GPIOA,GPIO_Pin_9);//主机向从机发送读取的请求
Delay_ms(20);//拉低至少18ms但不能超过30ms
GPIO_SetBits(GPIOA,GPIO_Pin_9);//主机拉高总线,准备等待从机回应
Delay_us(30);
DHT11_In_Init();//主机让出总线控制权
GPIO_SetBits(GPIOA,GPIO_Pin_9);
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}//等待从机响应信号
timeOut_Count = 0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 0 && timeOut_Count < 100)
{
Delay_us(1);
timeOut_Count++;
}//等待从机准备输出信号
timeOut_Count = 0;
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9) == 1)
{
for(i = 0;i < 5;i++)
{
DHTData[i] = DHT11_ReadByte();//读取5份数据
}
}
GPIO_ResetBits(GPIOA,GPIO_Pin_9);
Delay_us(55);
GPIO_SetBits(GPIOA,GPIO_Pin_9);
if(DHTData[0] + DHTData[1] + DHTData[2] + DHTData[3] == DHTData[4])
return 1;
else
return 0;
}
参考资料
产品手册说明书:链接:https://pan.baidu.com/s/1qKnJ2ZQrAPPIt6mEjrSv9Q
提取码:wpiv