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

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

相关推荐
UrSpecial2 小时前
GPIO 是什么?
单片机·嵌入式硬件
剑指offer.4 小时前
ARM裸机开发-SPI
arm开发·嵌入式硬件·嵌入式·arm
修船大队长5 小时前
配置接受报文每个报文对应一个mailbox配置流程记录
网络·单片机·mcu
搁浅小泽6 小时前
二极管选型技术规范
单片机·嵌入式硬件·汽车
搁浅小泽7 小时前
电感选型技术规范
单片机·嵌入式硬件·汽车
..Dauntless..7 小时前
【stm32】串口——在MCU内部的工作过程
stm32·单片机·嵌入式硬件
lzqrzpt8 小时前
临沂LED驱动电源工程选型标准与工艺对比解析
python·单片机·嵌入式硬件·物联网
小黄蚁8 小时前
使用LVGL模拟示波器创建正弦函数波形
单片机·学习
hahaha60168 小时前
黑体轨迹和色温--光源白点
人工智能·嵌入式硬件·算法·计算机视觉
Code_Solitude10 小时前
开发板点灯实验源码
stm32·单片机·嵌入式硬件