alphaess_comm_can.c
alphaess_inverter_can_data_check():数据搬运与标志置位(:1330)4.9 定时/调度与 uCOS-II 协作4.10 关键全局变量读写汇总5. 对外接口本文件导出(供外部调用)本文件依赖的外部符号6. 依赖关系依赖被依赖7. 备注与风险点源文件路径:
midware/inverter/alphaess/alphaess_comm_can.c所属模块:midware/inverter/alphaess(AlphaESS 逆变器 CAN 通信 + VAVE 电表芯片校准) 代码行数:1403
1. 文件职责
本文件实现 AlphaESS 储能逆变器的 CAN 侧通信主逻辑,是 EMS 与逆变器 DSP 之间除 SCI(串口)之外的第二条控制通道。它承担四件事:一是完成 EMS→逆变器的身份握手(0x181 "AlphaESS"),二是把 g_t_inv_info 中已经算好的功率/电池/备份/UPS 指令周期性组帧下发,三是接收并解析逆变器与 VAVE 电表芯片回传的 0x263~0x269、0x301~0x310 运行数据,把电网/光伏三相电压、电流、功率填进 g_t_meter.t_grid_info.t_data / g_t_pv_info.t_data,四是承载 DSP 电表芯片的整定/校准参数(0x340~0x350、0x360、0x361)下发与回读。
它处于「逻辑层算出功率 → CAN 下发 → 逆变器执行 → CAN 回传实际值 → 逻辑层闭环」这条数据流的中段,被 task_inverter_can(inverter.c:1199)以 30 ms 周期调用;alphaess_inverter_can_data_check() 则在同一次任务里被紧接着调用,负责把 CAN 收到的数据"搬运"到全局电表结构并置位相应的重发标志。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
ALPHAESS_INV_DEBUG | 宏 | 调试打印总开关,本文件内为 (0),默认关闭 |
ALPHAESS_EMS_INV_IDCODE_PACK (0x181) | 宏 | EMS→INV 握手帧 ID,数据域为 ASCII "AlphaESS" |
ALPHAESS_EMS_CTRL_BACKUP (0x184) | 宏 | EMS→INV 备份/UPS 使能控制帧 |
ALPHAESS_EMS_INV_SET_CTRL_MODE (0x190) | 宏 | EMS→INV 控制模式帧(单相/三相不平衡) |
ALPHAESS_GINLONG_EMS_CTRL_INV_AC_POWER1 (0x192) | 宏 | EMS→INV AC 有功功率给定(总有功 + A/B/C 相) |
ALPHAESS_EMS_CTRL_INV_AC_POWER2 (0x193) | 宏 | EMS→INV 直流侧充/放电限值 + 软启动 + 电池连接状态 + 电池总电流 |
ALPHAESS_EMS_READ_BAT_CHG_DISCHG (0x194) | 宏 | EMS→INV 电池最大充/放电功率(变化时才发) |
ALPHAESS_EMS_SET_INV_CTRL_ARG1 (0x195) | 宏 | EMS→INV MPPT 百分比 + 备份输出频率偏移 |
ALPHAESS_EMS_SEND_BAT_STATE (0x1A0) | 宏 | EMS→INV 电池运行状态(电压/继电器/SOC/强充使能) |
ALPHAESS_EMS_SEND_BAT_PROTECT (0x1A1) | 宏 | EMS→INV 电池保护参数(放电截止电压/电流、充电截止电压/电流) |
ALPHAESS_INV_EMS_IDCODE_PACK (0x201) | 宏 | INV→EMS 握手应答帧 ID |
ALPHAESS_INV_EMS_RETURN_RUN_INFO_PACK4~PACKA (0x263~0x269) | 宏 | INV→EMS 运行数据回传帧,共 7 帧 |
DSP_METER_RUN_INFO_PACK1~PACK10 (0x301~0x310) | 宏 | VAVE 电表芯片回传运行数据(正反向电能、三相电压/电流/有功/视在、版本号) |
DSP_METER_CALI_DATA_PACK0~PACKA (0x340~0x34A) | 宏 | VAVE 电表芯片校准数据下行帧(电压/电流/PV 电流/放电功率/充电功率校准点、校准模式、CT 自检) |
DSP_METER_CALI_DATA_PACKB (0x350) | 宏 | 双向帧:下行为相数据校准,上行为 0x350 回读帧 |
DSP_METER_CALI_DATA_PACKC (0x360) | 宏 | 设置储能逆变发电量 / 买电量 |
DSP_METER_CALI_DATA_PACKD (0x361) | 宏 | 设置并网机发电量 |
ZERO_CONFIRM_CNT | 宏 | 值为 5,连续 N 次采样为 0 才判定为真实 0(毛刺滤波阈值) |
zero_glitch_filter_t | 结构体 | 采样值偶发 0 毛刺滤波器状态:s32_last_value + u8 zero_cnt |
ALPHAESS_OPERATION_MODE_E | 枚举 | 逆变器工作模式:上电/等待/旁路/自检/并网/离网/自测试/故障/升级/关机/直流模式,另含 ALPHAESS_POWER_ON_E_2 = 255 |
SEND_CALIBRATION_DATA_FLAG | 联合体 | 16 位校准发送标志位域(电压/电流/PV 电流/放电功率 0-1/PV 放电功率 0-1/充电功率 0-1/校准模式/CT 自检/相位校准/发电量设置),含 bit14/bit15 保留位 |
DSP_METER_CALIBRATION_DATA | 结构体 | DSP 电表全部可写参数容器,含 R/S/T 三相各类校准点、校准模式、CT 自检、相位数据、储能逆变与并网机发电量;#pragma pack(1) 紧凑布局 |
CAN_MSG_TYPEDEF_T | 结构体 | 外部类型(hardware/can/can0.h:21),CAN 报文描述:frame_id / frame_type / frame_len / frame_data[8] / reading_flag |
METER_DATA_T | 结构体 | 外部类型(midware/meter/meter.h:189),标准电表数据(电压/电流/有功/无功/功率因数/频率/电能) |
CAN_FT_DATA | 宏 | CAN 数据帧类型标志(can0.h) |
cWaitMode/cNormalMode/cUPS/cFaultMode/cCheckMode/cSelfTest/cByPassMode/cDCMODE | 宏 | 外部宏(inverter.h:20~27),逆变器统一运行模式码 |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
alphaess_comm_init_can | 全局 | CAN 初始化与 CAN 侧标志复位;预分频不为 4 时重新 can1_mode_init(4) |
ems_ate_reset_dsp | 全局 | ATE 复位 DSP:连发 AC 功率、DC 限值、电池可用功率、电池状态四类帧 |
CAN_Send_Msg | static | CAN 发送封装,保证相邻两帧至少间隔 1 个 tick,转发 can1_send_standard_pack |
parse_alphaess_work_mode | 全局 | 把 ALPHAESS 工作模式码翻译为项目统一运行模式码(cWaitMode 等) |
send_ems_inv_idcode_cmd | static | 发送 0x181 握手帧,数据域 ASCII "AlphaESS" |
set_inv_ctrl_mode | static | 发送 0x190 控制模式帧(单相=1 / 三相不平衡=2),成功后清标志 |
send_ac_ctrl_inv_power1 | static | 组发 0x192:总有功 + A/B/C 三相有功,含放电/充电额定功率限幅 |
send_dc_ctrl_inv_power_2 | static | 组发 0x193:电池充/放电限值、软启动、电池连接状态、电池总电流 |
send_ems_read_bat_power | static | 组发 0x194:电池最大充/放电功率,仅当值变化或强制发送时发出 |
send_bat_run_info | static | 组发 0x1A0:电池电压、继电器状态、SOC、强充使能 |
send_bat_protect_info | static | 组发 0x1A1:放电截止电压/电流、充电截止电压/电流(4 × s16) |
send_bat_state | static | 组合调用 send_bat_run_info + send_bat_protect_info |
ems_ctrl_inv_backup | static | 发送 0x184 备份/UPS 使能帧,成功后清 u8_set_backup_enable_flag |
ems_ctrl_inv_inv_ctrl_arg1 | static | 发送 0x195 MPPT 百分比 + 备份输出频率偏移,成功后清标志 |
ems_send_340pack | static | 发送 0x340:R/S/T 相电网电压校准点,发完清标志并清缓冲区 |
ems_send_341pack | static | 发送 0x341:R/S/T 相电网电流校准点 |
ems_send_342pack | static | 发送 0x342:R/S/T 相 PV 电流校准点 |
ems_send_343pack | static | 发送 0x343:R/S/T 相电网放电功率校准点 0 |
ems_send_344pack | static | 发送 0x344:R/S/T 相电网放电功率校准点 1 |
ems_send_345pack | static | 发送 0x345:R/S/T 相 PV 放电功率校准点 0 |
ems_send_346pack | static | 发送 0x346:R/S/T 相 PV 放电功率校准点 1 |
ems_send_347pack | static | 发送 0x347:R/S/T 相电网充电功率校准点 0 |
ems_send_348pack | static | 发送 0x348:R/S/T 相电网充电功率校准点 1 |
ems_send_349pack | static | 发送 0x349:校准模式、复位校准模式、清除电量指令 |
ems_send_34Apack | static | 发送 0x34A:CT 自检模式使能 |
ems_send_350pack | static | 发送 0x350:R/S/T 相校准数据 + 校准模式触发 |
ems_send_360pack | static | 发送 0x360:储能逆变发电量(高/低字节)与买电量(高/低字节) |
ems_send_361pack | static | 发送 0x361:并网机发电量(高/低字节) |
ems_send_dsp_meter_calibration_data | static | 扫描 send_cali_data_flag 的 14 个 bit,按 bit 序号分派到 ems_send_3xxpack |
alphaess_inverter_comm_can | 全局 | 本文件主入口:握手 + 周期下发 + CAN 接收解析 + 链路丢失检测 |
alphaess_inverter_can_data_check | 全局 | CAN 侧数据后处理:把 DSP 电表数据搬到全局电表结构,检测三不平衡/UPS 变化置重发标志 |
zero_glitch_filter | 全局 | 采样值偶发 0 毛刺滤波:非 0 直接更新,0 则沿用上次值,连续 5 次 0 才放行真 0 |
zero_glitch_filter_reset | 全局 | 复位毛刺滤波器状态 |
4. 核心逻辑解析
4.1 CAN 帧格式与总线配置
全部报文使用 CAN 2.0 标准帧(11 位 ID),frame_len 恒为 8,数据域多字节字段一律 大端(高字节在前)。命令字即 CAN ID 本身,没有额外帧头与长度域;帧的语义完全由 ID 区分,因此 0x350 这类 ID 是双向复用的(下行校准数据、上行回读)。
总线由 alphaess_comm_init_can() 配置:can1_mode_init(4)(can1.c:47),预分频 = 4,BS1 = 16TQ、BS2 = 4TQ、SJW = 3TQ,注释标明 250 kbps。同时初始化四个 CAN 侧标志位(u8_ems_inv_idcode_flag、u8_set_inv_ctrl_mode_flag、u8_set_backup_enable_flag、u8_set_inv_ctrl_arg_flag1 全置 TRUE)并预置 u16_mppt_percentage = 10000(100.00%)、u8_ups_enable = 0x02。
CAN_Send_Msg()(:98)是唯一的发送出口,用一个 static tick 保证 相邻帧间隔 ≥ 1 tick(1 ms):
if(abs(OSTimeGet() - s_u32_send_tick) < 1) OSTimeDlyHMSM(0, 0, 0, 1);
s_u32_send_tick = OSTimeGet();
return can1_send_standard_pack(TxMsg);
4.2 链路建立状态机(握手)
alphaess_inverter_comm_can() 内部是一个以 g_t_alphaess_comm_info.u8_inv_parameter_init_flag 为闸门的隐式状态机:
- 未初始化(
u8_inv_parameter_init_flag == FALSE):- 若
u8_ems_inv_idcode_flag == TRUE(尚未握手成功)→ 握手态。每 1000 tick(1 s)发一次 0x181,同时把s_u8_send_bat_parameter_flag置 TRUE;收到 0x201 应答后该标志被清,进入下一态。 - 若
u8_ems_inv_idcode_flag == FALSE(已握手)→ 运行态。先按需发送一次性命令(0x190 / 0x184 / 0x195),然后每 20 tick(20 ms)发送send_bat_state()(0x1A0+0x1A1) +send_ac_ctrl_inv_power1()(0x192) +send_dc_ctrl_inv_power_2()(0x193);0x194 只在与上次缓存值不同或强制时发送。 - 时钟回绕保护:所有 tick 比较都写成
if((OSTimeGet() - tick) > N) ... else if(tick > OSTimeGet()) tick = OSTimeGet();,当u32计时器溢出导致tick大于当前值时直接把基准时间重置为当前时间,避免长时间不发帧。
- 若
- 已初始化(
u8_inv_parameter_init_flag == TRUE):直接走 else 分支,只把s_u8_send_bat_parameter_flag = TRUE,完全不下发任何 CAN 帧,仅保留接收解析。也就是说串口侧参数初始化期间 CAN 只监听不控制。
u8_inv_parameter_init_flag 由 alphaess_comm_usart.c:119 / :3659 / :4424 置 TRUE,在 :5112 被清除,是跨文件的同步点。
4.3 AC 功率下发与限幅算法(0x192)
send_ac_ctrl_inv_power1()(:229)先判 ATE 模式:
- ATE 模式:总有功 =
u32_ac_rate_discharge_power,三相值 0。 - 正常运行:分单相/三相不平衡两条路径——单相取
parallel_read_ac_total_set_inv_power();三相不平衡时总有功置 0,A/B/C 分别取parallel_read_ac_three_phase_set_inv_power(PHASE_L1/L2/L3)。
随后做符号相关限幅:
if (l_s16_ac_set_actpower > 0 && abs(...) > u32_ac_rate_discharge_power) → 取 +放电额定
else if (l_s16_ac_set_actpower <= 0 && abs(...) > u32_ac_rate_charge_power) → 取 -充电额定
注意三相独立值 l_s16_inv_ac_set_a/b/c_real_actpower 没有参与限幅,只对总有功限幅,这是一个潜在的一致性缺口。
4.4 电池状态与保护参数下发(0x1A0 / 0x1A1 / 0x193 / 0x194)
send_bat_run_info()(:405)在 ATE 模式下固定填frame_data[2] = 0x03,否则填[电压高字节, 电压低字节, 继电器状态, SOC/10, 0x00, 强充使能, 0, 0]。SOC 做了/10缩放(:415)。send_bat_protect_info()(:460)把放电截止电压、放电最大电流、充电截止电压、充电最大电流四个s16大端拼进 8 字节。send_dc_ctrl_inv_power_2()(:294)打包[充电限值, 放电限值, 软启动, 电池连接状态, 电池总电流];其中总电流来自pvcharger_read_bat_curr(),是s16赋给s16变量但由u16声明路径间接处理(:300)。send_ems_read_bat_power()(:342)采用事件触发:只有(s_u16_bat_pchg != 目标) || (s_u16_bat_pdischg != 目标) || send_flag == TRUE才发帧,发送成功才把缓存更新为当前值;返回值被上层当"是否还需要再发"用(:1123s_u8_send_bat_parameter_flag = (send_ems_read_bat_power(...) == FALSE);)。
4.5 校准数据分派(0x340~0x361)
ems_send_dsp_meter_calibration_data()(:978)是本文件的一个小型"命令分发器",for (i = 0; i < 13; i++) 扫描 dsp_meter_calibration_data.send_cali_data_flag.u16_all 的第 i 位,命中则 switch(i) 调对应 ems_send_3xxpack()。每个 pack 函数统一模式:填 ID → 填 8 字节大端数据 → CAN_Send_Msg → 若成功清对应 bit → memset 清零数据段。
bit 序号到帧的映射(:986~:1040):
0→340, 1→341, 2→342, 3→343, 4→344, 5→345, 6→346, 7→347, 8→348, 9→349, 0x0A→34A, 0x0B→350, 0x0C→360, 0x0D→361。
主循环里对这套标志做了两次处理:函数入口处(:1063)先统一发送并把 u16_all 清零一次;运行态分支内(:1118)又判断了一次 u16_all(此时恒为 0,属冗余代码)。
4.6 接收解析与数据落地
接收端是一个 while(get_can1_standard_pack(&l_t_inveter_info) == TRUE) 的排空循环(:1128),逐帧 switch(frame_id):
| 帧 ID | 落地目标 |
|---|---|
| 0x201 | 清 u8_ems_inv_idcode_flag、清 u8_inverter_can_comm_lost_flag、刷新 s_u32_can_rcv_tick |
| 0x263 | u16_grid_volt_a/b、s32_grid_actpower_a/b |
| 0x264 | u16_grid_volt_c、s32_grid_actpower_c/t、u16_grid_freq |
| 0x265 | u16_backup_volt_a/b、s32_backup_actpower_a/b |
| 0x266 | u16_backup_volt_c、s32_backup_actpower_c/t、u16_backup_freq |
| 0x267 | s32_backup_apparentpower_a/b/c/t |
| 0x268 | s32_inv_actpower_a/b/c |
| 0x269 | s32_inv_actpower_t、u16_inv_freq、u8_run_mode(经 parse_alphaess_work_mode)、s16_bat_power、u8_inv_bat_breaker_statuse |
| 0x301 | dsp_meter_grid_data.u32_energy_output[PHASE_T] / u32_energy_input[PHASE_T](32 位四字节拼接) |
| 0x302/0x303 | dsp_meter_grid_data.u16_volt[PHASE_A/B/C],经毛刺滤波;0x303 另填 u16_frequent |
| 0x304/0x305 | dsp_meter_grid_data.s16_current[A/B/C] |
| 0x306 | dsp_meter_pv_data.s16_current[A/B],并用 电压 × 电流 / 1000 反算 s32_actpower[PHASE_A] |
| 0x307 | dsp_meter_pv_data.s16_current[PHASE_C] |
| 0x308/0x309 | dsp_meter_grid_data.s32_actpower[A/B] 与 [C]/[PHASE_T] |
| 0x30A/0x30B | 空实现(break),未使用 |
| 0x30C/0x30D | dsp_meter_pv_data.s32_actpower[A/B/C],经毛刺滤波;0x30D 另填 [PHASE_T] |
| 0x30F | 空实现 |
| 0x310 | 8 字节写入 g_t_meter.t_grid_info.u8_vave_software_version[0..7] |
| 0x350 | 回读 s16_calib_r/s/t_data 与 u16_calib_mode_trigger |
u8_run_mode 的更新有双重门控(:1188):u8_inverter_comm_lost_flag == FALSE 且 is_inverter_firm_download_finished() == FALSE 时才允许刷新运行模式,避免升级期间模式跳变。
排空循环有一个看门狗(:1302):if(abs(l_u32_inv_recv_tick - OSTimeGet()) > 10) break;,即处理累计超过 10 tick 仍未排空就强制退出,防止 CAN 持续灌帧饿死同任务里的其他处理。
4.7 链路丢失与自愈时序
15 s 无 0x201/0x263~0x269 → alphaess_comm_init_can()(重新配 CAN + 复位标志)
55 s 仍无 → g_t_inv_info.t_run_info.u8_inverter_can_comm_lost_flag = TRUE
alphaess_comm_init_can() 会把四个标志重新置 TRUE,因此重连后会自动重跑"握手 → 一次性命令 → 周期下发"流程。注意阈值判断是嵌套的:只有 ≥15000 才继续判 ≥55000,所以 55 s 的判据一定在 15 s 之后才生效。
4.8 alphaess_inverter_can_data_check():数据搬运与标志置位(:1330)
- 若
u8_ems_inv_idcode_flag == TRUE(还没握手)直接 return。 - 仅在
BOARD_EMS3_6_3_E/BOARD_EMS3_6_4_E两种板型上,把 DSP 电表数据搬到全局电表:- 未插电网电表(
meter_get_meter_or_ct(GRID_METER) == FALSE)时,若逆变器处于cUPS则整个METER_DATA_T清零,否则memcpydsp_meter_grid_data; - 未插 PV 电表时,若系统模式为
DC_SYSTEM_MODE则清零,否则memcpydsp_meter_pv_data。
- 未插电网电表(
- 用 static
s_u8_inv_three_unbalance_mode做边沿检测,三不平衡模式变化时置u8_set_inv_ctrl_mode_flag = TRUE(下一轮会重发 0x190)。 - 用 static
s_t_run_control_cmd.u8_ups_enable做边沿检测,UPS 使能变化时置u8_set_backup_enable_flag = TRUE(重发 0x184)。
4.9 定时/调度与 uCOS-II 协作
| 调用点 | 任务 | 优先级 | 循环节拍 | 说明 |
|---|---|---|---|---|
alphaess_inverter_comm_can() | task_inverter_can(inverter.c:1249) | 15(app_cfg.h:66) | OSTimeDlyHMSM(0,0,0,30) = 30 ms | 等 g_t_fast_dispatch_flag 的 PEND_INV_CALCULATE_DONE 事件标志,20 tick 超时 |
alphaess_inverter_can_data_check() | 同上(inverter.c:1250) | 15 | 30 ms | 紧随其后 |
alphaess_comm_init_can() | inverter_init()(inverter.c:90)、alphaess_comm_usart.c:5692、本文件自愈路径 | — | — | 三处初始化 |
时间基准为 OSTimeGet(),OS_TICKS_PER_SEC = 1000(UCOSII/uCOS-CONFIG/os_cfg.h:51),即 1 tick = 1 ms。
任务与逻辑层的同步:task_inverter_can 里 g_t_alphaess_comm_info.u32_ems_send_inv_ctrl_power_tick1 = 0(inverter.c:1212)在收到 PEND_INV_CALCULATE_DONE 时被清零,等于"逻辑层刚算完,立刻允许下一轮功率下发",形成 20 ms 的功率刷新节拍;TASK_INVERTER_CAN_PRIO 也可被 OSTimeDlyResume 主动唤醒(inverter.c:1186)。本文件不直接使用信号量或消息邮箱,全部通过全局标志位 + tick 差值实现"软同步"。
4.10 关键全局变量读写汇总
| 变量 | 方向 | 触发条件 |
|---|---|---|
dsp_meter_calibration_data(本文件定义,:27) | 写(清标志/清数据) | 各 ems_send_3xxpack 发送成功后清对应 bit;ems_send_350pack 回读分支写 s16_calib_*_data |
s_u32_can_rcv_tick(:28) | 写 | 收到 0x201 或任一 0x263~0x269 刷新;0x30x 电表帧不刷新 |
dsp_meter_grid_data / dsp_meter_pv_data(:29~:30) | 读/写 | 接收解析写入;alphaess_inverter_can_data_check 读出并 memcpy 到 g_t_meter |
g_t_alphaess_comm_info.u8_ems_inv_idcode_flag | 写 | 初始 TRUE,收 0x201 后置 FALSE |
g_t_alphaess_comm_info.u32_ems_inv_idcode_tick / u32_ems_send_inv_ctrl_power_tick1 | 写 | 每次成功发送后刷新 |
g_t_alphaess_comm_info.u8_set_inv_ctrl_mode_flag / u8_set_backup_enable_flag / u8_set_inv_ctrl_arg_flag1 | 写(清) | 对应帧发送成功后清;由 alphaess_inverter_can_data_check、inverter_set_mppt_percentage(inverter.c:7214)等外部置位 |
g_t_inv_info.t_run_info.* | 写 | 接收解析写入电网/备份/逆变器三相电压电流功率、运行模式、电池功率、空开状态 |
g_t_inv_info.t_run_info.u8_inverter_can_comm_lost_flag | 写 | 0x201 到达清 FALSE;55 s 超时置 TRUE |
g_t_inv_info.t_config_data.u32_ac_rate_* / u32_dc_rate_* | 读 | 0x192/0x193/0x194 限幅与 ATE 模式取值 |
g_t_meter.t_grid_info.u8_vave_software_version[9] | 写 | 0x310 帧写入 8 字节 |
5. 对外接口
本文件导出(供外部调用)
| 符号 | 使用者 |
|---|---|
alphaess_inverter_comm_can() | task_inverter_can(inverter.c:1249) |
alphaess_inverter_can_data_check() | task_inverter_can(inverter.c:1250) |
alphaess_comm_init_can() | inverter_init()(inverter.c:90)、alphaess_comm_usart.c:5692、alphaess_upgrade.c:534/583 |
ems_ate_reset_dsp() | task_inverter_can(inverter.c:1255,由 u8_ate_reset_dsp_flag 触发) |
parse_alphaess_work_mode() | 声明于本文件头,实际调用点在本文件 :1191(alphaess_comm_usart.c:1259 中为注释掉的旧调用) |
zero_glitch_filter() / zero_glitch_filter_reset() | 目前仅本文件内使用(全工程搜索无其他调用者),属"导出但未被外部使用" |
dsp_meter_calibration_data | 通过 alphaess_comm_can.h:206 导出,供 HMI/Modbus 等填写校准参数 |
s_u32_can_rcv_tick / dsp_meter_grid_data / dsp_meter_pv_data | static,不导出 |
本文件依赖的外部符号
| 来源文件 | 使用内容 |
|---|---|
hardware/can/can1.c | can1_send_standard_pack、get_can1_standard_pack、get_can1_prescaler、can1_mode_init |
hardware/can/can0.h | CAN_MSG_TYPEDEF_T、CAN_FT_DATA |
midware/meter/meter.h | METER_DATA_T、PHASE_A/B/C/T、GRID_METER、PV_METER、meter_get_meter_or_ct、g_t_meter |
midware/inverter/inverter.h | g_t_inv_info、cWaitMode 等模式宏 |
midware/inverter/pvcharger.c | pvcharger_read_bat_curr/volt/soc、pvcharger_read_bat_relay_state/connect_state、pvcharger_read_bat_max_charge_power/max_dischg_power、pvcharger_read_bat_dischg/charge_cut_off_volt、pvcharger_read_bat_max_dischg/charge_current |
midware/inverter/parallel.h | parallel_read_ac_total_set_inv_power、parallel_read_ac_three_phase_set_inv_power、parallel_read_ac_*_set_bat_charge/dischg_limit_power、parallel_read_ac_*_set_bat_forced_charge_en |
midware/inverter/alphaess/alphaess_comm_usart.h | g_t_alphaess_comm_info(ALPHAESS_TABLE_T) |
net/inv_download.h | is_inverter_firm_download_finished() |
logic/logic.h | g_t_logic_info.t_config_data.u8_system_mode、DC_SYSTEM_MODE |
system/board_init/board_init.h | get_board_type、BOARD_EMS3_6_3_E、BOARD_EMS3_6_4_E |
UCOSII | OSTimeGet、OSTimeDlyHMSM、abs() |
6. 依赖关系
依赖
alphaess_comm_can.h、alphaess_comm_usart.h、logic.h、inverter.h、can1.h、inv_download.h、system_config.h、meter.h、board_init.h、bms.h(.c 头部 :13~:22)。
被依赖
midware/inverter/inverter.c(:90、:1249、:1250、:1255)——唯一的运行时调用方;midware/inverter/alphaess/alphaess_upgrade.c(:14、:124~:125、:534、:583)——升级流程需要g_u8_fw_sdram1/2之外,还调用alphaess_comm_init_can()复位 CAN;midware/inverter/alphaess/alphaess_comm_usart.c(:5692)——逆变器长时间停留上电模式时复位 CAN;- 任何需要读
dsp_meter_calibration_data或DSP_METER_CALIBRATION_DATA定义的文件(经alphaess_comm_can.h)。
7. 备注与风险点
- 头文件前向声明不完整(
alphaess_comm_can.h:34~52):set_inv_ctrl_mode、send_bat_run_info、send_bat_protect_info、ems_send_34Apack、ems_send_350pack、ems_send_360pack、ems_send_361pack都没有前向声明,靠"定义先于使用"侥幸编译通过。属版本遗留,建议补齐。 handle_alphaess_inv_set_battery_shutdown_flag是死声明(alphaess_comm_can.h:213):全工程搜索不到定义,任何引用都会链接失败。- 校准点清除时机可疑:
ems_send_340pack等函数在CAN_Send_Msg之后无条件memset清零数据段(如 :590),即使发送失败也会清掉待发值,只有标志位在失败时保留 —— 下一轮重发会发出全 0 值。ems_send_34Apack(:863)和ems_send_361pack的最后一次memset(&u16_pgu_gen_l,0,4)范围也与帧长度不匹配(后者只清 4 字节,前者完全不清)。 ems_send_344pack清错了标志位(:706):发送 0x344(放电功率校准点 1)后清的是u8_send_pchg_calibration1_flag(充电功率校准 1,对应 0x348),而 0x344 对应的应是u8_send_pdischg_calibration1_flag。这会导致 0x344 的 bit 永不清除/0x348 的 bit 被误清。- 三相独立功率未限幅(:244~:246):
l_s16_inv_ac_set_a/b/c_real_actpower直接由parallel_read_ac_three_phase_set_inv_power()装入 CAN 帧,没有与u32_ac_rate_discharge_power比较,存在越界给定风险。 abs()与无符号混用:send_ac_ctrl_inv_power1里abs(l_s16_ac_set_actpower)依赖l_s16_*为有符号;但 :239 把u32_ac_rate_discharge_power赋给s16 l_s16_ac_set_actpower,额定功率超过 32767 W 会截断。- 链路丢失判据只看 0x201/0x263~0x269(:1308):
s_u32_can_rcv_tick在 0x301~0x310 电表帧分支里没有被刷新,若逆变器只回电表帧而不回运行帧会被误判为丢失。另外注释写"超过15S没有接收到0x269帧数据",与实际(任一运行帧都算)不符。 g_t_meter.t_grid_info.u8_vave_software_version[9]写入 8 字节(:1286~:1289):下标 8 保留为 0 是合理的,但没有任何长度断言。send_ems_read_bat_power的缓存与返回语义耦合:返回值被上层反转为s_u8_send_bat_parameter_flag(:1123),且l_u16_bat_pmaxchg是u16而pvcharger_read_bat_max_charge_power()返回s32(pvcharger.h:91),负值或超大值会被截断。send_bat_run_info的 SOC 缩放:pvcharger_read_bat_soc()/10后压进单字节frame_data[3](:415、:443),无范围钳位,SOC 原始值偏大时会溢出到低 8 位。u8_inv_parameter_init_flag == TRUE时完全不下发(:1317~:1320):这是有意设计(串口初始化期间 CAN 只监听),但若串口流程卡死在该状态,CAN 侧将永久失去控制能力,缺少超时兜底。ems_send_dsp_meter_calibration_data的循环边界为i < 13(:980):结构体位域实际定义了 14 个有效标志(bit0~bit13,即 0x0D 也有效),13恰好覆盖i = 0..12,因此 bit13(设置并网机发电量 0x361)永远扫不到;case 0x0D: ems_send_361pack();是不可达代码。这是明确的差一错误。- 主循环里对
send_cali_data_flag.u16_all的重复判断(:1063 与 :1118):第二次判断时该值已被 :1067 清零,属冗余分支。 ems_ctrl_inv_backup未在开头前向声明(:40 有声明,但set_inv_ctrl_mode等没有,见第 1 条);INOVANCE_INV_DEBUG_CAN宏在set_inv_ctrl_mode里被使用(:207),与本文件厂商无关,是复制粘贴残留。