当前位置: 首页 > news >正文

基于智能家居项目 实现DHT11驱动源代码

DHT11 温湿度传感器的数据读取一般分为 四个步骤,下面详细介绍每个步骤的具体内容:    

步骤一:主机发送起始信号

  • 主机(如 MCU)主动向 DHT11 发送开始信号,方式为:

    • 将数据线拉低 至少 18ms(确保 DHT11 能够识别这是一个起始信号);

    • 然后拉高数据线 20~40μs

  • 这个动作通知 DHT11 准备发送数据。


步骤二:DHT11 发出响应信号

  • 接收到主机的起始信号后,DHT11 做出响应:

    • 首先将数据线拉低 80μs

    • 然后拉高数据线 80μs

  • 表示 DHT11 已准备好传输数据。


步骤三:DHT11 传输40位数据

  • DHT11 按顺序传送 40 位数据(高位先传),格式如下:

  •  

    8位湿度整数 + 8位湿度小数 + 8位温度整数 + 8位温度小数 + 8位校验和

  • 每一位的传输方式:

    • 逻辑“0”:拉高约 26~28μs

    • 逻辑“1”:拉高约 70μs

    • 起始位:先拉低数据线约 50μs

    • 数据位:


步骤四:主机校验数据完整性

  • 主机接收完 40 位数据后,将前四个字节相加(无进位):

  •  

    校验 = 湿度整数 + 湿度小数 + 温度整数 + 温度小数

  • 与第五字节(校验和)进行比较,验证数据是否正确;

  • 若相符,说明读取成功。

在DHT11.c文件中

#include "DHT11.h"#include  "delay.h"
//初始化DHT11_Data引脚void DHT11_Init(){	///因为PB3是不可用的,所以我们先解除把不可用	//打开GPIOA时钟	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	GPIO_PinRemapConfig (GPIO_Remap_SWJ_JTAGDisable , ENABLE);	//初始化GPIO口为开漏输出
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;				GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;	GPIO_Init (GPIOA, &GPIO_InitStruct);//打开GPIOA时钟	DHT11_H; //初始化为高电平	delay_ms(1000); //进行一个延时,目的越过模块不稳定期}//主机发送起始信号void Start(){	DHT11_L;	delay_ms(20);
	DHT11_H  // 释放总线,等待从机响应}//响应函数,就是主机读取IO口,是否为在指定电平,判断响应完成//比如返回0,表示响应成功u8 Respond(){	u8 time_out = 0;	while(DHT11_R == 1)// 等待主机响应	{		time_out++;		delay_us(1);		if(time_out > 50) //说明等待时间超长,没有等到应答信号		{			return 1;
		}
	}	time_out =0;	while(DHT11_R == 0) // 开始响应	{		time_out++;		if(time_out > 100) //等待时间>100		{			return 2;
		}	}	if(time_out < 50) //响应时间过短	{		return 3;
	}
	while(DHT11_R == 1) //从机等待主机准备
	return 0;
}//读取DHT1140位数据
void DHT11_Read(u8 *pData){	u8 i,j;	for(i = 0 ; i<5;i++)	{		for(j = 0;j<8;j++)		{			while(DHT11_R == 0);			delay_us(50);
			pData[i] <<= 1;			if(DHT11_R == 1)			{				pData[i] |= 1;				while(DHT11_R == 1);			}
		}	}}//获取温湿度数据
u8 DHT11_Get(u8 *shi,u8 * temp){	u8 ret;	u8 datas[5];
	Start();	ret = Respond();	if(ret ==1)	{		return 1; //相应失败
	}	DHT11_Read(datas);	if( (datas[0]+ datas[1] + datas[2] + datas[3]) != datas[4])	{		return 2 ;// 接收数据错误	}	*shi = datas[0] + datas[1]/10;	if(datas[3] & 0x80) //判断温度为负数	{		*temp = (datas[2] + (datas[3]& 0x0F) / 10 )* -1;
	}	else{
		*temp = datas[2] + datas[3]/10;	}	return 0;}

重点讲一下,DHT11获取函数和DHT11读取函数

一、读取 DHT11 的 40 位数据:DHT11_Read(u8 *pData)

