智能家居DIY实战:基于STM32与ESP8266的云端温湿度监控系统开发指南
在万物互联的时代背景下,智能家居系统正从概念走向千家万户。本文将手把手带您实现一个完整的智能家居原型系统——通过STM32微控制器搭配ESP8266 WiFi模块,将温湿度数据上传至OneNET物联网平台,并探讨移动端交互的扩展可能。这个项目不仅适合创客爱好者练手,更能为智能家居产品开发提供可靠的技术验证。
1. 硬件系统架构设计
1.1 核心硬件选型与连接
本系统的硬件架构采用三层设计:感知层、控制层和网络层。感知层由DHT11温湿度传感器构成,负责环境数据采集;控制层以STM32F103C8T6为核心,进行数据处理和系统调度;网络层则通过ESP-01S模块实现互联网接入。
关键硬件连接示意图:
| 模块 | STM32引脚 | 连接方式 | 备注 |
|---|---|---|---|
| ESP8266 TX | PB11 | USART3_RX | 需配置上拉电阻 |
| ESP8266 RX | PB10 | USART3_TX | 串口波特率115200 |
| DHT11 DATA | PA0 | GPIO输入 | 单总线协议 |
| OLED SCL | PB6 | I2C1_SCL | 可选显示模块 |
| OLED SDA | PB7 | I2C1_SDA | 可选显示模块 |
注意:ESP8266模块建议独立供电,工作电流需确保在200mA以上,避免因供电不足导致WiFi连接不稳定。
1.2 开发环境搭建
推荐使用Keil MDK作为主要开发环境,配合STM32CubeMX进行外设初始化:
# 安装必要工具链 sudo apt install arm-none-eabi-gcc sudo apt install openocd # STM32CubeMX配置步骤: 1. 选择STM32F103C8Tx系列芯片 2. 启用USART3异步模式(115200bps,8N1) 3. 配置PB10/PB11为USART3_TX/USART3_RX 4. 生成代码时选择MDK-ARM工具链硬件调试阶段,建议先通过串口助手测试ESP8266AT指令响应:
# Python简易AT指令测试脚本示例 import serial ser = serial.Serial('/dev/ttyUSB0', 115200) ser.write(b'AT\r\n') response = ser.read_all() print(response.decode())2. OneNET平台配置与接入
2.1 云端服务创建流程
OneNET作为中国移动物联网开放平台,为设备接入提供了完善的支持:
产品创建:登录控制台→多协议接入→添加产品
- 联网方式选择WiFi
- 接入协议选择HTTP
- 操作系统选择Linux(与实际无关)
设备添加:在产品下创建设备
- 记录设备ID和Master-APIKey
- 开启数据流管理功能
API接口准备:
- 数据点上传接口:
http://api.heclouds.com/devices/[device_id]/datapoints - 数据查询接口:
http://api.heclouds.com/devices/[device_id]/datastreams/[stream_name]
- 数据点上传接口:
2.2 HTTP通信协议实现
ESP8266通过HTTP POST方式上传数据,报文格式如下:
POST /devices/[设备ID]/datapoints HTTP/1.1 api-key: [Master-APIKey] Host: api.heclouds.com Content-Length: [数据长度] {"datastreams":[{"id":"temp","datapoints":[{"value":25}]}]}对应的STM32代码实现:
void send_to_onenet(float temperature, float humidity) { char json_payload[256]; sprintf(json_payload, "{\"datastreams\":[" "{\"id\":\"temp\",\"datapoints\":[{\"value\":%.1f}]}," "{\"id\":\"humi\",\"datapoints\":[{\"value\":%.1f}]}" "]}", temperature, humidity); char http_header[512]; sprintf(http_header, "POST /devices/%s/datapoints HTTP/1.1\r\n" "api-key: %s\r\n" "Host: api.heclouds.com\r\n" "Content-Length: %d\r\n\r\n" "%s", DEVICE_ID, API_KEY, strlen(json_payload), json_payload); esp8266_send_data((uint8_t *)http_header, 1000); }3. 嵌入式端开发详解
3.1 ESP8266驱动开发
ESP8266模块通过AT指令集进行控制,需要实现以下核心功能:
- 基础通信函数:
uint8_t esp8266_send_cmd(uint8_t *cmd, uint8_t *ack, uint16_t timeout) { USART3_RX_STA = 0; u3_printf("%s\r\n", cmd); while(timeout--) { Delay_ms(10); if(USART3_RX_STA & 0x8000) { if(strstr((char*)USART3_RX_BUF, (char*)ack)) { return 0; // 成功 } USART3_RX_STA = 0; } } return 1; // 超时 }- WiFi连接流程:
- AT+CWMODE=1 (STA模式)
- AT+CWJAP="SSID","password" (连接路由器)
- AT+CIPSTART="TCP","api.heclouds.com",80 (建立TCP连接)
- AT+CIPMODE=1 (进入透传模式)
3.2 数据采集与处理
DHT11传感器采用单总线协议,读取时序如下:
#define DHT11_PIN GPIO_Pin_0 void DHT11_Start() { GPIO_InitTypeDef GPIO_InitStruct; // 配置为输出模式 GPIO_InitStruct.GPIO_Pin = DHT11_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // 主机拉低18ms GPIO_ResetBits(GPIOA, DHT11_PIN); Delay_ms(18); GPIO_SetBits(GPIOA, DHT11_PIN); // 切换为输入模式 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStruct); } uint8_t DHT11_ReadByte() { uint8_t data = 0; for(int i=0; i<8; i++) { while(!GPIO_ReadInputDataBit(GPIOA, DHT11_PIN)); // 等待低电平 Delay_us(30); if(GPIO_ReadInputDataBit(GPIOA, DHT11_PIN)) { data |= (1 << (7-i)); } while(GPIO_ReadInputDataBit(GPIOA, DHT11_PIN)); // 等待高电平结束 } return data; }4. 系统优化与扩展
4.1 低功耗设计策略
对于电池供电场景,可采用以下优化措施:
- 间歇工作模式:
- 设置STM32进入STOP模式
- 通过RTC定时唤醒(如每5分钟)
- 唤醒后采集数据并立即上传
void enter_stop_mode(uint32_t seconds) { RTC_SetAlarm(RTC_GetCounter() + seconds); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); SystemInit(); // 唤醒后需重新初始化时钟 }- ESP8266电源管理:
- 通过MOSFET控制模块供电
- 仅在需要通信时上电
- 发送完成后立即断电
4.2 微信小程序对接思路
OneNET平台提供完善的API支持移动端开发:
数据获取流程:
- 小程序通过HTTPS调用OneNET API
- 使用设备ID和API Key进行鉴权
- 解析返回的JSON数据
控制指令下发:
- 创建命令型数据流
- 小程序发送POST请求到OneNET
- STM32定期查询命令状态
// 小程序示例代码 wx.request({ url: 'https://api.heclouds.com/devices/[device_id]/datastreams', header: { 'api-key': '[API_KEY]' }, success(res) { console.log(res.data) } })4.3 异常处理机制
健壮的系统需要完善的错误恢复机制:
网络重连策略:
- 指数退避算法
- 最大重试次数限制
- 本地数据缓存
传感器故障检测:
- 数据合理性校验
- 超时处理
- 备用数据源切换
void sensor_read_retry(DHT11_Data *data, uint8_t max_retry) { uint8_t retry = 0; while(retry < max_retry) { if(DHT11_Read(data) == SUCCESS) { if(data->humidity <= 100 &&>