OpenVINOTM,给你看得见的未来!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » STM32G070RB探测19-单总线采集温湿度

共4条 1/1 1 跳转至

STM32G070RB探测19-单总线采集温湿度

高工
2021-01-10 21:46:28    评分

上次用的温湿度传感器是AHT10,我看课程里用的是DHT11,我画的PCB上也刚好有DHT11,两者有点区别,AHT11是IIC采集,而DHT11是单总线采集,也就是一个IO口就可以采集到温湿度,今天就来搞一下这个单总线.先看数据手册

再细看读取步骤

总结一下: 1.上电先等待1S:此时DATA高电平 2.发送起始信号:先由DATA由高拉低, 持续18ms-30ms,然后拉高 3.DHT11应答:DHT11先拉低83us作为应答,再输出87us通知单片机接收数据 4.接收数据:数据为40为数据, 位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平 位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。

需要: 单总线要求IO口既要输出也要输入,这是我们可以外加上拉电阻,把DATR引脚设置为开漏输出,此时高电平不输出(由外部上下拉决定),低电平为低电平,同时也能读取IO变化.这就跟51单片机的IO口类似了. ms级延迟函数我们已经有了,就差个us级延迟函数

先写个us级延迟函数,这里我们使用定时器实现

先点出来一个定时器

我们不需要中断,使用查询方式即可,生成

因为主频为64MMHz,分频64,定时器的频率为1MHz=1000KHz=1000000Hz,即计数一次周期为1s/1000000=1us

我们直接写个延迟函数

void Delay_us(uint16_t us)
{
	uint16_t differ = 0xffff-us-10;//初值,多减10以防没检测到
	__HAL_TIM_SET_COUNTER(&htim17,differ);	//设定TIM7计数器起始值
	HAL_TIM_Base_Start(&htim17);		//启动定时器
	while(differ < 0xffff-10)//等于是加了一个us的值,加一次1us
	{
		differ = __HAL_TIM_GET_COUNTER(&htim17);		//查询计数器的计数值
	}
	HAL_TIM_Base_Stop(&htim17);
}

验证一下

HAL_GPIO_TogglePin(LDO_GPIO_Port,LDO_Pin);
Delay_us(100);

while(1)中添加代码,100us变换一次IO,用逻辑分析仪抓一下

看起来可能是差了一点,但是其中包括了GPIO操作的时间,改一下数值再测下

HAL_GPIO_TogglePin(LDO_GPIO_Port,LDO_Pin);
Delay_us(50);

看起来蛮准的

写驱动

点出来DATA引脚设置,开漏输出

void DATA_SET(GPIO_PinState val)
{
	HAL_GPIO_WritePin(DHT_GPIO_Port,DHT_Pin,val);
}
uint8_t DATA_GET(void)
{
	return HAL_GPIO_ReadPin(DHT_GPIO_Port,DHT_Pin);
}

1.发送起始信号:先由DATA由高拉低, 持续18ms-30ms,然后拉高

void DHT11_Start(void)//发送起始信号
{
	DATA_SET(GPIO_PIN_RESET); 	//拉低
	HAL_Delay(20);    	//至少18ms
	DATA_SET(GPIO_PIN_SET);  	//拉高
	Delay_us(30);     	//至少20~40us
}

2.DHT11应答:DHT11先拉低83us作为应答,再输出87us通知单片机接收数据

uint8_t DHT11_Check(void)//检测从机响应信号
{
	uint8_t retry=0;
	while (DATA_GET()&&retry<100)//拉低40~80us
	{
		retry++;
		Delay_us(1);
	};
	if(retry>=100)
		return 1;
	else
		retry=0;
	while (!DATA_GET()&&retry<100)//拉高40~80us
	{
		retry++;
		Delay_us(1);
	};
	if(retry>=100)
		return 1;
	return 0;	//检测到DHT11返回0
}

3.初始化

uint8_t DHT11_Init(void)//DHT11初始化,成功返回0
{
	HAL_Delay(1000);
	DHT11_Start();
	return DHT11_Check();
}

4.读取一位

uint8_t DHT11_Read_Bit(void)//读取一位
{
 	uint8_t retry=0;
	while(DATA_GET()&&retry<100)//等待变为低电平
	{
		retry++;
		Delay_us(1);
	}
	retry=0;
	while(!DATA_GET()&&retry<100)//等待变为高电平
	{
		retry++;
		Delay_us(1);
	}
	Delay_us(40);	//等待40us
	if(DATA_GET())
		return 1;
	else return 0;
}

5.读取一个字节

uint8_t DHT11_Read_Byte(void)//读取一个字节
{
	uint8_t i,dat;
	dat=0;
	for (i=0;i<8;i++){
   		dat<<=1;
	    dat|=DHT11_Read_Bit();
    }
    return dat;
}

6.读取5个字节

uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi)//DHT11读取,成功返回0
{
 	uint8_t buf[5];
	uint8_t i;
	DHT11_Start();
	if(DHT11_Check()==0){
		for(i=0;i<5;i++){
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){
			*humi=(buf[0]<<8) + buf[1];
			*temp=(buf[2]<<8) + buf[3];
		}
	}else return 1;
	return 0;
}

测试

while(DHT11_Init())
{
    printf("DHT11 Checked failed!!!\r\n");
}
uint16_t temperature;
uint16_t humidity;
while (1)
{
    DHT11_Read_Data(&temperature,&humidity);
    printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff);
    printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);
    HAL_Delay(500);
}

效果如下

对比AHT10和DHT11,温度差别不大,但湿度差别很大,差的有点不敢相信哈哈



工程师
2021-01-12 06:44:56    评分
2楼

谢谢分享!学习学习!


工程师
2021-01-12 22:15:49    评分
3楼

感谢您的分享


工程师
2021-01-12 22:38:07    评分
4楼

学到了


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]