一、模块分析:
原理图和引脚连接图:
由图可知DHT11(温湿度模块)是单总线的连接,数据的输入输出由一根线完成,DQ网络标号对应的引脚是PG9就是GPIO外设接口G组的第九个引脚。
二、DHT11时序图:
由上图可以判断当主机开始信号发送之后手袋DHT11响应信号并开始接受数据时,我们可以通过判断高电平的维持时间来获取当前接受的数据位是0/1这样就可以把数据保存下来。判断的依据是开始接受数据前延时超过26-28us,当延时过后检测到的还是高电平(高电平持续70us为数据1)那就证明该数据位为‘1’。因为每一个比特位传输完成之后会有50us的延迟所以当比特位为0时前面已经延时超过高电平时间所以比特位为0时,检测到的是低电平,由此来保存温湿度数据。
三、部分关键代码:
#include “dht11.h”
//单数据总线接口 —>PG9
void DHT11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//1:第一步永远是打开时钟,查看固件库
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOG, ENABLE );
//对结构体成员进行赋值(输出 推挽 上拉 50MHZ)
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//输出模式
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
//2:对GPIOG进行初始化
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_Init( GPIOG ,&GPIO_InitStructure);
}
/*=2-配置GPIO口的输入模式函数=========*/
static void DHT11_Mode_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//浮空输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空输入
GPIO_Init(GPIOG,&GPIO_InitStruct);
}
/*=2-配置GPIO口的输出模式函数=========*/
static void DHT11_Mode_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//上拉推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOG,&GPIO_InitStruct);
}
/3-配置8位接收数据函数,根据DHT11数据传输时序图编写=/
//数据是高位先出
static uint8_t Read_Byte(void)
{
uint8_t i,temp=0;
for(i=0;i<8;i++)
{
//数据准备输出 每个数据都有50US的低电平,然后判断后面高电平是时长来决定是1还是0
//0:高电平时长26~28us
//1:高电平时长70us
/*每一个bit都是以50us的低电平开始,等电平置高,则跳出循环*/
while( DQ_IN() == 0 );
/*‘0’表示的置高时间过短,可直接判断‘1’表示的时间,但滞留时间不宜过长,以防跳出下一位的开始时间*/
delay_us(40);
if( DQ_IN() == 1 )//如果还是高电平,那就是数据1
{
/*等待跳出‘1’置高表示的时间*///等待剩余的高电平时间结束
while( DQ_IN() == 1);
/*把第(7-i)位置 '1'*/
temp |= (uint8_t)(0x01<<(7-i));
}
else
{
/*把第(7-i)位置 '0'*/
temp &= (uint8_t)~(0x01<<(7-i));
}
}
return temp;
}
/*
*功 能:获取温湿度值
*参 数:保存温度读数据的结构体指针
返回值:成功返回1 失败返回0
*
/
/4-根据总时序图编写接收数据函数=/
uint32_t DHT11_GET_TEMP_HUM(DHT11_Data_TypeDef * DHT11_Data)
{
uint16_t count = 0;
DHT11_Mode_OUT();//输出模式
DQ_OUT(0); /*将主机拉低*/
delay_ms(20);/*配置主机拉低时间,至少拉低18ms*/
DQ_OUT(1);/*将主机拉高*/
delay_us(30);
DHT11_Mode_IN();//输入模式
if( DQ_IN() == 0)
{
//printf("开始获取数据\r\n");
//因为在空闲状态下,管教是高电平,所以这个时候如果是低电平,则模块有响应
//等待拉高 时长80us
while(DQ_IN() == 0)//等待80us结束
{
count++;
if(count > 1000)
return 0;
delay_us(1);//每1us检测一次是否拉高
}
//printf("80us low\r\n");
count = 0;
//等待拉高 时长80us
while( DQ_IN()== 1)//等待80us结束
{
count++;
if(count > 1000)
return 0;
delay_us(1);//每1us检测一次是否拉高
}
// printf("80us hight\r\n");
// 获取5个字节数据
//分析40位数据,8Bit湿度整数 +8Bit湿度小数 +8Bit温度整数 +8Bit温度小数
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();
// printf("get data success\r\n");
/*读取结束,将主机设为输出模式*/
DHT11_Mode_OUT();//输出模式
DQ_OUT(1);/*将主机拉高,方便下次读取数据*/
if(DHT11_Data->check_sum == (DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int + DHT11_Data->temp_deci))
{
printf("校验和正常\r\n");
return 1;
}
else
{
printf("校验和失败\r\n");
return 0;
}
}
else
return 0;
}