EMS 知识库
首页 / knowledge/代码解析/midware/inverter/parallel_comm

parallel_sci.h

源文件路径: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~0x03REG_INV_RATE_*s16_inverter_rated_output/input/bat_charge/bat_dischg_power(逆变器额定功率)
0x04~0x05REG_BAT_CAPACITY_H/L_Eu32_bat_capacity(32 位拆两寄存器)
0x06~0x0AREG_BAT_WORK_FLAG/NUM/SOC/VOLTAGE/CURRENT_E电池工作标志位域、并机簇数、SOC、母线电压、电流
0x0B~0x10REG_BAT_POWER_H/L、REG_BAT_MAX_CHARGE_POWER_H/L、REG_BAT_MAX_DISCHARGE_POWER_H/Ls32_Pbat、s32_bat_max_charge_power、s32_bat_max_dischg_power(32 位各拆两寄存器)
0x11REG_UPGRADE_FLAG_Efrom_machine_upgrade_flag_u.u8_upgrade_flag
0x12~0x19REG_PV_L1..L4_VOLTAGE/POWER_Es16_Upv1..4、s16_Ppv1..4
0x1A~0x1FREG_GRID_L1..L3_VOLTAGE/POWER_Es16_Ugrida/b/c、s16_Pgrida/b/c
0x20~0x21REG_GRID_ALL_POWER_E、REG_GRID_FREQUENT_Es16_Pgridt、s16_Fgrid
0x22~0x29REG_BACKUP_L1..L3_VOLTAGE/POWER_E、REG_BACKUP_ALL_POWER_E、REG_BACKUP_FREQUENT_Es16_Ubackupa/b/c、s16_Pbackupa/b/c、s16_Pbackupt、s16_Fbackup
0x2A~0x2EREG_INV_L1..L3_POWER_E、REG_INV_ALL_POWER_E、REG_INV_FREQUNET_Es16_Pinva/b/c、s16_Pinvt、s16_Finv
0x2F~0x32REG_INV_WORK_MODE_E、REG_INV_BAT_POWER/VOLTAGE/CURRENT_Eu8_work_mode、s16_Pbat_inv、s16_Ubat_inv、s16_Ibat_inv
0x33REG_FEEDIN_FLAG_Eu8_feedin_flag

2.2 REG_PARALLEL_QUERY_MODBUS_E 控制段(0x50~0x6E)分组

地址区间名称族写入目标(g_t_from_machine_running_info)
0x50~0x51REG_SET_AEQUENCE_CONTROL_E、REG_SET_THREE_UNBALANCE_MODE_E顺序控制模式、三相不平衡模式(只取 bit0)
0x52~0x58REG_SET_DC_*DC 总量三类功率 + DC 三相电池功率与三相逆变功率
0x59~0x5CREG_SET_AC_TOTAL_*AC 逆变总功率、电池充/放总限值、强制充电使能
0x5D~0x62REG_SET_AC_THREE_PHASE_*AC 三相逆变功率、三相电池充/放限值、三相强制充电使能
0x63~0x65REG_SET_MPPT_PERCENTAGE_E、REG_SET_SAFETY_E、REG_SET_FASESUB_EMPPT 百分比、安规码、安规子项
0x66REG_SET_UPGRADE_FLAG_Ehost_machine_upgrade_flag_u.u8_upgrade_flag
0x67~0x6CREG_BB_MODEL、REG_GC_CONTROL_EN、REG_FREQ_DISPATCH_EN、REG_NN_SHORT_DETECT_EN、REG_DRM_MODE、REG_BACKUP_ENBB 模式、油机控制使能、调频调度使能、N-N 短接检测、DRM 模式、备电使能
0x6D~0x6EREG_SET_INV_ON_OFF、REG_SET_BMS_SHUTDOWN逆变器开关机、BMS 关机
0x6FREG_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)0x005(含 CRC2)parallel_sci.c:178-186
①应答从机 → 广播PARALLEL_BROADCAST_ADDRESS(0x00)PARALLEL_NETWORKING_CODE(0x41)uid0,uid1,mac0,mac1,mac29parallel_sci.c:1178-1190
② 地址分配主机 → 广播PARALLEL_BROADCAST_ADDRESS(0x00)PARALLEL_NET_ASSIGN_CODE(0x42)uid0,uid1,addr,mac0,mac1,mac210parallel_sci.c:126-139
③ 组网完成从机 → 主机(单播)本机 addrPARALLEL_NET_COMPLETE_CODE(0x43)uid0,uid16parallel_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_addrPARALLEL_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 <= idxPARALLEL_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 里:

