pvcharger.c
inverter_pvcharger_info_handle()(第 159 行)4.2 本地采集:pvcharger_local_info_handle()(第 44 行)4.3 主机广播:pvcharger_send_host_machine_info()(第 101 行)4.4 从机接收与心跳:pvcharger_from_machine_recv_sync()(第 146 行)4.5 从机数据处理(inverter_pvcharger_info_handle 的 else 分支,第 168-245 行)4.6 pvcharger_read_* 系列:纯访问器4.7 关键全局变量的读写关系5. 对外接口5.1 本文件导出的函数5.2 本文件导出的全局变量5.3 本文件调用的外部函数/变量6. 依赖关系6.1 依赖(本文件包含/使用的模块)6.2 被依赖7. 备注与风险点源文件路径:
midware/inverter/pvcharger.c所属模块:midware/inverter(逆变器中间件 / PV 充电器模式) 代码行数:514
1. 文件职责
本文件实现 EMS 的"PV 充电器"模式数据通路:把电池数据(无论来自本地 BMS 还是来自外部 Modbus 主机)统一收敛成一张 PVCHARGR_INFO_T 表,并对充放电能力做安全限值处理,再发布给下游使用。它处于"电池/BMS 与外部 Modbus 主机 → 统一电池信息表 → 能量调度与 Modbus 从机寄存器"的中间转换层。角色由 g_t_inv_info.t_config_data.u8_pv_charger_mode 决定:非 PVCHARGR_FROM_E 时由本地 BMS 填表(pvcharger_local_info_handle),为 PVCHARGR_FROM_E 时由外部 Modbus 主机写入的 g_modbus_pvchargr_info 经换算得到结果;另外提供主机侧的 Modbus 广播发送(pvcharger_send_host_machine_info)。驱动来源是 inverter.c:1168 的逆变器任务(周期调用 inverter_pvcharger_info_handle)与 interface.c:328(触发主机广播),从机侧收帧由 modbus.c:8073-8103 的寄存器写回调反向通知(pvcharger_from_machine_recv_sync)。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
PVCHARGR_INFO_T | 结构体(pvcharger.h:49-69,#pragma pack(1)) | 电池信息主表,字段顺序即 Modbus 寄存器顺序(状态位、SOC、电压、电流、功率、充放最大功率、充放截止电压/限流、型号、额定电压/容量/DOD、瞬时额定电压、充放电第一段限流) |
BATTERY_STATE_U | 联合体(pvcharger.h:25-37) | 电池状态位域(u16):bit_bms_comm_flag:2、bit_bms_work_flag:4、bit_bms_relay_flag:2、bit_bms_upgrade_flag:2、bit_bat_ready_flag:2、bit_reserve_flag:4 |
BATTERY_TYPE_U | 联合体(pvcharger.h:39-47) | 电池类型(u16):byte_battery_series / byte_battery_model |
PVCHARGR_MODE_E | 枚举(pvcharger.h:17-22) | PVCHARGR_SINGLE_E=0 / PVCHARGR_FROM_E=1 / PVCHARGR_HOST_E=2 |
g_modbus_pvchargr_info | 全局变量(第 25 行) | 从机角色下由外部 Modbus 主机写入的原始寄存器镜像 |
g_control_pvchargr_info | 全局变量(第 26 行,头文件未 extern) | 中间"受控量":把 g_modbus_pvchargr_info 的充电功率 /4 并夹到逆变器额定值后暂存 |
g_inverter_pvchargr_info | 全局变量(第 27 行) | 对下游发布的最终数据;本地模式由 BMS 直接填,从机模式由 g_control_pvchargr_info 拷贝而来 |
s_u8_pvcharger_comm_flag | static(第 29 行) | PV 充电器通信健康标志,初值 TRUE;15 s 无帧置 FALSE |
s_u32_pvcharger_recv_tick | static(第 30 行) | 最后一次收到外部主机帧的 tick;pvcharger_from_machine_recv_sync 刷新 |
PVCHARGR_BROADCAST_ADDR | 宏(modbus.h:21) | 0,PV 充电器广播地址(主机→从机) |
FUNC_WRITE_REGISTER | 宏(modbus.h:26) | 0x10,Modbus 写多个保持寄存器功能码 |
REG_PV_CHARGER_BATTERY_STATE_E | 宏(modbus.h:1298) | 0x2340,PV 充电器电池状态起始寄存器 |
REG_PV_CHARGER_CONFIG_MAX_E | 宏(modbus.h:1314) | 寄存器区间上界(不含),MAX - BATTERY_STATE 即需要下发的寄存器个数 |
buff_send_modbus[] | 全局数组(modbus.c 定义) | Modbus 发送缓冲区,pvcharger_send_host_machine_info 直接借用组帧 |
ems_set_fault_bit | 函数(data.c:338) | 置/清 g_t_ems_info.u_ems_fault.u32_all 的某一位 |
UPDT_BMS / Get_Status_Is_Updated_From_Server / GetPercentDownloadBMS / IsDownloadBMS | 宏/函数(upd_download.h、bms_download.h) | BMS 升级状态标志来源 |
FORCE_CHG_FORBID_DISCHG_E / FORCE_CHG_ALLOW_DISCHG_E | 宏(bms.h) | BMS 强制充电相关状态(本文件未用到,见 parallel.c 同类判定) |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
pvcharger_local_info_handle | static,第 44 行 | 从本地 BMS 采集全部电池信息填入 g_inverter_pvchargr_info,并做状态位与限值归零 |
pvcharger_send_host_machine_info | 全局,第 101 行 | 以 Modbus 功能码 0x10 广播本机电池寄存器区间给外部从机,500 tick 限流 |
pvcharger_from_machine_recv_sync | 全局,第 146 行 | 置通信健康标志 TRUE 并刷新接收时间戳(由 Modbus 写回调触发) |
inverter_pvcharger_info_handle | 全局,第 159 行 | 主入口:按角色选数据源,从机模式做 15 s 超时/换算/夹紧,最后置故障位 22 |
pvcharger_read_machine_mode | 全局,第 259 行 | 返回配置的 PV 充电器角色 |
pvcharger_read_bat_connect_state | 全局,第 271 行 | 返回 bit_bms_comm_flag |
pvcharger_read_bat_work_state | 全局,第 283 行 | 返回 bit_bms_work_flag |
pvcharger_read_bat_relay_state | 全局,第 295 行 | 返回 bit_bms_relay_flag |
pvcharger_read_bat_soc | 全局,第 307 行 | 返回 u16_battery_soc |
pvcharger_read_bat_volt | 全局,第 319 行 | 返回 s16_battery_volt |
pvcharger_read_bat_curr | 全局,第 331 行 | 返回 s16_battery_curr |
pvcharger_read_bat_power | 全局,第 343 行 | 返回 s32_battery_power |
pvcharger_read_bat_max_charge_power | 全局,第 355 行 | 返回 s32_battery_max_charge_power |
pvcharger_read_bat_max_dischg_power | 全局,第 367 行 | 返回 s32_battery_max_dischg_power |
pvcharger_read_bat_charge_cut_off_volt | 全局,第 379 行 | 返回 s16_battery_charge_cut_off_volt |
pvcharger_read_bat_max_charge_current | 全局,第 391 行 | 返回 s16_battery_max_charge_current |
pvcharger_read_bat_dischg_cut_off_volt | 全局,第 403 行 | 返回 s16_battery_dischg_cut_off_volt |
pvcharger_read_bat_max_dischg_current | 全局,第 415 行 | 返回 s16_battery_max_dischg_current |
pvcharger_read_bat_series | 全局,第 427 行 | 返回 byte_battery_series |
pvcharger_read_bat_model | 全局,第 439 行 | 返回 byte_battery_model |
pvcharger_read_bat_rated_volt | 全局,第 451 行 | 返回 u16_battery_rated_volt |
pvcharger_read_bat_rated_volt_instant | 全局,第 463 行 | 返回 u16_battery_rated_volt_instant |
pvcharger_read_bat_charge_pro_cur_step_1 | 全局,第 475 行 | 返回 u16_charge_pro_cur_step_1 |
pvcharger_read_bat_discharge_pro_cur_step_1 | 全局,第 487 行 | 返回 u16_discharge_pro_cur_step_1 |
pvcharger_read_bat_rated_capacity | 全局,第 499 行 | 返回 u32_battery_rated_capacity |
pvcharger_read_bat_rated_dod | 全局,第 511 行 | 返回 u8_battery_rated_dod |
4. 核心逻辑解析
4.1 主状态机:inverter_pvcharger_info_handle()(第 159 行)
只有一个二分支角色判断,没有多状态迁移:
if (g_t_inv_info.t_config_data.u8_pv_charger_mode != PVCHARGR_FROM_E)
/* 单机 / 主机 分支 */
pvcharger_local_info_handle(); // 由本地 BMS 填表
s_u8_pvcharger_comm_flag = TRUE; // 永远视为通信正常
s_u32_pvcharger_recv_tick = OSTimeGet();
else
/* PVCHARGR_FROM_E 分支:本机是外部 Modbus 主机的从机 */
...
ems_set_fault_bit(22, (s_u8_pvcharger_comm_flag == FALSE));
关键点:非从机模式下通信健康标志被无条件置真并刷新时间戳(第 164-165 行),因此故障位 22 只在 PVCHARGR_FROM_E 模式下才可能被置位。这是"单机模式不存在通信"的自然结果,但也意味着故障位 22 的语义严格是"PV 充电器从机模式通信丢失"。
4.2 本地采集:pvcharger_local_info_handle()(第 44 行)
逐字段从 BMS 取数(单位换算点见下表),共 6 组:
| 目标字段 | 来源 | 备注 | ||
|---|---|---|---|---|
bit_bms_comm_flag | bms_get_connect_state() | |||
bit_bms_work_flag | bms_read_work_status() | 4 bit 位域,可容纳多档工况 | ||
bit_bms_relay_flag | bms_read_relay_status() | |||
bit_bms_upgrade_flag | `Get_Status_Is_Updated_From_Server(UPDT_BMS) \ | \ | (GetPercentDownloadBMS() > 50 && IsDownloadBMS())` | 与 parallel.c:261 同一判据:"云端已标记升级"或"下载进度已过 50% 且正在下载" |
bit_bat_ready_flag | bms_get_ready_enable() | |||
u16_battery_soc | bms_read_total_soc() | 单位 0.1% | ||
s16_battery_volt | bms_read_total_volt() / 10 | 唯一做了单位换算的字段:BMS 给 0.1 V,这里转成 1 V | ||
s16_battery_curr | bms_read_total_cur() | |||
s32_battery_power | bms_read_total_power() | |||
s32_battery_max_charge_power / _dischg_power | bms_read_max_charge_power() / bms_read_max_dischg_power() | |||
s16_battery_charge_cut_off_volt / _max_charge_current | bms_read_chg_cut_rate_volt() / bms_read_chg_max_rate_cur() | |||
s16_battery_dischg_cut_off_volt / _max_dischg_current | bms_read_dischg_cut_rate_volt() / bms_read_dischg_max_rate_cur() | |||
byte_battery_series / byte_battery_model | bms_read_battery_series_para_state() / bms_get_store_type() | |||
u16_battery_rated_volt / _rated_volt_instant | bms_cell_rated_vot() / bms_read_rated_vot_instant() | |||
u16_charge_pro_cur_step_1 / u16_discharge_pro_cur_step_1 | bms_read_charge_pro_cur_step_1() / bms_read_discharge_pro_cur_step_1() | |||
u32_battery_rated_capacity | bms_read_battery_capacity() | |||
u8_battery_rated_dod | bms_read_battery_available_capacity() | 名字是 DOD,取的是"可用容量" |
采集完做两级归零:
第一级(第 76-80 行)——"电池就绪"短路 BMS 状态位:
if (bit_bat_ready_flag != FALSE) {
bit_bms_comm_flag = FALSE;
bit_bms_work_flag = FALSE;
}
第二级(第 82-91 行)——任一门禁触发即清零全部能力量:
if (bit_bms_comm_flag == FALSE || bit_bms_work_flag == FALSE ||
bit_bms_upgrade_flag != FALSE || bit_bat_ready_flag != FALSE) {
s32_battery_max_charge_power = 0;
s32_battery_max_dischg_power = 0;
s16_battery_max_charge_current = 0;
s16_battery_max_dischg_current = 0;
}
因为第一级已经把 bit_bat_ready_flag != FALSE 时的前两位清成 FALSE,所以第二级的条件在这个场景下必然成立——"电池就绪"等价于"禁止一切充放电"。这是本文件最需要注意的语义。
4.3 主机广播:pvcharger_send_host_machine_info()(第 101 行)
定时(第 107-113 行):
static u32 s_u32_send_tick = 0;
if (abs(OSTimeGet() - s_u32_send_tick) < 500) return; // 500 tick 限流
s_u32_send_tick = OSTimeGet();
组帧(Modbus RTU,功能码 0x10 写多个保持寄存器):
| 偏移 | 内容 |
|---|---|
| 0 | PVCHARGR_BROADCAST_ADDR(0x00,广播地址) |
| 1 | FUNC_WRITE_REGISTER(0x10) |
| 2-3 | 起始寄存器 REG_PV_CHARGER_BATTERY_STATE_E(0x2340)大端 |
| 4-5 | 寄存器个数 = REG_PV_CHARGER_CONFIG_MAX_E - REG_PV_CHARGER_BATTERY_STATE_E 大端 |
| 6 | 数据字节数 = 寄存器个数 × 2 |
| 7+ | 各寄存器值,逐个大端两字节 |
| 末尾 2 字节 | CRC16(低字节在前) |
取值方式(第 124-130 行)是逐寄存器调 get_para_from_reg_addr(PVCHARGR_BROADCAST_ADDR, reg)——即用"寄存器地址"为键向 Modbus 模块索取本机值,而不是直接读 g_inverter_pvchargr_info 字段。这保证了"主机广播的寄存器映射"和"从机接收的寄存器映射"共用同一张表,是这套设计能自洽的关键。CRC 用 GetCrcCode_Modbus(),最后 modbus_send_data() 发出。
4.4 从机接收与心跳:pvcharger_from_machine_recv_sync()(第 146 行)
只有两行:
s_u8_pvcharger_comm_flag = TRUE;
s_u32_pvcharger_recv_tick = OSTimeGet();
由 modbus.c:8103 在写寄存器回调处理完 s32_battery_max_charge_power 时调用(即"外部主机每写一次寄存器区间就算一次心跳")。因为没有独立的收帧中断,心跳的粒度取决于主机写频率。
4.5 从机数据处理(inverter_pvcharger_info_handle 的 else 分支,第 168-245 行)
按顺序执行 6 步:
步骤 1:15 s 超时检测(第 169-176 行)
if (abs(s_u32_pvcharger_recv_tick - OSTimeGet()) >= 15000) { // 15 s 无帧
if (s_u8_pvcharger_comm_flag != FALSE) { // 只在"由好变坏"的沿上清一次
s_u8_pvcharger_comm_flag = FALSE;
memset(&g_modbus_pvchargr_info, 0x00, sizeof(PVCHARGR_INFO_T));
}
}
用"当前标志是否为真"做边沿检测,避免每一拍都 memset;g_modbus_pvchargr_info 清零后后续步骤自然得到全 0 结果。
步骤 2:拷贝并换算充电功率(第 178-183 行)
g_control_pvchargr_info = g_modbus_pvchargr_info; // 整表拷贝
g_control_pvchargr_info.s32_battery_max_charge_power = g_modbus_pvchargr_info.s32_battery_max_charge_power / 4;
g_control_pvchargr_info.s32_battery_max_charge_power = MIN(该值, inverter_read_rated_dc_charge_power());
g_control_pvchargr_info.s32_battery_max_dischg_power = MIN(该值, inverter_read_rated_dc_discharge_power());
/4 是一个无注释的魔法数(见第 7 节):充电功率被除以 4,而放电功率不作除——两者处理不对称。随后两个功率分别夹到逆变器额定 DC 充/放功率。
步骤 3:与本地采集同构的两级归零(第 185-200 行)——把 bit_bat_ready_flag 短路与"任一门禁清零"逻辑在 g_control_pvchargr_info 上重放一遍。注意这里是重复代码:同样的判据在第 76-91 行已经写过一次,只是作用对象不同。
步骤 4:负值钳位(第 202-220 行)——4 个字段分别 if (< 0) = 0:s32_battery_max_charge_power、s16_battery_max_charge_current、s32_battery_max_dischg_power、s16_battery_max_dischg_current。这 4 句是逐字段展开的同一段逻辑,可用循环或 if (<0) =0 一行处理。
步骤 5:发布(第 222 行)——g_inverter_pvchargr_info = g_control_pvchargr_info; 整表拷出。
步骤 6(第 249 行,两个分支之外):ems_set_fault_bit(22, (s_u8_pvcharger_comm_flag == FALSE));
注意:步骤 4 只夹紧了"能力量",没有夹紧 u16_battery_soc、s16_battery_volt 等状态量,这些字段直接来自外部主机,未经合理性校验。
4.6 pvcharger_read_* 系列:纯访问器
第 259-514 行共 23 个函数,除 pvcharger_read_machine_mode 读配置外,其余 22 个全部是 return g_inverter_pvchargr_info.<字段>; 的单行直读,没有任何判空、单位换算或范围检查。它们的存在意义是让 g_inverter_pvchargr_info 可以保持为全局变量而外部模块通过函数取数(一种弱封装),但实际上 modbus.c 是直接访问 g_inverter_pvchargr_info 字段的,两种风格并存。
4.7 关键全局变量的读写关系
| 变量 | 写方 | 读方 | 触发条件 |
|---|---|---|---|
g_modbus_pvchargr_info | modbus.c:8073-8135 寄存器写回调(逐字段,32 位分高低字两次写);本文件第 174 行 memset 清零 | 本文件第 178-183 行 | 外部主机下发 / 15 s 超时 |
g_control_pvchargr_info | 本文件第 178-220 行 | 本文件第 222 行 | 每周期从机模式 |
g_inverter_pvchargr_info | 本文件第 46-91 行(本地模式)、第 222 行(从机模式) | 本文件 pvcharger_read_* 全系列;modbus.c:5260-5321 | 每周期 |
s_u8_pvcharger_comm_flag | 第 148 行置 TRUE(收帧)、第 164 行置 TRUE(非从机模式)、第 173 行置 FALSE(超时) | 第 171、249 行 | 收帧 / 超时 / 角色 |
s_u32_pvcharger_recv_tick | 第 149、165 行 | 第 169 行 | 收帧 / 角色 |
buff_send_modbus[] | 第 115-135 行组帧 | modbus_send_data 发出 | 每 500 tick(主机模式) |
g_t_ems_info.u_ems_fault.u32_all 第 22 位 | 第 249 行 | 告警上报 | 每周期 |
5. 对外接口
5.1 本文件导出的函数
pvcharger_send_host_machine_info、pvcharger_from_machine_recv_sync、inverter_pvcharger_info_handle、pvcharger_read_machine_mode,以及 22 个 pvcharger_read_bat_*(完整清单见第 3 节)。唯一静态函数是 pvcharger_local_info_handle。
主要调用方:
| 调用方 | 用到的接口 |
|---|---|
midware/inverter/inverter.c:1168 | inverter_pvcharger_info_handle()(逆变器任务周期) |
midware/interface/interface.c:328 | pvcharger_send_host_machine_info() |
midware/interface/modbus/modbus.c:8103 | pvcharger_from_machine_recv_sync() |
midware/interface/modbus/modbus.c:8461,8491 | pvcharger_read_machine_mode() |
5.2 本文件导出的全局变量
g_modbus_pvchargr_info(pvcharger.h:72已 extern)g_inverter_pvchargr_info(pvcharger.h:73已 extern)g_control_pvchargr_info(仅本文件定义,头文件未 extern)
5.3 本文件调用的外部函数/变量
按 #include(第 13-20 行)分组:
| 来源模块 | 使用的函数/变量 |
|---|---|
inverter.h | inverter_read_rated_dc_charge_power、inverter_read_rated_dc_discharge_power、g_t_inv_info |
bms.h | bms_get_connect_state、bms_read_work_status、bms_read_relay_status、bms_get_ready_enable、bms_read_total_soc/volt/cur/power、bms_read_max_charge_power、bms_read_max_dischg_power、bms_read_chg_cut_rate_volt、bms_read_chg_max_rate_cur、bms_read_dischg_cut_rate_volt、bms_read_dischg_max_rate_cur、bms_read_battery_series_para_state、bms_get_store_type、bms_cell_rated_vot、bms_read_rated_vot_instant、bms_read_charge_pro_cur_step_1、bms_read_discharge_pro_cur_step_1、bms_read_battery_capacity、bms_read_battery_available_capacity |
upd_download.h | Get_Status_Is_Updated_From_Server、UPDT_BMS |
bms_download.h | GetPercentDownloadBMS、IsDownloadBMS |
modbus.h | buff_send_modbus、get_para_from_reg_addr、modbus_send_data、PVCHARGR_BROADCAST_ADDR、FUNC_WRITE_REGISTER、REG_PV_CHARGER_BATTERY_STATE_E、REG_PV_CHARGER_CONFIG_MAX_E |
data.h | ems_set_fault_bit |
crc.h | GetCrcCode_Modbus |
pvcharger.h / chip.h / includes.h | PVCHARGR_INFO_T、OSTimeGet、abs、memset、TRUE/FALSE |
6. 依赖关系
6.1 依赖(本文件包含/使用的模块)
pvcharger.h、inverter.h、bms.h、upd_download.h、bms_download.h、modbus.h、data.h、crc.h。
依赖方向:pvcharger.c → {bms(本地电池数据 + 升级状态)、inverter(额定 DC 充放功率)、modbus(寄存器取值、发送缓冲、发送函数)、data(故障位)}。
6.2 被依赖
midware/inverter/inverter.c(周期驱动inverter_pvcharger_info_handle)midware/interface/interface.c(调用主机广播)midware/interface/modbus/modbus.c(读写三个全局结构体、调用pvcharger_from_machine_recv_sync与pvcharger_read_machine_mode、把g_inverter_pvchargr_info作为 Modbus 从机寄存器源)
7. 备注与风险点
- "电池就绪"等价于"禁止一切充放电",且该逻辑被写了两遍。第 76-91 行(
g_inverter_pvchargr_info)与第 185-200 行(g_control_pvchargr_info)是同一段判据的复制粘贴。第一级把bit_bat_ready_flag为真时的bit_bms_comm_flag/bit_bms_work_flag强清为 FALSE,第二级的条件因而必然成立——bit_bat_ready_flag == TRUE的净效果是把最大充/放功率与最大充/放电流全部清零。如果bms_get_ready_enable()的语义是"电池准备好、可以接受功率指令",那么这段代码的方向是相反的。需要以 BMS 侧实现来判定,但从纯代码看这是可疑写法。
- 充电功率
/4而放电功率不除(第 180 行)。g_control_pvchargr_info.s32_battery_max_charge_power = g_modbus_pvchargr_info.s32_battery_max_charge_power / 4;没有注释,且同一段代码里紧邻的放电功率没有对应除法(第 183 行只做MIN)。若/4的意图是"外部主机上报的是 4 机总量、本机取 1/4 份额",那么放电功率同样应该除 4,否则本机在放电方向上会企图承担 4 倍能力。这是一个高风险的不对称。
- 手工展开的负值钳位(第 202-220 行)。4 个字段 4 个
if (< 0) = 0,没有覆盖u16_battery_soc、s16_battery_volt、s16_battery_curr、s32_battery_power、截止电压、额定电压、容量等字段。来自外部 Modbus 主机的状态量完全没有合理性校验,会被原样发布给modbus.c:5260-5321的从机寄存器与下游读取方。
g_control_pvchargr_info是未导出的全局变量。定义在pvcharger.c:26,头文件没有extern,本文件之外无人使用。应改为static,否则既污染全局命名空间又给外部"绕过限值处理直接读写中间量"留了后门。
buff_send_modbus[]是 Modbus 模块的共享全局缓冲区。pvcharger_send_host_machine_info()直接往里面组帧并调用modbus_send_data(),而 Modbus 任务/外部 485 通道同样在使用这个缓冲区。1600 字节左右的区域没有互斥保护,若主机广播(interface.c:328触发)与 Modbus 从机响应/轮询并发,存在组帧被覆盖的风险。由于调用点interface.c:328上下文是"EVC(充电桩)配置分支"之后紧接着的OSTimeDlyHMSM(0,0,0,100),看起来是靠任务时序错开的。
- 心跳粒度依赖外部主机的写行为。
pvcharger_from_machine_recv_sync()只在 Modbus 写寄存器回调里被调用(modbus.c:8103),且调用点在"s32_battery_max_charge_power低字写完之后"。如果外部主机只读不写、或写入的寄存器区间不覆盖该点,心跳不会刷新,15 s 后会被误判为通信丢失并把g_modbus_pvchargr_info清零。
s_u32_pvcharger_recv_tick的abs()比较(第 169 行)。OSTimeGet()返回INT32U,相减后传给abs();tick 回绕时该判据行为不可靠(parallel.c:1781有专门的回绕保护,本文件没有)。
emulator级的printf调试代码被注释保留了 22 行(第 224-245 行),且是用/* */块注释包住的printf。这类"随时准备打开"的调试代码长期留在源码里会导致误开启后阻塞任务,属版本遗留。
- 单位换算只做了一处。
s16_battery_volt = bms_read_total_volt() / 10(第 53 行)把 BMS 的 0.1 V 转成 1 V;而 SOC、电流、功率、截止电压、额定电压、容量等字段没有任何换算注释或缩放。同一结构体内不同字段单位不一致,且结构体定义(pvcharger.h)里也没有单位说明。
REG_PV_CHARGER_BATTERY_STATE_E处的寄存器个数由宏相减得到(第 119-121 行)。REG_PV_CHARGER_CONFIG_MAX_E - REG_PV_CHARGER_BATTERY_STATE_E被计算 3 次,且"数据字节数"字段直接写(寄存器个数) * 2(没有先转u8,赋给buff_send_modbus[]的u8元素时隐式截断)。若寄存器区间超过 127 个,字节数字段会溢出。当前区间远小于该值,但这是一个隐式截断点。
for (int i = 0; ...)使用 C99 循环内声明(第 124 行、第 1131 行等同类写法在parallel_sci.c也有)。Keil MDK 默认 C90 模式下会报错,说明工程实际开启了 C99(或--c99);这是编译配置依赖点,不是缺陷,但更换工具链时需注意。