inovance_comm_can.c
relink_grid_power_limit()4.4 交流功率下发与限幅 send_ac_ctrl_inv_power()4.5 电池相关帧的数据来源4.6 变化检测器 inovance_inverter_data_check_can()4.7 CAN 接收解析循环4.8 通讯丢失判定与重初始化4.9 升级期间的互斥5. 对外接口5.1 本文件导出(供外部调用)5.2 本文件调用/引用的外部符号5.3 本文件写入的全局状态6. 依赖关系7. 备注与风险点源文件路径:
midware/inverter/inovance/inovance_comm_can.c所属模块:midware/inverter/inovance(汇川 Inovance 逆变器通信协议) 代码行数:790
1. 文件职责
本文件是汇川(Inovance)逆变器与 EMS 之间 CAN 总线私有协议 的 EMS 侧实现,与同目录的 inovance_comm_usart.c(SCI/Modbus-RTU 通道)构成一套"双通道"接口:本文件负责高频、实时的功率与电池限值下发以及运行数据接收,SCI 通道负责参数整定、安规配置与故障录波。
数据流位置:向上从 logic/(并机功率分配 parallel_*)、midware/inverter/pvcharger.*(BMS 数据)读取目标值与限值,向下通过 can1 硬件层把 8 字节标准帧发到逆变器;反向把逆变器上报的三相电网/备电/机侧功率、频率、运行模式写入 g_t_inv_info.t_run_info,供 logic/ 与 hmi/ 使用。
被谁驱动:由 inverter.c:1264 在 uCOS-II 任务 task_inverter_can()(inverter.c:1199)中每个循环调用一次 inovance_inverter_comm_can(),随后调用一次 inovance_inverter_data_check_can();该任务以 g_t_fast_dispatch_flag 事件标志加 30 ms 延时驱动。
初始化入口 inovance_comm_init_can() 在 inverter.c:103(逆变器类型识别后)以及 inovance_comm_usart.c:2307(inovance_upgrade_init())和 inovance_comm_usart.c:413(软重启流程)中被调用。
本文件不产生新任务、不适用信号量/消息邮箱,全部以"轮询 + 标志位 + tick 时间戳"方式与 uCOS-II 协作。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
INOVANCE_INV_DEBUG_CAN | 宏 | 本文件所有 #if 调试打印的总开关,定义在 inovance_comm_can.h:16,值为 0(默认关闭) |
INOVANCE_EMS_INV_CAN_COMM_LOST_TIME | 宏 | CAN 通讯丢失判据,15 * 1000 ms(inovance_comm_can.h:17) |
CAN_MSG_TYPEDEF_T | 结构体 | CAN 帧容器,定义在 hardware/can/can0.h:20:frame_id(u32)、frame_type(u8)、frame_len(u8)、frame_data[8]、reading_flag,#pragma pack(1) 紧凑对齐 |
CAN_FT_DATA | 宏 | 帧类型 = 数据帧,赋值给 frame_type |
INOVANCE_EMS_INV_IDCODE_PACK = 0x181 | 宏 | EMS→逆变器 身份握手帧(inovance_comm_usart.h:125) |
INOVANCE_EMS_INV_SET_CTRL_MODE = 0x190 | 宏 | EMS→逆变器 三相平衡/不平衡控制模式(:126) |
INOVANCE_EMS_CTRL_INV_AC_POWER1 = 0x192 | 宏 | EMS→逆变器 交流有功功率设定(:127) |
INOVANCE_EMS_CTRL_INV_BAT_STATE = 0x193 | 宏 | EMS→逆变器 电池充放电限值 + 电池接入状态(:128) |
INOVANCE_EMS_SEND_BMS_POWER_LIMIT = 0x194 | 宏 | EMS→逆变器 BMS 最大充放电功率(:129) |
INOVANCE_EMS_SET_INV_CTRL_ARG1 = 0x195 | 宏 | EMS→逆变器 MPPT 百分比 / 备电频率偏移 / UPS 使能(:130) |
INOVANCE_EMS_SEND_BAT_RUNNING_DATA = 0x1A0 | 宏 | EMS→逆变器 电池运行数据(:131) |
INOVANCE_EMS_SEND_BAT_PROTECT = 0x1A1 | 宏 | EMS→逆变器 电池保护参数(:132) |
INOVANCE_INV_EMS_IDCODE_PACK = 0x201 | 宏 | 逆变器→EMS 身份应答(:134) |
INOVANCE_INV_EMS_RUN_INFO_PACK4 = 0x263 | 宏 | 逆变器→EMS 电网 A/B 相电压与有功(:135) |
INOVANCE_INV_EMS_RUN_INFO_PACK5 = 0x264 | 宏 | 逆变器→EMS 电网 C 相电压、总有功、电网频率(:136) |
INOVANCE_INV_EMS_RUN_INFO_PACK6 = 0x265 | 宏 | 逆变器→EMS 备电 A/B 相电压与有功(:137) |
INOVANCE_INV_EMS_RUN_INFO_PACK7 = 0x266 | 宏 | 逆变器→EMS 备电 C 相、备电总有功与频率(:138) |
INOVANCE_INV_EMS_RUN_INFO_PACK8 = 0x267 | 宏 | 逆变器→EMS 备电各相视在功率(:139) |
INOVANCE_INV_EMS_RUN_INFO_PACK9 = 0x268 | 宏 | 逆变器→EMS 机侧各相有功(:140) |
INOVANCE_INV_EMS_RUN_INFO_PACKA = 0x269 | 宏 | 逆变器→EMS 机侧总有功、逆变频率、运行模式、电池功率(:141) |
INOVANCE_INV_INIT_TIME | 宏 | 握手帧重发周期 2 * 1000 ms(inovance_comm_usart.h:27) |
INOVANCE_TYPE_E | 枚举 | 机型:INOVANCE_TYPE_T12=1 / T15=2 / T20=3 / T20_OLD=52(inovance_comm_usart.h:161),本文件用 t_run_info.u16_inv_type 决定爬坡上限 |
INOVANCE_TABLE_T | 结构体 | 汇川通信总表 g_t_inovance_comm_info(inovance_comm_usart.h:719),本文件只用其中的 CAN 部分字段与 t_run_info.u16_inv_type |
INVERTER_CONTROL_CMD_TABLE_T | 结构体 | 逆变器控制命令表(inverter.h:1857),inovance_inverter_data_check_can() 用其静态实例做"上一拍值"缓存 |
INVERTER_TABLE_T | 结构体 | 逆变器总表 g_t_inv_info(inverter.h:1929 外部声明),本文件读写其 t_run_info / t_control_cmd / t_config_data / t_safty_info |
PHASE_L1/L2/L3 | 枚举 | 相序标识(inverter.h:348),用于 parallel_read_ac_three_phase_set_inv_power() |
cNormalMode = 3 | 宏 | 逆变器正常运行模式(inverter.h:23) |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
CAN_Send_Msg (42) | static | CAN 发送统一出口:保证两帧之间至少间隔 2 ms,再调用 can1_send_standard_pack() |
send_ems_inv_idcode_cmd (63) | static | 发送 0x181 握手帧,数据域为 ASCII "AlphaESS" |
set_inv_ctrl_mode (92) | static | 发送 0x190 控制模式帧:三相不平衡置 2、平衡置 1、未知置 0 |
relink_grid_power_limit (131) | static | 按机型额定功率与"重连后速率"计算重连功率爬坡上限(double,返回累积值) |
send_ac_ctrl_inv_power (202) | static | 发送 0x192 交流有功设定:平衡模式用总有功,不平衡模式用三相各自值,并按爬坡上限限幅 |
send_inv_ac_ctrl_bat_state (289) | static | 发送 0x193:电池充/放电功率限值(u16)与电池接入状态 |
send_inv_bms_power_limit (326) | static | 发送 0x194:BMS 最大充电/放电功率,成功则清 u8_set_inv_bms_power_limit_flag |
send_inv_bms_running_data (363) | static | 发送 0x1A0:电池电压、继电器状态、SOC(写死 100)、充电状态 |
send_ems_set_bat_protect (415) | static | 发送 0x1A1:放电截止电压、放电最大电流、充电截止电压、充电最大电流,成功则清 u8_set_inv_bat_protect_flag |
set_inv_ctrl_arg1 (454) | static | 发送 0x195:MPPT 百分比、备电输出频率偏移、UPS 使能,成功则清 u8_set_inv_ctrl_arg1_flag |
inovance_comm_init_can (487) | 全局 | 初始化 CAN1 预分频为 8(若不等于 8 才重配),并置位全部首次下发标志、恢复默认控制参数 |
inovance_inverter_data_check_can (510) | 全局 | 变化检测器:比对三相模式、UPS 使能、BMS 限值、电池保护参数,按变化置对应下发标志 |
inovance_inverter_comm_can (593) | 全局 | CAN 通讯主循环:握手 → 周期/事件下发 → 批量收帧解析 → 通讯丢失判定与重初始化 |
说明:文件顶部第 25-33 行另有一份前向声明列表,其中声明了
CAN_Send_Msg、send_ems_inv_idcode_cmd、send_ac_ctrl_inv_power、set_inv_ctrl_arg1、send_ems_set_bat_protect、send_inv_bms_running_data、send_inv_bms_power_limit、send_inv_ac_ctrl_bat_state、set_inv_ctrl_mode共 9 个;relink_grid_power_limit因定义在使用点之前(131 行 vs 230 行)未列入声明。
4. 核心逻辑解析
4.1 握手与"上线"状态机
inovance_inverter_comm_can()(593)先用一个 u8_ems_inv_idcode_flag 把流程切成两半:
- 未握手阶段(
u8_ems_inv_idcode_flag == TRUE,602-612):每超过INOVANCE_INV_INIT_TIME(2000 ms)发一次 0x181 帧,数据域为'A','l','p','h','a','E','S','S'。握手期间 只发握手帧,不做任何功率/限值下发。 - 握手完成(收到 0x201,654-661):
u8_ems_inv_idcode_flag = FALSE,同时清u8_inverter_can_comm_lost_flag并刷新u32_ems_inv_can_comm_tick,此后进入常规下发。
该标志在 inovance_comm_init_can()(496)被重新置 TRUE,因此每次通讯丢失或初始化后都会重新走一遍握手流程。这种"握手-放行"设计确保逆变器在未确认 EMS 身份前不会接受功率指令。
4.2 下发通道的周期与事件划分
握手完成后,else 分支(614-646)按三种节奏下发:
| 触发方式 | 帧 ID | 周期/条件 | 位置 |
|---|---|---|---|
| 条件标志(变化驱动) | 0x190 set_inv_ctrl_mode() | u8_set_inv_ctrl_mode_flag == TRUE | 615-618 |
| 周期 50 ms | 0x192 → 0x1A0 → 0x193(三帧连发) | (OSTimeGet() - u32_ems_send_inv_ctrl_power_tick) > 50 | 620-630 |
| 条件标志 | 0x195 set_inv_ctrl_arg1() | u8_set_inv_ctrl_arg1_flag == TRUE | 632-635 |
| 条件标志 | 0x194 send_inv_bms_power_limit() | u8_set_inv_bms_power_limit_flag == TRUE | 637-640 |
| 条件标志 | 0x1A1 send_ems_set_bat_protect() | u8_set_inv_bat_protect_flag == TRUE | 642-645 |
每个 tick 比较后面都跟一段 else if(tick > OSTimeGet()) 的"回绕补偿"(如 627-630),把时间戳重新对齐到当前 tick,避免 u32 tick 溢出后长时间不再下发。
被置为 TRUE 的四个条件标志只在对应发送函数返回 TRUE 时才清零(119-122、350-353、474-477、441-444),即"发送成功才销账",形成一次到位的重发机制。
CAN_Send_Msg()(42)本身还有一层节流:若距上次发送不足 2 个 tick,则 OSTimeDlyHMSM(0,0,0,2) 延时 2 ms,保证 50 ms 内连发 3 帧时不会挤在同一时刻。
4.3 重连功率爬坡算法 relink_grid_power_limit()
该函数只在 send_ac_ctrl_inv_power() 中按 500 ms 周期被调用(228-236),内部再按实际 tick 差计算真实经过时间:
delta_ticks = current_tick - prev_relink_tick // 正常情况
= OS_TICKS_PER_SEC - prev + current + 1 // 回绕分支
delta_time_sec = delta_ticks * 0.001 // 隐含 1 tick = 1 ms
accumulated_error += delta_time_sec - 0.5 // 记录与理论 0.5 s 的偏差
rate_per_sec = (g_t_inv_info.t_safty_info.u16_rev_machine_rate / 1000.0) / 60.0
increment = rate_per_sec * inv_power_limit * delta_time_sec
relink_power_limit = min(relink_power_limit + increment, inv_power_limit)
- 额定功率
inv_power_limit按机型硬编码(151-168):INOVANCE_TYPE_T20/T20_OLD/default= 20000,T15= 15000,T12= 12000。 u16_rev_machine_rate的单位在inverter.h:568标注为"0.1%pn/Min 重连后速率",因此/1000.0得到每分钟额定功率占比,再/60.0得到每秒占比,乘额定功率即每秒瓦数增量。- 当
g_t_logic_info.t_logic_control_parameter.u8_grid_status == FALSE(离网)时,爬坡值直接归零并清误差(170-173),保证离网不参与重连限幅。 - 否则当
abs(accumulated_error * 10) >= 5(即累积偏差 ≥ 0.5 s)时清误差(176-180)。此处原本用于补偿的delta_time_sec += accumulated_error;已被注释(178 行),因此误差项实际上只做记录与复位,不参与计算。 - 结果钳位到
[0, inv_power_limit](187-188)。
4.4 交流功率下发与限幅 send_ac_ctrl_inv_power()
216-219 行按三相平衡状态取设定值:
- 平衡模式(
inverter_get_three_unbalance_mode() == FALSE):取parallel_read_ac_total_set_inv_power()存入s16。 - 不平衡模式:分别取
parallel_read_ac_three_phase_set_inv_power(PHASE_L1/L2/L3)。
238-245 行用爬坡值做双向限幅:
若 l_s16_ac_set_actpower > 0 且 |值| > relink_power_limit → 取 +relink_power_limit
若 l_s16_ac_set_actpower ≤ 0 且 |值| > relink_power_limit → 取 -relink_power_limit
即无论充电还是放电,幅度都被限制在同一个爬坡窗口内。帧数据域排布(267-277)为 4 个 16 位有符号量,大端(高字节在前):[0:1]=总有功、[2:3]=A 相、[4:5]=B 相、[6:7]=C 相,每相只发送 s32 的低 16 位。
248-258 行是一段被整块注释掉的 TOR_SAFTY_CONTROL_BAT 强制充电取反逻辑,属版本遗留代码。
4.5 电池相关帧的数据来源
- 0x193
send_inv_ac_ctrl_bat_state()(296-306):充/放电限值按平衡状态从parallel_read_ac_total_set_bat_charge_limit_power()/parallel_read_ac_three_phase_set_bat_charge_limit_power()等取值;frame_data[4]为pvcharger_read_bat_connect_state()(电池接入状态);[5:7]未使用,保持 0。 - 0x1A0
send_inv_bms_running_data()(363-405):[0:1]=电池电压、[2]=电池继电器状态、[3]=SOC、[5]=充电状态,[4]/[6]/[7]固定 0。其中l_u8_bat_soc = 100;是故意写的假数据(383 行注释"防止逆变器根据电池SOC进入某些逻辑")。充电状态取parallel_read_ac_total_set_bat_forced_charge_en(),为 TRUE 时置 2,否则 0;若inverter_read_run_mode() != cNormalMode则强制清 0(378-381)。 - 0x194
send_inv_bms_power_limit()(326-354):[0:1]=最大充电功率、[2:3]=最大放电功率,分别来自pvcharger_read_bat_max_charge_power()/pvcharger_read_bat_max_dischg_power()。 - 0x1A1
send_ems_set_bat_protect()(415-445):数据来自g_t_inv_info.t_run_info的四个保护值(u16_dischg_cut_rate_volt、u16_dischg_max_rate_cur、u16_chg_cut_rate_volt、u16_chg_max_rate_cur),它们由下一节的检测函数维护。
4.6 变化检测器 inovance_inverter_data_check_can()
522-523 行:若仍在握手阶段(u8_ems_inv_idcode_flag == TRUE)直接返回,不检测。
三类检测:
- 三相不平衡模式变化(525-529):与静态缓存
s_u8_inv_three_unbalance_mode比较,变化则置u8_set_inv_ctrl_mode_flag。 - UPS 使能变化(531-535):与静态
INVERTER_CONTROL_CMD_TABLE_T s_t_run_control_cmd的u8_ups_enable比较,变化则置u8_set_inv_ctrl_arg1_flag。注意只用了该结构体一个字段,其余字段未被使用。 - BMS 功率限值变化(539-544):最大充/放功率任一变化即置
u8_set_inv_bms_power_limit_flag。
电池保护参数部分(546-583)是核心限值算法:
l_u16_dischg_max_rate_cur = pvcharger_read_bat_max_dischg_current()
l_u16_chg_max_rate_cur = pvcharger_read_bat_max_charge_current()
l_u16_dischg_max_rate_volt = pvcharger_read_bat_dischg_cut_off_volt()
l_u16_chg_max_rate_volt = pvcharger_read_bat_charge_cut_off_volt()
充电截止电压 > 配置上限 → 压回配置上限 (552-555)
放电截止电压 < 配置下限 → 抬回配置下限 (557-560)
放电最大电流 > 配置上限 → 压回配置上限 (562-565)
充电最大电流 > 配置上限 → 压回配置上限 (567-570)
只有四项中任一与 g_t_inv_info.t_run_info 现存值不同时才写入并置 u8_set_inv_bat_protect_flag(573-583)。电压限值方向不对称是刻意为之:充电截止电压是上限、放电截止电压是下限,二者都被"收紧"到配置允许范围内。
4.7 CAN 接收解析循环
648-778 行是接收主体:
l_u32_inv_recv_tick = OSTimeGet();
while(get_can1_standard_pack(&l_t_inverter_info) == TRUE) {
switch(frame_id) { ... }
if(abs(l_u32_inv_recv_tick - OSTimeGet()) > 10) break; // 单次最多解析 10 ms
}
get_can1_standard_pack() 从 can1 驱动的接收队列取帧,队列深度 CAN1_STANDARD_PACK_LEN = 80(hardware/can/can1.h:18)。每个 case 内都把两个字节拼成一个量并写回 g_t_inv_info.t_run_info,同时刷新 u32_ems_inv_can_comm_tick。解析出的字段映射如下:
| 帧 ID | 字节映射(大端) | 写入的全局量 |
|---|---|---|
| 0x263(664-667) | [0:1] / [2:3] / [4:5] / [6:7] | u16_grid_volt_a、s32_grid_actpower_a、u16_grid_volt_b、s32_grid_actpower_b |
| 0x264(679-682) | [0:1] / [2:3] / [4:5] / [6:7] | u16_grid_volt_c、s32_grid_actpower_c、s32_grid_actpower_t、u16_grid_freq |
| 0x265(694-699) | [0:1] / [2:3] / [4:5] / [6:7] | u16_backup_volt_a、s32_backup_actpower_a、u16_backup_volt_b、s32_backup_actpower_b(有功负值被钳到 0) |
| 0x266(711-716) | [0:1] / [2:3] / [4:5] / [6:7] | u16_backup_volt_c、s32_backup_actpower_c、s32_backup_actpower_t、u16_backup_freq(有功负值被钳到 0) |
| 0x267(728-731) | [0:1]…[6:7] | s32_backup_apparentpower_a/b/c/t |
| 0x268(743-745) | [0:1]/[2:3]/[4:5] | s32_inv_actpower_a/b/c |
| 0x269(756-759) | [0:1]/[2:3]/[4]/[5:6] | s32_inv_actpower_t、u16_inv_freq、u8_run_mode、s16_bat_power |
| 0x201(654-661) | 无数据解析 | 握手完成标志 |
注意所有解析都把 16 位值强转 (s16) 后再赋给 s32 字段(如 665 行),即符号扩展由 (s16) 强制转换完成;电压类字段则强转 (u16)。
4.8 通讯丢失判定与重初始化
if(abs(u32_ems_inv_can_comm_tick - OSTimeGet()) >= INOVANCE_EMS_INV_CAN_COMM_LOST_TIME /*15000*/)
{
inovance_comm_init_can();
g_t_inv_info.t_run_info.u8_inverter_can_comm_lost_flag = TRUE;
}
15 s 内没有收到任何帧(u32_ems_inv_can_comm_tick 未被刷新)即判为丢失:重新执行 inovance_comm_init_can()(重新握手 + 重新置全部下发标志),并置位丢失标记,由 inverter_lost_handle_can()(inverter.c)与 inverter_lost_handle() 转成故障位。
4.9 升级期间的互斥
598-599 行的门限:
if(!(is_inverter_firm_download_finished() || Get_Status_Is_Updated_From_Server(UPDT_INV3)))
- 条件为真 → 走正常 CAN 收发。
- 条件为假(固件下载完成或 UPDT_INV3 有效,即正在/即将升级)→ 只执行
u32_ems_inv_can_comm_tick = OSTimeGet();(788 行),既不发帧也不收帧,同时让丢失计时器不过期,避免升级期间误报通讯丢失。
这是本文件与 inovance_upgrade.c 之间唯一的协作点,走的是 net/inv_download.h 与 net/upd_download.h 提供的升级状态标志,不用信号量。
5. 对外接口
5.1 本文件导出(供外部调用)
| 名称 | 类型 | 调用方 |
|---|---|---|
inovance_comm_init_can | 函数 | inverter.c:103(机型识别后初始化)、inovance_comm_usart.c:2307(inovance_upgrade_init)、inovance_comm_usart.c:413(DSP 软重启后) |
inovance_inverter_comm_can | 函数 | inverter.c:1264,位于 task_inverter_can() 主循环 |
inovance_inverter_data_check_can | 函数 | inverter.c:1265,紧随上者之后 |
本文件没有导出任何全局变量(static 变量均为函数内局部静态)。
5.2 本文件调用/引用的外部符号
| 来源模块 | 符号 |
|---|---|
hardware/can/can1.h | can1_send_standard_pack、get_can1_standard_pack、can1_mode_init、get_can1_prescaler |
hardware/can/can0.h | CAN_MSG_TYPEDEF_T、CAN_FT_DATA |
midware/inverter/inverter.h | g_t_inv_info、inverter_get_three_unbalance_mode、inverter_read_run_mode、cNormalMode、PHASE_L1/L2/L3 |
midware/inverter/parallel.h | parallel_read_ac_total_set_inv_power、parallel_read_ac_three_phase_set_inv_power、parallel_read_ac_total_set_bat_charge_limit_power、parallel_read_ac_three_phase_set_bat_charge_limit_power、parallel_read_ac_total_set_bat_dischg_limit_power、parallel_read_ac_three_phase_set_bat_dischg_limit_power、parallel_read_ac_total_set_bat_forced_charge_en、parallel_read_ac_three_phase_set_bat_forced_charge_en |
midware/inverter/pvcharger.h | pvcharger_read_bat_connect_state、pvcharger_read_bat_volt、pvcharger_read_bat_soc、pvcharger_read_bat_relay_state、pvcharger_read_bat_max_charge_power、pvcharger_read_bat_max_dischg_power、pvcharger_read_bat_max_charge_current、pvcharger_read_bat_max_dischg_current、pvcharger_read_bat_charge_cut_off_volt、pvcharger_read_bat_dischg_cut_off_volt |
net/inv_download.h | is_inverter_firm_download_finished |
net/upd_download.h(经 inv_download.h 传递) | Get_Status_Is_Updated_From_Server、UPDT_INV3 |
logic/logic.h | g_t_logic_info.t_logic_control_parameter.u8_grid_status |
midware/inverter/inovance/inovance_comm_usart.h | g_t_inovance_comm_info、全部 CAN 帧 ID 宏、INOVANCE_TYPE_E、INOVANCE_INV_INIT_TIME |
| uCOS-II | OSTimeGet、OSTimeDlyHMSM |
5.3 本文件写入的全局状态
g_t_inovance_comm_info.u8_ems_inv_idcode_flag/u8_set_inv_ctrl_mode_flag/u8_set_inv_ctrl_arg1_flag/u8_set_inv_bms_power_limit_flag/u8_set_inv_bat_protect_flagg_t_inovance_comm_info.u32_ems_inv_idcode_tick/u32_ems_send_inv_ctrl_power_tick/u32_ems_inv_can_comm_tickg_t_inv_info.t_run_info.*(三相电网/备电/机侧电压电流功率、频率、运行模式、电池功率、电池保护参数、u8_inverter_can_comm_lost_flag)g_t_inv_info.t_control_cmd.u8_ups_enable(仅在 495 行初始化时)
6. 依赖关系
依赖(本文件 include/使用)
inovance_comm_can.h(自身头文件)inovance_comm_usart.h(帧 ID、通信总表、机型枚举——本文件所用全部 CAN ID 实际定义在此)inverter.h、parallel.h、pvcharger.h(后两者经inverter.h传递包含)logic.h(g_t_logic_info)、data.hinv_download.h→upd_download.h、server.hcan0.h、can1.hcrc.h、bms.h(含重复包含一次)、bms_download.h、meter.h、ems.h、system_config.h、wireless_driver.h
被依赖(谁用到本文件)
midware/inverter/inverter.c(初始化与两个任务级调用点)midware/inverter/inovance/inovance_comm_usart.c(inovance_upgrade_init()与软重启流程中调用inovance_comm_init_can())
7. 备注与风险点
- SOC 假数据:
send_inv_bms_running_data()第 383 行l_u8_bat_soc = 100;硬编码为 100,注释写明是为规避逆变器内部 SOC 逻辑。副作用是逆变器侧完全看不到真实 SOC,任何依赖 SOC 的逆变器保护失效。 - 接收缓冲区无长度上限:
while(get_can1_standard_pack(...))的解析循环没有帧数上限,只用 10 ms 时间窗兜底(774-777)。若 10 ms 内可解析的帧数不足,剩余帧会留到下一个 30 ms 周期,可能加剧队列积压(队列深度 80 帧)。 relink_grid_power_limit()中的误差补偿是死代码:第 178 行//delta_time_sec += accumulated_error;被注释,accumulated_error只做累加与清零,实质不影响输出;第 176 行阈值abs(accumulated_error * 10) >= 5的 10 倍放大属魔法数字。- tick 回绕处理不完整:142-144 行的回绕分支写成
OS_TICKS_PER_SEC - prev_relink_tick + current_tick + 1,这是"秒内计数器"的写法,而OSTimeGet()返回的是 32 位累计 tick,正确做法应是(u32)(current - prev)。由于 32 位 tick 在 1000 tick/s 下约 49.7 天才回绕,该分支实际几乎不可达,但逻辑本身错误。 - 窄化赋值/隐式截断(多处):
- 216 行
l_s16_ac_set_actpower = parallel_read_ac_total_set_inv_power();,s32 → s16。 - 296-297 行
parallel_read_ac_three_phase_set_bat_charge_limit_power()等返回s32,赋给u16。 - 333-334 行
pvcharger_read_bat_max_charge_power()/..._max_dischg_power()返回s32,赋给u16。 - 374 行
pvcharger_read_bat_volt()返回s16,赋给u16。 - 240/244 行
l_s16_ac_set_actpower = relink_power_limit;,double → s16隐式转换(当前上限 20000 不会溢出,但依赖该上限)。 - 546-550 行
pvcharger_read_bat_max_dischg_current()等返回s16,赋给u16,若 BMS 上报负值(无效值)会回绕成接近 65535 的大数,随后的"大于配置上限则压回"判断将失效,把无效保护值原样下发给逆变器。
- 216 行
send_ac_ctrl_inv_power()与send_inv_ac_ctrl_bat_state()的平衡判据写法不一致:前者用== FALSE/!= FALSE(216-219),后者用== FALSE的二分(296-297)。若inverter_get_three_unbalance_mode()返回非 0/1 的值(1 以外的真值),两处行为会不同——set_inv_ctrl_mode()(97-108)的三分支写法正好说明该函数可能存在第三种返回值。default分支静默按 20 kW 处理(165-167):新增机型而未更新switch时,重连爬坡上限会按 T20 的 20000 W 计算,可能超过实际额定功率。- 头注释与实际签名不符(版本遗留):如 86 行注释
static u8 set_inv_ctrl_mode(void)实际为void(92 行);125 行注释static void relink_grid_power_limit(void)实际返回double(131 行);320 行注释static u8 send_inv_bms_power_limit(void)实际为void(326 行)。 - 冗余 include:
bms.h在第 4 行与第 16 行重复包含;crc.h、data.h、system_config.h、wireless_driver.h、ems.h、meter.h、can0.h、bms_download.h在本文件内未检出直接引用的符号(CAN_MSG_TYPEDEF_T/CAN_FT_DATA来自can0.h,其余应属历史遗留)。 - 被注释掉的整块逻辑:248-258 行
TOR_SAFTY_CONTROL_BAT强制充电取反逻辑;175-181 行的调试printf与误差补偿代码。 - 无应用层校验:CAN 帧不含 CRC 或序号,仅依赖 CAN 控制器硬件 CRC/自动重发;数据有效性完全靠周期性刷新帧体现,单帧错误无法在应用层识别。
- 魔法数字:50 ms 下发周期(620)、500 ms 爬坡调用周期(228)、10 ms 收帧时间窗(774)、20000/15000/12000 W 额定功率、
u8_ups_enable = 0x02(495)、u8_bat_chg_state = 2(377)均直接硬编码。