外设模块学习(6)——DHT11温湿度传感器(STM32)

目录

引言

一、DHT11概述

二、相关参数

[2.1 电气特性](#2.1 电气特性)

[2.2 引脚说明](#2.2 引脚说明)

[2.3 温湿度测试性能](#2.3 温湿度测试性能)

三、通信方式(单线双向)

[3.1 DHT11简化单总线协议说明](#3.1 DHT11简化单总线协议说明)

[3.2 DHT11单总线数据格式](#3.2 DHT11单总线数据格式)

[3.3 DHT11通信时序说明](#3.3 DHT11通信时序说明)

[3.4 主从通信步骤](#3.4 主从通信步骤)

[3.5 注意事项](#3.5 注意事项)

四、参考代码(基于STM32)

[4.1 DHT11驱动代码](#4.1 DHT11驱动代码)

1、dht111.h

2、dht11.c

[4.2 主函数代码](#4.2 主函数代码)

[4.3 测试效果](#4.3 测试效果)

参考资料


引言

本次学习一款温湿度传感器DHT11,学习之前需要具备STM32基础知识以及C语言基础。同时,本次学习我们参考奥松的温湿度模块 DHT11 产品手册进行DHT11的驱动代码编写。

一、DHT11概述

DHT11是一款含有已校准数字信号输出的温湿度 复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。

DHT11温湿度传感器应用广泛,常见于暖通空调、除湿器、农业、冷链仓储、测试及检测设备、消费品、 汽车、自动控制、数据记录器、气象站、家电、湿度调节器、医疗、其他相关湿度检测控制。

DHT11具有成本低、长期稳定、相对湿度和温度测量、品质卓越、超快响应、抗干扰能力强、超长的 信号传输距离、数字信号输出、精确校准等优点。

二、相关参数

2.1 电气特性

使用时一定要注意DHT11的供电电压范围,尽可能处于给定范围之间,避免电压过低或过高影响测量效果。

2.2 引脚说明

1、VDD供电3.3~5.5VDC

2、DATA串行数据,单总线

3、NC空脚(通常不引出)

4、GND接地,电源负极

2.3 温湿度测试性能

可见,DHT11的相对湿度测量范围是5~95 %RH。其中在温度为25℃时,精度±5 %RH等。

可见,DHT11的温度测量范围是-20~60℃,其中在温度为25℃时,±2℃的浮动范围等。

三、通信方式(单线双向)

3.1 DHT11简化单总线协议说明

手册上写的已经非常详细了,这里就不再赘述,直接上截图了,相信大家也能理解,如下图所示。


3.2 DHT11单总线数据格式

3.3 DHT11通信时序说明

如下图为DHT11与微控制器(主设备)进行通信时的数据时序图

3.4 主从通信步骤

主机和从机之间的通信可通过如下几个步骤完成(外设(如微处理器)读取DHT11的数据 的步骤)。

1、DHT11上电后等待1s稳定后处于输入状态,检测外部信号,此时总线空闲,默认拉高;

2、主机获取总线控制权,并拉低总线18~30ms,随后释放总线。总线空闲,默认拉高;

3、DHT11占据总线,拉低总线83us,产生应答;接着拉高总线87us,提示主机准备接收数据;

此时,对于主机来说,即检测总线是否拉低判断DHT11是否产生应答,接着若应答了,则继续等待DHT1应答信号结束,接着等待DHT11的拉高结束,完成响应信号的时序。

4、DHT继续占据总线,开始连续发送40位数据。发送数据"0",DHT11先拉低总线54us,再拉高总线23~27us;发送数据"1",DHT11先拉低总线54us,再拉低总线68~74us,连续重复40次;

对于主机来说,即读取每一位数据,连续8次进而读取一字节数据,连续读取5次字节数据进而获取完整40位数据。所以理解读取一位数据的方法即可以此类推。

这个**过程为:**读取总线电平,等待总线拉低完成,接着延迟30us越过出现数据0的时序(便于同时进行数据0或1的接收),然后读取总线电平,若为低说明此时DHT11发送的确实是数据"1",反之发送的是数据"0",最后若为数据1则继续等待总线拉高完成,反之则一位数据读取结束。

5、DHT11发送完40位数据后,会先拉低总线54us后自动释放总线,使总线空闲,默认拉高。

此时DHT11释放总线后,总线会处于空闲状态,此时需要等待DHT11内部重测温湿度数据并记录。故DHT11产生停止信号后主机不必恢复占据空闲的总线,影响DHT11的数据记录以及后续的通信。此时让总线空闲,自由时序即可。

最后,主机记录好40位数据,并进行校验,没有问题说明接受的数据无误,串口输出数据即可。

3.5 注意事项


四、参考代码(基于STM32)

最后,我们基于STM32的寄存器方式编写一下DHT11的驱动代码,实现串口打印温湿度数据。

4.1 DHT11驱动代码

1、dht111.h

cpp 复制代码
/*
 * @Descripttion: DHT11驱动程序(寄存器方式)
 * @Author: JaRyon
 * @version: v1.0
 * @Date: 2025-10-10 21:56:32
 */
#ifndef __DHT11_H
#define __DHT11_H

#include "stm32f10x.h"
#include "usart.h"
#include "Delay.h"

// 数据线状态
#define DHT11_SDA_HIGH()    {GPIOA->BSRR |= GPIO_BSRR_BR5;} // 拉高
#define DHT11_SDA_LOW()     {GPIOA->BRR |= GPIO_BRR_BR5;}   // 拉低
// 读数据
#define DHT11_READ          (GPIOA->IDR & GPIO_IDR_IDR5)    // 读电平
// 应答与非应答
#define ACK 0
#define NACK 1

// 输入输出模式
typedef enum
{
    INPUT_MODE = 1,
    OUTPUT_MODE
}IOMode;

// 函数声明
// 配置初始化
void DHT11_Init(void);
// IO模式设置
void DHT11_SetIOMode(IOMode mode);
// 发送起始信号
void DHT11_Start(void);
// 等待DHT11响应
int8_t DHT11_Wait4Ack(void);
// 接收DHT11的一位数据
int8_t DHT11_ReadBit(void);
// 接收DHT11的一字节数据
int8_t DHT11_ReadByte(void);
// 读取DHT11发送的数据
// int8_t DHT11_GetHumTemp(int16_t *hunitidy, int16_t *temperature);

uint8_t DHT11_GetHumTemp(uint8_t *buffer);

#endif

2、dht11.c

cpp 复制代码
/*
 * @Descripttion: DHT11驱动程序(寄存器方式)
 * @Author: JaRyon
 * @version: v1.0
 * @Date: 2025-10-10 21:56:32
 */
#include "dht11.h"

/**
 * @brief  DHT11初始化函数
 * @return None
 */
void DHT11_Init(void)
{
    // 开漏输出  PA5 mode-11 cnf-01
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    GPIOA->CRL |= GPIO_CRL_MODE5;
    GPIOA->CRL &= ~GPIO_CRL_CNF5_1;
    GPIOA->CRL |= GPIO_CRL_CNF5_0;

    DHT11_SDA_HIGH();
}

/**
 * @brief  设置DHT11引脚模式
 * @param  mode: 输入模式或输出模式
 * @return None
 */
void DHT11_SetIOMode(IOMode mode)
{
    switch (mode)
    {
    case INPUT_MODE: // 浮空输入
        GPIOA->CRL &= ~(GPIO_CRL_MODE5 | GPIO_CRL_CNF5_1);
        GPIOA->CRL |= GPIO_CRL_CNF5_0;
        break;
    case OUTPUT_MODE:   // 开漏输出
        GPIOA->CRL |= GPIO_CRL_MODE5;
        GPIOA->CRL &= ~GPIO_CRL_CNF5_1;
        GPIOA->CRL |= GPIO_CRL_CNF5_0;
        break;
    default:
        break;
    }
}

/**
 * @brief  发送起始信号
 * @return None
 */
void DHT11_Start(void)
{
    // 1. 主机占用总线
    DHT11_SetIOMode(OUTPUT_MODE);

    // 2. SDA拉低, 发出起始信号
    DHT11_SDA_LOW();
    Delay_ms(20);

    // 3. 主机释放总线
    DHT11_SDA_HIGH();
    DHT11_SetIOMode(INPUT_MODE);
    Delay_us(20);
}

/**
 * @brief  等待DHT11响应
 * @return ACK表示成功,NACK表示失败
 * @attention 利用循环等待结束,避免延时超过或提前造成时序差错
 */
int8_t DHT11_Wait4Ack(void)
{
    // 1. 出现应答信号
    if (!DHT11_READ)
    {
        // 2. 等待DHT11拉低应答完成
        while (!DHT11_READ);

        // 3. 等待DHT11拉高完成,准备接收数据
        while (DHT11_READ);

        return ACK;
    }

    return NACK;
}

/**
 * @brief  读取一个位的数据
 * @return 读取到的位值(0或1)
 * @attention 利用循环等待结束,避免延时超过或提前造成时序差错
 */
// 接收DHT11的一位数据
int8_t DHT11_ReadBit(void)
{
    int8_t bit = 0x00;

    // 1. 等待总线低电平结束
    while (!DHT11_READ);

    // 2. 延时后接收数据
    Delay_us(28);
    if (DHT11_READ)
    {
        bit = 1;
        // 3. 等待总线高电平结束
        while (DHT11_READ);
    }
    else
    {
        bit = 0;
    }

    return bit;
}

/**
 * @brief  读取一个字节的数据
 * @return 读取到的字节值
 */
int8_t DHT11_ReadByte(void)
{
    int8_t byte = 0x00;

    for (uint8_t i = 0; i < 8; i++)
    {
        byte <<= 1;
        byte |= (DHT11_ReadBit() & 0x01);
    }
    return byte;
}

/**
 * @brief  获取温湿度数据
 * @param  buffer: 存储数据的缓冲区
 * @return 1表示成功,0表示失败
 * @attention DHT11自动释放总线,不用手动干预,且逻辑非的判断可能影响时序
 */
uint8_t DHT11_GetHumTemp(uint8_t *buffer)
{
    // 发送起始信号并等待响应
    DHT11_Start();
    if (DHT11_Wait4Ack() == NACK)
    {
        return NACK; // 响应失败
    }

    // 读取5个字节的数据
    for (uint8_t i = 0; i < 5; i++)
    {
        buffer[i] = DHT11_ReadByte();
    }

    // 校验数据
    return (buffer[0] + buffer[1] + buffer[2] + buffer[3] == buffer[4]) ? 1 : 0;
}

4.2 主函数代码

cpp 复制代码
/*
 * @Descripttion: 串口打印DHT11测量的温湿度数据(基于寄存器实现) 
 * @Author: JaRyon
 * @version: v1.0
 * @Date: 2025-10-10 21:56:32
 */
// DHT11对时序要求比较严格,需要严格按照指定时序接收数据
//时序模拟过程中尽可能减少无关指令

/* 引脚定义
		DHT11:
			VCC   --->   3.3/5V
			DATA  --->   PA5
			GND   --->   GND
		CH340:
			5V    --->   5V
			GND   --->   GND
			TX    --->   PA10
			RX    --->   PA9
*/

#include "stm32f10x.h"
#include "usart.h"
#include "dht11.h"

int main(void)
{
	uint8_t DHT11_Data[5] = {0}; // 存储温湿度数据的缓冲区
	uint8_t readRes;			 // 读取结果标志

	USART_Init();
	DHT11_Init();

	while (1)
	{
		// 读取温湿度数据
		readRes = DHT11_GetHumTemp(DHT11_Data);

		if (readRes)
		{
			// 数据读取成功,打印结果
			printf("Read Success!\r\n");
			printf("---------------------\r\n");
			printf("humidity: %d.%d %%RH \r\n", DHT11_Data[0], DHT11_Data[1]);
			printf("temperature: %d.%d C \r\n", DHT11_Data[2], DHT11_Data[3]);
			for (uint8_t i = 0; i < 5; i++)
			{
				printf("DHT11_Data[%d] = %d\n", i, *(DHT11_Data + i));
			}

			printf("CRC: 0x%02X \r\n", DHT11_Data[4]);
		}
		else
		{
			// 数据读取失败
			printf("Check Connected!\r\n");
		}
		printf("---------------------\r\n");

		// 每3秒读取一次
		Delay_ms(3000);
	}
}

4.3 测试效果


参考资料

DHT11 奥松-ASAIR_PDF_数据手册 | 电容式温湿度传感器模块


以上便是本次文章的所有内容,欢迎各位朋友在评论区讨论,本人也是一名初学小白,愿大家共同努力,一起进步吧!

鉴于笔者能力有限,难免出现一些纰漏和不足,望大家在评论区批评指正,谢谢!

相关推荐
桃里桑3 小时前
【嵌入式软件】STM32 UART转485通信问题
stm32·单片机·嵌入式硬件
萧技电创EIIA5 小时前
基于wifi摄像头与单片机的串口透传及二次开发
单片机·51单片机·硬件工程·个人开发
三佛科技-134163842125 小时前
迷你加湿器方案开发,加湿器/香薰机MCU控制方案开发设计
单片机·嵌入式硬件·智能家居·pcb工艺
一支闲人6 小时前
带你了解STM32:SPI通信(硬件部分)
stm32·单片机·嵌入式硬件·基础知识
我先去打把游戏先8 小时前
VSCode通过SSH连接到Ubuntu虚拟机失败“找不到ssh安装”问题解决
笔记·vscode·单片机·嵌入式硬件·学习·ubuntu·ssh
XiangrongZ8 小时前
江协科技STM32课程笔记(三)—定时器TIM(输出比较)
笔记·科技·stm32
学工科的皮皮志^_^11 小时前
电压源和电流源学习理解
单片机·嵌入式硬件·学习
linweidong12 小时前
跨平台驱动开发:打造兼容多款MCU的硬核方案
驱动开发·单片机·嵌入式硬件·bsp·rtos·spi驱动·hal设计
易享电子13 小时前
基于单片机大棚浇水灌溉控制系统Proteus仿真(含全部资料)
单片机·嵌入式硬件·fpga开发·51单片机·proteus