parallel_sci.h
REG_PARALLEL_QUERY_MODBUS_E 遥测段(0x00~0x33)分组2.2 REG_PARALLEL_QUERY_MODBUS_E 控制段(0x50~0x6E)分组2.3 编码包装3. 函数清单4. 核心逻辑解析4.1 组网三段式握手(三段码 + 广播地址)4.2 普通 Modbus 状态机的状态划分与"反序"CRC4.3 组网状态机的状态划分4.4 寄存器表的双向复用4.5 与 uCOS-II 任务/同步机制的配合5. 对外接口5.1 本文件导出5.2 使用方5.3 本文件依赖6. 依赖关系7. 备注与风险点源文件路径:
midware/inverter/parallel_comm/parallel_sci.h所属模块:midware/inverter/parallel_comm(并机通信 / SCI 串口通道) 代码行数:160
1. 文件职责
本文件是 EMS 并机 SCI(串口 Modbus-RTU)通道的协议字典与状态机状态枚举集合,配合 parallel_sci.c 使用。它规定了三类内容:一是 Modbus 通信常量(主机/从机地址、功能码 0x03/0x10、寄存器区起始地址与数量),二是组网三段式握手的功能码(0x41 组网开始 / 0x42 地址分配 / 0x43 组网完成)与广播地址,三是并机寄存器地址总表 REG_PARALLEL_QUERY_MODBUS_E —— 这张表同时被 parallel_sci.c 的读映射(Parallel_get_para_from_reg_addr)与写映射(Parallel_Set_Para_to_Reg_Addr)当作 switch 标签,是"Modbus 寄存器号 ↔ 结构体字段"映射的唯一权威来源。
此外本文件用两个 enum 把 parallel_sci.c 中两个接收状态机的状态点显式命名,使状态迁移可读。文件本身不含任何代码,被 parallel_sci.c 与 midware/inverter/parallel.c 包含。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
PARALLEL_HOST_MACHINE_ADDRESS | 宏 = 0x01(第 15 行) | 主机 Modbus 地址常量。parallel_sci.c 全文未引用,实际主机地址在 CAN/SCI 两种协议里都恒为 0(广播地址) |
PARALLEL_FROM_MACHINE_ADDRESS | 宏 = 0x02(第 16 行) | 从机 Modbus 地址常量。同样未被引用,从机地址由组网过程动态分配(g_t_from_machine_networking_info.u8_parallel_addr) |
PARALLEL_HOST_MACHINE_READ_CODE | 宏 = 0x03(第 17 行) | Modbus 功能码"读保持寄存器",主机读从机遥测、从机用它组应答帧 |
PARALLEL_HOST_MACHINE_WRITE_MULTI_CODE | 宏 = 0x10(第 18 行) | Modbus 功能码"写多个保持寄存器",主机下发控制量 |
PARALLEL_QUERY_DATA_REGISTER_ADDRESS | 宏 = 0x00(第 19 行) | 遥测区(常规数据)起始寄存器地址 |
PARALLEL_QUERY_DATA_NUM | 宏 = 52(第 20 行) | 遥测区寄存器数量,覆盖寄存器 0x00~0x33;对应 Modbus 应答的 104 字节数据域 |
PARALLEL_CONTROL_DATA_REGISTER_ADDRESS | 宏 = 0x50(第 21 行) | 控制区起始寄存器地址 |
PARALLEL_CONTROL_DATA_NUM | 宏 = 31(第 22 行) | 控制区寄存器数量,覆盖寄存器 0x50~0x6E;对应主机写帧 62 字节数据域 |
PARALLEL_NETWORKING_CODE | 宏 = 0x41(第 23 行) | 组网开始指令(主机广播 / 从机应答复用同一码) |
PARALLEL_NET_ASSIGN_CODE | 宏 = 0x42(第 24 行) | 地址分配指令(主机 → 指定 uid 的从机) |
PARALLEL_NET_COMPLETE_CODE | 宏 = 0x43(第 25 行) | 组网完成指令(从机 → 主机,确认已采纳地址) |
PARALLEL_BROADCAST_ADDRESS | 宏 = 0x00(第 26 行) | 广播地址;也是组网帧首字节与主机在 CAN_ID 上的地址 |
E_MODBUS_Recv_Parallel_State | 枚举(第 30-44 行) | 普通 Modbus 帧接收状态机状态。PARALLEL_ADDR_M(0) 等地址 → PARALLEL_FUNC_M(1) 判功能码 → PARALLEL_REGISTER_BITS_8_15(2)/PARALLEL_REGISTER_BITS_0_7(3) 收寄存器地址 → PARALLEL_REGISTER_NUM_8_15(4)/PARALLEL_REGISTER_NUM_0_7(5) 收寄存器数 → PARALLEL_LEN_8_15(6)/PARALLEL_LEN_0_7(7) 收字节计数(仅 0x10)→ PARALLEL_DATA_RECVD(8) 收数据域 → PARALLEL_CRC_Bits_8_15(9)/PARALLEL_CRC_Bits_0_7(10) 收 CRC → PARALLEL_EXCEPTION_E(11) 异常。注意枚举顺序中 CRC_Bits_8_15 在 CRC_Bits_0_7 之前,而运行时先收低字节(Modbus 小端 CRC),因此状态赋值是"反序"的 |
E_MODBUS_Recv_Parallel_Networking_State | 枚举(第 46-58 行) | 组网帧接收状态机状态。PARALLEL_START_M 等广播地址 0x00 → PARALLEL_BROADCAST_ADDR_M 判 0x41/0x42 → PARALLEL_NET_FUNC_M(对 0x41 立即应答并返回)/ PARALLEL_UNIQUE_DEVICE_ID_0 → PARALLEL_UNIQUE_DEVICE_ID_1 收 2 字节 uid → PARALLEL_ASSIGN_ADDR 比对 uid 后采纳地址 → PARALLEL_NET_EXCEPTION_E 异常 |
REG_PARALLEL_QUERY_MODBUS_E | 枚举(第 60-152 行) | 并机寄存器地址总表,共 83 个枚举量:0x00~0x33(52 个)遥测寄存器;REG_SET_AEQUENCE_CONTROL_E = 0x50 起 31 个控制寄存器到 REG_SET_BMS_SHUTDOWN。末尾 REG_PARALLEL_MAX_MODBUS_E 作为哨兵,值为 0x6F |
2.1 REG_PARALLEL_QUERY_MODBUS_E 遥测段(0x00~0x33)分组
| 地址区间 | 名称族 | 数据来源(g_t_host_machine_running_info[0]) |
|---|---|---|
0x00~0x03 | REG_INV_RATE_* | s16_inverter_rated_output/input/bat_charge/bat_dischg_power(逆变器额定功率) |
0x04~0x05 | REG_BAT_CAPACITY_H/L_E | u32_bat_capacity(32 位拆两寄存器) |
0x06~0x0A | REG_BAT_WORK_FLAG/NUM/SOC/VOLTAGE/CURRENT_E | 电池工作标志位域、并机簇数、SOC、母线电压、电流 |
0x0B~0x10 | REG_BAT_POWER_H/L、REG_BAT_MAX_CHARGE_POWER_H/L、REG_BAT_MAX_DISCHARGE_POWER_H/L | s32_Pbat、s32_bat_max_charge_power、s32_bat_max_dischg_power(32 位各拆两寄存器) |
0x11 | REG_UPGRADE_FLAG_E | from_machine_upgrade_flag_u.u8_upgrade_flag |
0x12~0x19 | REG_PV_L1..L4_VOLTAGE/POWER_E | s16_Upv1..4、s16_Ppv1..4 |
0x1A~0x1F | REG_GRID_L1..L3_VOLTAGE/POWER_E | s16_Ugrida/b/c、s16_Pgrida/b/c |
0x20~0x21 | REG_GRID_ALL_POWER_E、REG_GRID_FREQUENT_E | s16_Pgridt、s16_Fgrid |
0x22~0x29 | REG_BACKUP_L1..L3_VOLTAGE/POWER_E、REG_BACKUP_ALL_POWER_E、REG_BACKUP_FREQUENT_E | s16_Ubackupa/b/c、s16_Pbackupa/b/c、s16_Pbackupt、s16_Fbackup |
0x2A~0x2E | REG_INV_L1..L3_POWER_E、REG_INV_ALL_POWER_E、REG_INV_FREQUNET_E | s16_Pinva/b/c、s16_Pinvt、s16_Finv |
0x2F~0x32 | REG_INV_WORK_MODE_E、REG_INV_BAT_POWER/VOLTAGE/CURRENT_E | u8_work_mode、s16_Pbat_inv、s16_Ubat_inv、s16_Ibat_inv |
0x33 | REG_FEEDIN_FLAG_E | u8_feedin_flag |
2.2 REG_PARALLEL_QUERY_MODBUS_E 控制段(0x50~0x6E)分组
| 地址区间 | 名称族 | 写入目标(g_t_from_machine_running_info) |
|---|---|---|
0x50~0x51 | REG_SET_AEQUENCE_CONTROL_E、REG_SET_THREE_UNBALANCE_MODE_E | 顺序控制模式、三相不平衡模式(只取 bit0) |
0x52~0x58 | REG_SET_DC_* | DC 总量三类功率 + DC 三相电池功率与三相逆变功率 |
0x59~0x5C | REG_SET_AC_TOTAL_* | AC 逆变总功率、电池充/放总限值、强制充电使能 |
0x5D~0x62 | REG_SET_AC_THREE_PHASE_* | AC 三相逆变功率、三相电池充/放限值、三相强制充电使能 |
0x63~0x65 | REG_SET_MPPT_PERCENTAGE_E、REG_SET_SAFETY_E、REG_SET_FASESUB_E | MPPT 百分比、安规码、安规子项 |
0x66 | REG_SET_UPGRADE_FLAG_E | host_machine_upgrade_flag_u.u8_upgrade_flag |
0x67~0x6C | REG_BB_MODEL、REG_GC_CONTROL_EN、REG_FREQ_DISPATCH_EN、REG_NN_SHORT_DETECT_EN、REG_DRM_MODE、REG_BACKUP_EN | BB 模式、油机控制使能、调频调度使能、N-N 短接检测、DRM 模式、备电使能 |
0x6D~0x6E | REG_SET_INV_ON_OFF、REG_SET_BMS_SHUTDOWN | 逆变器开关机、BMS 关机 |
0x6F | REG_PARALLEL_MAX_MODBUS_E | 哨兵值(0x50 + 31),不参与收发 |
2.3 编码包装
整个头文件被 #pragma pack(1)(第 29 行)与 #pragma pack()(第 154 行)包裹。虽然本文件只定义 enum 与宏(不定义结构体),但枚举的字节宽度实际由编译器决定:在 ARMCC 下该枚举按 int(4 字节)分配,因此这两个 pragma 对本文件是冗余的;真正的意义是保证 parallel_sci.h 被 parallel.h 关联包含时不会破坏后者的 pack(1) 状态(parallel.h:24 有自己的 pack(1))。
3. 函数清单
本文件为纯头文件,不含任何函数定义,仅有 2 个函数声明:
| 函数名 | 作用域 | 说明 |
|---|---|---|
parallel_sci_comm_host_machine_handle | 全局(声明,第 156 行) | 主机角色 SCI 通信主入口(定义于 parallel_sci.c:610):限速 200 ms、每 10 s 广播组网、每轮做一次"读全部从机 + 写全部从机"、15 s 心跳失联处理 |
parallel_sci_comm_from_machine_handle | 全局(声明,第 157 行) | 从机角色 SCI 通信主入口(定义于 parallel_sci.c:1531):10~99 ms 随机错峰后,未分配地址走组网状态机、已分配地址走 Modbus 从站状态机,末尾做 15 s 心跳失联处理 |
两个函数由 midware/inverter/parallel.c:1103 / parallel.c:1107 在 parallel_sci_comm_handle() 内按 g_t_inv_info.t_config_data.u8_parallel_mode 分发调用。
4. 核心逻辑解析
本文件无执行代码,其"逻辑"体现在三段式组网握手的码字定义与两个接收状态机的状态点划分上。
4.1 组网三段式握手(三段码 + 广播地址)
| 阶段 | 发出方 → 接收方 | 首字节 | 次字节 | 其余数据域 | 总长 | 定义位置 |
|---|---|---|---|---|---|---|
| ① 组网开始 | 主机 → 广播 | PARALLEL_BROADCAST_ADDRESS(0x00) | PARALLEL_NETWORKING_CODE(0x41) | 0x00 | 5(含 CRC2) | parallel_sci.c:178-186 |
| ①应答 | 从机 → 广播 | PARALLEL_BROADCAST_ADDRESS(0x00) | PARALLEL_NETWORKING_CODE(0x41) | uid0,uid1,mac0,mac1,mac2 | 9 | parallel_sci.c:1178-1190 |
| ② 地址分配 | 主机 → 广播 | PARALLEL_BROADCAST_ADDRESS(0x00) | PARALLEL_NET_ASSIGN_CODE(0x42) | uid0,uid1,addr,mac0,mac1,mac2 | 10 | parallel_sci.c:126-139 |
| ③ 组网完成 | 从机 → 主机(单播) | 本机 addr | PARALLEL_NET_COMPLETE_CODE(0x43) | uid0,uid1 | 6 | parallel_sci.c:1204-1213 |
关键语义:PARALLEL_NETWORKING_CODE 是双向复用的(主机发"谁来组网"、从机发"我来了"),靠方向区分而非码值;PARALLEL_NET_ASSIGN_CODE 与 PARALLEL_NET_COMPLETE_CODE 是单向的。PARALLEL_BROADCAST_ADDRESS 在这里既是 Modbus 从站地址 0,也承担"组网帧首字节"的角色,与 PARALLEL_HOST_MACHINE_ADDRESS = 0x01 形成对照——协议实际不使用 0x01/0x02 这两个常量,从机地址由 ② 阶段动态写进 PARALLEL_NET_ASSIGN_CODE 帧的第 5 字节(即 frame_data[4],parallel_sci.c:1510)。
4.2 普通 Modbus 状态机的状态划分与"反序"CRC
E_MODBUS_Recv_Parallel_State 的状态点直接对应字节偏移:
| 状态 | 递减语义 | 进入条件 | 下一状态 |
|---|---|---|---|
PARALLEL_ADDR_M(0) | 首字节须等于本机地址 | 输入字节 == g_t_from_machine_networking_info.u8_parallel_addr | PARALLEL_FUNC_M |
PARALLEL_FUNC_M(1) | 判功能码 | 字节 == 0x03 或 0x10(否则回 PARALLEL_ADDR_M) | PARALLEL_REGISTER_BITS_8_15 |
PARALLEL_REGISTER_BITS_8_15(2) | 寄存器地址高字节 | 无条件 | PARALLEL_REGISTER_BITS_0_7 |
PARALLEL_REGISTER_BITS_0_7(3) | 寄存器地址低字节 | 缓冲第 0 字节仍为本地地址 | PARALLEL_REGISTER_NUM_8_15 / PARALLEL_EXCEPTION_E |
PARALLEL_REGISTER_NUM_8_15(4) | 寄存器数高字节 | 无条件 | PARALLEL_REGISTER_NUM_0_7 |
PARALLEL_REGISTER_NUM_0_7(5) | 寄存器数低字节 | 按功能码分流:0x03 → CRC,0x10 → 长度 | PARALLEL_CRC_Bits_0_7 / PARALLEL_LEN_0_7 / PARALLEL_ADDR_M |
PARALLEL_LEN_8_15(6) | 字节计数高字节(0x10 路径,实现中未使用) | — | — |
PARALLEL_LEN_0_7(7) | 字节计数低字节 | 字节 == register_num * 2(否则异常) | PARALLEL_DATA_RECVD |
PARALLEL_DATA_RECVD(8) | 数据域 | 已收字节数 data_len + 7 <= idx | PARALLEL_CRC_Bits_0_7 |
PARALLEL_CRC_Bits_8_15(9) | CRC 高字节 | 无条件 | —(终态,校验后 return) |
PARALLEL_CRC_Bits_0_7(10) | CRC 低字节 | 无条件 | PARALLEL_CRC_Bits_8_15 |
PARALLEL_EXCEPTION_E(11) | 异常态 | 各步守卫失败时置入 | 无(switch 无此 case,只能靠 300 ms 超时退出) |
状态枚举顺序与运行时顺序相反是刻意设计但极易误读:枚举里 PARALLEL_CRC_Bits_8_15(9) 排在 PARALLEL_CRC_Bits_0_7(10) 之前(符合 Modbus 帧"低字节在前"的书写直觉),但代码里必须先进入 10 收低字节、再进 9 收高字节(parallel_sci.c:1368-1375),这样 crc_16 = byte | (byte2 << 8) 才是正确的 Modbus CRC 字节序。PARALLEL_LEN_8_15(6) 是枚举里的空档——因为字节计数只有 1 字节,实现直接跳到 PARALLEL_LEN_0_7,6 号状态永远到不了。
4.3 组网状态机的状态划分
E_MODBUS_Recv_Parallel_Networking_State 的状态点对应:
PARALLEL_START_M : 首字节须为 PARALLEL_BROADCAST_ADDRESS(0x00)
PARALLEL_BROADCAST_ADDR_M : 次字节分流 —— 0x41 → PARALLEL_NET_FUNC_M
0x42 → PARALLEL_UNIQUE_DEVICE_ID_0
PARALLEL_NET_FUNC_M : 0x41 路径的终态:本机地址仍为 0 则立即应答并 return;
否则置 PARALLEL_NET_EXCEPTION_E(已有地址不再重复入网)
PARALLEL_UNIQUE_DEVICE_ID_0 : 0x42 路径,收 uid 第 0 字节(recv_buff[2])
PARALLEL_UNIQUE_DEVICE_ID_1 : 收 uid 第 1 字节(recv_buff[3])
PARALLEL_ASSIGN_ADDR : 收分配地址字节(recv_buff[4])并比对 recv_buff[2]/[3] 与本机 uid,
匹配则采纳地址 + 应答,否则 PARALLEL_NET_EXCEPTION_E
PARALLEL_NET_EXCEPTION_E : 异常态,`switch` 无 `case`,靠 300 ms 超时退出
与普通 Modbus 状态机的关键差异:组网状态机没有任何 CRC 校验状态点。枚举里不存在 PARALLEL_NET_CRC_*,实现也只把 CRC 字节当作普通字节吞掉(parallel_sci.c:1500-1519),身份确认完全依赖 uid 比对。
4.4 寄存器表的双向复用
REG_PARALLEL_QUERY_MODBUS_E 是同名枚举被用在两个语义相反的 switch 里:
- 读方向:
Parallel_get_para_from_reg_addr(parallel_sci.c:870-1111)以寄存器号为标签,从g_t_host_machine_running_info[0]取值,用于从机组0x03应答(共 52 个case,与PARALLEL_QUERY_DATA_NUM一致)。 - 写方向:
Parallel_Set_Para_to_Reg_Addr(parallel_sci.c:729-862)以寄存器号为标签,把值写入g_t_from_machine_running_info(共 31 个case,与PARALLEL_CONTROL_DATA_NUM一致)。
因此同一份枚举里 0x00~0x33 的名字(如 REG_BAT_SOC_E)在从机上其实是"我要上报的 SOC",0x50~0x6E 的名字(如 REG_SET_SAFETY_E)在从机上是"主机要我设的安规"。两段地址空间不重叠(0x33 < 0x50)正是这种双向复用能成立的前提,也是 PARALLEL_QUERY_DATA_NUM(52) 与 PARALLEL_CONTROL_DATA_NUM(31) 之间留下 0x34~0x4F 空隙的全部原因。
4.5 与 uCOS-II 任务/同步机制的配合
本头文件本身不涉及任何任务或同步原语。两个入口函数由 task_parallel_sci 在单一任务上下文中串行调用(midware/inverter/inverter.c:1296-1307,周期 100 ms),所以 Parallel_Set_Para_to_Reg_Addr/Parallel_get_para_from_reg_addr 对全局结构体的读写没有使用临界区或信号量,靠"同一任务内串行"这一隐含前提保证一致性。
5. 对外接口
5.1 本文件导出
| 类别 | 符号 |
|---|---|
| 通信常量宏 | PARALLEL_HOST_MACHINE_ADDRESS、PARALLEL_FROM_MACHINE_ADDRESS、PARALLEL_HOST_MACHINE_READ_CODE、PARALLEL_HOST_MACHINE_WRITE_MULTI_CODE、PARALLEL_QUERY_DATA_REGISTER_ADDRESS、PARALLEL_QUERY_DATA_NUM、PARALLEL_CONTROL_DATA_REGISTER_ADDRESS、PARALLEL_CONTROL_DATA_NUM、PARALLEL_NETWORKING_CODE、PARALLEL_NET_ASSIGN_CODE、PARALLEL_NET_COMPLETE_CODE、PARALLEL_BROADCAST_ADDRESS |
| 状态机枚举 | E_MODBUS_Recv_Parallel_State、E_MODBUS_Recv_Parallel_Networking_State |
| 寄存器地址枚举 | REG_PARALLEL_QUERY_MODBUS_E(83 个枚举量,含哨兵 REG_PARALLEL_MAX_MODBUS_E) |
| 函数声明 | parallel_sci_comm_host_machine_handle、parallel_sci_comm_from_machine_handle |
导出方式为无 #include 条件的裸宏/枚举,任何包含本头的文件都会看到全部寄存器名。
5.2 使用方
| 使用方 | 用途 |
|---|---|
midware/inverter/parallel_comm/parallel_sci.c:13 | 包含本头,全部宏与两个枚举的实际使用者(组帧 + 两张映射 switch + 两个接收状态机) |
midware/inverter/parallel.c:16(含 parallel_sci.h) | 仅为调用两个 parallel_sci_comm_* 函数入口;parallel.c 自身不使用寄存器枚举 |
5.3 本文件依赖
#include "chip.h"(第 12 行)—— 提供u8/u16/s16/s32基础类型。本文件通篇只有宏、enum与两个void f(void)声明,实际未使用任何chip.h类型,该 include 在头文件层面是冗余的。- 无其它 include。所有结构体(
PARALLEL_HOST_MACHINE_RUNNING_INFO_T等)由parallel.h提供,本文件不引用它们,故两者之间无编译期耦合。
6. 依赖关系
- 依赖:
chip.h(冗余依赖,见第 7 节)。 - 被依赖:
midware/inverter/parallel_comm/parallel_sci.c(唯一重度使用者)midware/inverter/parallel.c(仅用于调用两个入口函数)- 间接受影响:
midware/inverter/inverter.c(通过task_parallel_sci→parallel_sci_comm_handle()) - 与
midware/inverter/parallel_comm/parallel_can.h构成同一套语义的两套编码:CAN 通道用0x190~0x2C0的扩展帧 ID 表达相同内容,SCI 通道用0x00~0x6E的 Modbus 寄存器表达。两份头文件的寄存器/ID 分组顺序一一对应(例如 CAN 的0x191DC 总量 ↔ SCI 的0x52~0x54),是理解并机协议族的关键对照。
7. 备注与风险点
PARALLEL_HOST_MACHINE_ADDRESS(0x01)与PARALLEL_FROM_MACHINE_ADDRESS(0x02)是全工程死宏。grep全工程无任何使用点。实际协议里主机地址恒为 0(=PARALLEL_BROADCAST_ADDRESS),从机地址由组网动态分配。这两个宏的存在会误导读者以为地址是静态编址。
PARALLEL_LEN_8_15是永远到不了的枚举值。Modbus0x10帧的字节计数只有 1 字节,实现从PARALLEL_REGISTER_NUM_0_7直接跳PARALLEL_LEN_0_7(parallel_sci.c:1333)。留下PARALLEL_LEN_8_15(6) 让人误以为支持 16 位长度(即多寄存器批量写超过 127 个寄存器的场景)。
- CRC 两个状态的枚举编号与实际接收顺序相反。枚举里
PARALLEL_CRC_Bits_8_15是 9、PARALLEL_CRC_Bits_0_7是 10,而运行路径是 10 → 9。任何按枚举名"从 9 到 10"推导状态迁移的维护者都会写出错误的状态机。建议在头文件里对这两个状态加注释说明"运行时先 0_7 后 8_15"。
PARALLEL_EXCEPTION_E与PARALLEL_NET_EXCEPTION_E定义了但没有恢复路径。两个switch都没有对应的case(parallel_sci.c:1268-1410、1454-1520),进入异常态后只能等 300 ms 超时自动 return。这两个枚举值在语义上宣告了"有异常处理",实际却没有处理逻辑。
- 寄存器枚举完全不做区间/长度校验。
PARALLEL_QUERY_DATA_NUM(52) 与REG_FEEDIN_FLAG_E(0x33) 的一致性、PARALLEL_CONTROL_DATA_NUM(31) 与REG_SET_BMS_SHUTDOWN(0x6E=0x50+30) 的一致性都靠人工数数维持;两张switch里任意缺少一个case(例如Parallel_set里缺REG_SET_INV_ON_OFF的break)都不会有编译期报错。建议加static_assert/编译期校验或在头文件中注明"三段必须同步修改"。
REG_PARALLEL_MAX_MODBUS_E的语义是"最大地址 + 1"还是"最大地址"未定义:它紧跟在REG_SET_BMS_SHUTDOWN(0x6E)之后,因此值为 0x6F。名字里没有NUM/COUNT后缀,也没有注释说明是否是PARALLEL_CONTROL_DATA_NUM的冗余表达,容易被误用为数组长度。
- 枚举名里的拼写错误会永久固化:
REG_SET_AEQUENCE_CONTROL_E(应为SEQUENCE,第 120 行)、REG_GRID_FREQUENT_E(FREQUENCY,第 98 行)、REG_INV_FREQUNET_E(FREQUENCY,第 112 行)、REG_SET_FASESUB_E(PHASESUB/FASESUB,第 141 行)、REG_SET_DC_THREE_PHASE_*与REG_SET_DC_TOTAL_*中 DC/AC 段命名风格不一致。这些标识符已被parallel_sci.c的两张大switch引用 83 处,重命名成本会随协议扩展线性增长。
- 遥测段与控制段之间的地址空隙(
0x34~0x4F)无任何说明。读者无法从本文件判断这段空间是"预留扩展"还是"历史遗留";若是预留,重复使用会破坏现有解包偏移(主机侧parallel_sci.c:478-530是按recv_buff的绝对字节偏移硬编码解包的,一旦寄存器表插入新项或改变顺序,主机与从机两端必须同时改,否则数据静默错位)。
- 头文件包含
chip.h但自身不需要(第 12 行)。这与parallel_can.h是同一问题:本文件只有宏和枚举,不依赖chip.h的任何类型。该 include 会让任何只想要寄存器名的文件被迫引入整个chip.h。
#pragma pack(1)包裹纯枚举定义属冗余且可能产生副作用。若某编译器把#pragma pack作用于后续所有类型,且本头被包含顺序恰好插在别的结构体定义之前/中间,就可能改变那些结构体的对齐。当前工程里包含顺序固定(parallel_sci.c先含parallel_sci.h再含parallel.h,后者自带pack(1)),暂未暴露问题,但这是隐式全局状态。