详解DHT11数字温湿度传感器实验

数字传感器

数字传感器是指将传统的模拟式传感器经过加装或改造A/D转换模块,使之输出信号为数字量(或数字编码)的传感器,主要包括:放大器、A/D转换器、微处理器(CPU)、存储器、通讯接口、温度测试电路等,在微处理器和传感器变得越来越便宜的今天,全自动或半自动(通过人工指令进行高层次操作,自动处理低层次操作)系统可以包含更多智能性功能,能从其环境中获得并处理更多不同的参数。

特点

1、先进的A/D转换技术和智能滤波算法,在满量程的情况下仍可保证输出码的稳定。

2、可行的数据存储技术,保证模块参数不会丢失。

3、良好的电磁兼容性能。

4、传感器的性能采用数字化误差补偿技术和高度集成化电子元件,用软件实现传感器的线性、零点、温漂、蠕变等性能参数的综合补偿,消除了人为因素对补偿的影响,大大提高了传感器综合精度和可靠性。

5、传感器的输出一致性误差可以达到0.02%以内甚至更高,传感器的特性参数可完全相同,因而具有良好的互换性。

6、采用A/D转换电路、数字化信号传输和数字滤波技术,传感器的抗干扰能力增加,信号传输距离远,提高了传感器的稳定性。

7、数字传感器能自动采集数据并可预处理、存储和记忆,具有唯一标记,便于故障诊断。

8、传感器采用标准的数字通讯接口,可直接连入计算机,也可与标准工业控制总线连接,方便灵活。

9, 数字传感器是将AD,EPROM,DIE(指还未封装的传感器芯片,属于裸片,大小介于cell和chip之间),封装在一块用PCB,金属块或陶瓷板上的集成。通过各种温度,压力点的校准,计算出DIE的线性,再利用AD去补偿的方法加工而成的。

应用及前景

在微处理器和传感器变得越来越便宜的今天,全自动或半自动(通过人工指令进行高层次操作,自动处理低层次操作)系统可以包含更多智能性功能,能从其环境中获得并处理更多不同的参数。尤其是MEMS(微型机电系统)技术,它使数字传感器的体积非常微小并且能耗与成本也很低。以纳米碳管或其它纳米材料制成的纳米传感器同样具有巨大的潜力 [1] 。

即使在萌芽阶段,人们仍然认为在不久的将来数字传感器对电子市场具有重要的推动作用。制作数字传感器的接口以及支持用于数字传感器网络的形式多样的通讯协议都是对技术工艺的巨大挑战。传感器的非均质特性和其操作条件的多样化也对技术工艺提出了巨大的挑战。

现在系统设计所包含的传感器和处理器越来越多。随着传感器和处理器价格的不断降低,取代机械控制结构的阈值也在不断变化。在系统中选择正确的传感器组合和处理算法可以显著地降低原材料及能耗的费用并提高系统的总体性能。目前,不断提高操作的简化程度和延长能源的使用寿命变得越来越重要,尤其是如今越来越多的传感器网络动辄就配置1000或更多的传感器节点。

DHT11是一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。DHT11与单片机之间能采用简单的单总线进行通信,仅仅需要一个I/O口。传感器内部湿度和温度数据40Bit的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。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的管脚排列如图36.1.1所示:

图36.1.1 DHT11管脚排列图

虽然DHT11与DS18B20类似,都是单总线访问,但是DHT11的访问,相对DS18B20来说要简单很多。下面我们先来看看DHT11的数据结构。

DHT11数字湿温度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由5Byte(40Bit)组成。数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出。DHT11的数据格式为:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。其中校验和数据为前四个字节相加。

传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。例如,某次从DHT11读到的数据如图36.1.2所示:

图36.1.2 某次读取到DHT11的数据

由以上数据就可得到湿度和温度的值,计算方法:

湿度= byte4 。 byte3=45.0 (%RH)

温度= byte2 。 byte1=28.0 ( ℃)

校验= byte4+ byte3+ byte2+ byte1=73(=湿度+温度)(校验正确)

可以看出,DHT11的数据格式是十分简单的,DHT11和MCU的一次通信最大为3ms左右,建议主机连续读取时间间隔不要小于100ms。

下面,我们介绍一下DHT11的传输时序。DHT11的数据发送流程如图36.1.3所示:

图36.1.3 DHT11数据发送流程

首先主机发送开始信号,即:拉低数据线,保持t1(至少18ms)时间,然后拉高数据线t2(20~40us)时间,然后读取DHT11的相应,正常的话,DHT11会拉低数据线,保持t3(40~50us)时间,作为响应信号,然后DHT11拉高数据线,保持t4(40~50us)时间后,开始输出数据。

DHT11输出数字‘0’的时序如图36.1.4所示:

图36.1.4 DHT11数字‘0’时序

DHT11输出数字‘1’的时序如图36.1.5所示:

图36.1.5 DHT11数字‘1’时序

通过以上了解,我们就可以通过STM32来实现对DHT11的读取了。DHT11的介绍就到这里,更详细的介绍,请参考DHT11的数据手册。

36.2 硬件设计

由于开发板上标准配置是没有DHT11这个传感器的,只有接口,所以要做本章的实验,大家必须找一个DHT11插在预留的DHT11接口上。

本章实验功能简介:开机的时候先检测是否有DHT11存在,如果没有,则提示错误。只有在检测到DHT11之后才开始读取温湿度值,并显示在LCD上,如果发现了DHT11,则程序每隔100ms左右读取一次数据,并把温湿度显示在LCD上。同样我们也是用DS0来指示程序正在运行。

