第十六章 DHT11实验 本章将向大家介绍如何使用 W7500EVB来读取 DHT11 数字温湿度传感器,从而得到周围环境湿度和温度,将温度和湿度显示在OLED 屏上。
本章分为如下几个部分:
16.1 DHT11 简介
16.2 硬件设计
16.3 软件设计
16.4 下载验证
16.1 DHT11 简介DHT11 是一款温湿度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个 NTC测温元件,并与一个高性能 8 位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。 DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一个 IO 口。传感器内部湿度和温度数据会一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。 DHT11 功耗很低,5V 电源电压下,工作平均最大电流 0.5mA。
DHT11 的技术参数如下: l 工作电压范围: 3.3V-5.5V
l 工作电流 :平均 0.5mA
l 输出:单总线数字信号
l 测量范围:湿度 20~90%RH,温度 0~50℃
l 精度 :湿度±5%,温度±2℃
l 分辨率 :湿度 1%,温度 1℃ 虽然 DHT11 与 DS18B20 类似,都是单总线访问,但是 DHT11 的访问,相对 DS18B20 来说要简单很多。下面先来看看 DHT11 的数据结构。DHT11 数字温湿度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由 5Byte(40Bit)组成。数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出。 DHT11 的数据格式为: 8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和。其中校验和数据为前四个字节相加。传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。例如,某次从 DHT11 读到的数据,如图16.1.1所示: 图16.1.1 DHT11数据格式 由以上数据就可得到湿度和温度的值,计算方法:
湿度= byte4 . byte3=45.0 (%RH)
温度= byte2 . byte1=28.0 ( ℃)
校验= byte4+ byte3+ byte2+ byte1=73(=湿度+温度)(校验正确) 可以看出,DHT11 的数据格式是十分简单的,DHT11 和 MCU 的一次通信最大为 3ms 左右,建议主机连续读取时间间隔不要小于 100ms。下面,介绍一下 DHT11 的传输时序。 DHT11 的数据发送流程,如图16.1.2所示: 图16.1.2 DHT11通信时序 首先主机发送开始信号,即:拉低数据线,保持 t1(至少 18ms)时间。然后拉高数据线 t2(20~40us)时间。之后取 DHT11 的响应,正常的话, DHT11 会拉低数据线,保持 t3(40~50us)时间,作为响应信号。最后 DHT11 拉高数据线,保持 t4(40~50us)时间后,开始输出数据。DHT11 输出数字‘0’的时序,如图16.1.3所示:
图16.1.3 DHT11开始信号 DHT11 输出数字‘1’的时序,如图16.1.4所示:
图16.1.4 DHT11输出数字‘1’的时序 16.2 硬件设计本章实验功能简介:读取DHT11的温度和湿度并显示在 OLED 屏上。
所要用到的硬件资源如下: 1) OLED 模块 2) DHT11 温湿度传感器 16.3 软件设计打开 DHT11 数字温湿度传感器实验工程可以发现,在工程中添加了 dht11.c 文件和dht11.h 文件,所有 DHT11 相关的驱动代码和定义都在这两个文件中。 打开 dht11.c 代码如下: [mw_shl_code=applescript,true]void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = PA2;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
/*调用库函数,初始化DHT11_PORT*/
GPIO_Init(GPIOA, &GPIO_InitStructure);
PAD_AFConfig(PAD_PA, PA2, PAD_AF1);
GPIO_SetBits(GPIOA, PA2);
}
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = PA2;
/*设置引脚模式为浮空输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN ;
/*调用库函数,初始化DHT11_PORT*/
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = PA2;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
/*调用库函数,初始化DHT11_PORT*/
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
static uint8_t Read_Byte(void)
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
while(DHT11_DATA_IN()==Bit_RESET);
delay_10us(4); //延时x us 这个延时需要大于数据0持续的时间即可
if(DHT11_DATA_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */
{
/* 等待数据1的高电平结束 */
while(DHT11_DATA_IN()==Bit_SET);
temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
}
else // x us后为低电平表示数据“0”
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
}
}
return temp;
}
uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{
/*输出模式*/
DHT11_Mode_Out_PP();
/*主机拉低*/
DHT11_DATA_OUT(0);
/*延时18ms*/
delay_ms(18);
/*总线拉高 主机延时30us*/
DHT11_DATA_OUT(1);
delay_10us(3); //延时30us
/*主机设为输入 判断从机响应信号*/
DHT11_Mode_IPU();
/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
if(DHT11_DATA_IN()==Bit_RESET)
{
/*轮询直到从机发出 的80us 低电平 响应信号结束*/
while(DHT11_DATA_IN()==Bit_RESET);
/*轮询直到从机发出的 80us 高电平 标置信号结束*/
while(DHT11_DATA_IN()==Bit_SET);
/*开始接收数据*/
DHT11_Data->humi_int= Read_Byte();
DHT11_Data->humi_deci= Read_Byte();
DHT11_Data->temp_int= Read_Byte();
DHT11_Data->temp_deci= Read_Byte();
DHT11_Data->check_sum= Read_Byte();
/*读取结束,引脚改为输出模式*/
DHT11_Mode_Out_PP();
/*主机拉高*/
DHT11_DATA_OUT(1);
/*检查读取的数据是否正确*/
if(DHT11_Data->check_sum == DHT11_Data->humi_int +\
DHT11_Data->humi_deci +\
DHT11_Data->temp_int +\
DHT11_Data->temp_deci)
return SUCCESS;
else
return ERROR;
}
else
{
return ERROR;
}
}[/mw_shl_code] 该部分代码首先是通过函数 DHT11_Init 初始化引脚,然后根据前面介绍的单总线操作时序来读取 DHT11 的温湿度值的, DHT11 的温湿度值通过 DHT11_Read_Byte 函数读取。 接下来我们打开 main.c, 该文件代码如下: [mw_shl_code=applescript,true]int main()
{
/* 炜世科技—WIZnet W7500官方代理商,全程技术支持,价格绝对优势 */
DHT11_Data_TypeDef DHT11_Data;
uint8_t Temp[8] = "\0";
uint8_t Humi[9] = "\0";
SystemInit(); /* 系统内部时钟初始化 */
delay_init(); /* 系统滴答时钟配置*/
GPIO_Configuration(); /* DHT11管脚初始化 */
SSP_Configuration(); /* SPI0配置初始化 */
OLED_init(); /* OLED屏配置初始化 */
OLED_Show_Hybrid(0, 0, (uint8_t*)"炜世科技W7500EVB");
while(1)
{
Read_DHT11(&DHT11_Data);
Temp[0] = 'T';
Temp[1] = 'E';
Temp[2] = 'M';
Temp[3] = 'P';
Temp[4] = ':';
Temp[5] = DHT11_Data.temp_int/10 + '0';
Temp[6] = DHT11_Data.temp_int%10 + '0';
Temp[7] = '\0';
Humi[0] = 'H';
Humi[1] = 'U';
Humi[2] = 'M';
Humi[3] = 'I';
Humi[4] = ':';
Humi[5] = DHT11_Data.humi_int/10 + '0';
Humi[6] = DHT11_Data.humi_int%10 + '0';
Humi[7] = '%';
Humi[8] = '\0';
OLED_Show_Hybrid(2, 26, (uint8_t*)Temp);
OLED_SHOWCHAR(2, 82, centigrade);
OLED_Show_Hybrid(4, 26, (uint8_t*)Humi);
delay_ms(100);
}
}[/mw_shl_code] 主函数比较简单,进行一系列初始化后,那么每隔 100ms 读取一次转换数据并显示在OLED屏上。 16.4 下载验证在代码编译成功之后,下载代码到W7500EVB 开发板上,可以在OLED屏上看到当前的温度和湿度,如图16.4.1所示: 图16.4.1 W7500EVB DHT11试验结果
|