基于RISC-V的CH32V103智能电表系统开发实践
1. 项目概述
这个项目是基于RISC-V架构的CH32V103开发板为核心控制器,构建的一套完整的单相智能电表系统。作为一名嵌入式开发工程师,我最近完成了这个项目的开发工作,现在将整个实现过程和经验分享给大家。
这个智能电表系统能够实时采集单相电能参数(包括电压、电流、有功功率、无功功率、电能、功率因数等),通过OLED屏幕本地显示,同时通过以太网模块将数据上传至云端平台,实现远程监控和设备控制。整套系统采用了模块化设计,硬件上包含电能计量模块、以太网模块、OLED显示模块等,软件上实现了数据采集、处理、显示和网络通信的全套功能。
2. 硬件系统设计
2.1 核心控制器选型
我们选择了沁恒微电子的CH32V103作为主控芯片,这是一款基于RISC-V架构的32位通用增强型MCU,主要特性包括:
- 最高72MHz主频
- 64KB Flash + 20KB SRAM
- 丰富的外设接口:USART、SPI、I2C等
- 内置硬件CRC计算单元
- 低功耗设计
选择这款芯片主要基于以下考虑:
- RISC-V架构的开源特性降低了开发成本
- 芯片性能完全满足电能数据处理需求
- 内置硬件CRC单元简化了通信协议实现
- 丰富的外设接口方便系统扩展
2.2 电能计量模块
系统采用了IM1253B单相电能计量模块,该模块具有以下特点:
- 支持220V交流电测量
- 可测量电压、电流、功率、电能等参数
- 采用Modbus RTU通信协议
- 精度等级0.5级
模块通过UART接口与主控芯片通信,每秒钟主控会发送读取指令,获取最新的电能数据。
2.3 网络通信模块
为了实现远程监控,系统集成了以太网模块,主要功能包括:
- 通过串口与主控通信
- 支持TCP/IP协议栈
- 可将数据转发至云端服务器
- 支持远程指令接收和执行
我们选择了成熟的商业模块,大大简化了网络通信部分的开发工作。
2.4 显示与人机交互
本地显示采用了0.96寸OLED屏幕,通过I2C接口与主控连接。OLED屏幕具有以下优势:
- 低功耗
- 高对比度
- 宽视角
- 支持多页显示
系统设计了三页显示界面,通过定时自动切换,展示不同的电能参数。
3. 软件架构设计
3.1 主程序流程
主程序采用前后台架构,主要流程如下:
系统初始化
- 时钟配置
- GPIO初始化
- UART初始化
- 定时器初始化
- OLED初始化
主循环
- 处理电能数据采集
- 更新OLED显示
- 处理网络通信
- 执行控制指令
int main(void) { // 系统初始化 DisableGlobalIRQ(); board_init(); gpio_init(B2, GPO, 0, GPIO_PIN_CONFIG); gpio_init(C0, GPO, 1, GPIO_PIN_CONFIG); gpio_init(C1, GPO, 1, GPIO_PIN_CONFIG); uart_init(UART_1, 4800, UART1_TX_A9, UART1_RX_A10); // 电能计量模块 uart_init(UART_2, 115200, UART2_TX_A2, UART2_RX_A3); // 以太网模块 U_OLED_Init(); timer_pit_interrupt_ms(TIMER_1, 10); EnableGlobalIRQ(0); // 主循环 while (1) { // OLED显示处理 if (U_Tim_Count > 250) { U_Tim_Count = 0; OLED_Show_Change++; if (OLED_Show_Change > 2) OLED_Show_Change = 0; } // 显示页面切换 switch (OLED_Show_Change) { case 0: U_Show_IM1253B_Data1(1, U_IM1253B_Data); break; case 1: U_Show_IM1253B_Data2(0, U_IM1253B_Data); break; case 2: U_Show_IM1253B_Data3(1, U_IM1253B_Data); break; } // 定时采集电能数据 if (MCU_Interrupt0_Timer_1S_End) { U_Send_RendCommand_IM1253B(); MCU_Interrupt0_Timer_1S_End = 0; U_Send_Ethernet_Data(); systick_delay_ms(100); U_Send_Ethernet_Data2(); } U_Calculation_IM1253B_Data(); receive_key(); } }3.2 电能数据采集
电能计量模块采用Modbus RTU协议通信,主控每秒钟发送读取指令,获取电能数据。数据采集流程如下:
- 主控发送读取指令
- 电能模块返回数据帧
- 主控接收并校验数据
- 数据解析和计算
void U_Send_RendCommand_IM1253B(void) { uint8_t ReadCommad[8] = {0x01, 0x03, 0x00, 0x48, 0x00, 0x08, 0xc4, 0x1a}; for (uint8_t i = 0; i < 8; i++) { uart_putchar(UART_1, ReadCommad[i]); systick_delay_ms(1); } }数据接收通过串口中断实现,接收完成后进行CRC校验:
void USART1_IRQHandler(void) { static uint8_t U_GetData; uart_query(UART_1, &U_GetData); USART_ClearITPendingBit(USART1, USART_IT_RXNE); U_MCU_UART1_GetData_End = U_Get_IM1253B_Data(U_GetData); }3.3 网络通信实现
网络通信部分主要负责将电能数据上传至云端,并接收远程控制指令。通信流程如下:
- 主控将电能数据打包
- 通过串口发送给以太网模块
- 以太网模块将数据转发至云端
- 接收云端下发的控制指令
数据打包函数示例:
void U_Send_Ethernet_Data(void) { uint8_t U_Send_Ethernet_Data[45] = {0x01, 0x46, 0x00, 0x00, 0x00, 0x10, 0x20}; Float_Data_Arry_Change_uchar(U_Send_Ethernet_Data, U_IM1253B_Data_Float,10); U_GetCrcData(U_Send_Ethernet_Data, 39); uart_putbuff(UART_2, U_Send_Ethernet_Data, 41); }指令接收处理:
uint8_t U_Get_Ethernet_Data(uint8_t Get_Data) { static uint8_t i = 0; static uint8_t E_Data_Buf[8] = {0}; E_Data_Buf[i++] = Get_Data; if (E_Data_Buf[0] != 0x01) i = 0; if ((i == 2) && (E_Data_Buf[1] != 0x05)) i = 0; if ((i == 3) && (E_Data_Buf[2] != 0x00)) i = 0; if ((i == 4) && (E_Data_Buf[3] != 0x00)) i = 0; if(i == 8) { memcpy(Ethernet_Data_Buf, E_Data_Buf, 9); // 执行控制指令 if(Ethernet_Data_Buf[4] == 0xFF) { // 开启设备 gpio_write(C3, 1); } else { // 关闭设备 gpio_write(C3, 0); } } }4. 云端平台配置
我们使用了有人云平台作为远程监控端,主要配置步骤如下:
- 创建设备模板,定义数据点
- 配置通信协议(Modbus RTU over TCP)
- 设计监控界面
- 配置报警规则
- 设置用户权限
云端平台可以实时显示电能数据,支持历史数据查询,并能下发控制指令。平台还提供了手机APP和小程序,方便随时随地监控设备状态。
5. 系统测试与优化
5.1 功能测试
系统测试主要包括以下几个方面:
- 电能数据采集准确性测试
- OLED显示功能测试
- 网络通信稳定性测试
- 远程控制功能测试
- 系统长时间运行稳定性测试
测试结果表明,系统各项功能均达到设计要求,数据采集准确,通信稳定,控制可靠。
5.2 性能优化
在开发过程中,我们进行了以下优化:
- 数据采集间隔优化:平衡了数据实时性和系统负载
- 通信协议优化:减少了不必要的数据传输
- 显示刷新策略优化:降低了OLED屏幕刷新频率
- 中断处理优化:确保关键任务及时响应
6. 开发经验分享
6.1 关键问题与解决方案
电能数据跳变问题
- 现象:采集到的电压、电流值偶尔出现跳变
- 原因:电源干扰导致计量模块工作不稳定
- 解决:增加电源滤波电容,优化PCB布局
网络通信丢包问题
- 现象:云端偶尔收不到数据
- 原因:串口通信缓冲区溢出
- 解决:增加流控机制,优化数据发送间隔
OLED显示闪烁问题
- 现象:屏幕切换时出现闪烁
- 原因:直接清屏导致
- 解决:采用局部刷新策略,避免全屏清空
6.2 实用技巧
- Modbus CRC校验优化利用CH32V103内置的硬件CRC单元,可以大幅提高校验效率:
uint16_t Calc_CRC16(uint8_t *pBuf, uint16_t len) { CRC_ResetDR(); for(uint16_t i=0; i<len; i++) { CRC->DR = pBuf[i]; } return CRC->DR; }- 数据打包技巧浮点数传输时,可以将其转换为4字节传输,接收端再还原:
void FloatToBytes(float f, uint8_t *bytes) { union { float f; uint8_t b[4]; } u; u.f = f; memcpy(bytes, u.b, 4); }- 低功耗设计在不需要实时显示的场合,可以降低MCU主频,关闭不必要的外设,显著降低系统功耗。
7. 项目扩展方向
这个智能电表系统还有很大的扩展空间:
增加三相电能测量功能通过选用三相电能计量模块,可以扩展为三相电表系统。
本地数据存储增加SD卡或Flash存储,实现电能数据本地记录。
无线通信支持增加Wi-Fi或4G模块,提供更灵活的组网方式。
电能质量分析增加谐波分析、电压波动等电能质量监测功能。
预付费功能实现IC卡预付费或远程充值功能。
这个项目完整展示了基于RISC-V MCU的嵌入式系统开发流程,从硬件选型、软件设计到系统集成和测试。在实际开发过程中,我深刻体会到良好的架构设计和细致的调试工作对项目成功的重要性。希望这个分享能给正在开发类似项目的朋友一些参考和启发。
