stm32项目实战一之智能家居(一)

#DHT11#stm32单片机#学习笔记

DHT11是一款数字温湿度传感器,和单片机的连接采用单总线协议。

相关参数:1、供电电压:3-5.5V
                   2、供电电流:最大2.5mA
                   3、温度范围:0-50℃误差±2℃
                   4、湿度范围:20-90%RH误差±5%RH
                   5、响应时间:1/e(63%) 6-30s
                   6、测量分辨率分别为8bit(温度)、8bit(湿度)
                   7、采样周期间隔不得低于1秒钟
                   8、模块尺寸:30x20mm

DHT11的封装如下图,如果在绘制元器件封装时需注意

DHT11的引脚数为四个,其各引脚功能如下图所示。但市面上还有三引脚的,毕竟只用到了三引脚,多做一引脚的目的是美观,或者说是方便连接

学看懂手册对我们的开发有很大裨益,资料部分可上网或在购买模块时向商家所要。

典型的DHT11模块与单片机连接电路如下图所示:

此图并附加了一些额外条件,但在正常情况下,我们数据传送不会超过20m。

下图是在嘉立创中DHT11的原理图及其对应pcb元器件封装,引脚号直接连接DATA上,但上图中显示需加一个上拉电阻,此在原理图中不需加,因为在stm32单片机内部集成了上拉电阻(上拉输入)。在接电路板时需注意电源的连接,以免接反造成短路损坏电路板

一次完整的数据传输为40bit,高位显出。(单片机一次接收到完整的数据是5个字节)

数据格式:

8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和

单片机一次性取5个字节,取第一个和第三个字节(取值首先要进行校验!)下图为一组校验示例。

通讯过程如图1所示:

第一部分为DHT11初始化,如下图:

第一部分可分为两个部分,黑线部分为MCU(单片机)的复位,其余部分为DHT11响应。

第二部分为数据传送部分,如下图:

第二部分也可以分为两部分,虚线前为数据“0”,虚线后为数据“1”

第三部分为结束,如下图:

此上图中DHT11为从机,MCU为主机。时序图第一部分先由主机拉低18ms然后再拉高总线(释放总线),延时20~40us,此时复位信号发送完毕(因为有一个上拉电阻,所以释放时候有一个拉高电平的状态)。

注意:单片机引脚由输出便输入。

DHT11检测道MCU复位信号后,拉低总线80us表示响应,再拉高总线80us后开始传输数据。

当传送数据时候,DHT信号向单片机发送信号。此下图反应传送数据“1”和传送数据“0”的时序图。

由两图发现两个图的区别主要是中间部分,这让我们在编程时候更加方便。

DHT11以高电平的长短定义数据为是“0”还是“1”,当50us低电平时隙过后拉高总线,高电平持续26~28us表示数据“0”;持续70us表示数据“1”。

当最后1bit数据传送完毕后,DHT11拉低总线50us,表示数据传送完毕,随后总线由上拉电阻拉高进入空闲状态。

总结:主机发送起始信号    (单片机引脚设置为输入)    
           从机应答
           主机开始接收数据
           从机把总线拉低,持续50us,从机拉高总线后,延迟40 us左右,主机读取总线电平,如果为低电平,则为“0”,如果为高电平,则为“1”。继续重复上述步骤累计40次。

下示代码为DHT11的初始化代码

u8 DHT11_chushihua(void)
{
		u8 cnt=0;
	  DHT11_OUT(); //配置引脚为输出	
    DHT11_WRITE=0; 	//输出低电平
    delay_ms(20);    //延时20ms	
    DHT11_WRITE=1; 	 //输出高电平
		delay_us(30);     //延时30us
		DHT11_IN();	 				//引脚为输入
    while (!DHT11_READ&&cnt<100)//优先级"!" > "<" > "&&"(!DHT11_READ)&&(cnt<100)
	{
		cnt++;
		delay_us(1);
	};	 
	if(cnt>=100)//检测低电平相应时间
		return 1;
	else 
		cnt=0;//return 函数会结束当前函数
    while (DHT11_READ&&cnt<100)//检测高电平相应时间
	{
		cnt++;
		delay_us(1);
	};
	if(cnt>=100)
		return 1;    
	return 0;
}

                                                注:return语句会结束当前函数

搞懂此代码首先要搞到几位优先级,在代码注释中已经写出。

结合此时序图看代码:

刚进入低电平
左边:DHT11_READ为0    取反后为1,为真    
右边:此时cnt为0,cnt<100满足,为真进入while循环定时1us,cnt自增1
左边:DHT11_READ为0         取反后为1,为真    
右边:此时cnt为1

