目录
DHT11简介
这是一款数字温湿度传感器,可以同时测量温度和湿度,传输接口是以数字信号输出的方式进行。实物图和原理图如下:
由图可知,DHT11有四根引脚,一根接电源,一根接地,一根传输数据(单线双向),一根作为保护电路。
DHT11使用
查看引脚编号
通讯过程
数据格式
8bit湿度整数数据+8bit湿度小数数据 +8bit温度整数数据+8bit温度小数数据 +8bit校验和 。数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据 +8bit温度整数数据+8bit温度小数数据”所得结果的末8位。
信号格式
刚开始,数据线为输出模式,用户必须主动发信号,等到DHT响应以后,转输出模式为输入模式,DHT开始传输数据
总线空闲状态为高电平,主机把总线拉低等待DHT1 1响应,主机把总线拉低必 须大于18毫秒,保证DHT11能检测到起始信号。
DHT11接收到主机的开始信号后, 等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束 后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换 到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。
数据传输
数据0为高电平26-28us、数据1为高电平80us,以50us为间隔将数据隔离开,其真实过程中会有一丢丢误差。
代码
//Dht11.c
#include "stm32f4xx.h" // Device header
#include "BitBand.h" // Component selection
#include "delay.h"
#include "stdio.h"
void Dht11_Init()
{
//PG9
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//协议都配推挽
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
GPIO_Init(GPIOG,&GPIO_InitStruct);
}
void Dht11_Run()
{
uint32_t time=0;
uint32_t i=0;
uint32_t j=0;
uint32_t data[5]={0};
//更改GPIO引脚为输出模式
GPIO_InitTypeDef GPIO_InitStruct;
//参数初始化
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//协议都配推挽
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
GPIO_Init(GPIOG,&GPIO_InitStruct);
//要告诉DHT11我要数据
PGout(9)=0;//拉低电平
delay_ms(20);//为了发送一个大于18us的低电平信号
PGout(9)=1;//拉高电平
delay_us(30);//协议规定,发送信号后续需要等20-40us,我们取中间30us
//进入数据获取阶段
//更改GPIO引脚为输入模式
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;
GPIO_Init(GPIOG,&GPIO_InitStruct);
//等待回响信号,说明DHT11已经拿到了数据,准备发给你,看你还在不在?
time=0;
while(PGin(9)==1)//阻塞等待低电平到来,
{
delay_us(1);
time++;
if(time>=1000000)//排除没有收到发送信号情况
{
printf("回响信号超时");
}
}
time=0;
while(PGin(9)==0)//协议规定需要80us的低电平
{
delay_us(1);
time++;
if(time>=100)
{
printf("回响信号的低电平超时\n");
}
}
time=0;
while(PGin(9)==1)//协议规定需要80us的高电平
{
delay_us(1);
time++;
if(time>=100)
{
printf("回响信号的高电平超时\n");
}
}
///?????????????此处牵扯时序问题
//有效数据获取
for(i=0;i<5;i++)
{
data[i]=0;
for(j=0;j<8;j++)
{
while(PGin(9)==0);//度过间隔信号
delay_us(40);
if(PGin(9)==1)
{
data[i] |= 1<<(7-j);
while(PGin(9)==1);
}
}
}
printf("data = %d,%d,%d,%d\n",data[0],data[1],data[2],data[3]);
}
实验总结
时序问题
由于DHT11数据传输速度都在us级别,我们测量过程中必须十分精确,而且要考虑时序的问题,我在实验过程中为了方便查错,写了很多printf函数,结果发生了数据无法输出的错误。
最后经过不断的测验和分析,发现了是由于多打印了一个printf而拖慢了整个数据传输的监测过程,在监测输入的数据前,我的printf打印时间超过了数据的发送时间,致使最后数据已经传输完毕我却才开始监测的错误。
协议优化
DHT11的数据传输其实就是规定了一个协议:发送获取数据信号、 DHT回响信号、间隔时间、数据传输信号(0是30us左右、1是80us左右)
这些紫色字体都是DHT11传输数据时约定好的,但是此处还存在一些可优化部分:01数据的传输是us定值,虽然已经很快了,但是当数据量达到一定大的时候,就会显得有些慢,想要优化,但是协议规定的数据传输方式又无法改变。
所以我们可以改变一点数据传输的方式,不再以us时间来做为信号,而是两个同步的电信号之间的高低电平规定来传输,例如IIC协议。