从0到1:基于STM32与FreeRTOS的智能家居中控系统设计实录

一、项目背景:让中控"有大脑"

过去的家居控制器多为单任务设计------一个循环控制灯、温湿度传感器、WiFi模块,结构简单但不灵活。

我希望构建一个多任务、可扩展、具实时响应能力的中控系统。

系统目标:

  • 以 STM32F407 为核心,运行 FreeRTOS 实时操作系统;

  • 管理温湿度、光照、灯光控制模块;

  • 支持 ESP8266 WiFi 模块远程通信;

  • 具备低功耗与容错机制;

  • 提供 OLED 状态显示界面。

✳️ 应用场景:家庭环境监测 + 灯光控制 + 无线云端通信


二、硬件设计与模块选型

1️⃣ 硬件模块清单

模块 型号 接口 功能
主控芯片 STM32F407VGT6 ARM Cortex-M4 系统主控
温湿度传感器 DHT11 GPIO 环境检测
WiFi 模块 ESP8266 UART 无线通信
OLED 显示 SSD1306 I2C 信息显示
蜂鸣器与按键 自制板 GPIO 用户交互
电源 AMS1117-3.3V - 稳压供电

2️⃣ 硬件连接结构(简化图)

复制代码
        ┌──────────────┐
        │   STM32F407  │
        │              │
        │ I2C → OLED   │
        │ UART → ESP8266 │
        │ GPIO → DHT11 │
        │ GPIO → LED/Buzzer │
        └──────────────┘

电源统一采用 5V 输入,经 AMS1117 稳压至 3.3V,主控与 WiFi 共用。


三、软件架构与任务划分

系统运行 FreeRTOS v10.4,采用任务 + 队列通信模式。核心结构如下:

复制代码
+-----------------------+
|   FreeRTOS Kernel     |
|-----------------------|
| WifiTask (3)          | 高优先级,网络通信任务
| SensorTask (2)        | 中优先级,采集DHT11数据
| DisplayTask (1)       | 低优先级,OLED刷新
| ControlTask (2)       | 按键与输出控制
| PowerTask (0)         | 低功耗管理
+-----------------------+

📁 模块划分

/Core/Src

├── main.c

├── freertos.c

├── task_sensor.c

├── task_wifi.c

├── task_display.c

├── driver_dht11.c

├── driver_oled.c

└── utils_log.c


四、主要任务与代码实现

1️⃣ 传感器任务(SensorTask)

负责定时采集温湿度数据并发送到队列中。

复制代码
#include "dht11.h"
#include "cmsis_os.h"

extern QueueHandle_t xSensorQueue;

void SensorTask(void *argument) {
    SensorData_t data;
    float t = 0, h = 0;
    for (;;) {
        if (DHT11_ReadData(&t, &h) == HAL_OK) {
            data.temperature = t;
            data.humidity = h;
            xQueueSend(xSensorQueue, &data, 0);
        }
        vTaskDelay(pdMS_TO_TICKS(2000)); // 每2秒更新一次
    }
}

驱动层(driver_dht11.c):

复制代码
uint8_t DHT11_ReadData(float *temp, float *humi) {
    uint8_t buf[5] = {0};
    // 发送起始信号
    DHT11_Start();
    if (DHT11_CheckResponse() == HAL_OK) {
        for (int i = 0; i < 5; i++) buf[i] = DHT11_ReadByte();
        *humi = buf[0];
        *temp = buf[2];
        return HAL_OK;
    }
    return HAL_ERROR;
}

2️⃣ WiFi任务(WifiTask)

通过 UART 与 ESP8266 通信,实现数据上报与指令接收。

复制代码
#include "esp8266.h"

