parallel_can.h
源文件路径:
midware/inverter/parallel_comm/parallel_can.h所属模块:midware/inverter/parallel_comm(并机通信 / CAN 通道) 代码行数:70
1. 文件职责
本文件是 EMS 并机 CAN 通道的协议字典:它把"主机 → 从机"和"从机 → 主机"两个方向上全部使用的 CAN 扩展帧 ID 用宏一一枚举出来,并定义了广播地址(0)与扩展 ID 的通信标识位。业务层(parallel.c)把要下发的功率指令写进 g_t_host_machine_running_info[] 字段;通信层(parallel_can.c)按本文件给出的 ID 逐帧组包发出,并在收帧时用 frame_id & 0xFFFFFF 反查这些 ID 决定拆包到哪个字段。因此本文件是"字段 ↔ CAN ID"映射的唯一权威来源,改任何一个宏都会同时影响发送与接收两侧。本文件只做宏定义与两个函数声明,不含代码,被 parallel.c(包含本头以使用 PARALLEL_MAX_NUM 相关的 CAN 语义)与 parallel_can.c 使用。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
PARALLEL_BROADCAST_ADDR | 宏 | 0,并机广播地址。主机占用 0 号地址,因此广播帧也等价于"主机发的、无人应答"的帧 |
PARALLEL_COMMUNICATION_ADDRESS_OFFSET | 宏 | 0x10000000,CAN 扩展 ID 的"这是并机报文"标志位(bit 28)。收帧侧用 (frame_id & OFFSET) == FALSE 来过滤非并机帧 |
PARALLEL_HOST_MACHINE_NETWORKING_0X181 | 宏 | 0x181,主从机组网帧(数据帧):主机下发的"已给你分配地址"答复,也是从机侧的接收对象 |
PARALLEL_HOST_MACHINE_NETWORKING_0X201 | 宏 | 0x201,主从机组网帧(远程帧):主机周期性广播的"请未分配地址的从机报到";从机收到远程帧后回一个同 ID 的数据帧 |
PARALLEL_HOST_MACHINE_POWER_CONTROL_0X190 | 宏 | 0x190,从机功率控制指令(控制模式类):顺序控制模式、三相不平衡模式、BB 模式、油机使能、调频使能、逆变器开关机、BMS 关机 |
PARALLEL_HOST_MACHINE_POWER_CONTROL_0X191 | 宏 | 0x191,从机功率控制指令(DC 侧总量控制):DC 电池/逆变/电网总设定功率 |
PARALLEL_HOST_MACHINE_POWER_CONTROL_0X192 | 宏 | 0x192,从机功率控制指令(DC 侧三相控制):DC 三相电池功率 + 三相逆变功率 |
PARALLEL_HOST_MACHINE_POWER_CONTROL_0X195 | 宏 | 0x195,从机功率控制指令(AC 侧控制):AC 逆变总功率、AC 电池充/放总限值、强制充电使能 |
PARALLEL_HOST_MACHINE_POWER_CONTROL_0X196 | 宏 | 0x196,从机功率控制指令(AC 侧控制):AC 三相逆变功率 |
PARALLEL_HOST_MACHINE_POWER_CONTROL_0X197 | 宏 | 0x197,从机功率控制指令(AC 侧控制):AC 三相电池充/放限值与强制充电使能 |
PARALLEL_HOST_MACHINE_SET_CONTROL_PARAMETER_0X19A | 宏 | 0x19A,设置逆变器控制参数:MPPT 百分比、N-N 短接检测、DRM 模式、备电使能 |
PARALLEL_HOST_MACHINE_SET_SAFETY_REGULATION_0X19B | 宏 | 0x19B,设置从机并网参数:安规(safety)与安规子项(safesub) |
PARALLEL_HOST_MACHINE_EMS_RUNNING_DATA_0X1C0 | 宏 | 0x1C0,主机 EMS 运行信息:当前只下发 EMS 升级标志字节 |
PARALLEL_FROM_MACHINE_NETWORKING_0X201 | 宏 | 0x201,主从机组网帧(数据帧):从机对远程帧的应答,携带设备 ID + MAC + 本机地址 |
PARALLEL_FROM_MACHINE_DATA_CHECK_0X202 | 宏 | 0x202,返回数据出错信息。全工程仅有此定义,parallel_can.c 与任何其它文件均未使用(见第 7 节) |
PARALLEL_FROM_MACHINE_INVERTER_SPECIFICATION_0X220 | 宏 | 0x220,从机逆变器规格:额定输出/输入功率、额定电池充/放功率(各 2 字节) |
PARALLEL_FROM_MACHINE_SAFETY_REGULATION_0X240 | 宏 | 0x240,从机并网参数。定义了但未被 parallel_can.c 处理(从机安规是主机下发的,见第 7 节) |
PARALLEL_FROM_MACHINE_INVERTER_RUNNING_DATA_0X260 ~ 0X26A | 宏(11 个) | 从机逆变器运行信息分片:0x260 PV1/PV2 电压功率、0x261 PV3/PV4、0x262 PV 充电器 PV/电池功率(32 位)、0x263 电网 L1/L2 电压功率、0x264 电网 L3+总功率+频率、0x265 备电 L1/L2、0x266 备电 L3+总功率+频率、0x267 定义了但双方都未使用、0x268 逆变三相功率、0x269 逆变总功率+频率+工作模式+电池功率、0x26A 电池电压、电流、馈网标志 |
PARALLEL_FROM_MACHINE_BATTERY_INFORMATION_0X290 | 宏 | 0x290,从机电池信息:电池额定容量(32 位) |
PARALLEL_FROM_MACHINE_BATTERY_RUNNING_DATA_0x2A0 ~ 0x2A2 | 宏(3 个) | 从机电池运行信息:0x2A0 电池状态位+组数+SOC、0x2A1 母线电压+电流+电池功率(32 位)、0x2A2 电池最大充/放功率(各 32 位) |
PARALLEL_FROM_MACHINE_EMS_RUNNING_DATA_0x2C0 | 宏 | 0x2C0,从机 EMS 运行信息:当前只上传从机 EMS 升级标志字节 |
parallel_can_comm_host_machine_handle | 函数声明 | 主机角色下 CAN 通信主入口(parallel_can.c:184) |
parallel_can_comm_from_machine_handle | 函数声明 | 从机角色下 CAN 通信主入口(parallel_can.c:564) |
3. 函数清单
本文件为纯头文件,不含任何函数定义,仅有 2 个函数声明:
| 函数名 | 作用域 | 说明 |
|---|---|---|
parallel_can_comm_host_machine_handle | 全局(声明) | 主机角色 CAN 通信:周期发组网远程帧、广播控制参数、逐机单播功率指令,并收帧解析从机数据、做 15 s 心跳超时判定 |
parallel_can_comm_from_machine_handle | 全局(声明) | 从机角色 CAN 通信:未组网时周期上报组网数据;已组网时应答远程帧并周期上报规格/电池/运行数据;收主机指令并做 15 s 心跳判定 |
两个函数均由 midware/inverter/parallel.c:1037/1041 在 parallel_can_comm_handle() 内按 u8_parallel_mode 分发调用。
4. 核心逻辑解析
本文件无执行代码,其"逻辑"是CAN 扩展帧 ID 的位域复用规则与收发 ID 的对称/不对称关系。
4.1 扩展 ID 的位域划分
结合 parallel_can.c:57-58(发送)与 parallel_can.c:335-340(接收)可还原出 29 位扩展 ID 的实际用途:
bit28 : 并机报文标志,恒为 1(= PARALLEL_COMMUNICATION_ADDRESS_OFFSET 0x10000000)
bit24-27 : 机器地址(send_id & 0xF),主机发时为 0(广播)或从机地址 i(单播)
bit0-23 : 基础 ID,取本文件定义的 0x181 / 0x190 / ... / 0x2C0
发送侧 parallel_can.c:57-58:
TxMsg->frame_id |= PARALLEL_COMMUNICATION_ADDRESS_OFFSET; // 置 bit28
TxMsg->frame_id |= (send_id & 0xF) << 24; // 置 bit24-27
接收侧 parallel_can.c:335-337:
l_u8_parallel_comm_rx_addr = ((frame_id >> 24) & 0xF); // 取位 24-27
if (((frame_id & PARALLEL_COMMUNICATION_ADDRESS_OFFSET) == FALSE) || // bit28 必须为 1
(l_u8_parallel_comm_rx_addr >= PARALLEL_MAX_NUM)) continue; // 地址必须 < 16
之后用 frame_id & 0xFFFFFF 取基础 ID 做 switch 分派(parallel_can.c:345、parallel_can.c:369、parallel_can.c:776)。注意 & 0xFFFFFF 只保留 bit0-23,因此 bit24-27 的地址与 bit28 的标志被同时剥离,这是位域划分能成立的前提。
4.2 收发 ID 的对称关系
| 方向 | 基础 ID | 帧类型 | 周期 | 位置 |
|---|---|---|---|---|
| 主机 → 广播 | 0x201 | 远程帧 | 3500 ms | parallel_can.c:200-202 |
| 主机 → 广播 | 0x190、0x19A、0x19B、0x1C0 | 数据帧 | 500 ms | parallel_can.c:211-255 |
| 主机 → 单播(逐台) | 0x191、0x192、0x195、0x196、0x197 | 数据帧 | 50 ms | parallel_can.c:273-326 |
| 从机 → 主机 | 0x181(组网答复,主机发、从机收) | 数据帧 | 主机收帧触发 | parallel_can.c:142-153 |
| 从机 → 主机 | 0x201(组网上报) | 数据帧 | 1000 ms(未组网时)/ 应答远程帧 | parallel_can.c:519-528、parallel_can.c:785 |
| 从机 → 主机 | 0x220、0x290、0x2A0、0x2A1、0x2A2、0x2C0 | 数据帧 | 500 ms | parallel_can.c:593-657 |
| 从机 → 主机 | 0x260、0x261、0x263、0x264、0x265、0x266、0x268、0x269、0x26A | 数据帧 | 50 ms | parallel_can.c:664-761 |
三类不对称/空洞可直接从宏定义与实现对照看出:
0x201是双向复用但语义相反:主机侧定义PARALLEL_HOST_MACHINE_NETWORKING_0X201(远程帧请求),从机侧定义PARALLEL_FROM_MACHINE_NETWORKING_0X201(数据帧应答),两个宏值相同。接收侧靠frame_type == CAN_FT_REMOTE区分(parallel_can.c:352、parallel_can.c:783)。0x181的方向注释是错的:宏名叫PARALLEL_HOST_MACHINE_NETWORKING_0X181("主机"),但它在parallel_can.c:779(从机侧接收switch)和parallel_can.c:347(主机侧接收switch,注释写"多主机")里都出现在接收分支。实际方向是"主机 → 从机"的地址分配答复,所以名字里的 HOST 表示"由主机发出",而0x201的 HOST/FROM 两个宏则表示"主机请求 / 从机应答"——命名体系不自洽。0x202(返回数据出错信息)、0x267(从机逆变器运行信息)、0x240(从机并网参数)三个宏全工程无使用。0x262(PV 充电器 PV/电池功率)主机侧有解析(parallel_can.c:397)但从机侧从不发送。这五处构成"定义了协议但未实现"的空洞。
4.3 载荷格式约定(无长度冗余)
从 parallel_can.c 的组帧可见所有并机 CAN 帧都是固定 8 字节数据域(frame_len = 8),无长度字段、无功能码:字段语义完全由 ID 决定,字段排列为大端(>> 8 高字节在前,>>24/16/8/0 四字节大端)。这一约定由 hardware/can/can1.h 的 CAN_MSG_TYPEDEF_T(frame_id / frame_type / frame_len / frame_data[8])承载,本文件不重复定义结构体。
校验上分两类:
- 组网帧(
0x201/0x181)带 CRC8/MAXIM:第 8 字节为前 7 字节的GetCrcCode_8_MAXIM()(parallel_can.c:152、parallel_can.c:527、parallel_can.c:92-96、parallel_can.c:542-546)。 - 数据帧不带应用层校验:完全依赖 CAN 控制器自身的 CRC 与 ACK 机制,因此
0x190~0x2C0的载荷没有校验字段。
5. 对外接口
5.1 本文件导出
- 宏:
PARALLEL_BROADCAST_ADDR、PARALLEL_COMMUNICATION_ADDRESS_OFFSET,以及"主机 ID 段"12 个(0x181、0x201、0x190~0x197、0x19A、0x19B、0x1C0)和"从机 ID 段"18 个(0x201、0x202、0x220、0x240、0x260~0x26A、0x290、0x2A0~0x2A2、0x2C0)。 - 函数声明:
parallel_can_comm_host_machine_handle、parallel_can_comm_from_machine_handle。 - 导出方式为无
#include条件的裸宏,任何包含本头的文件都会看到全部 ID。
5.2 使用方
| 使用方 | 用途 |
|---|---|
midware/inverter/parallel_comm/parallel_can.c:13 | 包含本头,全部 ID 宏的实际使用者(发送组帧 + 接收 switch 分派) |
midware/inverter/parallel.c:15 | 包含本头,仅为调用两个 parallel_can_comm_* 函数入口 |
5.3 本文件依赖
#include "chip.h"—— 提供u8/u16/s16/s32基础类型。本文件本身没有使用这些类型(只有宏与两个void函数声明),因此这个 include 在头文件层面是冗余的,实际是被.c顺带获得的。
5.4 相关但不在本文件的外部符号
parallel_can.c 使用了以下不在本头文件声明的符号:
| 符号 | 定义位置 |
|---|---|
CAN_MSG_TYPEDEF_T | hardware/can/can0.h:20-28(parallel_can.c 经 CAN1.h/includes.h 获得) |
CAN_FT_DATA / CAN_FT_REMOTE | HALLIB/GD32F4xx_standard_peripheral/Include/gd32f4xx_can.h:673-674 |
can1_send_exten_pack / get_can1_exten_pack | hardware/can/can1.h:26,30 |
PARALLEL_MAX_NUM、g_t_host_machine_*、g_t_from_machine_* | midware/inverter/parallel.h、midware/inverter/parallel.c |
GetCrcCode_8_MAXIM | common/crc.h |
6. 依赖关系
- 依赖:
chip.h(且是冗余依赖,见第 7 节)。 - 被依赖:
midware/inverter/parallel_comm/parallel_can.c(唯一重度使用者)midware/inverter/parallel.c(仅用于调用两个入口函数)- 间接受影响:
midware/inverter/inverter.c(通过task_inverter_can→parallel_can_comm_handle())
7. 备注与风险点
- 三个宏定义后从未使用(死代码):
PARALLEL_FROM_MACHINE_DATA_CHECK_0X202(第 37 行)——"返回数据出错信息",全工程仅有此一处定义,无发送方也无接收方。协议层预留但未落地,或已被数据帧的隐式 CRC 取代。PARALLEL_FROM_MACHINE_INVERTER_RUNNING_DATA_0X267(第 50 行)——主机侧接收switch(parallel_can.c:369-479)中没有0x267分支,从机组帧(parallel_can.c:664-761)也不发0x267。ID 被跳过。PARALLEL_FROM_MACHINE_SAFETY_REGULATION_0X240(第 41 行)——注释是"从机并网参数",但实际方向是主机用0x19B下发给从机,从机从不回报安规。这个 ID 的存在会让读者误以为有从机安规上报通道。
0x262只收不发,形成"孤儿接收分支":parallel_can.c:397-402会解析0x262帧填充s32_Ppv_pvcharger/s32_Pbat_pvcharger,但parallel_can.c:664-761的从机发送逻辑没有任何一帧使用0x262。同时parallel.c:209-210把本机的这两个字段硬置 0,说明该数据源在 CAN 通道上事实上不可用。
0x201双向复用导致头文件命名误导。PARALLEL_HOST_MACHINE_NETWORKING_0X201(第 21 行,注释"主从机组网帧(远程帧)")与PARALLEL_FROM_MACHINE_NETWORKING_0X201(第 36 行,注释"主从机组网帧(数据帧)")是同一个 ID。任何按名字判断"哪一个 ID 是主机发的"的读者都会误判方向;区分只能靠frame_type。同理0x181被归在"主机 CAN ID"段却由主机发出、从机接收,命名与语义方向不一致。
- 缺少"从机数据帧无校验"的一致性说明。组网帧带 CRC8/MAXIM,数据帧不带;本头文件对 ID 的注释只描述内容不描述校验,读者必须读
parallel_can.c才能发现这个差异。建议在头文件里对两类帧明确标注校验方式。
PARALLEL_COMMUNICATION_ADDRESS_OFFSET与地址掩码的耦合未文档化。0x10000000的注释只写"通讯地址偏移",没有说明它是"并机报文标志位"以及"地址在 bit24-27"这一分层。收帧侧如果只写frame_id & 0xFFFFFF而不先检查 bit28,就会把其它模块发的0x190等 ID 误判为并机帧——parallel_can.c:336恰好有这个检查,但规则未在头文件中固化,新增收发点容易遗漏。
- 头文件包含
chip.h但自身不需要。本文件通篇只有宏和两个void f(void)声明,不依赖chip.h的任何类型。该 include 会让任何只想要 ID 宏的文件被迫引入整个chip.h,增加编译耦合与循环包含风险。
- ID 空间未做区间保护。
0x1C0(主机 EMS 上报)与0x2C0(从机 EMS 上报)相距 0x100,看起来是"主机段 0x1xx / 从机段 0x2xx"的划分,但0x201同时出现在两段(第 21 行与第 36 行),破坏了这一规律。若将来需要按段批量过滤(例如只接收 0x2xx),会因为0x201而被误伤。