下面我将为您提供一个完整、详细的指南,从项目概述、系统架构、硬件选型、软件设计、关键代码示例到未来扩展方向,系统地介绍如何构建一个基于STM32的智能家居系统。

(图片来源网络,侵删)
项目概述
目标: 设计并实现一个以STM32微控制器为核心,能够通过手机App或网页远程控制家中多种设备(如灯光、窗帘、温湿度传感器等)的智能家居系统。
核心功能:
- 设备控制: 远程开关灯、调节风扇风速、控制窗帘电机。
- 环境监测: 实时采集并显示室内温湿度。
- 用户交互: 通过手机App或网页进行远程控制和状态查看。
- 自动化场景: (可选)实现定时任务或条件触发(如温湿度超过阈值自动开窗)。
核心技术栈:
- 硬件: STM32微控制器、ESP8266/ESP32 Wi-Fi模块、各类传感器和执行器。
- 软件:
- STM32端: STM32CubeMX配置、HAL库编程、FreeRTOS实时操作系统。
- 通信: MQTT协议(轻量级,适合物联网)或HTTP协议。
- 服务器: 自建MQTT Broker(如Mosquitto, EMQX)或使用云服务(如阿里云IoT, AWS IoT Core)。
- 应用端: 使用Blynk、MIT App Inventor快速开发App,或使用HTML/CSS/JS开发Web控制面板。
系统架构设计
一个典型的物联网智能家居系统通常分为四层:感知层、网络层、平台层、应用层。