因此同一份枚举里 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 本文件依赖

6. 依赖关系

7. 备注与风险点

  1. PARALLEL_HOST_MACHINE_ADDRESS(0x01)与 PARALLEL_FROM_MACHINE_ADDRESS(0x02)是全工程死宏。grep 全工程无任何使用点。实际协议里主机地址恒为 0(=PARALLEL_BROADCAST_ADDRESS),从机地址由组网动态分配。这两个宏的存在会误导读者以为地址是静态编址。
  1. PARALLEL_LEN_8_15 是永远到不了的枚举值。Modbus 0x10 帧的字节计数只有 1 字节,实现从 PARALLEL_REGISTER_NUM_0_7 直接跳 PARALLEL_LEN_0_7(parallel_sci.c:1333)。留下 PARALLEL_LEN_8_15(6) 让人误以为支持 16 位长度(即多寄存器批量写超过 127 个寄存器的场景)。
  1. CRC 两个状态的枚举编号与实际接收顺序相反。枚举里 PARALLEL_CRC_Bits_8_15 是 9、PARALLEL_CRC_Bits_0_7 是 10,而运行路径是 10 → 9。任何按枚举名"从 9 到 10"推导状态迁移的维护者都会写出错误的状态机。建议在头文件里对这两个状态加注释说明"运行时先 0_7 后 8_15"。
  1. PARALLEL_EXCEPTION_E 与 PARALLEL_NET_EXCEPTION_E 定义了但没有恢复路径。两个 switch 都没有对应的 case(parallel_sci.c:1268-1410、1454-1520),进入异常态后只能等 300 ms 超时自动 return。这两个枚举值在语义上宣告了"有异常处理",实际却没有处理逻辑。
  1. 寄存器枚举完全不做区间/长度校验。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/编译期校验或在头文件中注明"三段必须同步修改"。
  1. REG_PARALLEL_MAX_MODBUS_E 的语义是"最大地址 + 1"还是"最大地址"未定义:它紧跟在 REG_SET_BMS_SHUTDOWN(0x6E)之后,因此值为 0x6F。名字里没有 NUM/COUNT 后缀,也没有注释说明是否是 PARALLEL_CONTROL_DATA_NUM 的冗余表达,容易被误用为数组长度。
  1. 枚举名里的拼写错误会永久固化: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 处,重命名成本会随协议扩展线性增长。
  1. 遥测段与控制段之间的地址空隙(0x34~0x4F)无任何说明。读者无法从本文件判断这段空间是"预留扩展"还是"历史遗留";若是预留,重复使用会破坏现有解包偏移(主机侧 parallel_sci.c:478-530 是按 recv_buff 的绝对字节偏移硬编码解包的,一旦寄存器表插入新项或改变顺序,主机与从机两端必须同时改,否则数据静默错位)。
  1. 头文件包含 chip.h 但自身不需要(第 12 行)。这与 parallel_can.h 是同一问题:本文件只有宏和枚举,不依赖 chip.h 的任何类型。该 include 会让任何只想要寄存器名的文件被迫引入整个 chip.h。
  1. #pragma pack(1) 包裹纯枚举定义属冗余且可能产生副作用。若某编译器把 #pragma pack 作用于后续所有类型,且本头被包含顺序恰好插在别的结构体定义之前/中间,就可能改变那些结构体的对齐。当前工程里包含顺序固定(parallel_sci.c 先含 parallel_sci.h 再含 parallel.h,后者自带 pack(1)),暂未暴露问题,但这是隐式全局状态。