STM32实战:基于DHT11的智能温湿度监测与OLED显示

文章目录

    • 一、前言
      • [1.1 项目背景](#1.1 项目背景)
      • [1.2 DHT11传感器特点](#1.2 DHT11传感器特点)
      • [1.3 应用场景](#1.3 应用场景)
      • [1.4 技术栈](#1.4 技术栈)
      • [1.5 学习目标](#1.5 学习目标)
    • 二、系统架构设计
      • [2.1 整体架构](#2.1 整体架构)
      • [2.2 数据流程](#2.2 数据流程)
    • 三、硬件准备
      • [3.1 硬件清单](#3.1 硬件清单)
      • [3.2 引脚分配](#3.2 引脚分配)
      • [3.3 硬件连接图](#3.3 硬件连接图)
    • 四、DHT11驱动开发
      • [4.1 DHT11通信协议](#4.1 DHT11通信协议)
      • [4.2 DHT11驱动代码](#4.2 DHT11驱动代码)
    • 五、OLED显示驱动
      • [5.1 SSD1306驱动代码](#5.1 SSD1306驱动代码)
    • 六、主程序实现
      • [6.1 主程序代码](#6.1 主程序代码)
    • 七、常见问题
      • [7.1 DHT11读取失败](#7.1 DHT11读取失败)
      • [7.2 OLED显示异常](#7.2 OLED显示异常)
    • 八、扩展功能
      • [8.1 数据存储](#8.1 数据存储)
      • [8.2 无线传输](#8.2 无线传输)
    • 九、总结
      • [9.1 核心知识点](#9.1 核心知识点)
      • [9.2 扩展方向](#9.2 扩展方向)

一、前言

1.1 项目背景

温湿度监测是物联网应用中最基础也是最重要的功能之一。无论是智能家居、农业大棚、仓储管理还是工业生产,都需要实时监测环境温湿度。DHT11是一款性价比极高的数字温湿度传感器,配合OLED显示屏,可以快速构建一个完整的温湿度监测系统。

1.2 DHT11传感器特点

  • 成本低:单价仅几元钱
  • 使用简单:单总线数字接口
  • 响应快:约2秒采样周期
  • 稳定性好:已校准数字信号输出
  • 免外围元件:内置电阻,直接连接

1.3 应用场景

  • 智能家居:室内环境监测
  • 农业大棚:作物生长环境监控
  • 仓储物流:货物存储环境记录
  • 机房监控:服务器运行环境监测
  • 实验室:实验环境数据采集

1.4 技术栈

类别 技术/器件 说明
主控芯片 STM32F103C8T6 ARM Cortex-M3
传感器 DHT11 温湿度传感器
显示屏 SSD1306 0.96寸 128×64 OLED
通信协议 单总线/I2C DHT11/OLED
开发环境 Keil MDK-ARM 集成开发环境

1.5 学习目标

通过本教程,你将学会:

  • ✅ DHT11单总线通信协议
  • ✅ OLED I2C驱动开发
  • ✅ 中文显示实现
  • ✅ 数据存储与历史曲线
  • ✅ 报警阈值设置

二、系统架构设计

2.1 整体架构

单总线
I2C
GPIO
GPIO
USART
温湿度数据
显示数据
STM32F103主控
DHT11传感器
OLED显示屏
蜂鸣器
LED指示灯
串口调试

2.2 数据流程





系统启动
初始化外设
读取DHT11
数据有效?
更新显示
错误处理
检查报警
超限?
触发报警
正常状态
延时2秒

三、硬件准备

3.1 硬件清单

序号 名称 数量 参考价格 说明
1 STM32F103C8T6核心板 1 ¥12 主控芯片
2 DHT11温湿度模块 1 ¥6 传感器
3 SSD1306 OLED 0.96寸 1 ¥10 I2C接口
4 有源蜂鸣器 1 ¥2 报警提示
5 LED灯 2 ¥1 状态指示
6 电阻220Ω 2 ¥0.2 LED限流
7 杜邦线 若干 ¥3 连接线

3.2 引脚分配

功能 STM32引脚 连接对象 说明
DHT11_DATA PA0 DHT11 DATA 单总线数据
I2C_SCL PB6 OLED SCL I2C时钟
I2C_SDA PB7 OLED SDA I2C数据
BEEP PA1 蜂鸣器 报警输出
LED_RED PA2 红灯 高温指示
LED_BLUE PA3 蓝灯 高湿指示
USART_TX PA9 USB-TTL 调试输出
USART_RX PA10 USB-TTL 调试输入

3.3 硬件连接图

复制代码
STM32F103C8T6
┌─────────────────────────────────────┐
│                                     │
│  PA0 ────────────> DHT11 DATA       │
│                                     │
│  PB6 ────────────> OLED SCL         │
│  PB7 ────────────> OLED SDA         │
│                                     │
│  PA1 ────────────> 蜂鸣器           │
│  PA2 ────────────> LED_RED          │
│  PA3 ────────────> LED_BLUE         │
│                                     │
│  PA9 ────────────> USB-TTL RX       │
│  PA10 ───────────> USB-TTL TX       │
│                                     │
└─────────────────────────────────────┘

四、DHT11驱动开发

4.1 DHT11通信协议

DHT11使用单总线串行通信,一次完整的数据传输为40bit:

  • 湿度整数:8bit
  • 湿度小数:8bit(DHT11固定为0)
  • 温度整数:8bit
  • 温度小数:8bit(DHT11固定为0)
  • 校验和:8bit(前4字节之和)

时序要求:

  • 主机启动信号:拉低18ms,然后拉高20-40us
  • DHT11响应:拉低80us,然后拉高80us
  • 数据位0:50us低电平 + 26-28us高电平
  • 数据位1:50us低电平 + 70us高电平

4.2 DHT11驱动代码

📄 创建文件:Hardware/dht11.h

c 复制代码
#ifndef __DHT11_H
#define __DHT11_H

#include "sys.h"

// DHT11引脚定义
#define DHT11_PIN       GPIO_Pin_0
#define DHT11_PORT      GPIOA

// 控制宏
#define DHT11_HIGH()    GPIO_SetBits(DHT11_PORT, DHT11_PIN)
#define DHT11_LOW()     GPIO_ResetBits(DHT11_PORT, DHT11_PIN)
#define DHT11_READ()    GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)

// 数据结构
typedef struct {
    uint8_t humidity_int;      // 湿度整数部分
    uint8_t humidity_deci;     // 湿度小数部分
    uint8_t temperature_int;   // 温度整数部分
    uint8_t temperature_deci;  // 温度小数部分
    uint8_t checksum;          // 校验和
} DHT11_Data;

// 函数声明
void DHT11_Init(void);
uint8_t DHT11_ReadData(DHT11_Data *data);
float DHT11_GetTemperature(DHT11_Data *data);
float DHT11_GetHumidity(DHT11_Data *data);

#endif

📄 创建文件:Hardware/dht11.c

c 复制代码
#include "dht11.h"
#include "delay.h"

/**
 * DHT11初始化
 * 配置为开漏输出,需要外部上拉电阻
 */
void DHT11_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 配置为开漏输出
    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  // 开漏输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
    
    // 初始状态高电平
    DHT11_HIGH();
}

/**
 * 设置DHT11引脚为输出模式
 */
static void DHT11_SetOutput(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}

/**
 * 设置DHT11引脚为输入模式
 */
static void DHT11_SetInput(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}

/**
 * 读取一个bit
 * @return: 0或1
 */
static uint8_t DHT11_ReadBit(void)
{
    // 等待低电平结束
    while (DHT11_READ() == Bit_RESET);
    
    // 延时40us
    delay_us(40);
    
    // 读取电平
    if (DHT11_READ() == Bit_SET)
    {
        // 等待高电平结束
        while (DHT11_READ() == Bit_SET);
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * 读取一个字节
 */
static uint8_t DHT11_ReadByte(void)
{
    uint8_t byte = 0;
    
    for (int i = 0; i < 8; i++)
    {
        byte <<= 1;
        byte |= DHT11_ReadBit();
    }
    
    return byte;
}

/**
 * 读取DHT11数据
 * @param data: 数据存储结构
 * @return: 0-成功,1-失败
 */
uint8_t DHT11_ReadData(DHT11_Data *data)
{
    uint8_t buf[5];
    
    // 设置为输出模式
    DHT11_SetOutput();
    
    // 发送起始信号:拉低18ms
    DHT11_LOW();
    delay_ms(20);
    
    // 拉高20-40us
    DHT11_HIGH();
    delay_us(30);
    
    // 切换为输入模式
    DHT11_SetInput();
    
    // 等待DHT11响应(拉低80us)
    uint16_t timeout = 100;
    while (DHT11_READ() == Bit_SET)
    {
        if (--timeout == 0) return 1;
        delay_us(1);
    }
    
    timeout = 100;
    while (DHT11_READ() == Bit_RESET)
    {
        if (--timeout == 0) return 1;
        delay_us(1);
    }
    
    // 等待响应结束(拉高80us)
    timeout = 100;
    while (DHT11_READ() == Bit_SET)
    {
        if (--timeout == 0) return 1;
        delay_us(1);
    }
    
    // 读取40bit数据
    for (int i = 0; i < 5; i++)
    {
        buf[i] = DHT11_ReadByte();
    }
    
    // 切换回输出模式
    DHT11_SetOutput();
    DHT11_HIGH();
    
    // 校验数据
    if ((buf[0] + buf[1] + buf[2] + buf[3]) != buf[4])
    {
        return 1;  // 校验失败
    }
    
    // 保存数据
    data->humidity_int = buf[0];
    data->humidity_deci = buf[1];
    data->temperature_int = buf[2];
    data->temperature_deci = buf[3];
    data->checksum = buf[4];
    
    return 0;
}

/**
 * 获取温度值
 */
float DHT11_GetTemperature(DHT11_Data *data)
{
    float temp = data->temperature_int;
    temp += data->temperature_deci / 10.0f;
    
    // 处理负温度(最高位为1表示负温)
    if (data->temperature_int & 0x80)
    {
        temp = -temp;
    }
    
    return temp;
}

/**
 * 获取湿度值
 */
float DHT11_GetHumidity(DHT11_Data *data)
{
    float humi = data->humidity_int;
    humi += data->humidity_deci / 10.0f;
    return humi;
}

五、OLED显示驱动

5.1 SSD1306驱动代码

📄 创建文件:Hardware/oled.h

c 复制代码
#ifndef __OLED_H
#define __OLED_H

#include "sys.h"

// OLED参数
#define OLED_WIDTH  128
#define OLED_HEIGHT 64

// I2C地址
#define OLED_ADDR   0x78

// 函数声明
void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr);
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *str);
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len);
void OLED_ShowFloat(uint8_t x, uint8_t y, float num, uint8_t int_len, uint8_t dec_len);
void OLED_DrawBMP(uint8_t x, uint8_t y, uint8_t width, uint8_t height, const uint8_t *bmp);
void OLED_SetPos(uint8_t x, uint8_t y);

#endif

📄 创建文件:Hardware/oled.c

c 复制代码
#include "oled.h"
#include "i2c.h"
#include "oled_font.h"

extern I2C_HandleTypeDef hi2c1;

/**
 * 写命令
 */
static void OLED_WriteCommand(uint8_t cmd)
{
    uint8_t buf[2];
    buf[0] = 0x00;  // Control byte: Co=0, D/C#=0
    buf[1] = cmd;
    HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, buf, 2, HAL_MAX_DELAY);
}

/**
 * 写数据
 */
static void OLED_WriteData(uint8_t data)
{
    uint8_t buf[2];
    buf[0] = 0x40;  // Control byte: Co=0, D/C#=1
    buf[1] = data;
    HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, buf, 2, HAL_MAX_DELAY);
}

/**
 * OLED初始化
 */
void OLED_Init(void)
{
    delay_ms(100);  // 等待OLED上电稳定
    
    OLED_WriteCommand(0xAE);  // Display OFF
    OLED_WriteCommand(0x20);  // Set Memory Addressing Mode
    OLED_WriteCommand(0x10);  // 00:Horizontal, 01:Vertical, 10:Page
    OLED_WriteCommand(0xB0);  // Set Page Start Address
    OLED_WriteCommand(0xC8);  // Set COM Output Scan Direction
    OLED_WriteCommand(0x00);  // Set Low Column Address
    OLED_WriteCommand(0x10);  // Set High Column Address
    OLED_WriteCommand(0x40);  // Set Start Line Address
    OLED_WriteCommand(0x81);  // Set Contrast Control
    OLED_WriteCommand(0xFF);  // Max contrast
    OLED_WriteCommand(0xA1);  // Set Segment Re-map
    OLED_WriteCommand(0xA6);  // Normal display
    OLED_WriteCommand(0xA8);  // Set Multiplex Ratio
    OLED_WriteCommand(0x3F);  // 1/64 duty
    OLED_WriteCommand(0xA4);  // Output follows RAM content
    OLED_WriteCommand(0xD3);  // Set Display Offset
    OLED_WriteCommand(0x00);  // No offset
    OLED_WriteCommand(0xD5);  // Set Display Clock Divide
    OLED_WriteCommand(0xF0);  // Max frequency
    OLED_WriteCommand(0xD9);  // Set Pre-charge Period
    OLED_WriteCommand(0x22);  
    OLED_WriteCommand(0xDA);  // Set COM Pins Hardware Config
    OLED_WriteCommand(0x12);  // Alternative COM pin
    OLED_WriteCommand(0xDB);  // Set VCOMH Deselect Level
    OLED_WriteCommand(0x20);  // 0.77x Vcc
    OLED_WriteCommand(0x8D);  // Charge Pump Setting
    OLED_WriteCommand(0x14);  // Enable charge pump
    OLED_WriteCommand(0xAF);  // Display ON
    
    OLED_Clear();
}

/**
 * 设置显示位置
 */
void OLED_SetPos(uint8_t x, uint8_t y)
{
    OLED_WriteCommand(0xB0 + y);
    OLED_WriteCommand(((x & 0xF0) >> 4) | 0x10);
    OLED_WriteCommand(x & 0x0F);
}

/**
 * 清屏
 */
void OLED_Clear(void)
{
    for (uint8_t page = 0; page < 8; page++)
    {
        OLED_SetPos(0, page);
        for (uint8_t col = 0; col < 128; col++)
        {
            OLED_WriteData(0x00);
        }
    }
}

/**
 * 显示字符(8×16)
 */
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr)
{
    uint8_t c = chr - ' ';
    
    OLED_SetPos(x, y);
    for (uint8_t i = 0; i < 8; i++)
    {
        OLED_WriteData(ascii_8x16[c][i]);
    }
    
    OLED_SetPos(x, y + 1);
    for (uint8_t i = 0; i < 8; i++)
    {
        OLED_WriteData(ascii_8x16[c][i + 8]);
    }
}

/**
 * 显示字符串
 */
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *str)
{
    while (*str != '\0')
    {
        OLED_ShowChar(x, y, *str);
        x += 8;
        if (x > 120)
        {
            x = 0;
            y += 2;
        }
        str++;
    }
}

/**
 * 显示数字
 */
void OLED_ShowNum(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_ShowChar(x + 8 * t, y, ' ');
                continue;
            }
            else
            {
                enshow = 1;
            }
        }
        OLED_ShowChar(x + 8 * t, y, temp + '0');
    }
}

/**
 * 显示浮点数
 */
void OLED_ShowFloat(uint8_t x, uint8_t y, float num, uint8_t int_len, uint8_t dec_len)
{
    uint8_t i;
    uint32_t int_part, dec_part;
    
    // 处理负数
    if (num < 0)
    {
        OLED_ShowChar(x, y, '-');
        x += 8;
        num = -num;
    }
    
    // 分离整数和小数
    int_part = (uint32_t)num;
    dec_part = (uint32_t)((num - int_part) * pow(10, dec_len));
    
    // 显示整数部分
    OLED_ShowNum(x, y, int_part, int_len);
    x += int_len * 8;
    
    // 显示小数点
    OLED_ShowChar(x, y, '.');
    x += 8;
    
    // 显示小数部分
    OLED_ShowNum(x, y, dec_part, dec_len);
}

六、主程序实现

6.1 主程序代码

📄 创建文件:User/main.c

c 复制代码
/**
 * STM32 DHT11温湿度监测 + OLED显示
 * 主程序
 */

#include "stm32f10x.h"
#include "sys.h"
#include "dht11.h"
#include "oled.h"
#include "delay.h"
#include <stdio.h>
#include <string.h>

// 报警阈值
typedef struct {
    float temp_high;    // 温度上限
    float temp_low;     // 温度下限
    float humi_high;    // 湿度上限
    float humi_low;     // 湿度下限
} Alarm_Threshold;

// 全局变量
DHT11_Data dht11_data;
Alarm_Threshold alarm_threshold = {
    .temp_high = 30.0f,
    .temp_low = 10.0f,
    .humi_high = 80.0f,
    .humi_low = 30.0f
};

// 历史数据缓存(用于绘制曲线)
#define HISTORY_SIZE  64
float temp_history[HISTORY_SIZE];
float humi_history[HISTORY_SIZE];
uint8_t history_index = 0;

// 函数声明
void System_Init(void);
void Display_Update(void);
void Alarm_Check(void);
void History_Update(float temp, float humi);
void Draw_Curve(void);

int main(void)
{
    System_Init();
    
    // 显示启动画面
    OLED_ShowString(20, 2, (uint8_t *)"DHT11 Monitor");
    OLED_ShowString(30, 4, (uint8_t *)"Starting...");
    delay_ms(2000);
    OLED_Clear();
    
    printf("\r\n================================\r\n");
    printf("  DHT11 Temperature & Humidity\r\n");
    printf("================================\r\n");
    
    while (1)
    {
        // 读取DHT11数据
        if (DHT11_ReadData(&dht11_data) == 0)
        {
            float temperature = DHT11_GetTemperature(&dht11_data);
            float humidity = DHT11_GetHumidity(&dht11_data);
            
            // 更新历史数据
            History_Update(temperature, humidity);
            
            // 更新显示
            Display_Update();
            
            // 检查报警
            Alarm_Check();
            
            // 串口输出
            printf("Temp: %.1f C, Humi: %.1f %%\r\n", temperature, humidity);
        }
        else
        {
            printf("DHT11 Read Error!\r\n");
            OLED_ShowString(0, 6, (uint8_t *)"Sensor Error!");
        }
        
        // DHT11最小采样周期为2秒
        delay_ms(2000);
    }
}

/**
 * 系统初始化
 */
void System_Init(void)
{
    // 时钟配置
    SystemClock_Config();
    
    // 延时初始化
    delay_init();
    
    // 串口初始化
    USART1_Init(115200);
    
    // I2C初始化
    I2C1_Init();
    
    // OLED初始化
    OLED_Init();
    
    // DHT11初始化
    DHT11_Init();
    
    // GPIO初始化(蜂鸣器、LED)
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 初始状态
    GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3);
}

/**
 * 更新OLED显示
 */
void Display_Update(void)
{
    float temperature = DHT11_GetTemperature(&dht11_data);
    float humidity = DHT11_GetHumidity(&dht11_data);
    
    // 显示标题
    OLED_ShowString(0, 0, (uint8_t *)"Temp:");
    OLED_ShowString(0, 2, (uint8_t *)"Humi:");
    
    // 显示温度
    OLED_ShowFloat(40, 0, temperature, 2, 1);
    OLED_ShowString(90, 0, (uint8_t *)"C");
    
    // 显示湿度
    OLED_ShowFloat(40, 2, humidity, 2, 1);
    OLED_ShowString(90, 2, (uint8_t *)"%");
    
    // 绘制历史曲线
    Draw_Curve();
}

/**
 * 报警检查
 */
void Alarm_Check(void)
{
    float temperature = DHT11_GetTemperature(&dht11_data);
    float humidity = DHT11_GetHumidity(&dht11_data);
    
    uint8_t alarm = 0;
    
    // 温度报警
    if (temperature > alarm_threshold.temp_high)
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_2);  // 红灯亮
        alarm = 1;
    }
    else if (temperature < alarm_threshold.temp_low)
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_2);  // 红灯亮
        alarm = 1;
    }
    else
    {
        GPIO_ResetBits(GPIOA, GPIO_Pin_2);  // 红灯灭
    }
    
    // 湿度报警
    if (humidity > alarm_threshold.humi_high)
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_3);  // 蓝灯亮
        alarm = 1;
    }
    else if (humidity < alarm_threshold.humi_low)
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_3);  // 蓝灯亮
        alarm = 1;
    }
    else
    {
        GPIO_ResetBits(GPIOA, GPIO_Pin_3);  // 蓝灯灭
    }
    
    // 蜂鸣器报警
    if (alarm)
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_1);
        delay_ms(200);
        GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    }
}

