#DHT11#stm32单片机#学习笔记
DHT11是一款数字温湿度传感器,和单片机的连接采用单总线协议。
相关参数:1、供电电压:3-5.5V
2、供电电流:最大2.5mA
3、温度范围:0-50℃误差±2℃
4、湿度范围:20-90%RH误差±5%RH
5、响应时间:1/e(63%) 6-30s
6、测量分辨率分别为8bit(温度)、8bit(湿度)
7、采样周期间隔不得低于1秒钟
8、模块尺寸:30x20mm
DHT11的封装如下图,如果在绘制元器件封装时需注意
DHT11的引脚数为四个,其各引脚功能如下图所示。但市面上还有三引脚的,毕竟只用到了三引脚,多做一引脚的目的是美观,或者说是方便连接
学看懂手册对我们的开发有很大裨益,资料部分可上网或在购买模块时向商家所要。
典型的DHT11模块与单片机连接电路如下图所示:
此图并附加了一些额外条件,但在正常情况下,我们数据传送不会超过20m。
下图是在嘉立创中DHT11的原理图及其对应pcb元器件封装,引脚号直接连接DATA上,但上图中显示需加一个上拉电阻,此在原理图中不需加,因为在stm32单片机内部集成了上拉电阻(上拉输入)。在接电路板时需注意电源的连接,以免接反造成短路损坏电路板
一次完整的数据传输为40bit,高位显出。(单片机一次接收到完整的数据是5个字节)
数据格式:
8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和
单片机一次性取5个字节,取第一个和第三个字节(取值首先要进行校验!)下图为一组校验示例。
通讯过程如图1所示:
第一部分为DHT11初始化,如下图:
第一部分可分为两个部分,黑线部分为MCU(单片机)的复位,其余部分为DHT11响应。
第二部分为数据传送部分,如下图:
第二部分也可以分为两部分,虚线前为数据“0”,虚线后为数据“1”
第三部分为结束,如下图:
此上图中DHT11为从机,MCU为主机。时序图第一部分先由主机拉低18ms然后再拉高总线(释放总线),延时20~40us,此时复位信号发送完毕(因为有一个上拉电阻,所以释放时候有一个拉高电平的状态)。
注意:单片机引脚由输出便输入。
DHT11检测道MCU复位信号后,拉低总线80us表示响应,再拉高总线80us后开始传输数据。
当传送数据时候,DHT信号向单片机发送信号。此下图反应传送数据“1”和传送数据“0”的时序图。
由两图发现两个图的区别主要是中间部分,这让我们在编程时候更加方便。
DHT11以高电平的长短定义数据为是“0”还是“1”,当50us低电平时隙过后拉高总线,高电平持续26~28us表示数据“0”;持续70us表示数据“1”。
当最后1bit数据传送完毕后,DHT11拉低总线50us,表示数据传送完毕,随后总线由上拉电阻拉高进入空闲状态。
总结:主机发送起始信号 (单片机引脚设置为输入)
从机应答
主机开始接收数据
从机把总线拉低,持续50us,从机拉高总线后,延迟40 us左右,主机读取总线电平,如果为低电平,则为“0”,如果为高电平,则为“1”。继续重复上述步骤累计40次。
下示代码为DHT11的初始化代码
u8 DHT11_chushihua(void)
{
u8 cnt=0;
DHT11_OUT(); //配置引脚为输出
DHT11_WRITE=0; //输出低电平
delay_ms(20); //延时20ms
DHT11_WRITE=1; //输出高电平
delay_us(30); //延时30us
DHT11_IN(); //引脚为输入
while (!DHT11_READ&&cnt<100)//优先级"!" > "<" > "&&"(!DHT11_READ)&&(cnt<100)
{
cnt++;
delay_us(1);
};
if(cnt>=100)//检测低电平相应时间
return 1;
else
cnt=0;//return 函数会结束当前函数
while (DHT11_READ&&cnt<100)//检测高电平相应时间
{
cnt++;
delay_us(1);
};
if(cnt>=100)
return 1;
return 0;
}
注:return语句会结束当前函数
搞懂此代码首先要搞到几位优先级,在代码注释中已经写出。
结合此时序图看代码:
刚进入低电平
左边:DHT11_READ为0 取反后为1,为真
右边:此时cnt为0,cnt<100满足,为真进入while循环定时1us,cnt自增1
左边:DHT11_READ为0 取反后为1,为真
右边:此时cnt为1
到了81us
左边:DHT11_READ为1 取反后为0,为假。
跳出while循环
cnt变量的值就是DHT11_READ低电平的时间。
(检测高电平的代码部分与检测低电平的代码部分相似,在此不解释)
如果初始化函数返回零,表示DHT11初始化成功。
单片机一次接受到完整的数据是5个字节
首先要单片机接受一个字节
然后要单片机接受一个位
下面代码为接受一个字节的代码:
u8 DHT11_Read_Bit(void)
{
while(DHT11_READ);//检测到低电平
while(!DHT11_READ);//检测到高电平
delay_us(35);
if(DHT11_READ)
return 1;
else
return 0;
}
检测到低电平则是下面时序图中的点:
如果是高电平的话则一直在while中死循环,下一句则是检测高电平的到来,则是上诉点后最近的一个最高点。因为读取“1”和读取“0”的时序图只有在高电平持续时间上有区别,所以代码部分不需过于复杂。只要区分出是0还是1即可。
读取一个位后及读取一个字节,下列代码则为读取一个字节。
/*----------------------------------------------------------
函数名:DHT11读取一个字节
参数:无
返回值:返回一个字节
----------------------------------------------------------
*/
u8 DHT11_Read_Byte(void)
{
u8 mask,dat;
dat=0;
for(mask=0x80;mask!=0;mask>>=1)
{
if(DHT11_Read_Bit())
dat |=mask;
else
dat &=~mask;
}
return dat;
}
如接受一个1010 1100数据时候
第一次for循环:mask为1000 0000,满足if条件
dat|=mask 1000 0000
dat = 1000 0000 0000 0000
mask>>=1 mask!=0
第2次for循环:mask为0100 0000,满足else条件
dat&=~mask 1011 1111
dat = 1000 0000 1000 0000
mask>>=1 mask!=0
第三次for循环
mask为0010 0000,满足if条件
dat|=mask 0010 000
dat = 1010 0000 1000 000
此三次循环只是示范前三次,这样循环八次的话,则接收到一个字节。
接受一个字节后需接收五个字节,将接受的五个字节放入数组中。
for(i=0;i<5;i++)
{
buf[i]=DHT11_Read_Byte();
}
我们只需读出数组中第一位和第三位即可读出温湿度的整数部分,但在读取前需校验。
总结:主机发出起始信号
从机应答信号
接受5个字节的数据(接受1个位,1个字节,5个字节)
引脚初始化
下列函数为读取数组部分,并含有一定校验代码。这里的参数取值为何是指针的形式,简单一点说在指针运行后不会消失,而单纯的参数则只会运行一次后不再运行函数内容。(主函数调用子函数,且发生值传递,需用指针!)
/*----------------------------------------------------------
函数名:DHT11读取温湿度整数部分
参数:无
返回值:0,表示成功读取,非零,表示读取不成功
----------------------------------------------------------
*/
u8 DHT11_Read_Data(u8 *temperture,u8 *humidity)
{
u8 i;
u8 buf[5];
if(DHT11_chushihua()==0)//确认初始化成功
{
for(i=0;i<5;i++)
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[3]+buf[2])==buf[4])//校验
{
*temperture = buf[2];//温度整数部分
*humidity = buf[0];//湿度整数部分
return 0;//读取成功返回一个0
}
else
return 1; //读取失败返回一个1
}
else
return 1;
}
在.h文件中定义了一些宏定义,以便更好理解,且含有位带操作,和基于单片机寄存器的操作
#ifndef __DHT11_H__
#define __DHT11_H__
#include "stm32f10x.h" // Device header
#include "sys.c"
#define DHT11_WRITE PAout(5)
#define DHT11_READ PAin(5)
#define DHT11_IN() {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=8<<5*4;}
#define DHT11_OUT() {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=3<<5*4;}
u8 DHT11_chushihua(void);
u8 DHT11_Read_Bit(void);
u8 DHT11_Read_Byte(void);
u8 DHT11_Read_Data(u8 *temperture,u8 *humidity);
void DHT11_Init(void);
#endif
此宏定义中对于寄存器的操作需自行查手册阅读,阅读文献是一项重要的能力,举一反三也是,学习资料来源于bi站up主海创电子。