DHT11

DHT11

  • 前面一直在讲串口类设备,今天讲IO类设备,不同的接口方式

目录

DHT11

查资料

文档的梳理

代码编写

初始化(时钟、IO、其他)

单总线的读取流程

1、主机发送复位信号

2、DHT11响应信号

3、数据传输

4、校验数据

5、数据获取

main.c

补充: stlink有个调试的功能

- tip:可以适当的总结keil的错误,因为在keil出现的错误来来回回就只有几种错误,总结好,以后遇到错误,就可以更快的解决。


查资料

  • 上网查找官方文档,先看引脚

alt text

  • DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合 传感器。

-- 测量的范围 

alt text

-- DHT11硬件层 

alt text

-- DHT11 协议层

DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一 次通讯时间 4ms 左右,数据分小数部分和整数部分
一次完整的数据传输为 40bit,高位先出。
数据格式:8bit 湿度整数数据+8bit 湿度小数数据 +8bi 温度整数数据+8bit 温度小数数据 +8bit 校验和 

alt text

 校验:
校验和 = 8bit 湿度整数数据+8bit 湿度小数数据+8bi 温度整数数据+8bit 温度小数数据的后8 位

-- 通讯时序: 

alt text

输出:
空闲状态下:主机发送高电平
主机起始信号:发送至少 18ms 低电平
发送 20-40us 的高电平

输入:
DHT 响应信号:发送 80us 的低电平
发送 80us 的高电平
DHT 数据:信号 0/1 判断 保存 校验
DHT 结束信号:从机发送 50us 的低电平 主机拉高进入空闲状态

信号 0 判断: 

alt text

 发送 50us 的低电平 发送 26-28us 高电平

信号 1 判断 :
 

alt text

 发送 50us 的低电平 发送 70us 高电平

alt text

文档的梳理

  • 根据时序图和流程图可知DHT11的传输数据的流程

-- 重点(代码就是根据时序图来编写的)

alt text

alt text

代码编写

初始化(时钟、IO、其他)

-- 这里采用宏定义的方式将电平拉高拉低,使代码更加简洁明了,


#define DHT_OUT_L  GPIO_ResetBits(GPIOG,GPIO_Pin_11)
#define DHT_OUT_H  GPIO_SetBits(GPIOG, GPIO_Pin_11)
#define DHT_IN     GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)//读取输入的数据


void dht11_init(void)
{
	//时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
	
	//IO  PG11
	GPIO_InitTypeDef GPIO_InitStructure = {0};						//定义结构体变量,并且将结构体变量赋初值
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; 						//引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//速度
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;				//复用推挽
	GPIO_Init(GPIOG, &GPIO_InitStructure);
	
	//其他 -- 根据官方文档可知,在DHT11上电后,需要等待至少2s才完成传感器的初始化。初始化期间,传感器接入单总线的微处理器I/O应配置为开漏模式并输出高电平,以保证单总线处于空闲状态(高电平)。
	DHT_OUT_H;
	Delay_nms(20);(2000);
}
  • 在dht11.h里定义结构体
typedef struct {
	
	float tem;//温度
	float hum;//湿度
}DHT;

单总线的读取流程

1、主机发送复位信号

DHT11 的初始化过程同样分为复位信号和响应信号。 首先主机拉低总线至少18ms,然后再拉高总线,延时 20~40us,取中间值 30us,此时复位信号发送完毕

从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集。采集数据后转换到低速模式。

//1、起始信号
	
		DHT_OUT_L;
		Delay_nms(20);
		DHT_OUT_H;
	

2、DHT11响应信号

DHT11 检测到复位信号后,触发一次采样,并拉低总线 80us 表示响应信号,告诉主机数据已经准备好了;
然后 DHT11 拉高总线 80us,之后开始传输数据。如果检测到响应信号为高电平,则 DHT11 初始化失败,请检查线路是否连接正常。

  • 这里不用if来判断的原因是,说是延时80us,但实际的代码执行会有误差,程序也有被打断的情况,所以用while循环来延时,如果DHT11向单片机发送高电平,那将会一直在while循环中等待低电平,如果超过1000us,就不再等了,此为超时检测
