这个项目实现了一个完整的智能电表监测系统,核心功能包括交流电压/电流检测、功率计算、电能计量、温湿度监测以及无线数据传输。系统采用STM32单片机作为主控制器,通过各类传感器采集环境数据,并借助WiFi模块实现手机APP远程监控。我在实际开发中发现,这种设计方案特别适合家庭用电监测、小型设备能耗分析等场景。
系统硬件架构包含几个关键模块:STM32F103C8T6最小系统板作为控制核心,TV1005M电压互感器和TA1005M电流互感器负责市电参数采集,ESP8266 WiFi模块处理无线通信,LCD1602液晶屏提供本地显示,DHT11和DS18B20分别检测温湿度,继电器实现过载保护。这种模块化设计让系统具备良好的扩展性,比如可以轻松添加更多传感器或通信方式。
选择STM32F103C8T6作为主控主要基于三点考虑:首先,它具备12位ADC和多个定时器,正好满足电压电流采样需求;其次,72MHz主频足以处理实时数据计算;最后,丰富的外设接口方便连接各类模块。实际使用中,我建议为芯片单独配置一个3.3V LDO稳压器,避免电源噪声影响ADC精度。
最小系统板需要包含以下必要电路:
注意:STM32的ADC参考电压应连接稳定干净的3.3V电源,我在测试中发现电源波动会导致采样值跳变约±5LSB。
市电检测采用非接触式互感器方案,这是考虑到安全隔离的需求。TV1005M电压互感器变比为1000:1,输入220V时次级输出约0.22V交流信号。这个微弱信号需要经过以下处理流程:
电流检测使用TA1005M互感器,当5A电流通过时输出5mA电流信号。我设计了一个50Ω采样电阻将其转换为电压信号,后续处理流程与电压信号相同。实测中发现,互感器次级必须接负载电阻,否则输出波形会严重畸变。
ESP8266-01 WiFi模块是性价比之选,通过AT指令与STM32交互。硬件连接需要注意三点:
通信协议采用自定义的JSON格式,每秒钟上传一次数据包,例如:
json复制{
"V":220.5,
"I":1.2,
"P":264.6,
"E":1587.6,
"T":25.3,
"H":45.2
}
LCD1602采用4位数据线连接方式节省IO口,背光通过200Ω电阻限流。DHT11温湿度传感器需注意每次采集间隔不小于1秒。DS18B20采用寄生供电模式时,强上拉电阻要在转换期间保持接通。继电器驱动电路使用2N7000 MOSFET,并在线圈两端并联1N4148续流二极管。
系统软件采用前后台架构,主循环中处理非实时任务,关键时序由中断驱动。程序流程图如下:
定时器2配置为1kHz中断,用于产生精确的时间基准。定时器3触发ADC的规则组转换,采样率设为1kHz以满足Nyquist定理(市电50Hz基波)。
电压电流的有效值计算采用均方根算法:
c复制#define SAMPLE_NUM 100 // 每个周期20ms采样100点
float CalcRMS(uint16_t *adc_buf) {
float sum = 0;
for(int i=0; i<SAMPLE_NUM; i++){
float v = (adc_buf[i] - 2048) * 3.3 / 4096; // 去除偏置并转为电压值
sum += v * v;
}
return sqrt(sum / SAMPLE_NUM) * K; // K为互感器变比系数
}
功率计算采用瞬时功率积分法:
c复制float CalcPower(uint16_t *v_buf, uint16_t *i_buf) {
float sum = 0;
for(int i=0; i<SAMPLE_NUM; i++){
float v = (v_buf[i] - 2048) * 3.3 / 4096;
float i = (i_buf[i] - 2048) * 3.3 / 4096;
sum += v * i;
}
return sum / SAMPLE_NUM * Kv * Ki; // Kv、Ki为电压电流变比
}
电能累计通过定时中断实现,每1秒将当前功率值累加到电能寄存器中。为防止数据丢失,建议每5分钟将累计值写入STM32的Flash备份寄存器。
过载判断采用滞回比较策略,避免临界状态下的继电器抖动:
c复制#define POWER_THRESHOLD 200.0 // 200W阈值
#define HYSTERESIS 5.0 // 滞回区间
if(current_power > (POWER_THRESHOLD + HYSTERESIS)){
Relay_OFF();
buzzer_flag = 1;
}
else if(current_power < (POWER_THRESHOLD - HYSTERESIS)) {
buzzer_flag = 0;
}
// 手动控制优先级最高
if(manual_control) Relay_Set(manual_state);
蜂鸣器报警采用PWM驱动,产生间歇鸣响效果:
c复制// 定时器4中断处理
if(buzzer_flag){
static uint8_t cnt = 0;
if(++cnt >= 10){ // 0.5s周期
cnt = 0;
Buzzer_Toggle();
}
}
APP采用Android Studio开发,核心功能包括:
关键代码段 - TCP数据接收解析:
java复制private void startDataThread() {
new Thread(() -> {
try {
Socket socket = new Socket(ip, port);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
while(!Thread.interrupted()) {
String jsonStr = in.readLine();
JSONObject data = new JSONObject(jsonStr);
runOnUiThread(() -> {
tvVoltage.setText(String.format("%.1f V", data.getDouble("V")));
tvCurrent.setText(String.format("%.2f A", data.getDouble("I")));
// 更新其他UI...
});
}
} catch (Exception e) { e.printStackTrace(); }
}).start();
}
使用MPAndroidChart库实现动态曲线显示,我推荐采用以下配置:
图表刷新策略采用滑动窗口机制,只保留最近60秒的数据点。触摸交互支持缩放和滑动查看历史数据。
电压电流测量需要分三步校准:
我发现一个实用技巧:在无负载时,电流通道应显示约0.02A左右的噪声值(来自互感器本身),如果显示绝对零值可能意味着电路故障。
问题1:WiFi频繁断开
问题2:LCD显示乱码
问题3:功率计算偏差大
对于电池供电的应用场景,可以采取以下措施:
实测优化后,系统平均电流可从85mA降至15mA左右,显著延长电池寿命。
在实际部署中,我发现这个系统还有多个可扩展方向:
一个特别实用的改进是增加SD卡本地存储,这样即使网络中断也不会丢失数据。我测试过使用FATFS文件系统,每分钟写入一次数据,Class4的8GB卡可以存储约2年的用电记录。