DHT11温湿度传感器数据采集
前言
了解DHT11温湿度传感器相关知识,进行DHT11传感器的开发及数据获取,并通过串口调试助手查看
一、温湿度传感器相关知识
1. DHT11简介
DHT11温湿度传感器是一种比较便宜的常见的温湿度传感器,它的内部由两个元件构成,一个是电阻式的感湿元件用来检测环境湿度,另一个是NTC测温元件来测量温度,在测得数据后,两个元件会将数据传送给内部一个集成的8位的处理器来对数据进行处理,并将它们转换为数字量,这些数据可以通过串口传送给主机。DHT11温湿度传感器有四个管脚,只有一条是数据线接口,所以在传输数据时仅需要1个I/O就能同时传输测得的温度以及湿度,在进行程序编写时更加简洁方便。因为DHT11集成度较好,体积比较小,所以消耗也很小,抗干扰能力更强,稳定性较好,不易受到外界干扰。
Pin1 VDD 供电 3-5.5V DC Pin2 DATA 串行数据,单总线 Pin3 NC 空脚,悬空 Pin4 GND 接地,电源负极
DHT11集成度很高,封装的很简洁,只有四个管脚,所以连接也是相对比较方便。DHT11管脚Pin1接一个3-5.5V的直流电源的正极,管脚Pin2为数据端,主要用于传输数据,但是在接线时需要加一个5KΩ的上拉电阻连接到主机MCU上,用来保证数据传输的稳定性,同时还要注意这个5KΩ是在管脚Pin2与主机之间的接线小于20m时才有用,在大于20m时就需要根据实际情况来确定需要加多大的上拉电阻来保持稳定性。管脚Pin3不起什么作用,只需要将其悬空不接线即可,管脚Pin4接地。
2.数据格式
DHT11和DS18B20不同,DHT11不需要配置,可以直接读取数据,一次完整的数据传输为40bit,先传输高字节的数据再传输低字节的数据,也就是低位后出,高位先出模式。 数据格式: 8bit湿度整数数据 + 8bit湿度小数数据 +8bit温度整数数据 + 8bit温度小数数据 +8bit校验和 数据传送正确时校验和数据等于 8bit湿度整数数据 + 8bit湿度小数数据 +8bit温度整数数据 + 8bit温度小数数据 所得结果的末8位。
3.数据传输
数据线一开始处于高电平状态,用户MCU将总线电平拉低,表示用户要开始获取数据,然后将电平拉高并延时等待一段时间,等待DHT11回复,如果DHT11将总线拉低,表示已经收到主机信号,并响应主机信号,准备输出,然后将总线电平拉高,并延时一段时间,表示准备传输40bit的数据。然后将数据总线拉低一段时间开始传输数据,主要是进行2进制数据传输,传输0和1,并用不同的拉高电平延时时间来表示数据0和1。用户可以选择读取湿度还是温度,整数还是小数。并且数据传输是需要DHT11收到主机MCU发送的开始信号,才会开始采集数据传输数据,而且此时DHT11会转到低速模式。 总线在空闲时因为上拉电阻会处于高电平状态,主机用户MCU会发送信号将电平拉低至少18us,太短DHT11可能会检测不到主机的起始信号。之后主机会再将电平拉高20-40us,DHT11识别到后,会将电平拉低80us,表示DHT11已经接收到主机发送的开始信号,之后再将总线切换到输入模式,然后DHT11会再将电平拉高80us表示竹北开始传输数据。之后会再将电平拉低,然后开始传输数据。
当接收到主机的开始信号后,DHT11会将总线拉低80us来发送响应信号,表示已经接收到,然后会将总线拉高80us,并准备发送数据,每一位的数据都以50us的低电平间隙开始,就是每两个数据之间都有一个50us的低电平信号来表示一位数据传输完成。DHT11用电平拉高延时的时间来表示数据为位0还是1。通常用拉高26-28us来表示数据‘0’,用拉高70us来表示数据‘1’。当最后一位数据传输完成后,DHT11会将总线拉低50us,随后总线又会因为上拉电阻将总线拉高,并处于空闲状态。
DHT11读取数据“0”时序图 DHT11读数据“1”时序图
二、程序实现
1.dht11.h
DHT11的程序实现主要是根据它的读写时序来实现的,因此在进行程序的编写时要根据它的读写时序进行模拟,实现单片机与DHT11之间的数据通信。
代码如下(示例):
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
typedef struct
{
uint8_t humi_int;
uint8_t humi_deci;
uint8_t temp_int;
uint8_t temp_deci;
uint8_t check_sum;
} DHT11_Data_TypeDef;
#define DHT11_Dout_SCK_APBxClock_FUN RCC_APB2PeriphClockCmd
#define DHT11_Dout_GPIO_CLK RCC_APB2Periph_GPIOE
#define DHT11_Dout_GPIO_PORT GPIOE
#define DHT11_Dout_GPIO_PIN GPIO_Pin_6
#define DHT11_Dout_0 GPIO_ResetBits ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
#define DHT11_Dout_1 GPIO_SetBits ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
#define DHT11_Dout_IN() GPIO_ReadInputDataBit ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
void DHT11_Init ( void );
uint8_t DHT11_Read_TempAndHumidity ( DHT11_Data_TypeDef * DHT11_Data );
#endif
DHT11用到的数据总线是PE6,接线时,DHT11数据线接到PE6,以及我们需要用到的函数的声明: Void DHT11_Init(void)为DHT11的初始化函数; uint8_t DHT11_Read_TempAndHumidity ( DHT11_Data_TypeDef * DHT11_Data )为DHT11的数据读取函数,这个函数会将读取到的数据赋值给DHT11_Data结构体里的变量,然后还会有一个返回值判断是否读取成功;
2.dht11.c
代码如下(示例):
#include "dht11.h"
#include "delay.h"
static void DHT11_GPIO_Config ( void );
static void DHT11_Mode_IPU ( void );
static void DHT11_Mode_Out_PP ( void );
static uint8_t DHT11_ReadByte ( void );
void DHT11_Init ( void )
{
DHT11_GPIO_Config ();
DHT11_Dout_1;
}
static void DHT11_GPIO_Config ( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
DHT11_Dout_SCK_APBxClock_FUN ( DHT11_Dout_GPIO_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init ( DHT11_Dout_GPIO_PORT, &GPIO_InitStructure );
}
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
static uint8_t DHT11_ReadByte ( void )
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
while(DHT11_Dout_IN()==Bit_RESET);
delay_us(40);
if(DHT11_Dout_IN()==Bit_SET)
{
while(DHT11_Dout_IN()==Bit_SET);
temp|=(uint8_t)(0x01<<(7-i));
}
else
{
temp&=(uint8_t)~(0x01<<(7-i));
}
}
return temp;
}
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_Mode_Out_PP();
DHT11_Dout_0;
delay_ms(18);
DHT11_Dout_1;
delay_us(30);
DHT11_Mode_IPU();
if(DHT11_Dout_IN()==Bit_RESET)
{
while(DHT11_Dout_IN()==Bit_RESET);
while(DHT11_Dout_IN()==Bit_SET);
DHT11_Data->humi_int= DHT11_ReadByte();
DHT11_Data->humi_deci= DHT11_ReadByte();
DHT11_Data->temp_int= DHT11_ReadByte();
DHT11_Data->temp_deci= DHT11_ReadByte();
DHT11_Data->check_sum= DHT11_ReadByte();
DHT11_Mode_Out_PP();
DHT11_Dout_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;
}
3.main.c
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "dht11.h"
int main()
{
DHT11_Data_TypeDef Dht_Data;
char Temp_Str[ 10 ] = { 0 };
char Hum_Str[ 10 ] = { 0 };
USART_Config();
SysTick_Init();
printf("\r\n***Dht11 温湿度传感器实验***\r\n");
DHT11_Init();
while(1)
{
if(DHT11_Read_TempAndHumidity(&Dht_Data) == SUCCESS)
{
sprintf(Temp_Str,"%d.%d",Dht_Data.temp_int,Dht_Data.temp_deci);
sprintf(Hum_Str,"%d,%d",Dht_Data.humi_int,Dht_Data.humi_deci);
printf("温度数据为:%d.%d ℃\r\n",Dht_Data.temp_int,Dht_Data.temp_deci);
printf("湿度数据为:%d.%d %RH\r\n",Dht_Data.humi_int,Dht_Data.humi_deci);
}
else
printf("error\r\n");
delay_ms(2000);
}
}
4.串口显示
将开发板连接电脑,然后打开串口调试助手,就会看到温度以及湿度的数据
总结
做到这一步算是已经完成温湿度采集并串口显示,有需要的话可以进行LCD显示。
|