stm32驱动DHT11温湿度模块使用方法和问题小结

最近在总结做过的几个项目,今天小结一下DHT11模块的使用。
对DHT11的使用,就是编写时序和stm32进行通信。
DHT11和stm32是通过一根线进行通信的,双方通过这根线上的电平变化来识别各种信号。
DHT11每次传输数据会输出40bit的数据,即5个字节,它们的含义如下:
stm32驱动DHT11温湿度模块使用方法和问题小结_第1张图片
每一位bit是0还是1是通过高电平的持续时间来判断的,如下两张图所示,‘0’和
‘1’都是先持续50us的低电平,而后持续一段时间高电平,‘0’的高电平会持续26-28us,‘1’的电平会持续70us,因此你在判断每位数据是’0’还是’1’时,有两种方法,一种是看持续时间,显然高电平持续时间超过28us的就是’1’;另一种方法是选取一个时间点,比如在高电平开始40us后如果仍然是高电平,那就是‘1’,我用的第二种方式,因为即使是在40us后来检查电平,对数据是’0’的情况也很好判断,因为下一位数据’0’的持续时间是50us。
stm32驱动DHT11温湿度模块使用方法和问题小结_第2张图片stm32驱动DHT11温湿度模块使用方法和问题小结_第3张图片
代码的话我贴几个比较重要的
stm32发出的开始信号,使引脚从高电平变为低电平,低电平持续20ms后再拉高电平,高电平持续40us等待DHT11发个响应信号,注意此时引脚应设为输入模式。

//主机拉低20ms
	int retry=0;
	set_out_high();
	delay_ms(5);
	
	set_out_low();
	delay_ms(20);
	
	set_in_high();
	delay_us(40);

等待拉低代码如下,在编写时序时要检测到电平的变化可以使用下面的方法,使用while循环去检测,可以加上一个延时超时时间,我加的是100us,如果超过100us没有拉低就出错返回。

while(((GPIOB->IDR & (1<<0))==1) && retry <100)//等待拉低
	{
		delay_us(1);
		retry++;
	}
	if(retry>= 100)
	{
		printf("time out1\r\n");
		retry=0;
		return ;
	}else{
		retry = 0;
	}

等待拉高如下,功能同等待拉低相似

while(((GPIOB->IDR & (1<<0))==0) && retry <100)//等待拉高
	{
		delay_us(1);
		retry++;
	}
	if(retry>= 100)
	{
		printf("time out2\r\n");
		retry = 0;
		return ;
	}else{
		retry = 0;
	}

读取一个字节

for(j=0;j<8;j++)
	{
		while(((GPIOB->IDR & (1<<0))==0) && retry <100)//等待拉高
		{
			delay_us(1);
			retry++;
		}
		if(retry>= 100)
		{
			printf("time out4\r\n");
			retry = 0;
			return ;
		}else{
			retry = 0;
		}
		
		delay_us(40);
		if((GPIOB->IDR & (1<<0))==0)
		{
			h1->humi_int &= ~(1<<(7-j));
		}else{
			h1->humi_int |= 1<<(7-j);
			while(((GPIOB->IDR & (1<<0))==1) && retry <100)//等待拉低
			{
				delay_us(1);
				retry++;
			}
			if(retry>= 100)
			{
				printf("time out5\r\n");
				retry = 0;
				return ;
			}else{
				retry = 0;
			}
		}
	}

判断’0’还是’1’的逻辑代码上面已经说了,可以结合代码看一看。
校验和的话,我没有使用,因为数据还是狠准确地。

在实际应用时遇到个问题,我是采用循环读的,如下

while(1)
	{
	    //清除之前的数据
		h1.humi_dec=0;
		h1.humi_int=0;
		h1.ture_dec=0;
		h1.ture_int=0;
		//得到数据
		humiture_get(&h1);
		//打印数据
		printf("humi:%d.%d\r\n",h1.humi_int,h1.humi_dec);
		printf("ture:%d.%d\r\n",h1.ture_int,h1.ture_dec);
	}	 

结果每次开发板复位后只有第一次能成功读取,之后每次读取都会在发出开始信号阶段就超时返回。一开始以为是时序的问题,但由于最开始可以成功读出一次数据,表明时序是可以正常工作的,之后根据数据手册的时序图又检查了一遍,发现没有写结束信号,时序图中的结束信号是由主机主动拉高的,因此我加上了主动拉高的代码,并延时500ms,但问题依旧没有解决,最后我重头到尾看了一遍数据手册发现了这个
stm32驱动DHT11温湿度模块使用方法和问题小结_第4张图片
发现了左下角的注:采样周期间隔不得低于1秒钟。
所以我在数据采样结束后主动拉高电平并延时1.5秒,成功解决问题!

你可能感兴趣的:(stm32入门)