1. 项目概述:基于STM32的智能用电监控系统
这个巴掌大的装置是我去年在参与智慧城市项目时研发的副产品,核心功能是实时监测220V交流电参数并通过手机远程查看。别看它体积小,从强电处理到无线传输的全套技术栈都塞进去了。整套系统硬件成本控制在80元以内,但实现了商业级电表90%的功能,特别适合DIY爱好者复现或作为毕业设计项目。
系统采用模块化设计,主要包含四个功能单元:
- STM32F103C8T6最小系统板(蓝色药丸板)作为主控
- 电压/电流互感器组成的信号采集前端
- ESP8266 WiFi模块负责无线通信
- 继电器+指示灯构成的控制反馈单元
实测数据刷新率可达2次/秒,电压测量误差±1.5V,电流误差±0.02A,完全满足家用电器监控需求。最实用的过载保护功能,能在功率超限3秒内切断电路,响应速度比市面上多数智能插座都快。
2. 硬件设计详解
2.1 强电信号采集方案
市电参数采集是本系统最核心也是最危险的部分。我的方案是用互感器实现强弱电隔离:
电压采集通道:
- TV1005M电压互感器(变比1000:1000)
- 输入端串联200kΩ限流电阻
- 输出端接10kΩ负载电阻
- 全桥整流后采用两级RC滤波(100Ω+100μF → 50Ω+47μF)
电流采集通道:
- TA1005M电流互感器(5A/5mA)
- 次级并联100Ω采样电阻
- 信号放大电路采用LM358(增益约30倍)
- 同样配置整流滤波电路
重要提示:调试强电部分时必须使用隔离电源供电!我曾因贪方便直接用开发板USB供电,结果滤波电容放电时导致整个开发板带电,烧毁了两个串口芯片才找到原因。
2.2 主控电路设计
STM32的选型考虑:
- 需要2路ADC同步采样(电压+电流)
- 要求DMA传输减轻CPU负担
- 至少1个硬件串口与WiFi模块通信
- 定时器资源丰富
最终选择STM32F103C8T6的原因:
- 72MHz主频满足实时性要求
- 内置12位ADC支持双通道DMA传输
- 多达3个USART接口
- 价格仅8元左右
电路设计要点:
- ADC参考电压接3.3V稳压输出
- 为减小干扰,模拟部分单独铺铜
- 所有IO口串联100Ω电阻作保护
- 预留SWD调试接口
3. 软件实现关键点
3.1 ADC采样与数据处理
电压电流需要同步采样才能保证功率计算准确。配置要点:
c复制// ADC双通道DMA配置
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
hadc1.Init.DiscontinuousConvMode = DISABLE;
// 通道配置
sConfig.Channel = ADC_CHANNEL_0; // 电压通道PA0
sConfig.Rank = ADC_REGULAR_RANK_1;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_1; // 电流通道PA1
sConfig.Rank = ADC_REGULAR_RANK_2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 启动DMA采集
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 2);
实际值转换算法:
c复制float get_voltage() {
float raw = adc_buffer[0] * 3.3f / 4096.0f;
return raw * 65.8f + 2.1f; // 校准系数
}
float get_current() {
float raw = (adc_buffer[1] * 3.3f / 4096.0f) - 1.65f; // 去除偏置
return raw * 0.707f * 30.0f / 100.0f; // 放大倍数×互感比
}
3.2 WiFi通信实现
ESP8266配置流程:
- 上电发送AT指令测试连接
- 配置为STA模式连接路由器
- 建立TCP服务器监听端口
- 启用多连接模式(AT+CIPMUX=1)
数据上传协议设计要点:
- 采用紧凑型JSON格式
- 添加时间戳防止数据丢失
- 包含设备ID支持多设备组网
示例数据包:
json复制{
"dev":"PEM-001",
"t":1625097600,
"v":220.5,
"i":1.25,
"p":275.6,
"e":0.125
}
3.3 过载保护算法
采用状态机实现智能判断:
c复制#define OVERLOAD_POWER 200.0 // 200W阈值
#define OVERLOAD_TIME 3 // 持续3秒触发
static uint8_t overload_cnt = 0;
void check_overload(float power) {
if(power > OVERLOAD_POWER) {
if(++overload_cnt > OVERLOAD_TIME*10) { // 每100ms检测一次
relay_off();
send_alert("Overload!");
}
} else {
overload_cnt = 0;
if(is_manual_mode()) {
relay_set(get_manual_state());
}
}
}
4. 开发中的坑与解决方案
4.1 互感器相位差问题
初期发现功率计算误差达15%,原因是:
- 电压电流互感器存在约30°相位差
- 普通整流电路导致信号畸变
解决方案:
- 改用精密整流电路
- 软件补偿:对电流采样值做相位校正
- 增加校准模式,支持用户手动补偿
4.2 WiFi断连处理
现场测试发现的痛点:
- 路由器重启后模块不会自动重连
- TCP连接中断导致数据丢失
改进措施:
c复制void wifi_task() {
static uint32_t last_ack = 0;
if(HAL_GetTick() - last_ack > 5000) {
if(!wifi_check()) {
wifi_reconnect();
}
last_ack = HAL_GetTick();
}
}
4.3 电量累计误差
发现的问题:
- 简单累加导致误差随时间累积
- 单片机掉电数据丢失
最终方案:
- 采用梯形积分法提高精度
- 每5分钟保存数据到EEPROM
- 增加校准按钮重置电量
c复制void energy_calc() {
static float last_power = 0;
float delta = (current_power + last_power) * 0.5f * 5.0f / 3600.0f;
total_kwh += delta / 1000.0f;
last_power = current_power;
if(++save_cnt >= 60) { // 5分钟保存一次
eeprom_save(total_kwh);
save_cnt = 0;
}
}
5. 系统优化方向
5.1 硬件改进建议
- 升级到STM32F303提升ADC精度
- 增加OLED本地显示
- 采用导轨式安装结构
- 添加防雷击保护电路
5.2 软件功能扩展
- 用电异常检测算法:
c复制// 突变量保护
if(fabs(current - last_current) > 2.0) {
trigger_protection("Current surge!");
}
- 能耗分析功能:
- 生成24小时用电曲线
- 识别高耗能电器
- 电费预算预警
- 云端对接方案:
- 通过MQTT协议上传数据
- 微信小程序接入
- 支持OTA远程升级
这套系统经过三个月的实际运行测试,在出租屋、实验室等场景下表现稳定。最大的收获是深刻理解了强电处理的注意事项——现在每次接线都会下意识用右手操作,左手永远放在口袋里,这是被电击过才养成的"职业习惯"。