到了81us

左边:DHT11_READ为1        取反后为0,为假。

跳出while循环

cnt变量的值就是DHT11_READ低电平的时间。

(检测高电平的代码部分与检测低电平的代码部分相似,在此不解释)

如果初始化函数返回零,表示DHT11初始化成功。

单片机一次接受到完整的数据是5个字节

首先要单片机接受一个字节

然后要单片机接受一个位

下面代码为接受一个字节的代码:

u8 DHT11_Read_Bit(void)
{
  while(DHT11_READ);//检测到低电平
	while(!DHT11_READ);//检测到高电平
	delay_us(35);
	if(DHT11_READ)
		return 1;
	else
		return 0;
}

检测到低电平则是下面时序图中的点:

如果是高电平的话则一直在while中死循环,下一句则是检测高电平的到来,则是上诉点后最近的一个最高点。因为读取“1”和读取“0”的时序图只有在高电平持续时间上有区别,所以代码部分不需过于复杂。只要区分出是0还是1即可。

读取一个位后及读取一个字节,下列代码则为读取一个字节。

/*----------------------------------------------------------
	函数名:DHT11读取一个字节
	参数:无
	返回值:返回一个字节
	----------------------------------------------------------
*/
u8 DHT11_Read_Byte(void)
{
   u8 mask,dat;
	 dat=0;
	 for(mask=0x80;mask!=0;mask>>=1)
	{
	    if(DHT11_Read_Bit())
				dat |=mask;
			else
				dat &=~mask;
	}
	return dat;
}

如接受一个1010 1100数据时候

第一次for循环:mask为1000 0000,满足if条件

dat|=mask                                     1000 0000

dat = 1000 0000                            0000 0000

mask>>=1                                     mask!=0

第2次for循环:mask为0100 0000,满足else条件

dat&=~mask                                     1011  1111

dat = 1000 0000                            1000 0000

mask>>=1                                     mask!=0

第三次for循环

mask为0010  0000,满足if条件

dat|=mask                                    0010 000

dat = 1010 0000                         1000 000

此三次循环只是示范前三次,这样循环八次的话,则接收到一个字节。

接受一个字节后需接收五个字节,将接受的五个字节放入数组中。

for(i=0;i<5;i++)
		 {
			 buf[i]=DHT11_Read_Byte();
		 }

我们只需读出数组中第一位和第三位即可读出温湿度的整数部分,但在读取前需校验。

总结:主机发出起始信号

           从机应答信号

           接受5个字节的数据(接受1个位,1个字节,5个字节)

           引脚初始化

下列函数为读取数组部分,并含有一定校验代码。这里的参数取值为何是指针的形式,简单一点说在指针运行后不会消失,而单纯的参数则只会运行一次后不再运行函数内容。(主函数调用子函数,且发生值传递,需用指针!)

/*----------------------------------------------------------
	函数名:DHT11读取温湿度整数部分
	参数:无
返回值:0,表示成功读取,非零,表示读取不成功
	----------------------------------------------------------
*/
u8 DHT11_Read_Data(u8 *temperture,u8 *humidity)
{
	u8 i;
	u8 buf[5];
   if(DHT11_chushihua()==0)//确认初始化成功
	 {
	   for(i=0;i<5;i++)
		 {
			 buf[i]=DHT11_Read_Byte();
		 }
		 if((buf[0]+buf[1]+buf[3]+buf[2])==buf[4])//校验
		 {
		   *temperture = buf[2];//温度整数部分
		   *humidity = buf[0];//湿度整数部分
			 return 0;//读取成功返回一个0	
		 }
		 else
			 return 1; //读取失败返回一个1
	 }
  else
		  return 1;
}

在.h文件中定义了一些宏定义,以便更好理解,且含有位带操作,和基于单片机寄存器的操作

#ifndef __DHT11_H__
#define __DHT11_H__

#include "stm32f10x.h"                  // Device header
#include  "sys.c"

#define DHT11_WRITE   PAout(5)
#define DHT11_READ    PAin(5)

#define DHT11_IN()     {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=8<<5*4;}
#define DHT11_OUT()    {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=3<<5*4;}


u8 DHT11_chushihua(void);
u8 DHT11_Read_Bit(void);
u8 DHT11_Read_Byte(void);
u8 DHT11_Read_Data(u8 *temperture,u8 *humidity);
void DHT11_Init(void);
#endif

此宏定义中对于寄存器的操作需自行查手册阅读,阅读文献是一项重要的能力,举一反三也是,学习资料来源于bi站up主海创电子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值