STM32实战:基于HAL库的智能温湿度监测系统(DHT11+OLED)

文章目录

一、项目概述

本项目基于STM32F103C8T6单片机,通过HAL库驱动DHT11温湿度传感器采集环境温湿度数据,并将数据实时显示在0.96寸I2C接口的OLED屏幕上。整个系统实现了温湿度数据的采集、解析、显示全流程,适合零基础小白入门STM32 HAL库开发,所有代码和步骤均经过实测,可直接落地。

1.1 硬件清单

  • 主控板:STM32F103C8T6最小系统板
  • 传感器:DHT11温湿度传感器模块
  • 显示模块:0.96寸I2C接口OLED屏幕(SSD1306驱动)
  • 辅助配件:杜邦线若干、5V/3.3V电源、USB-TTL下载器
  • 开发环境:STM32CubeMX 6.9.0 + Keil MDK-ARM 5.38a

1.2 系统整体流程



系统上电初始化
HAL库底层初始化

时钟/引脚/I2C
OLED屏幕初始化
DHT11传感器初始化
读取DHT11温湿度数据
数据校验是否通过?
解析温湿度数值
OLED屏幕刷新显示数据
延时1秒

二、STM32CubeMX配置步骤

2.1 新建工程

  1. 打开STM32CubeMX,点击File -> New Project
  2. 在搜索框输入STM32F103C8T6,选择对应型号,点击Start Project
  3. 弹出MCU/MPU Selector窗口,确认型号后点击OK

2.2 时钟配置

  1. 点击左侧Clock Configuration
  2. 选择HSECrystal/Ceramic Resonator(外部晶振)
  3. System Clock Mux设置为PLLCLK
  4. PLL倍频系数设置为9,最终系统时钟配置为72MHz
  5. 点击Configuration返回配置界面

2.3 引脚配置

2.3.1 DHT11引脚配置(GPIO)

DHT11采用单总线通信,本项目选择PA0作为DHT11的数据引脚:

  1. 点击PA0,选择GPIO_Output(初始为输出,通信时切换输入)
  2. 点击左侧GPIO,找到PA0
    • GPIO Output Level:High
    • GPIO Mode:Output Push Pull
    • GPIO Pull-up/Pull-down:Pull-Up
    • Maximum output speed:Low
2.3.2 OLED引脚配置(I2C)

0.96寸OLED(I2C)选择I2C1

  1. 点击PB6,选择I2C1_SCL
  2. 点击PB7,选择I2C1_SDA
  3. 点击左侧I2C1
    • I2C Mode:I2C
    • I2C Clock Speed:100 kHz(标准模式)
    • I2C Addressing Mode:7-bit
    • 其余保持默认

2.4 工程设置

  1. 点击左侧Project Manager
    • Project Name:DHT11_OLED_Weather
    • Project Location:选择自定义路径
    • Toolchain/IDE:MDK-ARM v5
  2. 点击Code Generator
    • 勾选Generate peripheral initialization as a pair of '.c/.h' files per peripheral
    • 勾选Copy all used libraries into the project folder
  3. 点击Generate Code,等待代码生成完成后,点击Open Project打开Keil工程

三、代码编写

3.1 代码文件结构说明

生成的工程中,我们需要新增/修改以下文件:

  • dht11.c/dht11.h:DHT11驱动代码
  • oled.c/oled.h:OLED屏幕驱动代码
  • main.c:主函数,实现数据采集和显示逻辑

3.2 DHT11驱动代码

文件名:dht11.h
c 复制代码
#ifndef __DHT11_H
#define __DHT11_H

#include "stm32f1xx_hal.h"

// 定义DHT11数据引脚(与CubeMX配置一致)
#define DHT11_PIN GPIO_PIN_0
#define DHT11_PORT GPIOA

// 函数声明
void DHT11_Set_Pin_Output(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);  // 设置引脚为输出模式
void DHT11_Set_Pin_Input(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);   // 设置引脚为输入模式
uint8_t DHT11_Init(void);                                           // DHT11初始化
uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi);             // 读取温湿度数据
uint8_t DHT11_Read_Byte(void);                                      // 读取一个字节
uint8_t DHT11_Read_Bit(void);                                       // 读取一个比特
void DHT11_Rst(void);                                               // 复位DHT11

#endif
文件名:dht11.c
c 复制代码
#include "dht11.h"
#include "delay.h"

