三相多功能电表电路与代码实现
一、系统概述
三相多功能电表是一种用于测量三相交流电路中各种电参数的智能仪表,能够测量电压、电流、功率、电能、频率、功率因数等参数,并具备通信、显示、报警等功能。
二、电路设计
1. 系统框图
+-------------------+ +-------------------+ +-------------------+
| 电压采样电路 | | 电流采样电路 | | 微控制器 |
| (PT/CT) |---->| (CT/分流器) |---->| (STM32F407) |
+-------------------+ +-------------------+ +-------------------+
| | |
v v v
+-------------------+ +-------------------+ +-------------------+
| 信号调理电路 | | 信号调理电路 | | 通信接口 |
| (运放、滤波) | | (运放、滤波) | | (RS485, IR, RF) |
+-------------------+ +-------------------+ +-------------------+
|
v
+-------------------+
| 显示模块 |
| (LCD, LED) |
+-------------------+
|
v
+-------------------+
| 存储模块 |
| (EEPROM, Flash) |
+-------------------+
2. 关键电路设计
2.1 电压采样电路
- 使用电压互感器(PT)将高电压(如220V/380V)转换为低电压(如0-5V)
- 信号调理电路:运放缓冲、低通滤波(截止频率100Hz)
- 保护电路:TVS二极管、自恢复保险丝
2.2 电流采样电路
- 使用电流互感器(CT)或分流器(Shunt)将大电流转换为小电压
- 信号调理电路:运放放大、偏置调整、低通滤波
- 保护电路:双向TVS二极管
2.3 微控制器电路
-
核心:STM32F407ZGT6(ARM Cortex-M4, 168MHz)
-
外设:
- 多通道ADC(16位分辨率)
- 定时器(用于PWM、捕获、时基)
- UART、SPI、I2C(用于通信)
- GPIO(用于LCD、按键、指示灯)
2.4 通信接口电路
- RS485:MAX485芯片,半双工通信
- 红外:IRDA收发器
- 无线:LoRa模块(SX1278)
2.5 电源电路
- 输入:AC/DC转换(85-265V AC转5V DC)
- 输出:3.3V(给MCU及数字电路),±12V(给模拟电路)
三、代码实现
1. 系统初始化
#include "stm32f4xx_hal.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
// 系统时钟配置
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置主PLL
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
// 配置系统时钟
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
// 外设初始化
void Peripheral_Init(void) {
MX_GPIO_Init();
MX_ADC1_Init();
MX_ADC2_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
}
2. ADC采样与处理
// ADC采样数据结构
typedef struct {
float Ua, Ub, Uc; // 三相电压
float Ia, Ib, Ic; // 三相电流
float Pa, Pb, Pc; // 三相有功功率
float Qa, Qb, Qc; // 三相无功功率
float Sa, Sb, Sc; // 三相视在功率
float PFa, PFb, PFc; // 三相功率因数
float Freq; // 频率
float TotalEnergy; // 总有功电能
} PowerData;
// ADC DMA缓冲区
uint32_t adcBuffer[6]; // 6通道ADC数据
// 启动ADC采样
void Start_ADC_Sampling(void) {
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcBuffer, 6);
}
// 处理ADC数据
void Process_ADC_Data(PowerData* data) {
// 转换ADC原始值为实际电压/电流值
// 假设ADC参考电压3.3V,12位分辨率(0-4095)
// 电压分压比: 1000:1, 电流变比: 1000:1
// 电压采样值 (0-3.3V对应0-500V)
data->Ua = (adcBuffer[0] * 3.3 / 4095) * (500 / 3.3);
data->Ub = (adcBuffer[1] * 3.3 / 4095) * (500 / 3.3);
data->Uc = (adcBuffer[2] * 3.3 / 4095) * (500 / 3.3);
// 电流采样值 (0-3.3V对应-50A-50A)
data->Ia = ((adcBuffer[3] * 3.3 / 4095) - 1.65) * (50 / 1.65);
data->Ib = ((adcBuffer[4] * 3.3 / 4095) - 1.65) * (50 / 1.65);
data->Ic = ((adcBuffer[5] * 3.3 / 4095) - 1.65) * (50 / 1.65);
// 计算功率和电能
Calculate_Power(data);
Calculate_Energy(data);
}
// 计算功率参数
void Calculate_Power(PowerData* data) {
// 计算三相有功功率: P = U * I * cosφ
// 这里简化处理,实际需根据相位角计算
data->Pa = data->Ua * data->Ia;
data->Pb = data->Ub * data->Ib;
data->Pc = data->Uc * data->Ic;
// 计算总功率
float P_total = data->Pa + data->Pb + data->Pc;
// 计算功率因数 (简化处理)
data->PFa = (data->Ua != 0 && data->Ia != 0) ? data->Pa / (data->Ua * data->Ia) : 0;
data->PFb = (data->Ub != 0 && data->Ib != 0) ? data->Pb / (data->Ub * data->Ib) : 0;
data->PFc = (data->Uc != 0 && data->Ic != 0) ? data->Pc / (data->Uc * data->Ic) : 0;
// 计算频率 (使用过零检测)
data->Freq = Calculate_Frequency();
}
// 计算电能
void Calculate_Energy(PowerData* data) {
static uint32_t lastTime = 0;
uint32_t currentTime = HAL_GetTick();
float deltaTime = (currentTime - lastTime) / 3600000.0; // 小时
if (lastTime != 0) {
// 累加电能: E = P * t
data->TotalEnergy += (data->Pa + data->Pb + data->Pc) * deltaTime;
}
lastTime = currentTime;
}
3. 通信协议实现(Modbus RTU)
// Modbus寄存器映射
#define REG_VOLTAGE_A 0x0000
#define REG_VOLTAGE_B 0x0001
#define REG_VOLTAGE_C 0x0002
#define REG_CURRENT_A 0x0003
#define REG_CURRENT_B 0x0004
#define REG_CURRENT_C 0x0005
#define REG_POWER_P 0x0006
#define REG_ENERGY 0x0007
#define REG_FREQ 0x0008
#define REG_PF 0x0009
// Modbus RTU帧处理
void Process_Modbus_Frame(uint8_t* frame, uint16_t len) {
uint8_t address = frame[0];
uint8_t function = frame[1];
uint16_t crc = *(uint16_t*)(frame + len - 2);
// 验证CRC
if (Calculate_CRC(frame, len - 2) != crc) return;
// 处理不同功能码
switch (function) {
case 0x03: // 读保持寄存器
Handle_Read_Registers(frame, len);
break;
case 0x06: // 写单个寄存器
Handle_Write_Register(frame, len);
break;
case 0x10: // 写多个寄存器
Handle_Write_Registers(frame, len);
break;
default:
Send_Modbus_Exception(address, function, 0x01); // 非法功能
}
}
// 处理读寄存器请求
void Handle_Read_Registers(uint8_t* frame, uint16_t len) {
uint8_t address = frame[0];
uint16_t startReg = (frame[2] << 8) | frame[3];
uint16_t numRegs = (frame[4] << 8) | frame[5];
// 构建响应帧
uint8_t response[256];
response[0] = address;
response[1] = 0x03;
response[2] = numRegs * 2; // 字节数
// 填充寄存器值
for (int i = 0; i < numRegs; i++) {
uint16_t regValue = Read_Register(startReg + i);
response[3 + i*2] = (regValue >> 8) & 0xFF;
response[4 + i*2] = regValue & 0xFF;
}
// 计算CRC
uint16_t crc = Calculate_CRC(response, 3 + numRegs*2);
response[3 + numRegs*2] = (crc >> 8) & 0xFF;
response[4 + numRegs*2] = crc & 0xFF;
// 发送响应
HAL_UART_Transmit(&huart1, response, 5 + numRegs*2, 100);
}
// 读取寄存器值
uint16_t Read_Register(uint16_t regAddr) {
PowerData data;
Get_Current_PowerData(&data); // 获取当前电力数据
switch (regAddr) {
case REG_VOLTAGE_A: return (uint16_t)(data.Ua * 10);
case REG_VOLTAGE_B: return (uint16_t)(data.Ub * 10);
case REG_VOLTAGE_C: return (uint16_t)(data.Uc * 10);
case REG_CURRENT_A: return (uint16_t)(data.Ia * 100);
case REG_CURRENT_B: return (uint16_t)(data.Ib * 100);
case REG_CURRENT_C: return (uint16_t)(data.Ic * 100);
case REG_POWER_P: return (uint16_t)((data.Pa + data.Pb + data.Pc) * 10);
case REG_ENERGY: return (uint16_t)(data.TotalEnergy);
case REG_FREQ: return (uint16_t)(data.Freq * 10);
case REG_PF: return (uint16_t)(data.PFa * 1000);
default: return 0;
}
}
4. LCD显示驱动
// LCD显示数据结构
typedef struct {
char line1[17]; // 16字符+结束符
char line2[17];
char line3[17];
char line4[17];
} LCD_Display;
// 更新LCD显示
void Update_LCD_Display(PowerData* data) {
LCD_Display display;
// 格式化显示内容
snprintf(display.line1, 17, "Ua:%.1fV Ub:%.1fV", data->Ua, data->Ub);
snprintf(display.line2, 17, "Uc:%.1fV I:%.2fA", data->Uc, (data->Ia+data->Ib+data->Ic)/3);
snprintf(display.line3, 17, "P:%.1fW E:%.1fkWh",
data->Pa+data->Pb+data->Pc, data->TotalEnergy/1000);
snprintf(display.line4, 17, "F:%.1fHz PF:%.2f", data->Freq, data->PFa);
// 发送到LCD
LCD_SetCursor(0, 0);
LCD_PrintString(display.line1);
LCD_SetCursor(1, 0);
LCD_PrintString(display.line2);
LCD_SetCursor(2, 0);
LCD_PrintString(display.line3);
LCD_SetCursor(3, 0);
LCD_PrintString(display.line4);
}
// LCD底层驱动函数
void LCD_SetCursor(uint8_t row, uint8_t col) {
// 实现LCD光标定位
}
void LCD_PrintString(char* str) {
// 实现LCD字符串显示
}
5. 主程序逻辑
int main(void) {
// HAL库初始化
HAL_Init();
// 系统时钟配置
SystemClock_Config();
// 外设初始化
Peripheral_Init();
// 启动ADC采样
Start_ADC_Sampling();
// 初始化LCD
LCD_Init();
LCD_Clear();
LCD_PrintString("三相多功能电表");
HAL_Delay(1000);
// 主循环
PowerData currentData;
while (1) {
// 处理ADC数据
Process_ADC_Data(¤tData);
// 更新显示
Update_LCD_Display(¤tData);
// 处理通信
Process_Communication();
// 检查报警条件
Check_Alarms(¤tData);
// 延时
HAL_Delay(500);
}
}
// 处理通信
void Process_Communication(void) {
uint8_t rxBuffer[256];
uint16_t rxLen;
// 检查UART接收
if (HAL_UART_Receive(&huart1, rxBuffer, sizeof(rxBuffer), 10) == HAL_OK) {
// 处理Modbus帧
Process_Modbus_Frame(rxBuffer, sizeof(rxBuffer));
}
}
// 检查报警条件
void Check_Alarms(PowerData* data) {
// 过压报警
if (data->Ua > 250 || data->Ub > 250 || data->Uc > 250) {
Trigger_Alarm(OVER_VOLTAGE);
}
// 欠压报警
if (data->Ua < 180 || data->Ub < 180 || data->Uc < 180) {
Trigger_Alarm(UNDER_VOLTAGE);
}
// 过流报警
if (fabs(data->Ia) > 30 || fabs(data->Ib) > 30 || fabs(data->Ic) > 30) {
Trigger_Alarm(OVER_CURRENT);
}
// 缺相报警
if (fabs(data->Ia) < 0.1 || fabs(data->Ib) < 0.1 || fabs(data->Ic) < 0.1) {
Trigger_Alarm(PHASE_LOSS);
}
}
// 触发报警
void Trigger_Alarm(AlarmType type) {
// 设置报警灯
HAL_GPIO_WritePin(ALARM_LED_GPIO_Port, ALARM_LED_Pin, GPIO_PIN_SET);
// 发送报警信息
char msg[50];
switch (type) {
case OVER_VOLTAGE: snprintf(msg, sizeof(msg), "过压报警!"); break;
case UNDER_VOLTAGE: snprintf(msg, sizeof(msg), "欠压报警!"); break;
case OVER_CURRENT: snprintf(msg, sizeof(msg), "过流报警!"); break;
case PHASE_LOSS: snprintf(msg, sizeof(msg), "缺相报警!"); break;
}
// 显示报警信息
LCD_Clear();
LCD_PrintString("!!! 报警 !!!");
LCD_SetCursor(1, 0);
LCD_PrintString(msg);
// 蜂鸣器报警
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
}
参考代码 三相多功能电表电路原理图+源码+设计说明 www.youwenfan.com/contentcns/160735.html
四、系统功能
-
基本测量功能:
- 三相电压、电流有效值
- 三相有功/无功/视在功率
- 总电能计量
- 频率、功率因数测量
-
通信功能:
- Modbus RTU协议
- RS485/RS232接口
- 红外通信
- 无线LoRa通信
-
显示功能:
- LCD液晶显示
- LED状态指示
- 背光控制
-
报警功能:
- 过压/欠压报警
- 过流报警
- 缺相报警
- 失压报警
- 逆相序报警
-
数据存储:
- 电能数据冻结
- 历史事件记录
- 参数设置存储
-
安全功能:
- 密码保护
- 防窃电功能
- 自检功能
五、系统特点
-
高精度测量:
- 电压/电流精度:0.5级
- 功率精度:1.0级
- 电能精度:1.0级
-
宽范围测量:
- 电压:0-500V
- 电流:0-100A
- 频率:45-65Hz
-
高可靠性:
- 工业级元器件
- 宽工作温度范围(-25℃~+70℃)
- 抗电磁干扰设计
-
易用性:
- 中文菜单
- 大屏幕LCD显示
- 按键操作
-
扩展性:
- 支持多种通信协议
- 可配置输入输出接口
- 支持固件升级
六、应用实例
1. 工业配电监控
- 工厂配电室
- 变电站
- 工业生产线
2. 商业建筑能源管理
- 商场
- 写字楼
- 酒店
3. 智能电网
- 分布式能源监控
- 微电网管理
- 需求侧响应
七、总结
本三相多功能电表系统通过精心设计的电路和高效的代码实现,实现了对三相交流电力参数的精确测量、显示、存储和通信功能。系统采用模块化设计,各功能独立实现,便于维护和扩展。
系统特点:
- 高精度测量,满足工业级应用需求
- 丰富的通信接口,支持多种组网方式
- 完善的保护和报警功能,确保系统安全
- 友好的用户界面,便于操作和配置
- 工业级设计,适应恶劣工作环境