void WifiTask(void *argument) {
    char payload[64];
    SensorData_t rxData;

    ESP8266_Init();
    ESP8266_ConnectWiFi("MyHome", "12345678");

    for (;;) {
        if (xQueueReceive(xSensorQueue, &rxData, portMAX_DELAY)) {
            sprintf(payload, "{\"temp\":%.1f, \"humi\":%.1f}", 
                    rxData.temperature, rxData.humidity);
            ESP8266_SendData(payload);
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

WiFi驱动简化(esp8266.c):

复制代码
void ESP8266_SendData(char *data) {
    char cmd[128];
    sprintf(cmd, "AT+CIPSEND=%d\r\n", strlen(data));
    HAL_UART_Transmit(&huart1, (uint8_t *)cmd, strlen(cmd), 100);
    HAL_UART_Transmit(&huart1, (uint8_t *)data, strlen(data), 100);
}

3️⃣ 显示任务(DisplayTask)

复制代码
#include "oled.h"
void DisplayTask(void *argument) {
    SensorData_t sensor;
    char line1[16], line2[16];
    OLED_Init();

    for (;;) {
        if (xQueuePeek(xSensorQueue, &sensor, portMAX_DELAY)) {
            sprintf(line1, "Temp: %.1fC", sensor.temperature);
            sprintf(line2, "Humi: %.1f%%", sensor.humidity);
            OLED_Clear();
            OLED_ShowString(0, 0, line1);
            OLED_ShowString(0, 16, line2);
        }
        vTaskDelay(pdMS_TO_TICKS(1500));
    }
}

4️⃣ 控制任务与低功耗管理

按键中断触发控制灯光状态;空闲时进入低功耗模式:

复制代码
volatile uint8_t ledState = 0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == KEY_Pin) {
        ledState = !ledState;
        HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, ledState);
    }
}

void PowerTask(void *argument) {
    for (;;) {
        if (ledState == 0) {
            HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
        }
        vTaskDelay(pdMS_TO_TICKS(3000));
    }
}

五、系统调试与性能优化

✅ RTOS 调度优化

使用 STM32CubeIDE FreeRTOS Viewer 观察任务切换:

任务 周期(ms) CPU占用(%)
WifiTask 1000 28
SensorTask 2000 15
DisplayTask 1500 10
ControlTask 异步 5
IdleTask - 42

可见CPU空闲率>40%,系统运行平稳。

通过 vTaskSuspend() 在WiFi空闲时挂起任务,节省能耗约18%。


✅ 串口日志调试系统

增加简单日志模块(utils_log.c):

复制代码
void Log_Info(const char *fmt, ...) {
    char buf[128];
    va_list args;
    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);
    strcat(buf, "\r\n");
    HAL_UART_Transmit(&huart2, (uint8_t *)buf, strlen(buf), 100);
}

运行输出:

复制代码
[INFO] FreeRTOS started.
[INFO] Sensor: T=25.8 H=49.3
[INFO] WiFi: Send OK

✅ 功耗测试结果

模式 电流(mA)
全运行模式 22.8
WiFi空闲 13.4
STOP模式 3.2

节能策略包括:

  • 传感器周期采集;

  • 任务空闲挂起;

  • 动态时钟调节(降低主频到84MHz);

  • 关闭未用外设(ADC、TIM等)。


六、项目总结与经验分享

在本项目中,从硬件搭建到软件架构设计,我总结了几点关键经验:

  1. 架构先行:任务划分清晰、接口独立;

  2. 调度有序:FreeRTOS 的优先级规划非常关键;

  3. 日志必备:UART调试输出可快速定位死锁;

  4. 功耗优化:低功耗设计是嵌入式永恒主题;

  5. 模块复用:驱动层通用接口设计可快速移植。


七、未来展望

接下来我计划引入:

  • ✳️ TinyML(Micro speech模型),实现语音命令控制;

  • ✳️ MQTT 协议 接入云端;

  • ✳️ RISC-V 平台移植 实验对比;

  • ✳️ CI/CD 构建脚本 自动化编译固件。

相关推荐
云山工作室2 小时前
基于单片机的智能家居窗帘控制系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·课程设计
李boyang3 小时前
单片机通信协议--USART(串口通信)
单片机·嵌入式硬件·usart
YeGop4 小时前
51单片机数码管显示函数分享(8051汇编)
汇编·嵌入式硬件·51单片机
LaoZhangGong12310 小时前
STM32 F103外部晶振8MHz改为12MHz,如何配置?
c语言·stm32·单片机·嵌入式硬件·晶振
GilgameshJSS11 小时前
STM32H743-ARM例程41-FMC_INDEP
arm开发·stm32·单片机·嵌入式硬件
某林21213 小时前
如何使用ROS 2与STM32进行串口通信,并实现通过键盘按键‘1’来控制LED灯开关
stm32·嵌入式硬件·计算机外设
hazy1k13 小时前
51单片机基础-PWM、频率与占空比
stm32·单片机·嵌入式硬件·51单片机
逆小舟14 小时前
【STM32】智能排队控制系统
stm32·单片机·嵌入式硬件
GilgameshJSS14 小时前
STM32H743-ARM例程38-UART-IAP
c语言·arm开发·stm32·单片机·嵌入式硬件