1- DHT11介绍及工作原理
DHT11温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。
DHT11器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。单总线通常要求外接一个约5.1kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。
4根引脚,名称与功能如下:
- VCC:供电 3-5.5VDC
- GND:接地,电源负极
- DATA: 串行数据,单总线(CPU数据传输)
- NC:空脚(什么都没有接)
DHT11:异步(无同步时钟)、串行通信(只有一根线),半双工(一根线双向通信),电平信号发送
2- DHT11通信时序
用户主机(STM32单片机)发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11发送响应信号,送出40bit的采集数据,然后结束本次采集任务。 注:主机从DHT11读取的温湿度数据总是前一次的测量值,如两次测间隔时间很长,请连续读两次以第二次获得的值为实时温湿度值。
(1)主机发送起始信号
首先单片机将连接DHT11 DATA引脚的GPIO口输出低电平,且低电平保持时间不能小于18ms (t1)最大不能超多30ms,然后拉高数据线20~40us (t2) ,等待读取DHT11的响应信号。
(2)检测从机应答信号
DHT11的DATA引脚检测到外部信号有低电平(t1),并等待外部低电平信号结束(t2),延迟后DHT11的DATA引脚处于输出状态,之后DHT11开始输出80 us (t3)的低电平作为应答信号,紧接着输出80us(t4)的高电平通知主机准备接收数据。 主机的I/O此时处于输入状态,检测I/O有低电平(DHT11应答信号)后,等待80us的高电平后接受数据。
(3)数据传输
由DHT11的DATA引脚输出40位数据,采用高位优先方式(MSB),微处理器根据I/0电平的变化接收40位数据。 位数据“0”的格式为:50微秒的低电平和26-28us的高电平。 位数据“1”的格式为:50微秒的低电平加70us的高电平。
位数据“0”、“1”格式信号如图6所示:
单片机在处理数据接收时可以先等待低电平过去,即等待数据线拉高,再延时40us (因为40us大于28us且小于70us) ,再检测此时数据线是否为高,如果为高,则数据判定为1,否则为0。
(4)传输数据举例
DHT11在传输数据时,一次传输4字节温湿度值数据和1字节数据校验(总共40bit)。其数据格式为: 1B湿度整数数据+1B湿度小数数据+1B温度整数数据+ 1B温度小数数据+1B校验位。
【1】举例一(温度为正)
接收到的40位数据为: 计算: 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001(校验位) 说明接收数据正确:
湿度: 00110101(整数)=35H(16进制)=53%RH(相对湿度) 00000000(小数)=00H(16进制)=0.0%RH(相对湿度) 最终得出湿度为:53.0%RH
温度: 00011000(整数)=18H(16进制)=24℃ 00000100(小数)=04H(16进制)=0.4℃ 最终得出温度为:24.4℃
【2】举例二(温度为负)
当温度低于0℃时温度数据的低8位的最高位置为1。 -10.1℃表示为 0000 1010 1000 0001 看到1代表为负数,算的时候还是按照0来算,最后加上负号。
温度: 00001010(整数)=0AH(16进制)=10℃ 00000001(小数)=01H(16进制)=0.1℃ 最终得出温度为:-10.1℃
【3】举例三(校验位错误)
说明接收数据正确: 计算: 0011 0101 + 0000 0000 + 00011000 + 0000 0100 = 0101 0001不等于校验位,接收错误。本次不接收,重新接收数据。
3- 连接和配置
(1)dht11.c
#include "tim.h"
#include "gpio.h"
#include "main.h"
#include "usart.h"
typedef struct w1_gpio_s
{
GPIO_TypeDef *group;
uint16_t pin;
}w1_gpio_t;
static w1_gpio_t W1Dat =
{
.group = GPIOA,
.pin = GPIO_PIN_5,
};
#define W1DQ_Input() \
{\
GPIO_InitTypeDef GPIO_InitStruct = {0};\
GPIO_InitStruct.Pin = W1Dat.pin;\
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;\
GPIO_InitStruct.Pull = GPIO_PULLUP;\
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);\
}
#define W1DQ_Output() \
{\
GPIO_InitTypeDef GPIO_InitStruct = {0};\
GPIO_InitStruct.Pin = W1Dat.pin;\
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\
GPIO_InitStruct.Pull = GPIO_NOPULL;\
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);\
}
#define W1DQ_Write(x) HAL_GPIO_WritePin(W1Dat.group, W1Dat.pin, (x==1)?GPIO_PIN_SET:GPIO_PIN_RESET)
#define W1DQ_Read(x) HAL_GPIO_ReadPin(W1Dat.group, W1Dat.pin)
static void DHT11_StartSignal(void)
{
W1DQ_Output();
W1DQ_Write(0);
HAL_Delay(20);
W1DQ_Write(1);
delay_us(30);
W1DQ_Input();
}
uint8_t DHT11_RespondSignal(void)
{
uint8_t retry = 0;
while( W1DQ_Read() && retry < 100)
{
retry++;
delay_us(1);
}
if( retry >= 100)
{
printf("1 Timeout No response received\r\n");
return 1;
}
retry = 0;
while( !W1DQ_Read() && retry < 100 )
{
retry++;
delay_us(1);
}
if( retry >= 100)
{
printf("2 Timeout No response received\r\n");
return 1;
}
return 0;
}
uint8_t DHT11_ReadBit(void)
{
uint8_t retry = 0;
while( W1DQ_Read() && retry < 100 )
{
retry++;
delay_us(1);
}
while( !W1DQ_Read() && retry < 100 )
{
retry++;
delay_us(1);
}
delay_us(40);
if( W1DQ_Read() )
{
return 1;
}
else
{
return 0;
}
}
uint8_t DHT11_ReadByte(void)
{
uint8_t i,dat;
dat = 0;
for(i=0; i<8; i++)
{
dat <<= 1;
dat |= DHT11_ReadBit();
}
return dat;
}
int DHT11_SampleData(float *temperature, float *humidity)
{
uint8_t humi_H8bit;
uint8_t humi_L8bit;
uint8_t temp_H8bit;
uint8_t temp_L8bit;
uint8_t check_sum;
if( !temperature || !humidity)
{
return -1;
}
DHT11_StartSignal();
if(0 != DHT11_RespondSignal())
{
return -2;
}
humi_H8bit = DHT11_ReadByte();
humi_L8bit = DHT11_ReadByte();
temp_H8bit = DHT11_ReadByte();
temp_L8bit = DHT11_ReadByte();
check_sum = DHT11_ReadByte();
if((humi_H8bit + humi_L8bit + temp_H8bit + temp_L8bit) != check_sum )
{
return -3;
}
*humidity = (humi_H8bit*100 + humi_L8bit) / 100.00;
*temperature = (temp_H8bit*100 + temp_L8bit) / 100.00;
return 0;
}
(2)dht11.h
#ifndef INC_DHT11_H_
#define INC_DHT11_H_
#endif
int DHT11_SampleData(float *temperature, float *humidity);
(3)main.c
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "dht11.h"
...
int main(void)
{
float temperature, humidity;
...
printf("Welcome to the DHT11 project\r\n");
while (1)
{
if( DHT11_SampleData(&temperature, &humidity) < 0)
{
printf("ERROR: DHT11 sample data failure\r\n");
}
else
{
printf("DHT11 sample Tempeature: %.3f Relative Humidity: %.3f\r\n", temperature, humidity);
}
HAL_Delay(3000);
}
}
4- 结果呈现
保存烧录然后就可以看见我们获取到的温湿度了;用手捂住可以看见温湿度正在慢慢升高。
代码主要是看着实验室的资料敲出来的,但是都能够理解,看着datasheet敲代码可能还有一些困难,慢慢努力加油吧!
如有错误还请指出~
|