STM32一线协议-DHT11温湿度传感器采样实现


1- DHT11介绍及工作原理

DHT11温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。

DHT11器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。单总线通常要求外接一个约5.1kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。

在这里插入图片描述

4根引脚,名称与功能如下:

  • VCC:供电 3-5.5VDC
  • GND:接地,电源负极
  • DATA: 串行数据,单总线(CPU数据传输)
  • NC:空脚(什么都没有接)

DHT11:异步(无同步时钟)、串行通信(只有一根线),半双工(一根线双向通信),电平信号发送


2- DHT11通信时序

用户主机(STM32单片机)发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11发送响应信号,送出40bit的采集数据,然后结束本次采集任务。
注:主机从DHT11读取的温湿度数据总是前一次的测量值,如两次测间隔时间很长,请连续读两次以第二次获得的值为实时温湿度值。
在这里插入图片描述

(1)主机发送起始信号

首先单片机将连接DHT11 DATA引脚的GPIO口输出低电平,且低电平保持时间不能小于18ms (t1)最大不能超多30ms,然后拉高数据线20~40us (t2) ,等待读取DHT11的响应信号。

(2)检测从机应答信号

DHT11的DATA引脚检测到外部信号有低电平(t1),并等待外部低电平信号结束(t2),延迟后DHT11的DATA引脚处于输出状态,之后DHT11开始输出80 us (t3)的低电平作为应答信号,紧接着输出80us(t4)的高电平通知主机准备接收数据。
主机的I/O此时处于输入状态,检测I/O有低电平(DHT11应答信号)后,等待80us的高电平后接受数据。

(3)数据传输

由DHT11的DATA引脚输出40位数据,采用高位优先方式(MSB),微处理器根据I/0电平的变化接收40位数据。
位数据“0”的格式为:50微秒的低电平和26-28us的高电平。
位数据“1”的格式为:50微秒的低电平加70us的高电平。

位数据“0”、“1”格式信号如图6所示:
在这里插入图片描述

单片机在处理数据接收时可以先等待低电平过去,即等待数据线拉高,再延时40us (因为40us大于28us且小于70us) ,再检测此时数据线是否为高,如果为高,则数据判定为1,否则为0。

(4)传输数据举例

DHT11在传输数据时,一次传输4字节温湿度值数据和1字节数据校验(总共40bit)。其数据格式为:
1B湿度整数数据+1B湿度小数数据+1B温度整数数据+ 1B温度小数数据+1B校验位。
在这里插入图片描述

【1】举例一(温度为正)

接收到的40位数据为:
在这里插入图片描述
计算:
0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001(校验位)
说明接收数据正确:

湿度:
00110101(整数)=35H(16进制)=53%RH(相对湿度)
00000000(小数)=00H(16进制)=0.0%RH(相对湿度)
最终得出湿度为:53.0%RH

温度:
00011000(整数)=18H(16进制)=24℃
00000100(小数)=04H(16进制)=0.4℃
最终得出温度为:24.4℃

【2】举例二(温度为负)

当温度低于0℃时温度数据的低8位的最高位置为1。
-10.1℃表示为 0000 1010 1000 0001 看到1代表为负数,算的时候还是按照0来算,最后加上负号。

温度:
00001010(整数)=0AH(16进制)=10℃
00000001(小数)=01H(16进制)=0.1℃
最终得出温度为:-10.1℃

【3】举例三(校验位错误)

说明接收数据正确:
在这里插入图片描述
计算:
0011 0101 + 0000 0000 + 00011000 + 0000 0100 = 0101 0001不等于校验位,接收错误。本次不接收,重新接收数据。


3- 连接和配置

(1)dht11.c
/*
 * dht11.c
 *
 *  Created on: Oct 28, 2022
 *      Author: Administrator
 */

#include "tim.h"
#include "gpio.h"
#include "main.h"
#include "usart.h"

typedef struct w1_gpio_s
{
	GPIO_TypeDef   *group;
	uint16_t       pin;
}w1_gpio_t;

static w1_gpio_t  W1Dat =
{
		.group = GPIOA,
		.pin   = GPIO_PIN_5,
};

#define W1DQ_Input() \
{\
	GPIO_InitTypeDef GPIO_InitStruct = {0};\
	GPIO_InitStruct.Pin = W1Dat.pin;\
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;\
	GPIO_InitStruct.Pull = GPIO_PULLUP;\
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
	HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);\
}

#define W1DQ_Output() \
{\
	GPIO_InitTypeDef GPIO_InitStruct = {0};\
	GPIO_InitStruct.Pin = W1Dat.pin;\
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\
	GPIO_InitStruct.Pull = GPIO_NOPULL;\
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
	HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct);\
}

