1 前言
在我们日常的生活环境中,对于温度和湿度的测量很是需要
所以这次我们使用DHT11这个传感器来实现温湿度的测量
2 DHT11的介绍
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。产品为4针单排引脚封装,连接方便。
可以看到,这款DHT11的封装很是好看.
DHT11的详细参数如下所示
3 DHT11串行通信说明(单线双向)
3.1 单总线说明
3.2 单总线传送数据位定义
3.3 数据处理
![](https://img-blog.csdnimg.cn/3d088fec732042a6a1dc98f0c6c4fff9.png)
在处理数据的时候,我们要注意一些情况.
例如,我们的湿度的小数位永远都为0,所以湿度打印的时候不需要小数位.
再比如,温度也有细节,就是温度有负数哦,在一些偏北方的地区,在春冬季节经常都是零下,那么这款DHT11如何来测量零下的温度呢?
可以看到,其实处理起来也并不复杂,在零下的温度下面DHT11发送数据的温度的低八位的最高位会是1,我们只需要检测一下最高位是否为1,就能判断测量的温度是否为负数了.
如下是我写的相关代码,仅供参考
DHT11_Data->humi_high8bit = DHT11_ReadByte();
DHT11_Data->humi_low8bit = DHT11_ReadByte();
DHT11_Data->temp_high8bit= DHT11_ReadByte();
DHT11_Data->temp_low8bit = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
/*读取结束,引脚改为输出模式*/
DHT11_Mode_Out_PP();
/*主机拉高*/
DHT11_Dout_HIGH();
/* 对数据进行处理 */
humi_temp=DHT11_Data->humi_high8bit*10+DHT11_Data->humi_low8bit;
DHT11_Data->humidity =(float)humi_temp/10;
if(((DHT11_Data->temp_low8bit)>>7) == 1)
{
humi_temp=DHT11_Data->temp_high8bit*10+DHT11_Data->temp_low8bit;
DHT11_Data->temperature=-((float)humi_temp/10);
}
else
{
humi_temp=DHT11_Data->temp_high8bit*10+DHT11_Data->temp_low8bit;
DHT11_Data->temperature=(float)humi_temp/10;
}
最后就是关于校验位的处理
/*检查读取的数据是否正确*/
temp = DHT11_Data->humi_high8bit + DHT11_Data->humi_low8bit +
DHT11_Data->temp_high8bit+ DHT11_Data->temp_low8bit;
if(DHT11_Data->check_sum==temp)
{
return 1;
}
else
return 0;
很简单吧,其实就是对传过来的40位数据根据手册上面的说明及举例顺水推舟.
4 数据时序及读取步骤
4.1 读取DHT11 40位数据的时序
可以看到,从机(DHT11)发送信号的时候,会先发送低电平大约54us,然后拉高,发送高电平时间大约在23-27us确定从机发送的是低电平,在大约68-74us发送的是高电平.
根据这个规则,代码如下,仅供参考
/**
* 函数功能: 从DHT11读取一个字节
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
uint8_t DHT11_ReadByte ( void )
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
while(DHT11_Data_IN()==Bit_RESET);
Delay_us(40);
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
}
else // x us后为低电平表示数据“0”
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0
}
}
return temp;
}
这个函数实现了接受从机的1个字节的信号
4.2 整体步骤
如下就是整体的时序图
可以看出,大体的步骤就是主机先发,从机确认后从机准备发送,主机有确认好之后发送40位数据,发送玩之后就释放总线结束.
具体下来
/**
* 函数功能: 一次完整的数据传输为40bit,高位先出
* 输入参数: DHT11_Data:DHT11数据类型
* 返 回 值: 0: 读取出错
* 1:读取成功
* 说 明:8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
uint8_t temp;
uint16_t humi_temp;
/*输出模式*/
DHT11_Mode_Out_PP();
/*主机拉低*/
DHT11_Dout_LOW();
/*延时18ms*/
Delay_ms(18);
/*总线拉高 主机延时30us*/
DHT11_Dout_HIGH();
Delay_us(30); //延时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_high8bit = DHT11_ReadByte();
DHT11_Data->humi_low8bit = DHT11_ReadByte();
DHT11_Data->temp_high8bit= DHT11_ReadByte();
DHT11_Data->temp_low8bit = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
/*读取结束,引脚改为输出模式*/
DHT11_Mode_Out_PP();
/*主机拉高*/
DHT11_Dout_HIGH();
/* 对数据进行处理 */
humi_temp=DHT11_Data->humi_high8bit*10+DHT11_Data->humi_low8bit;
DHT11_Data->humidity =(float)humi_temp/10;
if(((DHT11_Data->temp_low8bit)>>7) == 1)
{
humi_temp=DHT11_Data->temp_high8bit*10+DHT11_Data->temp_low8bit;
DHT11_Data->temperature=-((float)humi_temp/10);
}
else
{
humi_temp=DHT11_Data->temp_high8bit*10+DHT11_Data->temp_low8bit;
DHT11_Data->temperature=(float)humi_temp/10;
}
/*检查读取的数据是否正确*/
temp = DHT11_Data->humi_high8bit + DHT11_Data->humi_low8bit +
DHT11_Data->temp_high8bit+ DHT11_Data->temp_low8bit;
if(DHT11_Data->check_sum==temp)
{
return 1;
}
else
return 0;
}
else
return 0;
}
5 总结
最后的实验结果如下
这一次,实现了对温湿度数据的读取,但是,我们这毕竟是一个智能时钟的项目啊,总不能通过串口将数据显示到电脑上面来吧,所以,我在下一次的实践中,将会实现在数码管上面的实现.实现很简单,但是其底层的原理也需要研究,我将使用的是TM1638,该芯片可以控制数码管,LED,还有按键,我将会在下一次深入研究.
下面是dht11.c和dht11.h
#include "Device/Include/stm32f10x.h" // Device header
#include "dht11.h"
#include "delay.h"
#include "LED.h"
void DHT11_Mode_IPU(void);
void DHT11_Mode_Out_PP(void);
uint8_t DHT11_ReadByte(void);
/**
* 函数功能: DHT11 初始化函数
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void DHT11_Init ( void )
{
DHT11_Dout_GPIO_CLK_ENABLE();
DHT11_Mode_Out_PP();
DHT11_Dout_HIGH(); // 拉高GPIO
}
/**
* 函数功能: 使DHT11-DATA引脚变为上拉输入模式
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = DHT11_Dout_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_Dout_PORT, &GPIO_InitStruct);
}
/**
* 函数功能: 使DHT11-DATA引脚变为推挽输出模式
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = DHT11_Dout_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_Dout_PORT, &GPIO_InitStruct);
}
/**
* 函数功能: 从DHT11读取一个字节
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
uint8_t DHT11_ReadByte ( void )
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
while(DHT11_Data_IN()==Bit_RESET);
Delay_us(40);
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
}
else // x us后为低电平表示数据“0”
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0
}
}
return temp;
}
/**
* 函数功能: 一次完整的数据传输为40bit,高位先出
* 输入参数: DHT11_Data:DHT11数据类型
* 返 回 值: 0: 读取出错
* 1:读取成功
* 说 明:8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
uint8_t temp;
uint16_t humi_temp;
/*输出模式*/
DHT11_Mode_Out_PP();
/*主机拉低*/
DHT11_Dout_LOW();
/*延时18ms*/
Delay_ms(18);
/*总线拉高 主机延时30us*/
DHT11_Dout_HIGH();
Delay_us(30); //延时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_high8bit = DHT11_ReadByte();
DHT11_Data->humi_low8bit = DHT11_ReadByte();
DHT11_Data->temp_high8bit= DHT11_ReadByte();
DHT11_Data->temp_low8bit = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
/*读取结束,引脚改为输出模式*/
DHT11_Mode_Out_PP();
/*主机拉高*/
DHT11_Dout_HIGH();
/* 对数据进行处理 */
humi_temp=DHT11_Data->humi_high8bit*10+DHT11_Data->humi_low8bit;
DHT11_Data->humidity =(float)humi_temp/10;
if(((DHT11_Data->temp_low8bit)>>7) == 1)
{
humi_temp=DHT11_Data->temp_high8bit*10+DHT11_Data->temp_low8bit;
DHT11_Data->temperature=-((float)humi_temp/10);
}
else
{
humi_temp=DHT11_Data->temp_high8bit*10+DHT11_Data->temp_low8bit;
DHT11_Data->temperature=(float)humi_temp/10;
}
/*检查读取的数据是否正确*/
temp = DHT11_Data->humi_high8bit + DHT11_Data->humi_low8bit +
DHT11_Data->temp_high8bit+ DHT11_Data->temp_low8bit;
if(DHT11_Data->check_sum==temp)
{
return 1;
}
else
return 0;
}
else
return 0;
}
#ifndef __DHT11_H__
#define __DHT11_H__
#include "Device/Include/stm32f10x.h" // Device header
typedef struct
{
uint8_t humi_high8bit; //原始数据:湿度高8位
uint8_t humi_low8bit; //原始数据:湿度低8位
uint8_t temp_high8bit; //原始数据:温度高8位
uint8_t temp_low8bit; //原始数据:温度高8位
uint8_t check_sum; //校验和
float humidity; //实际湿度
float temperature; //实际温度
} DHT11_Data_TypeDef;
/* 宏定义 -------------------------------------------------------------------*/
/*********************** DHT11 连接引脚定义 **************************/
#define DHT11_Dout_GPIO_CLK_ENABLE() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE)
#define DHT11_Dout_PORT GPIOD
#define DHT11_Dout_PIN GPIO_Pin_2
/*********************** DHT11 函数宏定义 ****************************/
#define DHT11_Dout_LOW() GPIO_WriteBit(DHT11_Dout_PORT,DHT11_Dout_PIN,Bit_RESET)
#define DHT11_Dout_HIGH() GPIO_WriteBit(DHT11_Dout_PORT,DHT11_Dout_PIN,Bit_SET)
#define DHT11_Data_IN() GPIO_ReadInputDataBit(DHT11_Dout_PORT,DHT11_Dout_PIN)
/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void DHT11_Init( void );
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef * DHT11_Data);
#endif