所要用到的硬件资源如下:

1) 指示灯DS0

2) TFTLCD模块

3) DHT11温湿度传感器

这些我们都已经介绍过了,DHT11和DS18B20的接口是共用一个的,不过DHT11有4条腿,需要把U13的4个接口都用上,将DHT11传感器插入到这个上面就可以通过STM32来读取温湿度值了。连接示意图如图36.2.1所示:

图36.2.1 DHT11连接示意图

这里要注意,将DHT11贴有字的一面朝内,而有很多孔的一面朝外,然后然后插入如图所示的四个孔内就可以了。

36.3 软件设计

打开上一章的工程,首先在HARDWARE文件夹下新建一个DHT11的文件夹。然后新建一个dht11.c和dht11.h的文件保存在DHT11文件夹下,并将这个文件夹加入头文件包含路径。

打开dht11.c在该文件下输入如下代码:

#include “dht11.h”

#include “delay.h”

//复位DHT11

void DHT11_Rst(void)

{

DHT11_IO_OUT(); //SET OUTPUT

DHT11_DQ_OUT=0; //拉低DQ

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

DHT11_DQ_OUT=1; //DQ=1

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

}

//等待DHT11的回应

//返回1:未检测到DHT11的存在

//返回0:存在

u8 DHT11_Check(void)

{

u8 retry=0;

DHT11_IO_IN();//SET INPUT

while (DHT11_DQ_IN&&retry《100)//DHT11会拉低40~80us

{

retry++;

delay_us(1);

};

if(retry》=100)return 1;

else retry=0;

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

{

retry++;

delay_us(1);

};

if(retry》=100)return 1;

return 0;

}

//从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读取一个字节

//返回值:读到的数据

u8 DHT11_Read_Byte(void)

{

u8 i,dat;

dat=0;

for (i=0;i《8;i++)

{

dat《《=1;

dat|=DHT11_Read_Bit();

}

return dat;

}

//从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;

}

//初始化DHT11的IO口 DQ 同时检测DHT11的存在

//返回1:不存在

//返回0:存在

u8 DHT11_Init(void)

{

RCC-》APB2ENR|=1《《8; //使能PORTG口时钟

GPIOG-》CRH&=0XFFFF0FFF;//PORTG.11 推挽输出

GPIOG-》CRH|=0X00003000;

GPIOG-》ODR|=1《《11; //输出1

DHT11_Rst();

return DHT11_Check();

}

该部分代码就是根据我们前面介绍的单总线操作时序来读取DHT11的温湿度值的,DHT11的温湿度值通过DHT11_Read_Data函数读取,如果返回0,则说明读取成功,返回1,则说明读取失败。保存dht11.c,并把该文件加入到HARDWARE组下,然后我们打开dht11.h,在该文件下输入如下内容:

#ifndef __DHT11_H

#define __DHT11_H

#include “sys.h”

//IO方向设置

#define DHT11_IO_IN() {GPIOG-》CRH&=0XFFFF0FFF;GPIOG-》CRH|=8《《12;}

#define DHT11_IO_OUT() {GPIOG-》CRH&=0XFFFF0FFF;GPIOG-》CRH|=3《《12;}

////IO操作函数

#define DHT11_DQ_OUT PGout(11) //数据端口 PG11

#define DHT11_DQ_IN PGin(11) //数据端口 PG11

u8 DHT11_Init(void); //初始化DHT11

u8 DHT11_Read_Data(u8 *temp,u8 *humi);//读取温湿度

u8 DHT11_Read_Byte(void); //读出一个字节

u8 DHT11_Read_Bit(void); //读出一个位

u8 DHT11_Check(void); //检测是否存在DHT11

void DHT11_Rst(void); //复位DHT11

#endif

此部分代码比较简单,接下来,我们先保存这段代码,然后打开test.c,在该文件下修改main函数如下:

int main(void)

{

u8 t=0;

u8 temperature;

u8 humidity;

Stm32_Clock_Init(9); //系统时钟设置

uart_init(72,9600); //串口初始化为9600

delay_init(72); //延时初始化

LED_Init(); //初始化与LED连接的硬件接口

LCD_Init(); //初始化LCD

usmart_dev.init(72); //初始化USMART

KEY_Init(); //按键初始化

POINT_COLOR=RED;//设置字体为红色

LCD_ShowString(60,50,200,16,16,“WarShip STM32”);

LCD_ShowString(60,70,200,16,16,“DHT11 TEST”);

LCD_ShowString(60,90,200,16,16,“ATOM@ALIENTEK”);

LCD_ShowString(60,110,200,16,16,“2012/9/12”);

while(DHT11_Init()) //DHT11初始化

{

LCD_ShowString(60,130,200,16,16,“DHT11 Error”);

delay_ms(200);

LCD_Fill(60,130,239,130+16,WHITE);

delay_ms(200);

}

LCD_ShowString(60,130,200,16,16,“DHT11 OK”);

POINT_COLOR=BLUE;//设置字体为蓝色

LCD_ShowString(60,150,200,16,16,“Temp: C”);

LCD_ShowString(60,170,200,16,16,“Humi: %”);

while(1)

{

if(t==0)//每100ms读取一次

{

DHT11_Read_Data(&temperature,&humidity); //读取温湿度值

LCD_ShowNum(60+40,150,temperature,2,16); //显示温度

LCD_ShowNum(60+40,170,humidity,2,16); //显示湿度

}

delay_ms(10);

t++;

if(t==20)

{

t=0;

LED0=!LED0;

}

}

}

发表评论