一、读取 DHT11 的 40 位数据:DHT11_Read(u8 *pData)
void DHT11_Read(u8 *pData){	u8 i, j;	for(i = 0; i < 5; i++)  // 总共要读取 5 个字节(8 位 * 5 = 40 位)	{		for(j = 0; j < 8; j++)  // 每个字节 8 位		{			while(DHT11_R == 0);  // 等待 DHT11 拉高,表示开始发送这一位的高电平部分			delay_us(50);  // 延时 50us,用于判断当前是 0 还是 1			pData[i] <<= 1;  // 左移一位,为当前位腾出位置			if(DHT11_R == 1)  // 如果此时仍然为高电平,则是“1”			{				pData[i] |= 1;  // 将当前最低位置 1				while(DHT11_R == 1);  // 等待高电平结束			}			// 如果延时后是低电平,就什么都不做,当前位默认是 0		}	}}🔍 核心原理解释:DHT11 发送每一位数据时,先是一个固定的低电平(约 50μs),然后是一个高电平:高电平持续 26~28μs 代表 0;高电平持续 70μs 代表 1;所以主机延时 50μs 后读取数据线状态,来判断是 0 还是 1。二、获取温湿度数据:DHT11_Get(u8 *shi,u8 *temp)
u8 DHT11_Get(u8 *shi, u8 *temp){	u8 ret;	u8 datas[5];	Start();              // 主机发送起始信号	ret = Respond();      // 等待 DHT11 响应	if(ret == 1)	{		return 1;         // 响应失败	}	DHT11_Read(datas);    // 读取 40 位数据到 datas[0] ~ datas[4]	// 校验和验证数据完整性	if ((datas[0] + datas[1] + datas[2] + datas[3]) != datas[4])	{		return 2;         // 校验失败,数据错误	}	// 获取湿度,datas[0]是整数部分,datas[1]是小数部分	*shi = datas[0] + datas[1] / 10;	// 获取温度,datas[2]是整数部分,datas[3]是小数部分	if(datas[3] & 0x80)  // 判断是否为负温(DHT11 其实不支持负温度,但兼容设计)	{		*temp = (datas[2] + (datas[3] & 0x0F) / 10) * -1;	}	else	{		*temp = datas[2] + datas[3] / 10;	}	return 0;  // 读取成功}🔍 注意点:Start() 和 Respond() 是发送起始信号和等待响应,属于步骤 1 和 2;校验和确保数据的可靠性;DHT11 实际只返回 整数值,小数部分一般为 0,设计保留是为了与 DHT22 等更高精度传感器兼容;datas[3] & 0x80 判负值是为兼容 DHT12 或 DHT22 数据格式,DHT11 实际温度是非负的,所以这段代码更具有通用性。

在DHT11.h文件

#ifndef _DHT11_H_#define _DHT11_H_
#include "stm32f10x.h"#define DHT11_H GPIO_SetBits (GPIOB,GPIO_Pin_3);#define DHT11_L GPIO_ResetBits (GPIOB, GPIO_Pin_3)#define DHT11_R GPIO_ReadInputDataBit (GPIOB, GPIO_Pin_3)void DHT11_Init();u8 DHT11_Get(u8 *shi,u8 * temp);#endif

相关文章:

  • Java——集合基础
  • 虹科干货 | CAN XL安全实践:深度防御下的密钥协商优化
  • AI+企业应用级PPT生成(实战)
  • 如何将两台虚拟机进行搭桥
  • BFS算法篇——打开智慧之门,BFS算法在拓扑排序中的诗意探索(上)
  • Python | Dashboard制作
  • 关于 ast: Babel AST 全类型总览
  • #跟着若城学鸿蒙#HarmonyOS NEXT学习之Blank组件详解
  • C语言—再学习(数据的存储类别)
  • 大模型——Crawl4AI为 LLM 和 RAG 准备高质量网页数据
  • electron 基础知识
  • 服务器租用与托管注意事项有哪些
  • 互联网大厂Java求职面试:优惠券服务架构设计与AI增强实践-4
  • Python Day 24 学习
  • 亚马逊云科技:开启数字化转型的无限可能
  • LeetCode 3335.字符串转换后的长度 I:I先递推
  • 标贝科技:大模型领域数据标注的重要性与标注类型分享
  • Linux——守护进程
  • 改变应用的安装目录
  • 浅谈 Redis 数据类型
  • 第十届影像上海博览会落幕后,留给中国摄影收藏的三个问题
  • 礼来公布头对头研究详细结果:替尔泊肽在所有减重目标中均优于司美格鲁肽
  • 社恐也能嗨起来,《孤独摇滚》千人观影齐舞荧光棒
  • 经济日报刊文:品牌经营不能让情怀唱“独角戏”
  • 19个剧团15台演出,上海民营院团尝试文旅融合新探索
  • 理财经理泄露客户信息案进展:湖南省检受理申诉,证监会交由地方监管局办理