快捷搜索:  汽车  科技

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)STM32F103C8T6引脚表1 引脚连线图从图1中可知,项目利用DHT11温湿度传感器来采集环境中的温度和湿度信息,当温湿度的值超过设定值时,继电器工作,带动风扇工作;LED灯闪烁,作为系统运行指示。5.2 项目连线概况表1为项目的连线概况,请大家将元件按表中的信息连接至STM32系统板上。

今天,我们要进入到智能家居系统的制作了。首先我们制作的是温湿度子系统。

5.1 温湿度子系统项目概况

图1是温湿度子系统的概况图。

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(1)

图1 温湿度子系统

从图1中可知,项目利用DHT11温湿度传感器来采集环境中的温度和湿度信息,当温湿度的值超过设定值时,继电器工作,带动风扇工作;LED灯闪烁,作为系统运行指示。

5.2 项目连线概况

表1为项目的连线概况,请大家将元件按表中的信息连接至STM32系统板上。

表1 引脚连线图

STM32F103C8T6引脚

元件

功能描述

PB15

DHT11_DATA

继电器连线

GND

DC-

PB12

IN或INx

PC13

LED1

LED连线

VCC3.3

阳极

GND

阴极(接电阻)

5.3 DHT11的使用

1. DTH11基本情况

DHT11是一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。

DHT11与STM32F103C8T6之间采用简单的单总线进行通信,仅仅需要一个I/O口与MCU相连就能够实时的采集本地湿度和温度。

DHT11 的技术参数如下:

工作电压范围:3.3V-5.5V

工作电流 :平均 0.5mA

输出:单总线数字信号

测量范围:湿度 20~90%RH,温度 0~50℃

精度 :湿度±5%,温度±2℃

分辨率 :湿度 1%,温度 1℃

图2和图3为DTH11实物和引脚图。

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(2)

图2 DTH11实物图

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(3)

图3 引脚图

图4为DTH11传感器模块图。

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(4)

图4 DTH11传感器模块

2. DTH11单总线数据格式

DHT11数字湿温度传感器采用单总线数据格式。即单个数据引脚端口完成输入输出双向传输。其数据包由5Byte(40Bit)组成,具体格式如图5所示。在图5中byte4的8位为湿度的整数部分,byte3的8位为湿度的小数部分;byte2的8位为温度的整数部分,byte1的8位为温度的小数部分;最后byte0的8位为校验和。传感器数据输出的是未编码的二进制数据。一次完整的数据传输为40bit,高位先出。

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(5)

图5 DTH11单总线数据格式

图5中所表示的温湿度数值分别为湿度45.0(%RH),温度28.0(℃),校验和为73。

具体计算方法,以湿度为例,byte3为小数,全为0,所以湿度的小数部分为0。湿度的整数部分为00101101,计算过程就是:

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(6)

图6 湿度的整数部分计算过程

所以湿度就是45.0(%RH)。

温度计算方法一样,小数部分为0,整数部分byte2为00011100,所以温度的计算过程为:

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(7)

图7 温度的整数部分计算过程

所以湿度就是28.0(℃)。

校验和的计算方法:

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(8)

图8 校验和计算方法

而温度和湿度相加为:45 28=73,所以校验正确。

3. DTH11数据传输时序分析和代码实现

图9和图10为DTH11数据传输时序。

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(9)

图9 DHT11数据传输时序

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(10)

图10 DHT11数据传输时序

在图10中,我们可以看出DHT11的传输可以分为两大部分,第一部分为DHT11初始化阶段;第二部分是DHT11初始化完成后的数据传送阶段。

在DHT11初始化阶段,又分为两个部分,第一部分是黑线部分,是主机信号部分;第二部分是棕线部分,是DHT11的应答部分。整个过程是,先由STM32主机发出信号,然后再由DHT产生应答,这样初始化就完成了。

在主机信号部分,由t1和t2两部分组成,过程是主机先拉低数据线,保持t1(至少 18ms)时间,然后拉高数据线t2(保持20~40us)时间,然后延时等待,如果读取到DHT11拉低数据线,说明DHT11运行正常,如果等不到DHT11拉低数据线,则说明DHT11运行不正常,初始化失败。

如果DHT11运行正常的话,DHT11会拉低数据线,保持t3(40~50us)时间,作为响应信号,然后DHT11拉高数据线,保持t4(40~50us)时间后,开始输出数据。

以上两步就完成了DHT11的初始化。

代码分析:

首先主程序执行DHT11_Init(),转入u8 DHT11_Init(void)函数,开始DHT11的初始化。

