文章目录
前言
温度和湿度是环境因素中非常重要的两个参数。它们对于人类的健康和舒适感、生物的生长发育、物体的保存和保护等都起着重要的影响。本文基于STM32驱动单总线设备DHT11来测量环境的温湿度,编程的重点在于DHT11的时序。
一、DHT11的相关特性
1.测量参数
采样周期间隔>=1S.
2.典型电路
建议连接线长度短于20m时使用5kΩ上拉电阻,大于20m时根据实际情况增加适合的上拉电阻。这里的VDD=3.3V,DATA引脚接单片机的PA5引脚。
3.串行接口(单线双向)
使用单总线的通讯方式与MCU进行数据的传输,当MCU给DHT11发送起始信号时,DHT11响应后开始采集数据,采集完成后,一次性向MCU发送40位完成的数据,并且数据是 高位先出 的。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。
其中数据传输正确时的校验和等于“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”所得结果的末8位。
二、使用步骤
1.相关的头文件代码
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
#include "delay.h"
#define DHT11_IO GPIO_Pin_5
#define DHT11_PORT GPIOA
#define DHT11_SET_IO(x) (x) ? GPIO_SetBits(DHT11_PORT, DHT11_IO) : GPIO_ResetBits(DHT11_PORT, DHT11_IO)
#define DHT11_READ_IO GPIO_ReadInputDataBit(DHT11_PORT, DHT11_IO)
extern u8 dht_data[5];
extern u8 wendu;
extern u8 shidu;
void rst_dht11(void);
u8 check_dht11(void);
u8 read_dht_bit(void);
u8 read_dht_byte(void);
u8 read_dht_data(void);
#endif
2.时序
2.1 复位和检测响应时序
//作用:初始化dht11的io为输出
//无返回值
//无输入参数
void init_dht11_out(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能A端口时钟
GPIO_InitStructure.GPIO_Pin = DHT11_IO; //GPIOA5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(DHT11_PORT, &GPIO_InitStructure); //初始化GPIOA5
GPIO_SetBits(DHT11_PORT, DHT11_IO);
}
//作用:初始化dht11的io为输入
//无返回值
//无输入参数
void init_dht11_in(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能A端口时钟
GPIO_InitStructure.GPIO_Pin = DHT11_IO; //GPIOA5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(DHT11_PORT, &GPIO_InitStructure); //初始化GPIOA5
}
void rst_dht11(void) //发送起始信号以复位
{
init_dht11_out();
DHT11_SET_IO(0);
delay_ms(20);
DHT11_SET_IO(1);
delay_us(30);
}
u8 check_dht11(void) //检查响应
{
u8 retry = 0;
init_dht11_in();
while(DHT11_READ_IO == 1) //等待dht低电平响应
{
delay_us(1);
retry ++;
if(retry >= 200) return 1; //等待时间过长
}
retry = 0;
while(DHT11_READ_IO == 0) //等待拉高电平,准备发送数据
{
delay_us(1);
retry ++;
if(retry >= 200) return 1; //等待时间过长
}
retry = 0;
while(DHT11_READ_IO == 1) //等待dht低电平响应,等待发0/1的共同电平到来
{
delay_us(1);
retry ++;
if(retry >= 200) return 1; //等待时间过长
}
return 0;
}
2.2 读1和读0时序
1.读0时序
2.读1时序
读取数据的代码如下,注意,每读完一次1都要等待高电平时序(读1的电平持续时间约为70us),结束才能读取下一位数据。
u8 read_dht_bit(void) //只读一位0/1
{
u8 retry = 0;
while(DHT11_READ_IO == 0) //等待发送0/1的低电平结束
{
delay_us(1);
retry ++;
if(retry >= 200) break;
}
delay_us(40); //排除0信号,检测1信号
if(DHT11_READ_IO) //是1信号就返回1
return 1;
else
return 0; //0信号返回0
return 0;
}
u8 read_dht_byte(void) //读取DHT的1个字节数据
{
u8 data = 0, i;
for(i = 0; i < 8; i ++)
{
if(read_dht_bit())
{
data |= (1 << (7 - i)); //高位先出,就将读到的数据按序移到相应位置
while(DHT11_READ_IO == 1); // 等待读1的高电平结束
}
}
return data;
}
3. DHT11温、湿度的读取操作
主机(MCU)发送复位信号后,DHT11进入温、湿度采集模式,并行MCU发送响应信号,温湿度采集完成后一次性完整地向MCU发送40bit的数据。在温、湿度等数据读取时采用数组来存放相关的数据,并进行数据的校验和检验,如果校验和正确,就显示一次数据。具体的函数代码如下:
//作用:读取温、湿度函数,温度和湿度的数值分别传输给wendu、shidu
//返回值:复位无响应返回1,校验和错误返回2,正常返回0.
//无输入参数
u8 read_dht_data(void) //读取5个字节的数据,包含温、湿度和校验位
{
u8 reack = 1, i;
rst_dht11(); //主机给起始信号
reack = check_dht11(); //检查dht的响应
if(reack == 0) //有响应
{
for(i = 0; i < 5; i ++)
dht_data[i] = read_dht_byte();
}
else //无响应返回1
return 1;
if(dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3] == dht_data[4]) //和校验
{
wendu = dht_data[2];
shidu = dht_data[0];
}
else //校验和不通过返回2
return 2;
return 0;
}
实物效果及总结
单总线的设备通常要根据时序图将复位、读取响应、读取一位数据、读取一个字节、最终读取数据。有些设备(比如上次更新的DS18B20检测温度)还需要写字节操作,并根据指令发送十六进制的指令进行使用。在写时序时一定要严格按照时序图的延时时间编写程序,通常使用while()判断电平来确定电平时序的却换,为了稳妥些(防止MCU卡死在时序函数的while死循环中),应该规定一定超时时间退出时序的死循环。