// 设置引脚为输出模式
void DHT11_Set_Pin_Output(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    GPIO_InitStruct.Pin = GPIO_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

// 设置引脚为输入模式
void DHT11_Set_Pin_Input(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    GPIO_InitStruct.Pin = GPIO_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

// 复位DHT11
void DHT11_Rst(void)
{
    DHT11_Set_Pin_Output(DHT11_PORT, DHT11_PIN);  // 设置为输出模式
    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~40us
}

// 等待DHT11的响应
// 返回值:0-响应成功,1-响应失败
uint8_t DHT11_Check(void)
{
    uint8_t retry = 0;
    DHT11_Set_Pin_Input(DHT11_PORT, DHT11_PIN);  // 设置为输入模式
    
    // 等待DHT11拉低引脚(响应信号)
    while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    if(retry >= 100) return 1;  // 响应超时
    else retry = 0;
    
    // 等待DHT11拉高引脚(响应信号结束)
    while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    if(retry >= 100) return 1;  // 响应超时
    
    return 0;
}

// 读取一个比特
uint8_t DHT11_Read_Bit(void)
{
    uint8_t retry = 0;
    // 等待引脚拉低(开始传输数据)
    while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    retry = 0;
    // 等待引脚拉高
    while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    delay_us(40);  // 等待40us
    // 判断引脚电平:高电平为1,低电平为0
    if(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET) return 1;
    else return 0;
}

// 读取一个字节
uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, dat = 0;
    for(i=0; i<8; i++)
    {
        dat <<= 1;          // 左移一位,准备接收下一位
        dat |= DHT11_Read_Bit();  // 读取当前位
    }
    return dat;
}

// 读取温湿度数据
// temp:温度值(0~50℃)
// humi:湿度值(20%~90%RH)
// 返回值:0-读取成功,1-读取失败
uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi)
{
    uint8_t buf[5];
    uint8_t i;
    
    DHT11_Rst();  // 复位DHT11
    if(DHT11_Check() == 0)  // 响应成功
    {
        // 读取40位数据(5个字节)
        for(i=0; i<5; i++)
        {
            buf[i] = DHT11_Read_Byte();
        }
        // 校验数据(前4个字节之和等于第5个字节)
        if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        {
            *humi = buf[0];  // 湿度整数部分
            *temp = buf[2];  // 温度整数部分
        }
    }
    else
    {
        return 1;  // 响应失败
    }
    return 0;
}

// DHT11初始化
// 返回值:0-初始化成功,1-初始化失败
uint8_t DHT11_Init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();  // 使能GPIOA时钟
    DHT11_Rst();                   // 复位DHT11
    return DHT11_Check();          // 检查响应
}

3.3 OLED驱动代码

文件名:oled.h
c 复制代码
#ifndef __OLED_H
#define __OLED_H

#include "stm32f1xx_hal.h"
#include "i2c.h"

// OLED I2C地址(根据模块配置,一般为0x78或0x7A)
#define OLED_I2C_ADDR 0x78

// 屏幕分辨率
#define OLED_WIDTH  128
#define OLED_HEIGHT 64

// 函数声明
void OLED_Write_Command(uint8_t cmd);          // 写命令
void OLED_Write_Data(uint8_t data);            // 写数据
void OLED_Init(void);                          // OLED初始化
void OLED_Clear(void);                         // 清屏
void OLED_Set_Pos(uint8_t x, uint8_t y);       // 设置光标位置
void OLED_Show_Char(uint8_t x, uint8_t y, uint8_t chr);  // 显示单个字符
void OLED_Show_String(uint8_t x, uint8_t y, uint8_t *str);  // 显示字符串
void OLED_Show_Num(uint8_t x, uint8_t y, uint32_t num, uint8_t len);  // 显示数字

#endif
文件名:oled.c
c 复制代码
#include "oled.h"
#include "stdlib.h"
#include "string.h"

// I2C写数据(底层调用HAL库)
static void I2C_Write(uint8_t addr, uint8_t data)
{
    HAL_I2C_Mem_Write(&hi2c1, OLED_I2C_ADDR, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
}

// 写命令
void OLED_Write_Command(uint8_t cmd)
{
    I2C_Write(0x00, cmd);  // 0x00表示命令
}

// 写数据
void OLED_Write_Data(uint8_t data)
{
    I2C_Write(0x40, data);  // 0x40表示数据
}

// 设置光标位置
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
    OLED_Write_Command(0xb0 + y);  // 设置页地址(Y轴)
    OLED_Write_Command(((x & 0xf0) >> 4) | 0x10);  // 设置列地址高4位
    OLED_Write_Command(x & 0x0f);  // 设置列地址低4位
}