//2、响应信号
	num = 0 ;
	
	//不用if,用while(时间范围判断)
	while(DHT_IN == 1)//主机等待从机发来低电平
	{
		//做一个超时判断
		num++;
		Delay_nus(1);
		if(num>1000)	//>83,时间要比它大
			return;
	}
	num = 0 ;
	while(DHT_IN == 0)//主机等待从机发来高电平
	{
		num++;
		Delay_nus(1);
		if(num>1000)
			return;
	}

3、数据传输

alt text

数据“0”的高电平持续 26~28us,数据“1”的高电平持续70us,每一位数据前都有 50us 的起始时隙。如果我们取一个中间值 40us 来区分数据“0”和数据“1”的时隙。
当数据位之前的 50us 低电平时隙过后,总线肯定会拉高,此时延时 40us 后检测总线状态,如果为高,说明此时处于 70us 的时隙,则数据为“1”;如果为低,说明此时处于下一位数据 50us 的开始时隙,那么上一位数据肯定是“0”。

为什么延时 40us?
由于误差的原因,数据“0”时隙并不是准确 26~28us,可能比这短,也可能比这长。
当数据“0”时隙大于 26~28us 时,
如果延时太短,无法判断当前处于数据“0”的时隙还是数据“1”的时隙;
如果延时太长,则会错过下一位数据前的开始时隙,导致检测不到后面的数据

//3、数据接收
	for(uint8_t i=0;i<5;i++)//循环40次,接收40位数据
	{
		for(uint8_t j=0;j<8;j++)
		{
					num = 0 ;
				
				while(DHT_IN == 1)//等待低电平到来
				{
					num++;
					Delay_nus(1);
					if(num>1000)	
						return;
				}
				num = 0 ;
				while(DHT_IN == 0)//等待高电平的到来
				{
					num++;
					Delay_nus(1);
					if(num>1000)
						return;
				}
				Delay_nus(40);	//数据0的话,延时后是低电平,如果是1的话,延时后是高电平
				
				if(DHT_IN ==0)
				{
					buff[i] &= ~(0x1<<7-j);
				}
				else 
				{
					buff[i] |= (0x1<<7-j);
				}
				
				
		}
	}

  • 通信完毕,释放总线
	//通信完毕后,释放总线
	DHT_OUT_H;

4、校验数据

alt text

//4、数据校验
	uint8_t data = buff[0]+buff[1]+buff[2]+buff[3];
	if(data != buff[4])
	{
		printf("校验错误");
		return;
	}

5、数据获取

  • 数值转换为10进制,还包括小数和整数,正数和负数

alt text

//5、数据获取
	if(buff[1]<10)			//如果只有一位小数
	dht.hum = buff[0]+buff[1]*0.1;
	else if(buff[1]>=10)//两位
	dht.hum = buff[0]+buff[1]*0.01;
	
	//温度小数部分最高位是否为1
	if(buff[3] & (0x1<<7))//负值
	{
		buff[3] &= ~(0x1<<7);//将最高位清0
		if(buff[3]<10)			//如果只有一位小数
		dht.tem = (buff[2]+buff[3]*0.1)*(-1);
		else if(buff[3]>=10)
		dht.tem = (buff[2]+buff[3]*0.01)*(-1);
		}
	else//正值
	{
		buff[3] &= ~(0x1<<7);
		if(buff[3]<10)			//如果只有一位小数
		dht.tem = buff[2]+buff[3]*0.1;
		else if(buff[3]>=10)
		dht.tem = buff[2]+buff[3]*0.01;
	}
	printf("tem:%.2f℃\r\n",dht.tem);
	printf("hum:%.2f%%RH\r\n",dht.hum);

main.c

int main()
{
	SysTick_Config(72000);
	usart_init();
	dht11_init();
	while(1)
	{
		if(dhtime >=2000)
		{
			dhtime =0 ;
			get_dht11_val();
		}
    }
}

补充: stlink有个调试的功能

alt text

  • 注:进入调试,不能点击板子上的复位按键

alt text

alt text

  • 添加断电(注意:有阴影的地方才能添加断点,因为有阴影的地方是程序运行的代码)

alt text

- tip:可以适当的总结keil的错误,因为在keil出现的错误来来回回就只有几种错误,总结好,以后遇到错误,就可以更快的解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值