在 制作基于stm32f103的温湿度检测时遇到的问题及解决方法

本文详细介绍了DHT11传感器在启动、数据采集及响应过程中的常见问题及其解决方案,包括启动判断、数据传输延迟以及代码中for循环的修复。同时,解释了DHT11与微处理器间单总线通讯的流程和数据格式,强调了信号时序的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、DHT11模块启动不了

1.没有做DHT11启动判断(若DHT11启动会出现一段低电平),(硬件启动有点玄学问题),如果一次不行就跳过这次循环,下一次再尝试启动DHT11传感器。或者尝试多次拉高电平然后再根据芯片手册的启动电平信号去改变电平信号。

2、屏幕上的数值反应有点慢。。有时候还会卡住。

猜想:可能是DHT11在某次数据采集过程中出现问题,然后在某个while循环中阻塞住了。
解决办法:在while循环中做延时有效性判断,若延时了很久那就直接return,进入下一次数据采集。
在这里插入图片描述

3.在DHT11_Read中总是卡在for循环中总是出不去

原因:因为for循环中定义的i为无符号整数。。默认大于等于0减不到小于0所以将i定义为int型即可
在这里插入图片描述在这里插入图片描述

注意点:

1、&&与&是不同的( || 与 | 同理)

&&:是逻辑与操作
&:按位与操作

项目原理

对我来说整个项目的难点在于DHT11采集。。OLED屏基本用商家给的测试代码移植一下就行了

DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次
通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数
部分用于以后扩展,现读出为零.操作流程如下:
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据
+8bit校验和
数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主
机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,
用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,
如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后
转换到低速模式。
1.通讯过程如图1所示
在这里插入图片描述

总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必
须大于18毫秒,保证DHT11能检测到起始信号。 DHT11接收到主机的开始信号后,
等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束
后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换
到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。
在这里插入图片描述线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉
高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定
了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有
响应,请检查线路是否连接正常.当最后一bit数据传送完毕后, DHT11拉低总线
50us,随后总线由上拉电阻拉高进入空闲状态。
在这里插入图片描述在这里插入图片描述

//DHT11代码
#include "DHT11.h"
int i;
int j ;
int crc = 0;
void DHT11_init(void){
	//配置data线为PB9
	GPIO_InitTypeDef 		GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//高速响应


	GPIO_Init(GPIOB,&GPIO_InitStructure);	
	
	GPIO_SetBits(GPIOB,GPIO_Pin_9);
	
	
}

int DHT11_Read(int* d){

	
	GPIO_InitTypeDef 		GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//高速响应
	GPIO_Init(GPIOB,&GPIO_InitStructure);	
	
	GPIO_SetBits(GPIOB,GPIO_Pin_9);
	delay_us(4);
	GPIO_ResetBits(GPIOB,GPIO_Pin_9);//时序置低为电平
	delay_ms(25);
	GPIO_SetBits(GPIOB,GPIO_Pin_9);//时序置为高电平
	delay_us(30);
//	OLED_ShowNum(8,8,1,2,2);
	//变为输入状态
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU;		
	GPIO_Init(GPIOB,&GPIO_InitStructure);	

	delay_us(5);
	//dht11 start
		i = 0;
	if(GPIO_ReadInputDataBit( GPIOB,GPIO_Pin_9) == 0){
			while(!GPIO_ReadInputDataBit( GPIOB,GPIO_Pin_9)){
				delay_us(1);
				i++;
				if(i >100){
					OLED_ShowNum(0,0,1,1,1);
					return -1;
				}
			}
			i = 0;
			//等待高电平
			for(j = 31;j >=0;j--){
				//delay_us(80);
				while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)){
					delay_us(1);
					i++;
					if(i >2000){
						OLED_ShowNum(0,0,3,1,1);
						return -2;
					}
				}//等待数据来临
				//OLED_ShowNum(8,8,3,2,2);
			
				while(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)){
					delay_us(1);
					i++;
					if(i >4000){
						OLED_ShowNum(0,0,4,1,1);
						return -3;
					}
				}
				//OLED_ShowNum(0,31-j,j,1,1);
				delay_us(32);
				if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)){
					*d |= 1<<j; // 按位或
				}

			}
			j = 0;
			for(i=7;i>=0;i--)
			{
				while(!GPIO_ReadInputDataBit( GPIOB,GPIO_Pin_9)){
					delay_us(1);
					j++;
					if(j >2000){
						OLED_ShowNum(0,0,5,1,1);
						return -4;
					}
				}//等待高电平
				j = 0;
				while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)){
					delay_us(1);
					j++;
					if(j >100){
						OLED_ShowNum(0,0,6,1,1);
						return -5;
					}
				}//等待数据来临
				delay_us(30);
				if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==1) //1
				{
								crc |= 1<<i;
				}
			}
			//if((((*d >> 8)&0xff)+(*d&0xff)+((*d >> 16)&0xff)+((*d >> 24)&0xff)) == crc&0xff){
				return 0;
			
			//}
			
		}
	else{
		return -1;
	}
	//OLED_Clear();
	return -1;
}


### 关于DHT11传感器3.32ms长的技术细节 #### 序分析 对于DHT11传感器而言,其通信协议规定主机(微控制器)发起一次查询请求后,需等待特定的间间隔以便接收来自DHT11的数据响应。具体来说,在启动信号发送完毕之后,DHT11会拉低总线大约80微秒作为应答信号,随后再次释放总线进入高阻态约80微秒[^1]。 紧接着,DHT11将依次传输相对湿度整数部分、相对湿度小数部分、温度整数部分、温度小数部分以及校验和各一字节的信息给主机。每一比特位的传送都遵循一定的高低电平持续间来区分逻辑'0'和逻辑'1'[ ^2]: - 对于表示‘0’的情况,DHT11保持低电平50微秒后再维持高电平26至28微秒; - 表达‘1’的候,则是在低电平同样约为50微秒的基础上延长高电平间为70微秒左右; 因此,整个数据帧由起始标志加上40个这样的比特组成,考虑到每次变化之间可能存在额外的小延迟,完成全部数据交换通常需要超过3毫秒甚至接近4毫秒的间窗口[^2]。这里提到的3.32ms可能是针对某些应用场景下对这一过程所需最短间的一个经验值或者是编程实现中的一个设定阈值。 ```c // 示例代码片段展示如何处理DHT11返回的数据流 uint8_t read_bit(void){ uint32_t timeout = 0; while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)==RESET && ++timeout<MAX_TIMEOUT); if(timeout >= MAX_TIMEOUT)return ERROR; delay_us(40); // 等待中间状态稳定 return GPIO_ReadInputDataBit(DHT11_PORT,DHT11_PIN)? HIGH_LEVEL : LOW_LEVEL ; } ``` 上述C语言函数`read_bit()`用于读取单个bit的数据,其中包含了必要的延操作以匹配实际硬件行为特征,确保能够正确解析每一位是代表'0'还是'1'^[2]^。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值