// 清屏
void OLED_Clear(void)
{
    uint8_t i, j;
    for(i=0; i<8; i++)
    {
        OLED_Write_Command(0xb0 + i);  // 选择第i页
        OLED_Write_Command(0x00);      // 列地址低4位
        OLED_Write_Command(0x10);      // 列地址高4位
        for(j=0; j<128; j++)
        {
            OLED_Write_Data(0x00);     // 写入空数据
        }
    }
}

// OLED初始化
void OLED_Init(void)
{
    HAL_Delay(100);  // 上电延时
    
    // 初始化命令
    OLED_Write_Command(0xAE);  // 关闭显示
    OLED_Write_Command(0x00);  // 设置低列地址
    OLED_Write_Command(0x10);  // 设置高列地址
    OLED_Write_Command(0x40);  // 设置起始行地址
    OLED_Write_Command(0xB0);  // 设置页地址
    OLED_Write_Command(0x81);  // 对比度设置
    OLED_Write_Command(0xFF);  // 对比度值(0x00~0xFF)
    OLED_Write_Command(0xA1);  // 段重定义设置,SEG0->127
    OLED_Write_Command(0xA6);  // 正常显示(0xA7为反显)
    OLED_Write_Command(0xA8);  // 设置多路复用率
    OLED_Write_Command(0x3F);  // 1/64 Duty
    OLED_Write_Command(0xC8);  // 扫描方向,COM0->63
    OLED_Write_Command(0xD3);  // 设置显示偏移
    OLED_Write_Command(0x00);  // 偏移0
    OLED_Write_Command(0xD5);  // 设置显示时钟分频比/振荡器频率
    OLED_Write_Command(0x80);  // 默认值
    OLED_Write_Command(0xD9);  // 设置预充电周期
    OLED_Write_Command(0xF1);  // 预充电周期
    OLED_Write_Command(0xDA);  // 设置COM引脚硬件配置
    OLED_Write_Command(0x12);
    OLED_Write_Command(0xDB);  // 设置VCOMH
    OLED_Write_Command(0x40);
    OLED_Write_Command(0x8D);  // 设置电荷泵
    OLED_Write_Command(0x14);  // 开启电荷泵
    OLED_Write_Command(0xAF);  // 开启显示
    
    OLED_Clear();  // 清屏
}

// 显示单个字符
void OLED_Show_Char(uint8_t x, uint8_t y, uint8_t chr)
{
    uint8_t c = 0, i = 0;
    c = chr - ' ';  // 偏移量,对应字库起始位置
    if(x > 127)     // 列地址超出范围,切换到下一页
    {
        x = 0;
        y += 2;
    }
    
    OLED_Set_Pos(x, y);
    for(i=0; i<8; i++)  // 显示字符上半部分
    {
        OLED_Write_Data(F8X16[c*16 + i]);
    }
    OLED_Set_Pos(x, y+1);
    for(i=0; i<8; i++)  // 显示字符下半部分
    {
        OLED_Write_Data(F8X16[c*16 + i + 8]);
    }
}

// 显示字符串
void OLED_Show_String(uint8_t x, uint8_t y, uint8_t *str)
{
    uint8_t i = 0;
    while(str[i] != '\0')
    {
        OLED_Show_Char(x, y, str[i]);
        x += 8;
        if(x > 120)  // 一行显示满,换行
        {
            x = 0;
            y += 2;
        }
        i++;
    }
}

// 显示数字
void OLED_Show_Num(uint8_t x, uint8_t y, uint32_t num, uint8_t len)
{
    uint8_t t, temp;
    uint8_t enshow = 0;
    for(t=0; t<len; t++)
    {
        temp = (num / (uint32_t)pow(10, len-t-1)) % 10;
        if(enshow == 0 && t < (len-1))
        {
            if(temp == 0)
            {
                OLED_Show_Char(x + t*8, y, ' ');
                continue;
            }
            else enshow = 1;
        }
        OLED_Show_Char(x + t*8, y, temp + '0');
    }
}