具体函数如下:

//初始化DHT11的IO口DQ,同时检测DHT11的存在,IO口选取PB15

//返回1:不存在

//返回0:存在

u8 DHT11_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ENABLE); //使能PB端口时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //PB15端口配置

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz

GPIO_Init(GPIOB &GPIO_InitStructure); //初始化IO口

GPIO_SetBits(GPIOB GPIO_Pin_15); //PB15 输出高

DHT11_Rst(); //复位DHT11

return DHT11_Check();//等待DHT11的回应

}

在DHT11_Init()函数中,完成了几个任务:①初始化PB15 IO口,作为DHT11的输入输出口;②进行DHT11复位,执行DHT11_Rst()函数;③最后整个函数返回DHT11_Check()的值。

下面我们先来看DHT11_Rst()函数,这个函数完成的是DHT11复位功能

//复位DHT11

void DHT11_Rst(void)

{

DHT11_IO_OUT(); //设置DHT11_IO为输出

DHT11_DQ_OUT=0; //拉低DQ_OUT

delay_ms(20); //拉低至少18ms

DHT11_DQ_OUT=1; //拉高DQ_OUT

delay_us(30); //主机拉高20~40us

}

第一句:DHT11_IO_OUT(),设定IO口为输出,以供主机发出信号,具体代码为:

void DHT11_IO_OUT(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ENABLE); //使能PB端口时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //PB15端口配置

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz

GPIO_Init(GPIOB &GPIO_InitStructure); //初始化IO口

}

执行完第一句话DHT11_IO_OUT()之后,执行第二句和第三句:

DHT11_DQ_OUT=0; //拉低DQ_OUT

delay_ms(20); //拉低至少18ms

上面两句的作用是拉低IO口的电平,并且延时20ms,这样就满足了DHT11初始化阶段中t1时间段的要求。

接下面执行第四句和第五句:

DQ_OUT=1; //拉高DQ_OUT

delay_us(30); //主机拉高20~40us

上面两句的作用是拉高IO口的电平,并且延时20~40us,完成t2时间段主机的等待应答任务。

至此,主机部分完成了,下面开始DHT11的响应部分。

DHT11的响应部分由DHT11_Check()函数来完成,具体代码如下:

u8 DHT11_Check(void)

{

u8 retry=0;

DHT11_IO_IN();//SET INPUT

while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~50us

{

retry ;

delay_us(1);

};

if(retry>=100)return 1;

else retry=0;

while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~50us

{

retry ;

delay_us(1);

};

if(retry>=100)return 1;

return 0;

}

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(11)

图11 DHT11初始化响应过程

从图11及代码可以看出,首先完成的是DHT11的IO口的初始化,初始化为输入(DHT11_IO_IN(););然后执行循环:

while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~50us

{

retry ;

delay_us(1);

};

在该循环中,当DHT11_DQ_IN接收到的是高电平,而且retry<100时,retry一直累加。DHT11_DQ_IN接收到的是高电平,说明DHT11并没有输出低电平,也就是说图11当中的t3并没有实现,主机没有接收到DHT11的初始化信息。直到等到retry达到100时,退出循环。

退出循环时,执行以下两句:

if(retry>=100)return 1;

else retry=0;

以上两句,如果retry>=100,输出1,说明初始化不成功,否则,说明在等待时间范围,DHT11接低了信号线,主机接收到信号。

接下来执行的又是循环:

while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~50us

{

retry ;

delay_us(1);

};

