DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上。
型号 | 温度范围 | 温度精度 | 湿度范围 | 湿度精度 |
---|---|---|---|---|
DHT11 | 0~50°C | ±2°C | 20~90%RH | ±5%RH |
一.接口说明
建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使用合适的上拉电阻,供电电压3~5.5V.
二.通信协议
单总线通信,数据获取间隔建议大于1s.
通信总过程
通信总过程如下图1:
总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。
起始信号
总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
数据信号
数字0信号表示方法如图3所示:
数字1信号表示方法.如图4所示:
![图4 信号1](https://img-blog.csdnimg.cn/20201022163045115.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NDUxODg0,size_16,color_FFFFFF,t_70#pic_center)
数据解析
一次完整的数据传输为40bit,高位先出。
数据格式:
8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据 +8bit校验和
数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。
三. 封装与引脚对应
引脚说明
Pin | 名称 | 注释 |
---|---|---|
1 | VDD | 供电3~5.5V |
2 | DATA | 数据 |
3 | NC | 空脚 |
4 | GND | 地 |
四. 代码
时钟初始化(重要):单总线有us级时序要求,延时与主频相关
/**
* @brief 系统时钟初始化
* @param None
* @retval None
*/
static void System_Timer_Init(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); /*时钟 初始化时钟为1分频 16M 2分频8M*/
}
DHT11数据读取程序:ms级延时来自于一个定时器,us级延时由逻辑分析仪测试加实验调整获得。
#include <stm8s.h>
#include <stdbool.h>
#include <string.h>
#include "bsp_task.h"
#include "hw_DHT11_driver.h"
#define DHT11_PORT GPIOC
#define DHT11_PIN GPIO_PIN_6
#define DHT11_OUT GPIO_Init(DHT11_PORT, DHT11_PIN, GPIO_MODE_OUT_PP_HIGH_FAST) //输出模式
#define DHT11_IN GPIO_Init(DHT11_PORT, DHT11_PIN, GPIO_MODE_IN_PU_NO_IT) //输入模式
#define DHT11_H GPIO_WriteHigh(DHT11_PORT,DHT11_PIN) //输出高
#define DHT11_L GPIO_WriteLow(DHT11_PORT,DHT11_PIN) //输出低
#define DHT11_READ GPIO_ReadInputPin(DHT11_PORT,DHT11_PIN) //数据读出
static bool hw_dht11_data_get(uint8_t *data);
static uint8_t debug[5] = {0};
/**
* @brief us级延时--非精准
* @param us 延时计数 24==100us 12==52.5us
* @retval None
*/
static void hw_dht11_delay_us(uint32_t us)
{
while(us--);
}
/**
* @brief 获得DHT11 1 bit数据
* @param None
* @retval 数据
*/
static uint8_t hw_dht11_bit_get(void)
{
uint8_t temp = 0;
for(int j = 0; j < 8; j++) //获取一个字节
{
while(DHT11_READ == RESET); //等待字节起始低电平结束
hw_dht11_delay_us(8); //大于40us (要求大于30us,小于70us)
temp <<= 1;
if(DHT11_READ != RESET)
{
temp |= 0x01;
}
while(DHT11_READ != RESET); //等待高电平结束
}
return temp;
}
/**
* @brief 获得DHT11温湿度数据
* @param data 数据接收缓存(5字节)
* @retval true 获取成功 false 获取失败
* @note 采样间隔必须大于1s,采样过程禁止打断
*/
static bool hw_dht11_data_get(uint8_t *data)
{
DHT11_OUT;
DHT11_H; //准备--总线空闲
Task_Delay_Ms_Time(2); //延时2ms
DHT11_L; //总线拉低--主机开始信号
Task_Delay_Ms_Time(25); //保持25ms --大于18ms
DHT11_H; //结束开始信号
hw_dht11_delay_us(10); //延时 20us~40us
DHT11_IN; //切换输入模式 准备读响应
if(DHT11_READ != RESET) //未检测到应答
{
return false;
}
while(DHT11_READ == RESET); //等待应答结束
while(DHT11_READ != RESET); //等待DHT11发送起始高电平结束
for(int i = 0; i < 5; i++) //共5字节
{
data[i] = hw_dht11_bit_get();
}
DHT11_OUT;
DHT11_H; //准备--总线空闲
return true;
}
/**
* @brief 获得DHT11温湿度数据
* @param temp 温度 hum 湿度
* @retval false 数据错误 true 数据正常
*/
bool hw_dht11_th_count(uint16_t *temp,uint16_t *hum)
{
uint8_t dht11_data[5] = {0};
if(!hw_dht11_data_get(dht11_data))
return false;
memcpy(debug,dht11_data,5);
if(dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3] != dht11_data[4])
return false;
*hum = 0xf0 | dht11_data[0];
*hum <<= 8;
*hum |= dht11_data[1];
*temp = 0xf0 | dht11_data[2];
*temp <<= 8;
*temp |= dht11_data[3];
return true;
}
五.文章引用
https://blog.csdn.net/u013151320/article/details/50389624
https://wenku.baidu.com/view/29bc6e8fb4daa58da1114a3a.html
https://blog.csdn.net/qq_27508477/article/details/83661672