前言

        本系统旨在设计一款基于DHT11温湿度传感器的检测装置,并通过蓝牙技术将数据上传,实现对环境温湿度的实时监测与远程数据传输。

DHT11产品概述

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

接口说明

        建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使 用合适的上拉电阻

 电源引脚

        DHT11的供电电压为3- 5.5V。传感器上电后,要等待1s以越过不稳定状态在此期间无需发送任何指令。电源引脚( VDD, GND)之间可增加一个100nF的电容,用以去耦滤波。

DHT11引脚说明

Pin 名称 注释
1 VDD 供电3- 5. 5VDC
2 DATA 串行数据,单总线
3 NC 空脚,请悬空
4 GND 接地,电源负极

代码部分

main.c

int main(void)
{
  /* USER CODE BEGIN 1 */
extern UART_HandleTypeDef huart2;
extern uint8_t dht11_data[5];

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();
  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
	HAL_Init();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
	
		DWT_Delay_Init();      
 
	
  /* USER CODE BEGIN 2 */

  printf("SystemCoreClock: %lu Hz\r\n", SystemCoreClock); // 打印 SystemCoreClock 的值
	printf("DWT->CTRL = 0x%08lX\r\n", DWT->CTRL);
  DHT11_Init(); // 初始?? DHT11
	printf("DHT11 Test Start...\r\n");

	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		uint8_t success = 0;
		for (int i = 0; i < 3; i++) {
			if (DHT11_Read_Data(&temperature, &humidity) == 0) {
        success = 1;
        break;
				}
    HAL_Delay(100);  // 间隔 100ms 重试
		}

    if (success)
    {
        uint8_t UserNo = 1;
				uint8_t DevNo = 1;
				uint8_t RoomNo = 1;
			
					 printf("$DT1$%d|%d|%d|%d.%d|%d.%d#\r\n",
           UserNo, DevNo, RoomNo,
           dht11_data[2], dht11_data[3],
           dht11_data[0], dht11_data[1]);
} 
    

    HAL_Delay(2000);  // 每2秒采集一次数据
  }
  /* USER CODE END 3 */
}

dht11.h 

#ifndef __DHT11_H
#define __DHT11_H

#ifdef __cplusplus
extern "C" {
#endif

#include "main.h"

/* DHT11 引脚定义 */
#define DHT11_PORT    GPIOG
#define DHT11_PIN     GPIO_PIN_9

extern uint8_t dht11_data[5];
/* 函数声明 */
uint8_t DHT11_Init(void);
uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity);
void DHT11_GPIO_Init(void);
void DHT11_Print_Data(void);  // 新增:打印数据到串口的函数
void DWT_Delay_Init(void);
/* 返回值定义 */
#define DHT11_OK          0    // 读取成功
#define DHT11_ERROR       1    // 读取失败
#define DHT11_TIMEOUT     2    // 超时错误
#define DHT11_CHECK_ERROR 3    // 校验错误

#ifdef __cplusplus
}
#endif

#endif /* __DHT11_H */ 

dht11.c

/* 设置 GPIO 为输入模式 */
static void DHT11_Mode_IPU(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DHT11_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP; // 使用内部上拉
    HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

void DHT11_GPIO_Init(void)
{
    __HAL_RCC_GPIOG_CLK_ENABLE(); // 确保端口时钟打开

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DHT11_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

void dht11_start(void)
{
    DHT11_Mode_Out_OD();  // 添加这行,设置为开漏输出模式
    HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
    HAL_Delay(20);  // 拉低至少18ms

    HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
    delay_us(30);   // 拉高20 - 40μs

    DHT11_Mode_IPU(); // 添加这行,切换为输入上拉模式
		delay_us(5);
}

uint8_t dht11_wait_response(void)
{
    uint16_t timeout = 0;
 
    // 等待传感器拉低
    while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
    {
        delay_us(1);
        timeout++;
        if (timeout > 300)
            return 1;  // 超时
    }
 
    timeout = 0;
    // 等待传感器拉高
    while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET)
    {
        delay_us(1);
        timeout++;
        if (timeout > 300)
            return 1;  // 超时
    }
 
    return 0;
}
/* 设置 GPIO 为开漏输出模式 */
static void DHT11_Mode_Out_OD(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DHT11_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP; // 使用内部上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 
    HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
     HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); // 确保在输出模式下释放总线
}

uint8_t DHT11_Init(void)
{
    // 初始化 DWT 用于微秒延时
    // 确保 SystemCoreClock 已经被正确设置
		DHT11_GPIO_Init();
    if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {
        CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
        DWT->CYCCNT = 0;
        DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    }

    // 上电后等待1秒越过不稳定状态
    HAL_Delay(1000);

    return DHT11_OK;
}

/* 读取一个位 */
static uint8_t DHT11_ReadBit(void)
{
    uint16_t timeout = 0;
 
    // 等待高电平
    while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET)
    {
        delay_us(2);
        timeout++;
        if (timeout > 500)
            return 0;  // 超时
    }
 
    delay_us(60);  // 等待40μs
 
    if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
    {
        // 等待高电平结束
        while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET)
        {
            delay_us(2);
            timeout++;
            if (timeout > 500)
                return 0;  // 超时
        }
        return 1;
    }
    else
    {
        return 0;
    }
}


/* 读取一个字节 */
static uint8_t DHT11_ReadByte(void)
{

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

}


/* 读取温湿度数据 */
uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity)
{
    uint8_t i;
    uint8_t checksum;
 
		memset(dht11_data, 0, sizeof(dht11_data));
    dht11_start();
    if (dht11_wait_response())
        return 1;  // 响应超时
 
    for (i = 0; i < 5; i++)
    {
        dht11_data[i] = DHT11_ReadByte();
    }
 
    checksum = dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3];
    if (checksum != dht11_data[4])
        return 1;  // 校验和错误
 
    *temperature = dht11_data[2];
    *humidity = dht11_data[0];
    return 0;
}

void DWT_Delay_Init(void)
{
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}


/* 精确微秒延时函数 */
static void delay_us(uint32_t us)
{
    uint32_t start_cycles = DWT->CYCCNT;
    uint32_t required_cycles = us * (SystemCoreClock / 1000000);

    // 等待直到经过所需的周期数
    while ((DWT->CYCCNT - start_cycles) < required_cycles);
}

  DWT->CYCCNT 是 Cortex-M 的 数据观察器周期计数器(Data Watchpoint and Trace Cycle Counter),可用于实现高精度微秒延时。

数据发送

        数据发送是由串口2进行数据发送,可选择USB转TTL模块或HC-05蓝牙模块进行数据发送,接线时需要遵循交叉接线。

        蓝牙模块接线时需注意VCC接3.3V

        通电后发现蓝牙模块持续快速闪烁,打开手机或电脑蓝牙与其进行配对

运行结果 

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