#define W1DQ_Write(x)  HAL_GPIO_WritePin(W1Dat.group, W1Dat.pin, (x==1)?GPIO_PIN_SET:GPIO_PIN_RESET)

#define W1DQ_Read(x)  HAL_GPIO_ReadPin(W1Dat.group, W1Dat.pin)

static void DHT11_StartSignal(void)
{
	W1DQ_Output();

	/*主机拉低 >= 18ms*/
	W1DQ_Write(0);
	HAL_Delay(20);

	/*主机拉高 >= 20-40us*/
	W1DQ_Write(1);
	delay_us(30);

	W1DQ_Input();
}

uint8_t DHT11_RespondSignal(void)
{
	uint8_t retry = 0;

	/*总线变成低电平说明设备发送了响应信号 80us*/
	while( W1DQ_Read()  && retry < 100)
	{
		retry++;
		delay_us(1);
	}

	/*超时设备没有收到响应信号*/
	if( retry >= 100)
	{
		printf("1 Timeout No response received\r\n");
		return 1;
	}

	/*从设备再把总线拉高表示从设备要发送数据了:80us*/
	retry = 0;
	while( !W1DQ_Read()  && retry < 100 )
	{
		retry++;
		delay_us(1);
	}

	if( retry >= 100)
	{
		printf("2 Timeout No response received\r\n");
		return 1;
	}

	return 0;
}

/*读取一个位*/
uint8_t DHT11_ReadBit(void)
{
	uint8_t retry = 0;

	/*从设备回复的每个数据以低电平标志开始:50uw*/
	while( W1DQ_Read()  && retry < 100 )
	{
		retry++;
		delay_us(1);
	}

	/*数据位都用高电平表示,但是高电平的长短决定数据是1还是0*/
	while( !W1DQ_Read()  && retry < 100 )
	{
		retry++;
		delay_us(1);
	}

	/*判断数据位是1(70us)还是0(26-28us)*/
	delay_us(40);
	if( W1DQ_Read() )
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

/*读取一个字节 MSB*/
uint8_t DHT11_ReadByte(void)
{
	uint8_t i,dat;

	dat = 0;

	for(i=0; i<8; i++)
	{
		dat <<= 1;
		dat |= DHT11_ReadBit();//每读取到一个位就当在最后一位
	}

	return dat;
}

int DHT11_SampleData(float *temperature, float *humidity)
{
	uint8_t   humi_H8bit;
	uint8_t   humi_L8bit;
	uint8_t   temp_H8bit;
	uint8_t   temp_L8bit;
	uint8_t   check_sum;

	if( !temperature || !humidity)
	{
		//printf("1\r\n");
		return -1;
	}

	/*主机发送起始信号并且等待设备的响应信号*/
	DHT11_StartSignal();

	if(0 != DHT11_RespondSignal())
	{
		//printf("2\r\n");
		return -2;
	}

	humi_H8bit = DHT11_ReadByte();
	humi_L8bit = DHT11_ReadByte();
	temp_H8bit = DHT11_ReadByte();
	temp_L8bit = DHT11_ReadByte();
	check_sum  = DHT11_ReadByte();

	if((humi_H8bit + humi_L8bit + temp_H8bit + temp_L8bit) != check_sum )
	{
		//printf("3\r\n");
		return -3;
	}

	*humidity = (humi_H8bit*100 + humi_L8bit) / 100.00;
	*temperature = (temp_H8bit*100 + temp_L8bit) / 100.00;

	return 0;
}
(2)dht11.h
/*
 * dht11.h
 *
 *  Created on: Oct 28, 2022
 *      Author: Administrator
 */

#ifndef INC_DHT11_H_
#define INC_DHT11_H_

#endif /* INC_DHT11_H_ */
int DHT11_SampleData(float *temperature, float *humidity);
(3)main.c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "dht11.h"
/* Private includes ----------------------------------------------------------*/
...
int main(void)
{
  /* USER CODE BEGIN 1 */
  float temperature, humidity;
  /* USER CODE END 1 */
  ...
  printf("Welcome to the DHT11 project\r\n");
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
	  if( DHT11_SampleData(&temperature, &humidity) < 0)
	  {
		  printf("ERROR: DHT11 sample data failure\r\n");
	  }
	  else
	  {
		  printf("DHT11 sample Tempeature: %.3f  Relative Humidity: %.3f\r\n", temperature, humidity);
	  }

	  HAL_Delay(3000);
  }
}

4- 结果呈现

保存烧录然后就可以看见我们获取到的温湿度了;用手捂住可以看见温湿度正在慢慢升高。
在这里插入图片描述

在这里插入图片描述


代码主要是看着实验室的资料敲出来的,但是都能够理解,看着datasheet敲代码可能还有一些困难,慢慢努力加油吧!

如有错误还请指出~

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值