STM32外设系列之DHT11温湿度传感器详解

文章标题

  • 一、DHT11简介
  • 二、数据手册分析
  • 2.1 接口说明
  • 2.2 串行通信说明
  • 2.2.1 单总线通信
  • 2.2.2 单总线传输数据位定义
  • 2.2.3 时序图
  • 三、DHT11程序设计
  • 3.1 初始化GPIO
  • 3.2 发送起始信号
  • 3.3 接收一个字节数据
  • 3.4 接收温湿度信息并校准
  • 四、总结
  • 一、DHT11简介

    DHT11是一款常用的数字温湿度传感器。传感器包括一个电容式感湿元件和一个 NTC 测温元件,能够测量皱纹环境的温湿度,常用于暖通空调、除湿器、农业、冷链仓储等方面。
    DHT11

    二、数据手册分析

    2.1 接口说明

    DHT11接口说明

    2.2 串行通信说明

    DHT11通过串行通信的方式,将采集到的环境温湿度信息传递给单片机。数据手册中,针对DHT11的串行通信做了详细介绍。

    2.2.1 单总线通信

    DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。设备(主机或从机)通过一个漏极开路或三态端口连至数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线;单总线通常要求外接一个约 4.7kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。

    2.2.2 单总线传输数据位定义

    DHT11的DATA引脚,用于单片机与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。数据格式

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

    数据手册中写明,湿度的小数部分为0。8bit 校验位等于所得结果的末 8 位。
    单总线格式定义
    对于校验位,数据手册中举例说明。比如接收到的40位数据为

    0011 0101 0000 0000 0001 1000 0000 0100 0101 0001
    湿度高8位 湿度低8位 温度高8位 温度低8位 校验位

    计算 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 + 0101 0001 = 0101 0001,与接收到的校验位相等,校验通过。如果校验不通过,则将此次接收到的数据丢弃,重新接收数据。

    2.2.3 时序图

    根据上面的介绍,如果单片机想要读取数据,需要先发送一个起始信号。起始信号需要拉低数据线至少18ms。
    起始信号

    DHT11检测到起始信号之后,等待起始信号低电平结束,然后输出应答信号。应答信号是先将数据线拉低83us,再拉高87us。

    应答信号

    然后DHT11就开始输出数据了,“0”和“1”的时序图如下

    “0”和“1”的时序图

    总时序图如下

    总时序图

    三、DHT11程序设计

    3.1 初始化GPIO

    根据上面的介绍,STM32的GPIO既需要用作输出,也需要用作输入。因此,STM32的GPIO需要有两种配置

    /*
     *==============================================================================
     *函数名称:Drv_Dht11_Gpio_OutInSet
     *函数功能:DHT11引脚输出/输入设置
     *输入参数:state:OUT:输出(0);IN:输入(1)
     *返回值:无
     *备  注:无
     *==============================================================================
     */
    void Drv_Dht11_Gpio_OutInSet (u8 state)
    {
    	// 结构体定义
     	GPIO_InitTypeDef  GPIO_InitStructure;
    	
    	// 开启时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	
    	// 初始化GPIO结构体
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    	if (state)
    	{
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入
    	}
    	else
    	{
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出
    	}
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     	GPIO_Init(GPIOA,&GPIO_InitStructure);
    }
    

    .h文件添加下面程序

    // GPIO模式
    #define OUT   0   // 输出模式
    #define IN    1   // 输入模式
    

    3.2 发送起始信号

    单片机的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms(最大不得超过 30ms),然后单片机的 I/O 设置为输入状态,由于上拉电阻,单片机器的 I/O 即 DHT11 的 DATA 数据线也随之变高,等待 DHT11 作出回答信号。程序设计如下

    /*
     *==============================================================================
     *函数名称:Drv_Dht11_Start
     *函数功能:向DHT11发送起始信号
     *输入参数:state:OUT:输出(0);IN:输入(1)
     *返回值:无
     *备  注:无
     *==============================================================================
     */
    void Drv_Dht11_Start (void)
    {
    	OLED_SDA_Set();   // 拉高一小段时间
    	delay_us(30);
    	
    	Drv_Dht11_Gpio_OutInSet(OUT);   // GPIO配置为输出模式
    	OLED_SDA_Clr();   // 拉低数据线
    	delay_ms(20);   // 保持20ms
    	
    	OLED_SDA_Set();   // 拉高一小段时间
    	delay_us(30);
    	
    	Drv_Dht11_Gpio_OutInSet(IN);   // GPIO配置为输入模式
    }
    

    3.3 接收一个字节数据

    /*
     *==============================================================================
     *函数名称:Med_Dht11_ReceOneByte
     *函数功能:接收一帧数据
     *输入参数:无
     *返回值:一字节接收数据
     *备  注:无
     *==============================================================================
     */
    u8 Med_Dht11_ReceOneByte (void)
    {
    	u8 tempVar = 0;   // 临时循环变量
    	u8 receData = 0;   // 接收数据
    	
    	for (tempVar = 0;tempVar < 8;tempVar ++)
    	{
    		while (!DHT11_SDA_DATA);   // 等待54us的低电平过去
    		delay_us(30);   // 延时30us之后判断是0还是1
    		
    		// 如果30us之后依旧为高电平
    		if (DHT11_SDA_DATA)
    		{
    			receData |= 1;   // 接收数据为1
    		}
    		while (DHT11_SDA_DATA);   // 等待高电平过去
    		
    		receData <<= 1;   // 左移
    	}
    	
    	return receData;
    }
    

    3.4 接收温湿度信息并校准

    /*
     *==============================================================================
     *函数名称:App_Dht11_Result_Process
     *函数功能:处理接收结果,得出正确的温湿度信息
     *输入参数:无
     *返回值:无
     *备  注:无
     *==============================================================================
     */
    u8 receData[4];   // 存储温湿度结果
    void App_Dht11_Result_Process (void)
    {
    	u8 receCheck = 0;   // 接收到的校验码
    	u8 tempCal = 0;   // 临时计算变量
    	
    	Drv_Dht11_Start();   // 发送一个起始信号
    	DHT11_SDA_Set();   // 拉高SDA
    	
    	// 等待应答信号
    	if (!DHT11_SDA_DATA)
    	{
    		while (!DHT11_SDA_DATA);   // 等待83us低电平结束
    		while (DHT11_SDA_DATA);   // 等待87us高电平结束
    		
    		// 开始接收数据
    		receData[0] = Med_Dht11_ReceOneByte();   // 湿度整数
    		receData[1] = Med_Dht11_ReceOneByte();   // 湿度小数
    		receData[2] = Med_Dht11_ReceOneByte();   // 温度整数
    		receData[3] = Med_Dht11_ReceOneByte();   // 温度小数
    		receCheck = Med_Dht11_ReceOneByte();   // 校验码
    		
    		tempCal = receData[0] + receData[1] + receData[2] + receData[3];
    		
    		// 如果校验失败
    		if (tempCal != receCheck)
    		{
    			// 清空接收
    			receData[0] = receData[1] = receData[2] = receData[3] = 0;
    		}
    	}
    }
    
    

    四、总结

    实际上面的程序设计有一些不足,比如某些地方不需要再拉高SDA线,在等到时使用了while语句但是没有超时检测。但是由于博主的DHT11坏了,目前买的新的还没到,无法继续调试,因此这里说明一下。后续会修改完善程序,补充应用实例。——2023年6月26日

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32外设系列之DHT11温湿度传感器详解

    发表评论