提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、硬件原理图
DHT11是通过单总线(PB5)与主机进行数据传输的。单片机发送一次复位信号后,DHT11 从低功耗模式转换到高速模式,等待主机复位结束后,DHT11 发送响应信号,并拉高总线准备传输数据。一次完整的数据为 40bit,按照高位在前,低位在后的顺序传输。
数据格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和,一共 5 字节(40bit)数据。由于 DHT11 分辨率只能精确到个位,所以小数部分是数据全为 0。校验和为前 4 个字节数据相加,校验的目的是为了保证数据传输的准确性。
二、CubeMx配置
配置PB5为开漏输出模式,在该模式下主机和从机均可以获取该数据线的控制权。
三、获取温湿度数据
本来使用的时序图来自于博文https://blog.csdn.net/m0_55849362/article/details/126426768?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170945072816800184177593%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=170945072816800184177593&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-126426768-null-null.142^v99^pc_search_result_base8&utm_term=DHT11&spm=1018.2226.3001.4187
操作时序
主机发送起始信号
DHT11 只有在接收到开始信号后才触发一次温湿度采集,如果没有接收到主机发送复位信号,DHT11 不主动进行温湿度采集。当数据采集完毕且无开始信号后,DHT11 自动切换到低速模式。
主机接收响应信号并且接受数据
DHT11 在拉高总线 80us 后开始传输数据。每 1bit 数据都以 50us 低电平时隙开始,告诉主机开始传输一位数据了。DHT11 以高电平的长短定义数据位是 0 还是 1,当 50us 低电平时隙过后拉高总线,高电平持续 26~28us 表示数据“0”;持续 70us 表示数据“1”。
当 最后 1bit 数据传送完毕后,DHT11 拉低总线 50us,表示数据传输完毕,随后总线由上拉电阻拉高进入空闲状态。
代码实现
#include "libs.h"
#include "gpio.h"
#include "drivers.h"
#include <stdio.h>
static int DHT11Read(DHT11_s *dht11Dev);
#define MYDHT11 \
{ \
.temperature = 0, \
.humidity = 0, \
.Read = DHT11Read, \
} \
DHT11_s DHT11Dev = MYDHT11;
static void UDelay(uint32_t us){
us = us * 45;
while(us--);
}
/*
*描述:主机给DHT11发送复位信号,让DHT11采集温湿度数据
*参数:无
*返回值:ESUCCESS 成功
* OTHER 失败
*/
static int DHT11Start(void){
DHT11DATAHIGH;
UDelay(2);
//拉低至少18ms
DHT11DATALOW;
MDelay(20);
//拉高20-40us
DHT11DATAHIGH;
return ESUCCESS;
}
/*
*描述:主机接受DHT11发送的一个字节数据
*参数:无
*返回值:data 接收的数据
*/
static int DHT11RecvByte(void){
uint8_t data = 0;
uint8_t newbit = 0;
int timeout = 0;
for(uint8_t i = 0;i < 8; i++){
//等待从机拉低 发送数据
timeout = 100;
while(DHT11DATA && timeout){
timeout--;
UDelay(1);
}
if(DHT11DATA && (timeout <= 0) ){
LogDebug("Timeout\r\n");
return -EIO;
}
//等待50us低电平过去
timeout = 100;
while(!DHT11DATA && timeout){
timeout--;
UDelay(1);
}
if(!DHT11DATA && (timeout <= 0) ){
LogDebug("Timeout\r\n");
return -EIO;
}
//延时40us
UDelay(50);
data = data << 1;
if(DHT11DATA){
newbit = 1;
}else{
newbit = 0;
}
data = data + newbit;
}
return data;
}
static int DHT11Read(DHT11_s *dht11Dev){
uint8_t data[5] = {0};
DHT11Start();
int timeout = 50;
//等待从机拉低
while(DHT11DATA && timeout){
timeout--;
UDelay(1);
}
if(DHT11DATA && (timeout <= 0) ){
LogDebug("Timeout\r\n");
return -EIO;
}
timeout = 100;
//发送响应信号
while(!DHT11DATA && timeout){
timeout--;
UDelay(1);
}
if(!DHT11DATA && (timeout <= 0) ){
LogDebug("Timeout\r\n");
return -EIO;
}
UDelay(80);
data[0] = DHT11RecvByte();
data[1] = DHT11RecvByte();
data[2] = DHT11RecvByte();
data[3] = DHT11RecvByte();
data[4] = DHT11RecvByte();
if(data[4] == (data[3]+data[2]+data[1]+data[0])){
dht11Dev->humidity = data[0];
dht11Dev->humidity = (dht11Dev->humidity<<8)+data[1];
dht11Dev->temperature = data[2];
dht11Dev->temperature = (dht11Dev->temperature<<8)+data[3];
LogDebug("humidity is %2d.%2d,temperature is %2d.%2d\r\n",(dht11Dev->humidity>>8),(dht11Dev->humidity&0x00FF),(dht11Dev->temperature>>8),(dht11Dev->temperature&0x00FF));
return ESUCCESS;
}
return -EIO;
}