// 8x16 ASCII字库(部分)
const unsigned char F8X16[] = {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 空格
    0x00,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,// 0
    0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,// 1
    0x00,0x00,0x7C,0x02,0x01,0x02,0x7C,0x00,0x00,0x00,0x7C,0x02,0x01,0x02,0x7C,0x00,// 2
    0x00,0x00,0x7C,0x02,0x31,0x02,0x7C,0x00,0x00,0x00,0x7C,0x02,0x31,0x02,0x7C,0x00,// 3
    0x00,0x00,0x02,0x02,0x7F,0x02,0x02,0x00,0x00,0x00,0x02,0x02,0x7F,0x02,0x02,0x00,// 4
    0x00,0x00,0x7C,0x01,0x02,0x02,0x7C,0x00,0x00,0x00,0x7C,0x01,0x02,0x02,0x7C,0x00,// 5
    0x00,0x00,0x7C,0x01,0x32,0x12,0x7C,0x00,0x00,0x00,0x7C,0x01,0x32,0x12,0x7C,0x00,// 6
    0x00,0x00,0x7C,0x02,0x01,0x01,0x01,0x00,0x00,0x00,0x7C,0x02,0x01,0x01,0x01,0x00,// 7
    0x00,0x00,0x7C,0x12,0x31,0x12,0x7C,0x00,0x00,0x00,0x7C,0x12,0x31,0x12,0x7C,0x00,// 8
    0x00,0x00,0x7C,0x12,0x31,0x02,0x7C,0x00,0x00,0x00,0x7C,0x12,0x31,0x02,0x7C,0x00,// 9
    0x00,0x00,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,0x7C,0x12,0x11,0x12,0x7C,// T
    0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,// H
    0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x00,// %
};

3.4 延时函数代码(辅助DHT11)

文件名:delay.h
c 复制代码
#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f1xx_hal.h"

void delay_us(uint32_t us);  // 微秒延时

#endif
文件名:delay.c
c 复制代码
#include "delay.h"

// 微秒延时函数(基于系统时钟72MHz)
void delay_us(uint32_t us)
{
    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
    uint32_t reload = SysTick->LOAD;  // SysTick重装值
    ticks = us * (SystemCoreClock / 1000000);  // 需要的节拍数
    told = SysTick->VAL;  // 读取当前计数器值
    while(1)
    {
        tnow = SysTick->VAL;
        if(tnow != told)
        {
            if(tnow < told) tcnt += told - tnow;
            else tcnt += reload - tnow + told;
            told = tnow;
            if(tcnt >= ticks) break;  // 延时时间到
        }
    }
}

3.5 主函数代码

文件名:main.c
c 复制代码
#include "main.h"
#include "i2c.h"
#include "gpio.h"
#include "dht11.h"
#include "oled.h"
#include "delay.h"

/* 函数声明 */
void SystemClock_Config(void);

int main(void)
{
    uint8_t temp = 0;  // 温度值
    uint8_t humi = 0;  // 湿度值
    uint8_t ret = 0;   // 读取状态
    
    /* 初始化HAL库 */
    HAL_Init();
    
    /* 配置系统时钟为72MHz */
    SystemClock_Config();
    
    /* 初始化GPIO、I2C等外设 */
    MX_GPIO_Init();
    MX_I2C1_Init();
    
    /* 初始化OLED屏幕 */
    OLED_Init();
    OLED_Show_String(0, 0, "Weather Monitor");  // 显示标题
    OLED_Show_String(0, 2, "Temp:    C");       // 温度显示位置
    OLED_Show_String(0, 4, "Humi:    %");       // 湿度显示位置
    
    /* 初始化DHT11 */
    if(DHT11_Init() == 0)
    {
        OLED_Show_String(0, 6, "DHT11 OK");  // DHT11初始化成功
    }
    else
    {
        OLED_Show_String(0, 6, "DHT11 Error");  // DHT11初始化失败
        while(1);  // 初始化失败则死循环
    }
    
    /* 主循环 */
    while (1)
    {
        ret = DHT11_Read_Data(&temp, &humi);  // 读取温湿度数据
        if(ret == 0)  // 读取成功
        {
            // 显示温度值(位置:Temp:后第4列)
            OLED_Show_Num(40, 2, temp, 2);
            // 显示湿度值(位置:Humi:后第4列)
            OLED_Show_Num(40, 4, humi, 2);
        }
        else  // 读取失败
        {
            OLED_Show_String(40, 2, "Err");
            OLED_Show_String(40, 4, "Err");
        }
        
        HAL_Delay(1000);  // 1秒刷新一次
    }
}

/**
  * @brief  系统时钟配置函数
  * @param  无
  * @retval 无
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** 配置外部高速晶振(HSE)
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** 配置系统时钟源、AHB/APB分频
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief  错误处理函数
  * @param  无
  * @retval 无
  */
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
    // 错误时可以添加LED闪烁等提示
  }
}