/**
 * 更新历史数据
 */
void History_Update(float temp, float humi)
{
    temp_history[history_index] = temp;
    humi_history[history_index] = humi;
    
    history_index++;
    if (history_index >= HISTORY_SIZE)
    {
        history_index = 0;
    }
}

/**
 * 绘制历史曲线
 */
void Draw_Curve(void)
{
    // 简化的曲线显示,实际应该绘制点阵图
    // 这里仅显示趋势指示
    uint8_t x = 0;
    uint8_t y = 6;
    
    OLED_SetPos(x, y);
    for (int i = 0; i < 128; i++)
    {
        // 根据历史数据计算显示点
        uint8_t data = 0;
        // ... 曲线绘制算法
        OLED_WriteData(data);
    }
}

七、常见问题

7.1 DHT11读取失败

原因:

  • 时序不精确
  • 上拉电阻缺失
  • 采样频率过高

解决:

  • 检查延时函数精度
  • 添加4.7K上拉电阻
  • 确保采样间隔≥2秒

7.2 OLED显示异常

原因:

  • I2C地址错误
  • 初始化序列错误
  • 电源不稳定

解决:

  • 确认地址是0x78或0x7A
  • 检查初始化命令
  • 添加电源滤波电容

八、扩展功能

8.1 数据存储