这回完成的是t4阶段,循环条件中如果DHT11_DQ_IN输出低电平((!DHT11_DQ_IN)或者retry<100,执行循环,说明t4没有拉高电平,直到拉高电平或retry>=100时,退出循环。

if(retry>=100)return 1;

return 0;

接下来又是输出,如果retry>=100,说明在规定的时间内DHT11始终没有输出高电平,初始化不成功。输出1,否则输出0。

综上所述,在DHT11初始化的两个阶段t3和t4中,只要有一个阶段没有实现,输出就为1,否则输出为0。当输出为0时,说明初始化成功。

第一部分完成了DHT11初始化,接下来完成数据的传输。

数据的传输分为三步:第一步,逐位读入DHT11数据;第二步:将每8位读入的数据形成数据字节;第三步,读取数据并进行数据校验。

第一步:逐位读入DHT11数据;

图12显示是DHT11中“0”的信号,从图中可知,0信号包括两个阶段,第一阶段为12—14us的低电平,第二个阶段为26—28us的高电平。当第二个阶段为26—28us的高电平时,输出为“0”。

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(12)

图12 DHT11中“0”的时序

基于stm32温湿度监测系统设计(零基础学习STM32智能家居系统之温湿度检测子系统的实现)(13)

图13 DHT11中“1”的时序

图13显示是DHT11中“1”的信号,从图中可知,“1”信号也包括两个阶段,第一阶段为12—14us的低电平,第二个阶段为116—118us的高电平。当第二个阶段为116—118us的高电平时,输出为“1”。

代码为:

//从DHT11读取一个位

//返回值:1/0

u8 DHT11_Read_Bit(void)

{

u8 retry=0;

while(DHT11_DQ_IN&&retry<100)//等待变为低电平

{

retry ;

delay_us(1);

}

retry=0;

while(!DHT11_DQ_IN&&retry<100)//等待变高电平

{

retry ;

delay_us(1);

}

delay_us(40);//等待40us

if(DHT11_DQ_IN)return 1;

else return 0;

}

在代码中包括了两个循环,第一段循环完成了DHT11输出信号第一阶段低电平的检测,第二段循环完成的是DHT11输出信号第二阶段高电平的检测。

最后的三句表示,在第二阶段高电平信号期间,如果40us时,DHT11_DQ_IN输出还是高电平,那么就输出1,如果输出是低电平,那么输出0。

第二步:将每8位读入的数据形成数据字节;

//从DHT11读取一个字节

//返回值:读到的数据

u8 DHT11_Read_Byte(void)

{

u8 i dat;

dat=0;

for (i=0;i<8;i )

{

dat<<=1;

dat|=DHT11_Read_Bit();

}

return dat;

}

在以上代码中,首先定义了两个U8的变量,i用来控制循环,而dat用来存储读入的字节,下面我们来看dat的变化过程。

首先dat=0,说明dat=00000000,进入循环后,当i=0时,dat<<=1,这时dat左移1位后再赋值给dat,结果为dat=00000000;

紧接着执行dat|= DHT11_Read_Bit(),以前面实例中湿度的整数部分byte4的值00101101为例,由于DHT11是高位先进,所以i=0时,DHT11_Read_Bit()取00101101的最高位,为0,执行dat|= DHT11_Read_Bit(),得出结果是dat=11111110。

接着执行i=1 DHT11_Read_Bit()取的是00101101的次高位,还是0,执行dat|= DHT11_Read_Bit()后,dat=11111100。

再接着执行i=2 DHT11_Read_Bit()取的是00101101的第三高位,为1,执行dat|= DHT11_Read_Bit()后,dat=11111001。

再接着执行i=3 DHT11_Read_Bit()取的是00101101的第四高位,为0,执行dat|= DHT11_Read_Bit()后,dat=11110010。

以此类推,可以得出dat的最终结果是00101101。

第三步,读取数据并进行数据校验。

//从DHT11读取一次数据

//temp:温度值(范围:0~50°)

//humi:湿度值(范围:20%~90%)

//返回值:0 正常;1 读取失败

u8 DHT11_Read_Data(u8 *temp u8 *humi)

{

u8 buf[5];

u8 i;

DHT11_Rst();

if(DHT11_Check()==0)

{

for(i=0;i<5;i )//读取40位数据

{

buf[i]=DHT11_Read_Byte();

}

if((buf[0] buf[1] buf[2] buf[3])==buf[4])

{

*humi=buf[0];

*temp=buf[2];

}

}else return 1;

return 0;

}

程序中首先定义了一个字符数组buf[5],buf[5]数组中包括5个8位的字符组,分别是buf[0]、buf[1]、buf[2]、buf[3]和buf[4]。

当DHT11初始化成功以后,系统依次读入5个字节的40位,buf[0]存放湿度整数、buf[1]存放湿度小数、buf[2]存放温度整数、buf[3]存放温度小数, buf[4]存放校验和的值。

然后执行:

if((buf[0] buf[1] buf[2] buf[3])==buf[4])

{

*humi=buf[0];

*temp=buf[2];

}

如果校验和没问题,那么将湿度整数的数值存入变量humi,将温度整数的数值存入变量temp。

4. 主程序的调用

#include "dht11.h"

DHT11_Init(); //温湿度传感器初始化

DHT11_Read_Data(&temp_value &humi_value); //读取温湿度值

以上是STM32 智能家居中温湿度子系统中DHT11传感器实现数据采集程序的解读,下一期将完成继电器带动风扇部分的设计。欢迎共同讨论,纠错。期待关注、点赞、转发。粉丝朋友可直接私信索要相关资料(项目源码)。

猜您喜欢: