用STM32F103+ESP8266打造智能插座:从硬件搭建到云端控制的完整指南
周末整理工作室时,发现角落里堆着几个闲置的STM32开发板和ESP8266模块,突然萌生一个想法——何不把这些电子积木变成实用的智能家居设备?于是,一款能远程监控功率、自动断电的智能插座就这样诞生了。这个项目不仅成本低廉(总成本不到100元),更重要的是它完美解决了我的两个痛点:随时查看高功耗设备的工作状态,以及避免忘记关闭设备导致的能源浪费。
1. 硬件选型与电路设计
1.1 核心元件选型要点
选择硬件时需要考虑三个关键因素:测量精度、安全隔离和成本控制。经过多次对比测试,我最终确定了以下配置方案:
主控芯片:STM32F103C8T6最小系统板(俗称"蓝 pill")
- 理由:72MHz主频足够处理电力参数计算,内置ADC满足基本采样需求
- 成本:约15元
WiFi模块:ESP-01S(ESP8266)
- 优势:支持AT指令和透传模式,尺寸小巧(24.8×16mm)
- 注意:需购买带转接板的版本方便调试
电流检测:TA1005M互感器 + 10Ω/2W取样电阻
- 特性:1000:1变比,最大5A输入
- 安全提示:一定要选用开合式互感器,避免直接接触强电
电压检测:TV1005M互感器 + 1kΩ分压电阻
- 参数:1000:1变比,输出0-1mA
- 校准技巧:用万用表测量实际输出电压,调整分压电阻值
继电器模块:HK19F-DC5V-SHG
- 关键指标:10A/250VAC触点容量
- 安全建议:选择带光耦隔离的型号
1.2 电路连接示意图
下面是经过实际验证的可靠连接方式:
220V L ────┬──── TA1005M ────> 负载 │ ├── TV1005M │ STM32 PA1 <── 电压检测电路 STM32 PA2 <── 电流检测电路 STM32 PA4 ───> 继电器控制 ESP8266 RX <─> STM32 TX (PA9) ESP8266 TX <─> STM32 RX (PA10)重要提示:强电部分必须做好绝缘处理,建议使用热缩管包裹所有裸露导线。调试时先用USB供电,确认低压电路正常工作后再接入220V。
2. 电力参数测量原理与校准
2.1 交流采样算法实现
市电测量最大的挑战是从交流信号中提取有效值。我采用了每个周期采样40点(50Hz地区)的方法:
#define SAMPLE_COUNT 40 uint16_t voltage_samples[SAMPLE_COUNT]; uint16_t current_samples[SAMPLE_COUNT]; void TIM3_IRQHandler(void) { static uint8_t sample_index = 0; if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { voltage_samples[sample_index] = Get_Adc(ADC_Channel_1); current_samples[sample_index] = Get_Adc(ADC_Channel_2); sample_index = (sample_index + 1) % SAMPLE_COUNT; TIM_ClearITPendingBit(TIM3, TIM_IT_Update); } }有效值计算公式:
float calculate_rms(uint16_t *samples, float scale) { float sum = 0; for(int i=0; i<SAMPLE_COUNT; i++){ sum += samples[i] * samples[i]; } return sqrt(sum / SAMPLE_COUNT) * scale; }2.2 校准实战步骤
校准是保证测量精度的关键,需要准备一个可调负载(如电灯泡)和标准功率计:
电压校准:
- 接入已知电压(如220V)
- 测量ADC输出值,计算比例系数
- 修改代码中的
voltage_scale参数
电流校准:
- 连接100W灯泡(电流约0.45A)
- 调整
current_scale直到读数匹配 - 验证多个负载点(如40W、200W)
功率验证:
- 对比智能插座与商用功率计的读数
- 误差应控制在±3%以内
校准参数示例:
| 参数 | 典型值 | 说明 |
|---|---|---|
| voltage_scale | 0.215 | 电压ADC值到实际电压转换系数 |
| current_scale | 0.0031 | 电流ADC值到实际电流转换系数 |
| power_threshold | 200000 | 过载保护阈值(单位mW) |
3. 网络通信与数据协议
3.1 ESP8266配置优化
默认的AT固件存在稳定性问题,建议刷入最新版本并优化配置:
AT+CWMODE=1 # 设置为Station模式 AT+CWJAP="SSID","password" # 连接WiFi AT+CIPMUX=1 # 启用多连接 AT+CIPSERVER=1,8080 # 创建TCP服务器 AT+CIPSTO=2880 # 设置超时为48分钟为提高可靠性,我添加了自动重连机制:
void check_wifi_connection() { if(HAL_GetTick() - last_response_time > 5000) { printf("AT+RST\r\n"); // 超时无响应则重启模块 last_response_time = HAL_GetTick(); } }3.2 精简数据协议设计
经过多次迭代,我设计了一套高效的数据格式:
V:228A:0456P:103456Q:00012.34T:1234R:1字段说明:
V:电压(V),3位整数A:电流(mA),4位整数P:功率(mW),6位整数Q:电量(Wh),固定8位(整数5位+小数2位)T:运行时间(秒),4位整数R:继电器状态,1=开,0=关
手机端解析示例(Android代码片段):
private void parseSocketData(String data) { Pattern pattern = Pattern.compile("V:(\\d+)A:(\\d+)P:(\\d+)Q:(\\d+\\.\\d+)T:(\\d+)R:(\\d+)"); Matcher matcher = pattern.matcher(data); if(matcher.find()) { float voltage = Integer.parseInt(matcher.group(1)); float current = Integer.parseInt(matcher.group(2)) / 1000.0f; float power = Integer.parseInt(matcher.group(3)) / 1000.0f; float energy = Float.parseFloat(matcher.group(4)); int runtime = Integer.parseInt(matcher.group(5)); boolean relayState = matcher.group(6).equals("1"); updateUI(voltage, current, power, energy, runtime, relayState); } }4. 手机端监控方案
4.1 免开发快速方案
对于不想编写APP的用户,我有三个即用型解决方案:
MQTT+Home Assistant:
- 修改固件发布数据到MQTT服务器
- 通过Home Assistant创建控制面板
- 优点:跨平台,支持自动化场景
TCP调试助手:
- 使用现成的网络调试APP
- 直接连接插座IP和端口
- 推荐应用:TCP/UDP调试工具(Android)
微信小程序:
- 利用ESP8266的HTTP服务
- 开发简易控制页面
- 示例代码片段:
wx.connectSocket({ url: 'ws://192.168.1.100:8080', success: function() { console.log('连接成功') } })
4.2 自定义APP开发要点
如果要开发专属APP,需要注意几个关键点:
- 心跳机制:每30秒发送心跳包维持连接
- 本地缓存:存储最近24小时数据用于离线查看
- 通知提醒:功率超限时推送报警
- UI设计建议:
- 实时显示电压、电流波形图
- 用电量柱状图按小时分组
- 一键导出用电报告
iOS端核心代码示例(Swift):
func setupSocket() { var inputStream: InputStream? var outputStream: OutputStream? Stream.getStreamsToHost(withName: "192.168.1.100", port: 8080, inputStream: &inputStream, outputStream: &outputStream) inputStream?.delegate = self outputStream?.delegate = self inputStream?.schedule(in: .current, forMode: .default) outputStream?.schedule(in: .current, forMode: .default) inputStream?.open() outputStream?.open() } func stream(_ aStream: Stream, handle eventCode: Stream.Event) { switch eventCode { case .hasBytesAvailable: let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 1024) let len = (aStream as! InputStream).read(buffer, maxLength: 1024) if len > 0 { let data = Data(bytes: buffer, count: len) if let text = String(data: data, encoding: .utf8) { parseData(text) } } default: break } }5. 安全增强与功能扩展
5.1 必须实现的安全措施
在多次实际使用中,我发现以下几个安全功能必不可少:
软硬件双重过流保护:
- 硬件:在继电器前串接10A保险丝
- 软件:增加瞬时功率突变检测
if(abs(current_power - last_power) > 100000) { // 100W突变 trigger_protection(); }
看门狗系统:
- 启用STM32独立看门狗(IWDG)
- 硬件看门狗芯片(如MAX706)
绝缘检测:
- 定期检测零火线间绝缘电阻
- 异常时自动断开并报警
5.2 值得添加的扩展功能
根据用户反馈,这些扩展功能很实用:
用电统计:
- 日/周/月用电报表
- 电费计算(可设置单价)
场景联动:
if(time > TIME_22_00 && power < 50) { auto_off(); // 晚上10点后如果功率低于50W自动关闭 }OTA升级:
- 通过手机APP推送固件更新
- 采用A/B双分区确保安全
语音控制:
- 对接天猫精灵/小爱同学
- 自定义语音指令
6. 常见问题排查指南
在帮助50+网友实现该项目后,我总结了最典型的故障现象及解决方法:
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电流测量值为零 | 互感器方向接反 | 调换互感器二次侧接线方向 |
| WiFi频繁断开 | 电源干扰 | 在ESP8266的3.3V引脚加100μF电容 |
| 继电器无法断开 | 续流二极管损坏 | 更换继电器模块或外接1N4007二极管 |
| 手机连接后无数据 | 防火墙拦截 | 检查路由器设置,关闭AP隔离功能 |
| 测量值波动大 | 采样不同步 | 改用过零检测触发ADC采样 |
对于想进一步优化的开发者,可以尝试:
- 改用STM32的硬件FFT计算谐波失真
- 添加PF(功率因数)检测功能
- 实现三相电平衡监测(需要3套检测电路)
这个项目最让我满意的不是技术实现,而是它实际解决了生活中的问题。现在我可以随时查看家里鱼缸加热棒的耗电情况,出差时发现异常立即远程断电,再也不用担心发生安全事故了。