(图片来源网络,侵删)
+-------------------+ +-------------------+ +-------------------+ +-------------------+
| 应用层 | | 平台层 | | 网络层 | | 感知层 |
| (手机App/网页) |<---->| (MQTT Broker/云平台)|<----| (Wi-Fi/蓝牙/Zigbee)|<---->| (STM32 + 传感器/执行器)|
+-------------------+ +-------------------+ +-------------------+ +-------------------+
^ ^ ^ |
| | | |
| | | v
| | | +-----------------+
| | | | 温湿度传感器 |
| | | | 继电器模块 |
| | | | 直流电机驱动 |
| | | | LED灯 |
+---------------------------+---------------------------+--------------------+-----------------+
- 感知层: 由STM32F103/F407等核心板、DHT11/DHT22温湿度传感器、继电器模块(控制220V家电)、直流电机驱动模块(控制窗帘)等组成,负责数据采集和执行控制指令。
- 网络层: 使用ESP8266 Wi-Fi模块作为STM32的“网络适配器”,STM32通过UART与ESP8266通信,发送AT指令控制其连接到Wi-Fi,并通过MQTT协议与服务器通信。
- 平台层: 部署一个MQTT消息代理服务器,它负责接收所有设备(我们的STM32系统)的“发布”(Publish)消息,并将这些消息“分发”(Subscribe)给所有订阅了该主题的客户端(手机App),它起到了一个中间桥梁的作用。
- 应用层: 用户通过手机App或网页上的客户端,订阅设备状态主题,发布控制指令,平台层将指令转发给STM32,并将STM32上报的状态显示给用户。
硬件选型与连接
1 核心控制器
- 推荐型号: STM32F103C8T6 ("蓝丸"),性价比高,资源足够(Flash: 64KB, RAM: 20KB),拥有多个UART、ADC、GPIO等。
- 进阶选择: STM32F407VGT6 ("黑丸"),性能更强,资源更丰富(FPU, 更多RAM/Flash),适合运行更复杂的协议或图形界面。
2 网络模块
- 推荐型号: ESP8266-01S,体积小,成本低,AT指令集成熟,完美配合STM32使用。
3 传感器与执行器
- 温湿度传感器: DHT11 (低成本) 或 DHT22 (高精度)。
- 灯光控制: 5V继电器模块,STM32的GPIO控制继电器线圈,继电器触点控制220V灯具的火线。
- 窗帘控制: L298N或DRV8833电机驱动模块,控制直流减速电机正反转。
- 状态指示: LED灯。
4 硬件连接示例 (STM32F103 + ESP8266)
| STM32引脚 | ESP8266引脚 | 功能 |
|---|---|---|
3V |
VCC |
供电 (ESP8266工作电压3.3V) |
GND |
GND |
地线 |
PA9 (TX) |
RXD |
STM32发送数据到ESP8266 |
PA10 (RX) |
TXD |
STM32接收来自ESP8266的数据 |
PC13 |
- | 连接一个LED,用于系统状态指示 |
注意: ESP8266的TXD引脚输出电压为3.3V,可以直接与STM32的RX引脚连接,但STM32的TX引脚输出为3.3V,对于某些版本的ESP8266可能不够稳定,如果遇到问题,可以考虑使用一个逻辑电平转换器。
软件设计
1 开发环境
- IDE: STM32CubeIDE (免费,集成了代码生成和调试功能)
- 工具: STM32CubeMX (用于引脚配置和初始化代码生成)
- 库: HAL库 (硬件抽象层)
- 实时操作系统: FreeRTOS (强烈推荐!),它可以将复杂的任务(如Wi-Fi通信、传感器采集、按键处理)分解为独立的任务,并行执行,提高系统响应速度和稳定性。
2 软件架构 (基于FreeRTOS)
我们将系统划分为几个独立的任务:
-
Task_MQTT_Client(MQTT客户端任务):- 负责初始化ESP8266,连接到Wi-Fi。
- 连接到MQTT Broker。
- 在循环中,通过串口接收来自ESP8266的MQTT消息,并解析。
- 发布传感器数据到指定主题(如
home/livingroom/temp)。 - 当接收到控制指令时,通过队列发送给控制任务。
-
Task_Sensor_Read(传感器读取任务):
(图片来源网络,侵删)- 以固定周期(如每2秒)读取DHT11的温湿度数据。
- 将读取到的数据打包成JSON格式,通过队列发送给MQTT任务。
-
Task_Control(控制任务):- 从MQTT任务的队列中接收控制指令(如
{"light": "on"})。 - 根据指令内容,操作相应的GPIO引脚,控制继电器、电机等执行器。
- 将设备当前状态(如
{"light_status": "on"})发布到MQTT Broker。
- 从MQTT任务的队列中接收控制指令(如
-
Task_UART_Comm(串口通信任务 - 可选):负责处理与ESP8266的串口通信细节,如发送AT指令、解析返回,将结果传递给MQTT任务,可以简化主任务的逻辑。
3 MQTT协议设计
主题命名规范:
- 设备上报数据 (Publish):
home/<room>/<device_id>/data(e.g.,home/livingroom/dht22/data)
- 设备接收控制指令 (Subscribe):
home/<room>/<device_id>/cmd(e.g.,home/livingroom/relay_1/cmd)
消息载荷示例:
- 上报数据:
{ "temperature": 25.6, "humidity": 60.2 } - 下发指令:
{ "device": "light", "status": "on" }
关键代码示例
1 STM32CubeMX 配置
- 选择
STM32F103C8T6芯片。 - 配置
SYS->Debug为Serial Wire。 - 配置
RCC->High Speed Clock (HSE)为Crystal/Ceramic Resonator。 - 配置
Clock Configuration,将HCLK设置为 72MHz。 - 配置
USART1:- Mode:
Asynchronous - Baud Rate:
115200 - 用于与ESP8266通信。
- Mode:
- 配置
USART2:- Mode:
Asynchronous - Baud Rate:
115200 - 用于打印调试信息(连接到USB-TTL模块)。
- Mode:
- 配置
GPIO:PC13:GPIO_Output(LED)PC0-PC5:GPIO_Output(控制继电器、电机驱动)
- 在
Middleware中,启用FreeRTOS,并创建几个任务(如MQTT_Task,Sensor_Task,Control_Task)。 - 生成代码。
2 FreeRTOS 任务示例代码 (main.c)
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "dht11.h" // 假设你有一个DHT11的驱动文件
/* Definitions for MQTT_Task */
osThreadId_t defaultTaskHandle;
#define MQTT_TASK_STK_SIZE 256
void MqttTask(void *argument);
/* Definitions for Sensor_Task */
osThreadId_t sensorTaskHandle;
#define SENSOR_TASK_STK_SIZE 128
void SensorTask(void *argument);
/* Definitions for Control_Task */
osThreadId_t controlTaskHandle;
#define CONTROL_TASK_STK_SIZE 128
void ControlTask(void *argument);
/* Queue definitions */
osMessageQueueId_t sensorDataQueue;
#define QUEUE_ITEM_SIZE sizeof(float)
#define QUEUE_ITEM_COUNT 5 // 存储温度和湿度数据
/* Private variables */
extern UART_HandleTypeDef huart1; // ESP8266
extern UART_HandleTypeDef huart2; // Debug
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
HAL_Init();
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_DHT11_Init(); // 初始化DHT11的GPIO
/* Create the semaphores, mutexes and data queues */
sensorDataQueue = osMessageQueueNew(QUEUE_ITEM_COUNT, QUEUE_ITEM_SIZE, NULL);
/* Create the thread(s) */
const osThreadAttr_t defaultTask_attributes = {
.name = "MQTT_Task",
.stack_size = MQTT_TASK_STK_SIZE,
.priority = (osPriority_t) osPriorityNormal,
};
defaultTaskHandle = osThreadNew(MqttTask, NULL, &defaultTask_attributes);
const osThreadAttr_t sensorTask_attributes = {
.name = "Sensor_Task",
.stack_size = SENSOR_TASK_STK_SIZE,
.priority = (osPriority_t) osPriorityBelowNormal,
};
sensorTaskHandle = osThreadNew(SensorTask, NULL, &sensorTask_attributes);
const osThreadAttr_t controlTask_attributes = {
.name = "Control_Task",
.stack_size = CONTROL_TASK_STK_SIZE,
.priority = (osPriority_t) osPriorityNormal,
};
controlTaskHandle = osThreadNew(ControlTask, NULL, &controlTask_attributes);
/* Start scheduler */
osKernelStart();
while (1)
{
}
}
// 传感器任务:读取数据并发送到队列
void SensorTask(void *argument)
{
float temp, humi;
DHT11_DataTypedef DHT11_Data;
for(;;)
{
if (DHT11_Read(&DHT11_Data) == DHT11_OK)
{
temp = (float)DHT11_Data.Temperature;
humi = (float)DHT11_Data.Humidity;
// 将数据发送到队列
osMessageQueuePut(sensorDataQueue, &temp, NULL, 0);
osMessageQueuePut(sensorDataQueue, &humi, NULL, 0);
printf("Temp: %.1f, Humi: %.1f\r\n", temp, humi);
}
osDelay(2000); // 每2秒读取一次
}
}
// MQTT任务:处理与ESP8266和MQTT服务器的通信
// (这是一个简化版,实际代码会更复杂,需要实现AT指令集和MQTT协议栈)
void MqttTask(void *argument)
{
// 1. 初始化ESP8266, 连接Wi-Fi
// ESP8266_Init();
// ESP8266_ConnectWiFi("Your_SSID", "Your_PASSWORD");
// 2. 连接MQTT Broker
// ESP8266_ConnectMQTT("broker.emqx.io", 1883, "client_id", "user", "pass");
// 3. 订阅控制主题
// ESP8266_SubscribeTopic("home/livingroom/relay_1/cmd");
for(;;)
{
// 4. 从队列获取传感器数据并发布
float data;
if(osMessageQueueGet(sensorDataQueue, &data, NULL, 0) == osOK)
{
// 这里需要将data转换成JSON格式,然后通过串口发送AT指令发布
// char payload[32];
// snprintf(payload, sizeof(payload), "{\"temperature\":%.1f}", data);
// ESP8266_PublishTopic("home/livingroom/dht22/data", payload);
}
// 5. 检查串口缓冲区,是否有MQTT消息到达
// char rx_buffer[128];
// if(HAL_UART_Receive(&huart1, (uint8_t*)rx_buffer, sizeof(rx_buffer), 100) == HAL_OK)
// {
// // 解析MQTT消息,如果是指令,则发送到控制任务
// // if(is_mqtt_control_command(rx_buffer))
// // {
// // osMessageQueuePut(controlQueue, command_data, NULL, 0);
// // }
// }
osDelay(100);
}
}
// 控制任务:执行控制指令
void ControlTask(void *argument)
{
for(;;)
{
// 这里应该从队列获取控制指令
// ControlCommand cmd;
// if(osMessageQueueGet(controlQueue, &cmd, NULL, 0) == os_OK)
// {
// if(strcmp(cmd.device, "light") == 0)
// {
// if(strcmp(cmd.status, "on") == 0) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
// else HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
// }
// }
osDelay(50);
}
}
快速原型方案 (Blynk)
如果觉得自己实现MQTT通信和App开发太复杂,可以使用Blynk平台,它能极大地加速开发过程。
- 注册Blynk账号并创建项目,获取
Auth Token。 - 在Blynk App中拖拽控件:添加按钮(控制灯)、滑动条(控制风扇)、数值显示(显示温湿度)等。
- STM32端集成Blynk库:下载Blynk库到你的STM32工程。
- 编写代码:
- 在
setup()中,使用Auth Token、Wi-Fi信息初始化Blynk。 - 使用
Blynk.virtualWrite(V0, temperature)将温湿度数据发送到App上的V0引脚。 - 使用
Blynk.write(V1, HIGH)来控制连接在V1引脚上的按钮。 - 设置
Blynk.onWrite(V1, myWriteHandler)函数,当App上的按钮被按下时,myWriteHandler函数会被执行,你可以在里面编写控制GPIO的代码。
- 在
优点: 开发速度极快,无需关心服务器和App界面。 缺点: 系统封闭在Blynk生态内,扩展性较差,依赖其服务器。
未来扩展方向
当基础系统搭建完成后,可以从以下几个方面进行扩展:
- 增加更多设备: 添加烟雾传感器、人体红外传感器、门窗磁传感器等,实现安防和自动化。
- 引入更高级的自动化: 实现场景模式(如“回家模式”自动开灯、开空调)、定时任务(如每天早上7点自动拉开窗帘)。
- 使用更强大的MCU: 升级到STM32F4/F7系列,运行嵌入式Linux(如Yocto Project),实现更复杂的功能,如图形界面、本地数据库等。
- 采用更专业的通信协议: 学习并使用CoAP、LwM2M等专为资源受限设备设计的物联网协议。
- 实现本地网关功能: 让STM32作为Zigbee/Z-Wave协调器,连接更多低功耗设备,再通过Wi-Fi与云端通信。
这个项目从零开始,涵盖了嵌入式系统开发的多个方面,是一个非常宝贵的实践机会,祝你项目顺利!