使用STM32内部Flash存储历史数据:

c 复制代码
void Save_Data_To_Flash(float temp, float humi)
{
    // Flash写入实现
    // ...
}

8.2 无线传输

添加ESP8266模块实现WiFi上传:

c 复制代码
void Upload_To_Cloud(float temp, float humi)
{
    // MQTT上传实现
    // ...
}

九、总结

9.1 核心知识点

  • DHT11单总线通信协议
  • I2C OLED驱动开发
  • 温湿度数据采集
  • 报警系统设计

9.2 扩展方向

  • 使用DHT22提高精度
  • 添加SD卡数据记录
  • 实现WiFi远程监控
  • 开发手机APP

如果本教程对你有帮助,欢迎点赞、收藏、关注!

相关推荐
qq_411262422 小时前
ESP32-C3 内置 USB Serial/JTAG 在 Windows下,不同板子不同端口
stm32·单片机·嵌入式硬件
最好有梦想~3 小时前
嵌入式Linux Lua使用ZeroBrane远程调试
linux·嵌入式硬件·lua
aini_lovee3 小时前
基于STM32的光电感烟火灾报警器设计
stm32·单片机·嵌入式硬件
拒朽3 小时前
51单片机学习(六)模块化编程和LCD调试工具
嵌入式硬件·学习·51单片机
somi73 小时前
ARM-09-I.MX6U-I2C
单片机·嵌入式硬件·i2c·自用
senijusene3 小时前
IMX6ULL 时钟系统配置与定时器 (EPIT/GPT)
stm32·单片机·fpga开发
会编程的小孩3 小时前
stm32f103c8t6工程模板 配置成stm32f407zgt6工程模板
stm32·单片机·嵌入式硬件
somi74 小时前
ARM-08-I.MX6U UART 串口
arm开发·单片机·嵌入式硬件·自用
mcupro4 小时前
TQTT_KU5P开发板教程---在Windows下XCKU5P+AD9361测试
嵌入式硬件·fpga开发·模块测试