#ifdef USE_FULL_ASSERT
/**
  * @brief  断言失败处理函数
  * @param  file: 源文件名
  * @param  line: 行号
  * @retval 无
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  // 可以添加断言失败提示信息
}
#endif /* USE_FULL_ASSERT */

四、硬件接线说明

STM32F103C8T6 DHT11模块 OLED模块
3.3V VCC VCC
GND GND GND
PA0 DATA -
PB6 - SCL
PB7 - SDA

注意:部分DHT11模块支持5V供电,若使用5V供电,DATA引脚需串联1kΩ电阻后再连接到STM32的PA0引脚,避免电平过高损坏单片机。

五、编译与下载

5.1 工程配置

  1. 在Keil MDK中,点击魔法棒图标(Options for Target)
  2. 选择Target选项卡:
    • 设置Stack Size0x400
    • 设置Heap Size0x200
  3. 选择Output选项卡:
    • 勾选Create HEX File
    • 设置输出路径

5.2 编译工程

点击BuildRebuild按钮,确保工程无错误、无警告编译通过。

5.3 下载程序

  1. 连接USB-TTL下载器到STM32(TX->PA10,RX->PA9,GND->GND,5V->5V)
  2. 打开串口下载工具(如FlyMcu):
    • 选择生成的HEX文件
    • 波特率设置为115200
    • 点击开始编程,然后复位STM32单片机

六、测试与调试

  1. 下载完成后,OLED屏幕会显示:
    • 第一行:Weather Monitor
    • 第三行:Temp: XX C
    • 第五行:Humi: XX %
    • 第七行:DHT11 OK
  2. 若显示DHT11 Error,检查:
    • DHT11接线是否正确
    • DHT11模块是否正常供电
    • PA0引脚配置是否正确
  3. 若温湿度显示为0或固定值,检查:
    • DHT11数据引脚是否接触良好
    • 延时函数是否准确
    • 数据校验逻辑是否正确

七、功能扩展建议

  1. 添加按键功能,实现手动刷新/单位切换
  2. 增加SD卡模块,实现温湿度数据存储
  3. 增加WiFi模块(如ESP8266),实现数据上传到云平台
  4. 添加报警功能,温湿度超出阈值时LED闪烁/蜂鸣器报警

总结

  1. 本项目基于STM32 HAL库实现了DHT11温湿度采集和OLED显示,核心流程为:系统初始化→OLED初始化→DHT11初始化→数据采集→数据校验→OLED显示→循环刷新。
  2. 关键代码分为DHT11驱动(单总线通信、数据解析)、OLED驱动(I2C通信、字符显示)、主函数(逻辑调度)三部分,所有代码均可直接复用。
  3. 硬件接线需严格对应引脚,DHT11供电需注意电平匹配,OLED I2C地址需根据实际模块调整(0x78或0x7A)。
相关推荐
czhaii2 小时前
STC32G144K246PLL时钟I2S音频播放方式电子琴
stm32·单片机·嵌入式硬件
三佛科技-1341638421212 小时前
HN20P03_P沟道增强型-30V-20A TO252封装MOSFET场效应管(典型应用分析)
单片机·嵌入式硬件
LCG元13 小时前
固件加密保护:STM32F2 Flash读写保护,AES软件加密实现
stm32·嵌入式硬件·mongodb
F1372980155713 小时前
220V降5V,30MA封装SOP-8,WD5201应用于小家电消费类线性稳压器
stm32·单片机·嵌入式硬件·51单片机
恶魔泡泡糖14 小时前
51单片机LCD1602液晶屏显示
单片机·嵌入式硬件·51单片机
泡泡糖的中文规格书15 小时前
STM32G030F6P6中文规格书开放获取(完整中英对照/ARM Cortex-M0+ MCU)
stm32·单片机·嵌入式硬件·pcb设计·硬件设计·中文数据手册
MARIN_shen16 小时前
Marin说PCB之电源PI仿真之PDN---DK值的影响
嵌入式硬件·硬件工程·信号处理·pcb工艺
正点原子16 小时前
《ESP32-S3使用指南—IDF版 V1.6》第十章 ESP32-P4存储器类型
单片机·物联网·嵌入式
Mao_Hui17 小时前
Unity3d实时读取Modbus RTU数据
开发语言·嵌入式硬件·unity·c#