alphaess_comm_usart.c
alphaess_recv_data,行 285-442)4.3 主通信状态机(alphaess_inverter_comm_usart,行 5090-5469)4.4 变化检测器(alphaess_inverter_data_check,行 5530-5723)4.5 数据解析与映射4.6 写操作的确认与重试策略4.7 安规双向映射4.8 定时/调度时序与 uCOS-II 配合4.9 关键全局变量的读写与触发4.10 AFCI 分支5. 对外接口5.1 本文件导出的函数(非 static)5.2 本文件导出的全局变量5.3 本文件调用的外部函数与变量6. 依赖关系7. 备注与风险点缓冲区越界风险(高)逻辑可疑/错误魔法数字与约定其它源文件路径:
midware/inverter/alphaess/alphaess_comm_usart.c所属模块:midware/inverter/alphaess(AlphaESS 逆变器厂商协议:Modbus-RTU 串口通信实现) 代码行数:5724
1. 文件职责
本文件是 AlphaESS 系列储能逆变器与 EMS 主控之间唯一的串口(SCI/UART2,Modbus-RTU 从站)协议实现:把 EMS 侧能量调度与配置结果翻译成 DSP 的寄存器写入,把 DSP 的遥测/故障/告警/安规参数翻译成 g_t_inv_info 与 g_t_alphaess_comm_info 中的结构化字段。它由 midware/inverter/inverter.c:1116-1117 在逆变器任务中每轮调用两个入口:alphaess_inverter_comm_usart() 负责实际收发与状态机推进,alphaess_inverter_data_check() 负责扫描"上层配置 vs 已下发快照"的差异并置位下发标志,两者通过 g_t_alphaess_comm_info 里约 60 个 u8_ems_set_*_flag / u8_ems_get_*_flag 完成"探测—发送—确认"的解耦。同一物理串口(uart2)还被 midware/afci/ 的 AFCI 板通信与升级复用,因此本文件的 alphaess_write_data / alphaess_recv_data 也是 AFCI 模块的物理层;此外 midware/interface/modbus/ 的 SunSpec 从站直接读 g_t_alphaess_comm_info 对外暴露数据。
2. 关键数据结构与宏
| 名称 | 类型(结构体/枚举/宏/联合体) | 说明 |
|---|---|---|
g_t_alphaess_comm_info | 全局变量(ALPHAESS_TABLE_T) | 行 36 定义,本模块核心状态容器(定义见 alphaess_comm_usart.h:632-712)。既是收发标志位的"消息邮箱",也是回读原始数据的暂存区 |
s_u8_temp_work_mode | 静态变量 | 行 37,初值 0x02。由 alphaess_inverter_data_check() 每轮刷新为"实际期望的启停模式",再被 set_inv_start_stop() 读取并映射成 DSP 命令字 |
s_u8_recv_buf[256] | 静态数组 | 行 38,ALPHAESS_INV_RECV_BUFFER_SIZE 字节的全局接收缓冲区,所有查询/设置函数共用(非重入) |
s_u8_config_save_flag | 静态变量 | 行 39,配置变化后置 TRUE,由 alphaess_inverter_comm_usart() 末尾统一触发 save_job_post(INVERTER_CONFIG_PAGE) 落盘,避免在收发热路径里直接写 Flash |
phase_base[3] | 非 static const 全局数组 | 行 42-47,三相在 CEI 自检报文中的起始字节偏移 {3, 27, 51}(L1/L2/L3)。注意它是外部可见符号,未加 static |
cei_map[] | static const 数组(CEI_MAP_T) | 行 49-62,意大利 CEI 自检 7 组保护项到报文字节偏移的映射:{value_offset, time_offset, res_offset, type},type 0=OVP2、1=UVP2、2=UVP1、3=OFP2、4=OFP1、5=UFP2、6=UFP1;OVP10min(type 7)被注释掉,改为在代码里单独处理(行 2188-2200) |
ALPHAESS_SLAVR_ADDRESS (0x03) | 宏 | 逆变器从站地址。ems_send_ctrl_data_to_inv_alphaess 用它填 tx_buf[0];send_query_data_to_inv_alphaess 里则硬编码 0x03(行 456) |
ALPHAESS_FUNC_READ_HOLDING_REGISTER (0x03) / ALPHAESS_FUNC_READ_INPUT_REGISTER (0x04) | 宏 | 读保持寄存器 / 读输入寄存器 |
ALPHAESS_FUNC_WRITE_SIGNAL_HOLDING_REGISTER (0x06) / ALPHAESS_FUNC_WRITE_MULTIPLE_HOLDING_REGISTER (0x10) | 宏 | 写单寄存器 / 写多寄存器。实际代码几乎只用 0x10 |
ALPHAESS_MAX_REGISTER_NUM (100) | 宏 | 多寄存器写的寄存器数上限,也是 ems_send_ctrl_data_to_inv_alphaess 的长度合法性门槛 |
ALPHAESS_INV_RECV_BUFFER_SIZE (256) | 宏 | 接收缓冲区尺寸,同时是 alphaess_recv_data 中隐式依赖的越界边界 |
ALPHAESS_DATA_RCV_TIMEOUT (500) | 宏 | 写超时(uCOS tick)与 alphaess_recv_data 里 500 tick 的等待上限 |
ALPHAESS_SEND_ERROR_COUNT_MAX (3) | 宏 | 连续失败 3 次后部分写函数"放弃重试并当作成功",见 4.6 节 |
ALPHAESS_ADDR_REG_* / ALPHAESS_NUM_* | 宏 | 全部寄存器地址与长度常量,定义见 alphaess_comm_usart.h:31-175。本文件是这些宏的主要消费者 |
ALPHAESS_SAFETY_COUNTRY_E | 枚举 | 逆变器侧安规国家码(alphaess_comm_usart.h:182-217),parse_alphaess_inv_safety() 与 alphaess_inverter_safety_set() 的主键 |
ALPHAESS_INV_MODEL_SUB_E | 枚举 | 逆变器型号码(alphaess_comm_usart.h:219-239),query_inv_device_info_alphaess() 的 switch 分支依据 |
ALPHAESS_INV_BAT_TYPE_E | 枚举 | 电池类型码(alphaess_comm_usart.h:241-252),set_bat_adapt_type() / set_bat_type() 使用 |
ALPHAESS_INV_VAR_RESPONSE_MODE_E | 枚举 | 无功响应模式(alphaess_comm_usart.h:254-264),query_inv_quiescent_volt_reactpower_support() / alphaess_set_quiescent_volt_reactpower_support() 使用 |
ALPHAESS_ERROR1_U / ALPHAESS_ERROR2_U | 联合体 | 32 位故障字位域(.h:266-360),query_inv_running_data_alphaess() 填充,parse_inv_err_msg_alphaess() 展开 |
ALPHAESS_WARNING1_U / ALPHAESS_WARNING2_U | 联合体 | 32 位告警字位域(.h:362-456),同上 |
CEI_MAP_T | 结构体 | CEI 自检映射项(.h:458-464),配合 cei_map[] 使用 |
CEI_SAFTY_TEST_RESULT_U | 联合体 | 16 位 CEI 自检结果位图,u16_all 为 0x5555 表示全项通过 |
ALPHAESS_RUN_TABLE_T | 结构体 | 运行原始数据表(.h:494-581),字段 t_alphaess_run_info 在 query_inv_running_data_alphaess() 中被整体填充 |
ALPHAESS_START_CONFIG_TABLE_T | 结构体 | 已下发配置快照(.h:583-608),在 alphaess_inverter_data_check() 中以 static s_t_start_cofig 存在,用于变化检测 |
ALPHAESS_HEAT_TABLE_T | 结构体 | 电池加热数据快照(.h:612-618),在 data_check 中以 static s_t_heat_data 存在 |
INVERTER_PARALLEL | 联合体 | 并机配置字节(.h:620-630),u8_inv_parallel.u8_all 整体下发到 40151 |
ALPHAESS_POWER_ON_E / ALPHAESS_POWER_ON_E_2 | 枚举值 | 来自 alphaess_comm_can.h:84,95(0 和 255),用于检测 DSP"卡在上电模式"并触发通信重初始化 |
AFCI_RUN_MODE_ALLOW(m) | 宏 | 来自本模块 .h:178,判断运行模式是否属于 cNormalMode/cUPS/cByPassMode,AFCI 自检前置条件 |
AFCI_SLAVR_ADDRESS (0x01) / AFCI_UPGRADE_ADDRESS (0xF8) | 宏 | 来自 midware/afci/afci_comm.h:22 / afci_upgrade.h:16,用于 alphaess_recv_data 的地址分流 |
INVERTER_CONFIG_PAGE | 宏 | 来自 data/system_config.h,save_job_post() 的页编号 |
PF_001_TO_01(val) | 宏 | 来自 midware/inverter/inverter.h:184,功率因数 0.01 分辨率转 0.1 |
DEBUG_ALPHAESS_INV (0) | 宏 | 本文件调试打印开关,.h:17 定义;几乎所有函数都有 #if (DEBUG_ALPHAESS_INV == 1) 的打印块 |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
alphaess_comm_init | 全局 | 行 110。冷启动/通信丢失后初始化:置位一批"回读/下发"标志,按机型选定 9600 或 115200 波特率并 usart2_init |
alphaess_inv_check_sci_baud | static | 行 214。设备信息 10 s 拿不到时,在 115200↔9600 之间来回切换波特率探测 |
alphaess_write_data | 全局 | 行 262。清空 uart2 缓冲后发出 len 字节,透传 usart2_send_data 的返回值 |
alphaess_recv_data | 全局 | 行 285。等待 uart2 异步收齐 ≥2 字节,按"从站地址 + 功能码"分流做 Modbus CRC 校验,成功时回传帧长、失败回传 0 |
send_query_data_to_inv_alphaess | static | 行 451。组 8 字节读寄存器请求帧(0x03, func, addr, num, CRC)并发出 |
ems_send_ctrl_data_to_inv_alphaess | static | 行 477。组写寄存器请求帧(0x10 多寄存器 / 0x06 单寄存器),含长度合法性检查与 CRC |
parse_alphaess_inv_safety | static | 行 519。把 DSP 安规码翻译成 EMS 侧 u8_safety/u8_safesub,与配置不一致时回写配置并置位相关回读标志 |
parse_inv_err_msg_alphaess | static | 行 716。把 u32_inv_fault1/2 的位域逐位映射到 g_t_inv_info.t_run_info.u_fault_code/u_fault_extend1_code/u_fault_extend2_code |
parse_inv_warning_msg_alphaess | static | 行 797。把 u32_inv_warning1/2 的位域逐位映射到 u_warning_code/u_warning_extend1_code |
alphaess_get_single_phase_self_test_data | 全局 | 行 884。单相机意大利自检结果汇总:由 u16_ovp/uvp/ofp/ufp2 阈值与 CEI 返回值判定 u_test_res |
alphaess_get_self_test_data | 全局 | 行 946。三相机意大利自检结果汇总:三组 u_cei_test_res 全为 0x5555 时置 0(通过),否则 0xFFFF(失败) |
query_inv_device_info_alphaess | static | 行 1014。读 30000+73 设备信息区:型号、SN、安规、额定功率、屏幕类型、DSP 主/从版本、硬件版本、Modbus/CAN 协议版本,并落盘配置 |
query_inv_running_data_alphaess | static | 行 1234。读 30200+115 运行数据区,填充 t_alphaess_run_info 并转发到 g_t_inv_info.t_run_info,最后调用两个 parse 函数 |
query_inv_running_data_alphaess_extand1 | static | 行 1491。读 30331+16 扩展区,取三相无功/视在功率与单相 PV 接入状态 |
alphaess_set_first_ongrid_pro_value | static | 行 1540。写 42001+4,下发首次并网 OVP/UVP/OFP/UFP 保护值 |
alphaess_set_ovp_uvp_pro_value | static | 行 1581。写 42005+16,下发三级过压/欠压值、时间(DSP 单位 2 ms,写时 /2)、10 min 过压、恢复值 |
alphaess_set_ofp_ufp_pro_value | static | 行 1671。写 42021+12,下发三级过频/欠频值与时间(/2) |
alphaess_set_self_pro_threshold_value | static | 行 1729。写 42033+15,下发频率变化率保护、ISO/DCI 阈值与时间、HVRT/LVRT 电压、四档 GFCI 阈值 |
alphaess_set_gfci30ma_pro_value | static | 行 1816。写 42044,单点下发 30 mA GFCI 阈值 |
alphaess_set_gfci60ma_pro_value | static | 行 1852。写 42045,单点下发 60 mA GFCI 阈值 |
alphaess_set_gfci150ma_pro_value | static | 行 1888。写 42046,单点下发 150 mA GFCI 阈值 |
alphaess_set_gfci300ma_pro_value | static | 行 1924。写 42047,单点下发 300 mA GFCI 阈值 |
query_inv_self_data_alphaess | static | 行 1959。读 42001+47 安规参数区,反向填充 g_t_inv_info.t_safty_info(时间 *2、*20,等待/重连时间 /2),并按奥地利安规特殊处理零电流电压 |
query_inv_cei_self_checking_data_alphaess | static | 行 2108。读 42048+81,按 phase_base[] + cei_map[] 三维展开三相 CEI 自检数据与逐项结果位 |
alphaess_set_function_enable | static | 行 2300。写 41000+26(52 字节),一次性下发全部功能使能与保护阈值包 |
query_inv_function_enable_data_alphaess | static | 行 2400。读 41000+26,反向填充功能使能包;成功返回 TRUE |
set_inv_sn | static | 行 2489。写 40202+16,把本机 SN 写入逆变器 |
set_inv_start_stop | static | 行 2524。写 40126,按 s_u8_temp_work_mode 映射启停命令字(1→1 启动,2→0 停止) |
alphaess_set_inv_on_off | static | 行 2576。写 40127,下发逆变器 ON/OFF(INV_SHUTDOWN 时写 1) |
query_inv_safety_actpower_setting | static | 行 2618。读 43000+51,解析频率降载(P-f)曲线、P-V 曲线、无功模式等 51 个寄存器 |
query_inv_safety_over_under_freq_mode | static | 行 2720。读 43000+51 但只取 43007/43031 两个位,用于过/欠频降载使能回读 |
alphaess_set_safety_actpower_setting | 全局 | 行 2759。写 43000+51(102 字节),下发完整 P-f / P-V 降载曲线,含 3 次失败放弃逻辑 |
set_pv_capacity | static | 行 2945。写 40134,下发 PV 装机容量 |
set_max_feedin_percent | static | 行 2983。写 40135,下发最大馈网功率比例 |
set_bat_chg_cut_volt | static | 行 3021。写 41111,下发充电截止电压 |
set_bat_dischg_cut_volt | static | 行 3060。写 41108,下发放电截止电压 |
set_bat_adapt_type | static | 行 3099。写 41106,仅下发"并联/串联"自适应类型 |
set_bat_type | static | 行 3144。写 41106,按电池型号映射成 96 V/150 V/300 V/9640-9650/DCDC/0xFF 工厂值下发 |
set_bat_heat_cut_volt | static | 行 3265。写 41134+2,下发电池加热电压(0.1 V)与加热电流(0.01 A) |
set_bat_heat_cmd | static | 行 3305。写 41028,下发电池加热指令 |
set_bat_heat_relay_sta | static | 行 3340。写 41140,下发电池加热继电器状态 |
alphaess_set_dc_double_pcharge | static | 行 3375。写 41141,下发"两倍电池充电功率"使能;成功后置 u8_query_inv_device_info_flag 触发重新读取设备信息 |
alphaess_set_italian_anti_backflow | static | 行 3411。写 41031,下发意大利防逆流使能(注释标记 //bufan) |
alphaess_inverter_energy_clear | static | 行 3446。写 40102+5(值为交替 0/1),清除逆变器各项发电量 |
alphaess_inverter_safety_set | static | 行 3490。把 EMS 侧 u8_safety/u8_safesub 反译成 DSP 安规码写 42000;成功后再触发一轮参数回读 |
system_start_first_setting | static | 行 3685。开机首次参数序列:依次回读功能使能、安规有功设置、静态无功支撑,任一失败返回 FALSE |
send_bat_info_to_inv | static | 行 3722。电池参数下发总控:按"电池+逆变器是否都支持自适应"分流到自适应新方案或旧方案,再下发充/放电截止电压 |
alphaess_restart_dsp | 全局 | 行 3794。写 40128,复位 DSP |
query_inv_quiescent_volt_reactpower_support | static | 行 3829。读 44000+26,解析无功模式位图、cosφ(P) 五点曲线、Q(U) 四点曲线与回差 |
query_inv_pu_mode_active_response_3tau | static | 行 3946。读 44034+2,解析 P-V 模式使能与 3τ 响应时间 |
query_inv_pe_loss_check_flag | static | 行 3992。读 40159,回读 PE 丢失检测使能 |
alphaess_overload_recovery | 全局 | 行 4034。写 40147=0x0D,清除逆变器过载等告警位 |
alphaess_set_generator_flag | 全局 | 行 4069。写 40149,下发油机接入使能(取 parallel_read_gc_control_en()) |
alphaess_set_grid_forming_flag | 全局 | 行 4104。写 40150,下发 Grid-Forming 使能(取 g_t_meter.t_config_data.u8_gridforming_en) |
alphaess_set_bb_enable | 全局 | 行 4139。写 40152,下发 BackupBox 机型/使能 |
alphaess_set_mppt_enable | 全局 | 行 4174。写 40153,下发 MPPT 扫描使能 |
alphaess_set_pv_charger_mode | 全局 | 行 4209。写 40157,下发 PV-Charger 模式(来自 PVCharger 取 2,否则 1) |
alphaess_set_quiescent_volt_reactpower_support | 全局 | 行 4244。写 44000+26(52 字节),下发完整 cosφ(P)/Q(U) 曲线,含 3 次失败放弃逻辑 |
alphaess_set_pu_mode_active_response_3tau | 全局 | 行 4357。写 44034+2,下发 P-V 降载使能与 3τ 响应时间 |
alphaess_set_pe_loss_check_flag | 全局 | 行 4408。写 40159,下发 PE 丢失检测使能;成功后置 u8_inv_parameter_init_flag 触发重新初始化 |
alphaess_set_phase_negation | 全局 | 行 4444。写 40156,下发相序自适应使能 |
alphaess_set_bat_ac_out | 全局 | 行 4481。发送非 Modbus 的厂商私有 14 字节帧(帧头 0x51 0x35),下发电池 AC 侧允充允放功率 |
query_inv_phase_negation | static | 行 4534。读 40156,回读相序自适应使能 |
alphaess_set_inv_operation_mode_alphaess | 全局 | 行 4576。写 40130,下发逆变器运行模式 |
query_inv_operation_mode_alphaess | static | 行 4613。读 40130,回读运行模式 |
alphaess_set_inv_parallel | 全局 | 行 4655。写 40151,整体下发并机配置字节;成功后记录 u16_ems_change_para_state_time |
alphaess_set_inv_bypass_mode | static | 行 4692。写 40161,下发 Bypass 模式使能 |
alphaess_set_bat_adapt_en | static | 行 4727。写 41136,下发电池自适应使能(入参决定开或关) |
send_inv_afci_enable | static | 行 4765。写 41023,下发 AFCI 使能,含 3 次失败放弃逻辑 |
send_inv_afci_fault_enable | static | 行 4811。写 40166,下发 AFCI 报错使能,含 3 次失败放弃逻辑 |
query_inv_afci_fault_enable | static | 行 4857。读 40166,回读 AFCI 报错使能,含 3 次失败放弃逻辑 |
query_inv_afci_enable | static | 行 4903。读 41023,回读 AFCI 使能,含 3 次失败放弃逻辑 |
alphaess_set_bat_adapt_protect_para | static | 行 4949。写 41137+3,下发电池自适应保护参数(瞬时额定电压、放电/充电电流) |
afci_self_check_condition | static | 行 4996。AFCI 自检前置条件判定:自检标志、回读使能、配置使能、运行模式四者同时满足 |
is_ready_to_query_inv_self_data | static | 行 5017。判断当前是否允许发起安规参数回读(无正在进行的安规写操作时才允许) |
alphaess_afci_comm_function | static | 行 5045。AFCI 通信总调度:使能下发、自检、告警清除、故障日志、升级后版本回读 |
alphaess_inverter_comm_usart | 全局 | 行 5090。主通信状态机,逐轮推动所有查询/下发/升级/通信丢失检测 |
alphaess_afci_data_check | static | 行 5478。AFCI 侧变化检测:告警自动清除、使能不一致时置位下发标志、拉弧故障日志触发 |
alphaess_inverter_data_check | 全局 | 行 5530。变化检测器,比较上层配置与已下发快照,置位对应的 u8_ems_set_*_flag |
4. 核心逻辑解析
4.1 物理帧格式(Modbus-RTU)
读请求(send_query_data_to_inv_alphaess,行 451-468):固定 8 字节。
[0] 从站地址 0x03(硬编码)
[1] 功能码 0x03(读保持) 或 0x04(读输入)
[2..3] 起始寄存器地址 大端
[4..5] 寄存器个数 大端
[6] CRC 低字节
[7] CRC 高字节
写请求(ems_send_ctrl_data_to_inv_alphaess,行 477-510):
多寄存器(0x10):[0]=0x03, [1]=0x10, [2..3]=地址, [4..5]=寄存器数, [6]=字节数(2*reg_num),
[7..7+len-1]=数据, [..]=CRC 低, CRC 高
单寄存器(0x06):[0]=0x03, [1]=0x06, [2..3]=地址, [4..5]=数据(由 tx_buff 覆盖), CRC 低, CRC 高
注意 0x06 分支(行 498-502)先在第 4-5 字节写寄存器数(行 489-490),随后又用 memcpy(l_u8_tx_buf + 4, tx_buff, 2) 覆盖为数据值——这是 Modbus 0x06 的正确布局,但读代码时容易误判为写错。
私有帧(alphaess_set_bat_ac_out,行 4481-4525):唯一不走标准 Modbus 写格式的路径。
[0..1] 固定帧头 0x51 0x35
[2..3] ctrlac 允许充放功率(s16,使能关时为 10000)
[4..5] ctrlpch 允许充电功率
[6..7] ctrlpdisch 允许放电功率
[8..11] batpch / batpdisch 电池最大充/放电功率
[12..13] CRC(`GetCrcCode_Modbus` 前 12 字节)
发完即返回(行 4522-4523),不等待应答,是 fire-and-forget。
CRC:全部使用 GetCrcCode_Modbus()(common/crc.c),发送时低字节先、高字节后(行 505-506、463-465)。
4.2 接收校验状态机(alphaess_recv_data,行 285-442)
这是全文件唯一的收帧逻辑,被所有查询/设置函数复用,s_u8_recv_buf 是共享缓冲。
时序:
usart2_is_recv_async_data()判断是否有异步数据;无数据直接*len = 0返回(行 296、435-441)。- 轮询
usart2_get_data_len()直到 ≥2 字节,每次OSTimeDlyHMSM(0,0,0,10)让出 10 ms;超过 500 tick(500 ms) 放弃并返回长度 0(行 298-307)。 - 一次性把
l_u16_len字节读到buf(行 309-316)。 - 按帧头分流做 CRC 校验,只有校验通过才
*len = l_u16_len,否则*len = 0:
| 分流条件 | 行号 | CRC 覆盖范围 |
|---|---|---|
buf[0]==0x03 && buf[1]==0x41/0x42/0x43(逆变器升级帧) | 318-348 | 0x42 → 前 6 字节、CRC 在 buf[6..7];0x41/0x43 → 前 4 字节、CRC 在 buf[4..5] |
buf[0]==0x03 && buf[1]==0x10/0x06(写应答回显) | 349-377 | 0x06 → 前 6 字节、CRC 在 buf[6..7];0x10 → 前 len-2 字节、CRC 在 buf[len-2..len-1] |
buf[0]==0x03 && buf[1]==0x03/0x04(读应答) | 378-402 | 前 buf[2]+3 字节,CRC 在 buf[buf[2]+3..buf[2]+4] |
buf[0]==0x01(AFCI 板)或 buf[0]==0xF8(AFCI 升级) | 403-426 | 前 len-2 字节,CRC 在 buf[len-2..len-1] |
| 其它 | 427-433 | 直接判为 CRC 错误,*len = 0 |
注意:本函数不做重试。重试语义分散在各调用方——大多数函数是"每轮调用一次,失败就下一轮再来",只有少数长帧写函数用静态计数器限次。
4.3 主通信状态机(alphaess_inverter_comm_usart,行 5090-5469)
这是一个"优先级递降 + 门控"的状态机,每轮由逆变器任务调用一次。
阶段 A:设备信息未拿到时(行 5093-5100)
u8_query_inv_device_info_flag == TRUE → 只执行 query_inv_device_info_alphaess();若仍未成功则调用 alphaess_inv_check_sci_baud()(行 5098)。此阶段其余所有命令都不发,是对 DSP 通信参数未知时的必要保护。
alphaess_inv_check_sci_baud()(行 214-253)自限速:距上次探测 <10 s 直接返回;然后 115200 → 9600 → 115200 来回切换并 usart2_init + usart2_clear_buffer。
阶段 B:正常运行(行 5101-5426,else 分支)
按如下优先级依次尝试,每一轮只推进能成功的那些(每个函数内部自带"发一帧 + 收一帧",所以一轮内实际可能发多帧):
- 开机首次参数设置(行 5104-5125):
u8_inv_parameter_init_flag == TRUE时,且距u32_query_inv_parameter_init_flag_tick> 3000 tick 才执行system_start_first_setting();成功则query_inv_pe_loss_check_flag()、query_inv_pu_mode_active_response_3tau()、清标志并ems_set_fault_bit(23, FALSE);失败则ems_set_fault_bit(23, TRUE)并 return(本轮不再发任何其它命令)。距上次 <3000 tick 时也 return。 - 电池信息下发(行 5127-5131):
u8_startingup_check_bat_flag == FALSE且pvcharger_read_bat_work_state() != FALSE时调send_bat_info_to_inv()。 - 电池加热三件套(行 5133-5155):加热指令、加热电压/电流、加热继电器状态,各自用
u8_bat_heat_*_data_flag == FALSE作为"待发"标志,成功后置 TRUE。 - 一批条件触发的单点命令(行 5157-5358),每个都用
if (TRUE == g_t_alphaess_comm_info.u8_ems_set_xxx_flag)守护:启停、Bypass、ON/OFF、清电量、安规写、首次并网值、OVP/UVP、OFP/UFP、自保护阈值、复位 DSP、告警恢复、油机、Grid-Forming、SN、BB、MPPT、PV-Charger、并机、PE 丢失、功能使能、四档 GFCI、安规有功设置、静态无功支撑、3τ、电池 AC 输出、两倍充电、相序、运行模式、意大利防逆流、PV 容量、最大馈网比例。 - 周期回读 1 s(行 5202-5216):
OSTimeGet() - u32_query_inv_running_data_tick > 1000→query_inv_running_data_alphaess()+query_inv_running_data_alphaess_extand1(),成功路径下还会在u8_afci_heart_flag == TRUE时执行set_afci_fac_mode(0)(行 5207-5210);随后更新时间戳。注意:时间戳更新在if内,无论收发是否成功都会推进(不是因为失败才重试)。
行 5213-5216 还有一条 tick 回卷保护:若 u32_query_inv_running_data_tick > OSTimeGet()(时间回绕)则强制同步。
- 周期回读 10 s(仅奥地利 TOR_ERZEUGER)(行 5415-5424):
(距上次 > 10000 tick && inverter_read_safety() == TOR_ERZEUGER) || u8_ems_get_inv_operation_mode_flag == TRUE→query_inv_operation_mode_alphaess(),带同样的 tick 回卷保护。 - 常驻守护式回读(行 5360-5413):
u8_ems_get_function_enable_flag→ 读功能使能;is_ready_to_query_inv_self_data()→ 读安规参数;u8_ems_get_cei_self_checking_data_flag→ 读 CEI 自检;u8_ems_get_safety_actpower_setting_flag→ 读 43000;u8_ems_get_quiescent_volt_reactpower_support_flag→ 读 44000;u8_ems_get_pu_3tau_flag_flag→ 读 44034;u8_ems_get_phase_negation_flag→ 读 40156;AFCI 使能/报错使能回读;u8_query_afci_device_info_flag→query_afci_software_version()+afci_log_init()。 - AFCI 通信(行 5336-5340):仅在"支持 AFCI 且逆变器固件、AFCI 固件都下载完成"时调用
alphaess_afci_comm_function()。
阶段 C:收尾(行 5428-5468)
- 配置落盘:
s_u8_config_save_flag == TRUE→ 清标志并save_job_post(INVERTER_CONFIG_PAGE)(行 5428-5432)。 - 固件升级优先:
is_inverter_firm_download_finished()为真时刷新u32_ems_inv_comm_tick并调alphaess_upgrade_handle()(行 5434-5442);AFCI 升级同理(行 5444-5448)。升级完成后正常通信被跳过,避免与升级帧争抢 uart2。 - 通信丢失检测(行 5450-5463):
l_u32_ugrade_finish_tick在"距升级完成 <120 s"时为 90000,否则 0;当abs(u32_ems_inv_comm_tick - OSTimeGet()) > 30*1000 + l_u32_ugrade_finish_tick时置u8_inverter_comm_lost_flag = TRUE并调用alphaess_comm_init()重新初始化。 - 升级状态上报 HMI:
u8_upgrade_status != 0→set_info_status(INV_UPGRADE_LOG)(行 5465-5468)。
4.4 变化检测器(alphaess_inverter_data_check,行 5530-5723)
本函数从不发帧,只比较"快照 vs 目标",置位标志后立即结束;下一轮主状态机才真正发送。这是本文件最重要的设计约定。
关键逻辑:
| 检测项 | 行号 | 动作 |
|---|---|---|
| 启停模式 | 5538-5551 | 若"离网时电池未启动"(PVCharger 未启动 && BMS 未 ready && 电网频率 <40 Hz && 上电 >2 s)则强制 s_u8_temp_work_mode = 0x01(停机),否则取 t_control_cmd.u8_start_stop;与快照不同则置 u8_set_inv_start_stop_flag |
| PV 装机容量 | 5561-5565 | 与 g_t_logic_info.t_config_data.PV_Capacity_Storage 比较,变化置 u8_ems_set_inv_pv_capacity_storage_flag |
| 最大馈网比例 | 5567-5571 | 与 u8_max_feedin_percent 比较,变化置 u8_ems_set_inv_max_feedin_percent_flag |
| 电池充/放电截止电压、充/放电电流、瞬时额定电压 | 5573-5585 | 任一变化则整体刷新快照并清 u8_startingup_check_bat_flag(触发重新下发电池信息) |
| 电池型号 | 5587-5592 | 变化则清 u8_startingup_check_bat_flag 并置 u8_ems_set_int_bat_type_flag |
| 电池加热三参数 | 5594-5612 | 与 g_t_bat_info.t_run_info 比较,变化则把对应 u8_bat_heat_*_data_flag 清 FALSE(重新下发) |
| 安规 | 5614-5618 | t_safty_info.u8_safety/u8_safesub 与配置不一致则置 u8_ems_set_inv_safety_arg_flag1 |
| 油机 | 5620-5624 | 与 parallel_read_gc_control_en() 比较 |
| Grid-Forming | 5626-5630 | 与 g_t_meter.t_config_data.u8_gridforming_en 比较 |
| BB 机型 | 5632-5636 | 与 t_run_info.u8_bb_model 比较 |
| MPPT 扫描 | 5638-5642 | 与 u8_inv_mpptscan_enable 比较 |
| PV-Charger 模式 | 5644-5648 | 与 u8_pv_charger_mode 比较 |
| 并机方案 | 5651-5682 | 若当前并机方案不是 CAN 且有 u8_para_module_addr_same 告警/u8_para_module_wrong 故障,则清这两个位并 inverter_reset();方案变化时:非 CAN 则把并机三位置 0,CAN 则从配置刷新并机字节,最后置 u8_ems_set_inv_parallel_flag |
| DSP 卡在上电模式 | 5684-5699 | u16_work_mode == ALPHAESS_POWER_ON_E 或 ALPHAESS_POWER_ON_E_2 且通信未丢失时 u8_inverter_poweron_mode_cnt++,超过 10 次则 alphaess_comm_init() + alphaess_comm_init_can() 并清计数;否则清零计数 |
| N-N 短路检测 | 5701-5704 | u16_n_n_short_value & 0x02 与配置 u8_nn_short_detect_state & 0x02 不一致则置 u8_ems_set_function_enable_flag |
| 逆变器 ON/OFF | 5706-5710 | 快照与 t_run_info.u8_set_inv_on_off 比较 |
| Bypass 模式 | 5712-5716 | 快照与 t_run_info.u8_inv_bypass_enable 比较 |
| AFCI | 5718-5721 | 支持 AFCI 时调 alphaess_afci_data_check() |
4.5 数据解析与映射
query_inv_device_info_alphaess(行 1014-1225) —— 只在开机时执行一次(成功后清 u8_query_inv_device_info_flag):
- 帧合法性:
buf[0]==0x03 && buf[1]==0x04 && buf[2]==73*2(行 1026-1029)。 - 死循环保护:若 DSP 主/从版本字节
buf[135]/buf[136]都为 0,说明从机还没起,保持标志为 TRUE 下轮再读(行 1034-1037)。 - 机型映射:
(buf[3]<<8)|buf[4]按ALPHAESS_BW_G3_*枚举 switch 成SUB_S5…SUB_T15(行 1041-1114)。 - SN:
memcpy(u8_inv_sn, &buf[7], 16);若首位是空格、含"11111111111111"、或(BW OEM 且与本机 SN 不同)则置u8_ems_set_inv_sn_flag要求重写 SN(行 1117-1124)。 - 安规:
(buf[55]<<8)|buf[56]→parse_alphaess_inv_safety()(行 1127)。 - 额定功率:
buf[57..58](AC 充/放)、buf[59..60](DC 放)、buf[73..74](DC 充);DC 充为 0 时用 DC 放补齐(行 1129-1136)。 - 版本号:DSP 主/从用同一个
buf[129..136] + buf[138]拼成"V%c%c%c%c%c%c%c%c%c"(行 1141-1149)——两处代码完全一样,实际未区分主从;硬件版本按板型取常量VERSION_INV_HARD或buf[99..102](行 1151-1158)。 - 协议版本:
buf[139]起为 Modbus 版本、buf[145]起为 CAN 版本;strncmp(modbus_ver,"V1.00",5) > 0时置g_t_logic_info.u8_bat_adapt_inv_flag = TRUE,即"逆变器支持电池自适应"(行 1167-1177)。 - 变化落盘:额定功率/硬件版本/机型任一变化则回写
t_config_data并置s_u8_config_save_flag(行 1183-1197)。 - 首次成功时记录
u32_query_inv_parameter_init_flag_tick(行 1199-1203),后续system_start_first_setting()的 3000 tick 延时基准。 - 成功后置
u8_query_afci_device_info_flag = TRUE并Set_Setup_Config_Status(FALSE)(行 1205-1206)。
query_inv_running_data_alphaess(行 1234-1482) —— 1 s 周期的主遥测通道,长度校验 buf[2]==115*2:
- 大量
(buf[i]<<8)|buf[i+1](u16)与(buf[i]<<24)|…|buf[i+3](u32/s32)大端解析,写入t_alphaess_run_info。后半段改用buf[n+32]的常量折叠写法(行 1314-1356),n+32与前半段的行号偏移不同,是维护陷阱。 - 故障/告警 4 字节的字节序是倒装的(行 1340-1343):
u32_err1_all = (buf[161+32]<<24)|(buf[162+32]<<16)|(buf[159+32]<<8)|(buf[160+32]),即 DSP 按"高字在前"发送。
- 单位换算与转发(行 1358-1426):PV 电压
/10(1 V)、PV 电流/10(0.1 A)、功率 1:1;电网电流由"备电侧电流 − 逆变侧电流"导出(仅u16_grid_freq > 4500即 45 Hz 时才计算,否则置 0,行 1403-1414);电池电压/电流/10;机内温度/10;母线电压/10;功率因数用PF_001_TO_01宏换算。 - 最后调用
parse_inv_err_msg_alphaess()与parse_inv_warning_msg_alphaess()。
parse_inv_err_msg_alphaess(行 716-788) —— 纯位对位搬运,约 50 行赋值。两个特殊点:
- GFCI 屏蔽:
u8_gfci_shield_flag == TRUE时先清掉u32_inv_fault1.bit.u8_gfci再搬运(行 738-742),告警侧同理(行 824-828)。 - 电网丢失故障抑制:对
SUB_S5/S3_6/S6/S8/S10机型直接清u8_grid_loss_fault(行 778-782);其它机型在三相电压同时 <15 或同时 >15 时也清(行 783-787)。这是用"电压一致性"过滤误报。 - 注意
u8_output_overload被赋值两次(行 726 来自u32_inv_fault1.bit.u8_over_load,行 773 又来自u32_inv_warning1.bit.u8_over_load),后者覆盖前者。 - 行 814 有一行被注释掉的
u8_grid_loss_alarm映射,说明电网告警已被有意废弃。
parse_inv_warning_msg_alphaess(行 797-875) —— 同样逐位搬运。开头(行 799-806)在 g_t_bat_info.t_config_data.u8_ready == TRUE(系统未接电池)时把 u8_bat_open/u8_bat_high/u8_bat_low 清 0,其中 u8_bat_low 被赋了两次(应是 u8_bat_under 之类的另一个位被写错,见第 7 节)。
query_inv_cei_self_checking_data_alphaess(行 2108-2291) —— 本文件唯一使用"表驱动"的解析:
for phase in 0..2: // 三相
base = phase_base[phase] // 3 / 27 / 51
for i in cei_map[]: // 7 组保护项
value = BE16(buf + base + value_offset)
time = BE16(buf + base + time_offset)
res = BE16(buf + base + res_offset)
switch (type) 分别写入 t_phase_safty_info[phase] 与 u_cei_test_res[phase].bit
for phase in 0..2: // OVP10min 单独处理
off = 147 + phase*6 // L1:147, L2:153, L3:159
time = BE16(buf+off+2) / 1000
三相共占 3×24 = 72 字节(3..74),OVP10min 段从 147 起,加 3×6 = 18 字节到 164,落在 165 字节响应(1+1+1+162+2)之内。
意大利自检判定:
query_inv_running_data_alphaess里的u16_cei_ovtrv/uvtrv/oftrv/uftrv四个返回值(行 1348-1351)供alphaess_get_single_phase_self_test_data()使用:四者全部非零时u_test_res = 0(通过),否则0xFFFF(行 926-936)。alphaess_get_self_test_data()则以三相u_cei_test_res[i].u16_all == 0x5555为通过条件(行 948-957),并把三相机t_phase_safty_info[i]的阈值/时间逐项搬到t_safty_tset_info[i](行 959-1004)。
4.6 写操作的确认与重试策略
绝大多数写函数是同一模板:
组帧 → alphaess_write_data(...) → alphaess_recv_data(...) → 检查
if (len > 0 && buf[0] == 0x03 && buf[1] == 0x10) { 清标志; 更新时间戳; return TRUE; }
else { return FALSE; } // 下轮由主状态机重发
有 6 个函数额外引入了"失败 N 次即放弃并当作成功"的静态计数器(ALPHAESS_SEND_ERROR_COUNT_MAX = 3):
| 函数 | 行号 | 副作用 |
|---|---|---|
alphaess_set_safety_actpower_setting | 2761, 2918-2934 | 达 3 次后清标志、置 u8_ems_get_safety_actpower_setting_flag = TRUE |
alphaess_set_quiescent_volt_reactpower_support | 4246, 4332-4347 | 达 3 次后清标志、置回读标志 |
send_inv_afci_enable | 4767, 4777-4801 | 达 3 次后清标志、置 u8_ems_get_inv_afci_enable_flag = TRUE |
send_inv_afci_fault_enable | 4813, 4823-4847 | 达 3 次后清标志、置回读标志 |
query_inv_afci_fault_enable | 4859, 4869-4891 | 达 3 次后仍以 buf[3..4] 作为结果写入(buf 可能还是上一帧的内容) |
query_inv_afci_enable | 4905, 4915-4939 | 同上 |
4.7 安规双向映射
回读方向(parse_alphaess_inv_safety,行 519-707):DSP 的 ALPHAESS_* 码 → EMS 的 u8_safety + u8_safesub。三个国家需要二次判断以区分子标准:
ALPHAESS_UNE_217002:若当前配置是NTS_Type_A或UNE217002则保持原样,否则回落RD1699(行 573-589)。ALPHAESS_VDE_0126:配置为VDE0126_GR时保持,否则VDE0126_50HZ(行 601-612)。- 末尾(行 693-706)若解析结果与配置不一致,回写配置、置三个回读标志与
s_u8_config_save_flag,并OSTimeDlyHMSM(0,0,1,0)阻塞 1 s 后再置u8_ems_get_self_data_flag——这是全文件仅有的几处主动 delay 之一。
下发方向(alphaess_inverter_safety_set,行 3490-3676):反向映射,AS4777_2 需按 u8_safesub 分 A/B/C/NZ,其余一对一。若 EMS 侧安规码不在支持表内(default),则不发送,只把 u8_ems_set_inv_safety_arg_flag1 清掉并回写配置。写成功后一次性置位 u8_query_inv_device_info_flag、u8_inv_parameter_init_flag、u8_ems_get_function_enable_flag、u8_ems_get_safety_actpower_setting_flag、u8_ems_get_quiescent_volt_reactpower_support_flag 并刷新两个时间戳(行 3657-3665),即 改安规后强制全量重读。
4.8 定时/调度时序与 uCOS-II 配合
- 时间基准:
OSTimeGet()返回 uCOS-II tick;从> 1000表示 1 s 的用法看,OS_TICKS_PER_SEC为 1000,即 tick = 1 ms。 - 主要时间常量:设备信息波特率探测 10 s(行 216)、参数初始化延时 3 s(行 5106)、运行数据回读 1 s(行 5202)、运行模式回读 10 s(行 5415)、通信丢失 30 s + 升级后宽限 90 s(行 5450-5459)、升级完成窗口 120 s(行 5450)、AFCI 告警自动清除 10 s(行 5491)、AFCI 升级后回读 50 s(行 5074)、接收等待 500 ms(行 301)。
- 没有使用信号量或消息邮箱:本文件与任务间的同步完全依赖
g_t_alphaess_comm_info里的标志位。所有收发都在调用者(逆变器任务)上下文内同步完成,因此alphaess_recv_data里的OSTimeDlyHMSM会阻塞整个逆变器任务——最坏情况 500 ms。 - 两处主动 delay:
parse_alphaess_inv_safety末尾 1 s(行 705)、set_inv_start_stop成功后 2 s(行 2551)、alphaess_recv_data等待循环内每次 10 ms。这些 delay 会让同一任务内的其它逆变器处理(例如inverter.c里同轮调用的其它厂商分支)被推迟。 - tick 回卷保护:行 5213-5216 与 5421-5424 显式处理
u32_*_tick > OSTimeGet()的情况,但u32_ems_inv_comm_tick(行 5459)与u32_query_inv_parameter_init_flag_tick(行 5106)等其它比较点没有同样的保护。
4.9 关键全局变量的读写与触发
| 变量 | 写入者 | 读取者 | 触发条件 |
|---|---|---|---|
g_t_alphaess_comm_info.u8_query_inv_device_info_flag | 行 116、1036、1204、3388、3658 | 主状态机 5093、data_check 5535 | 开机置位;版本读到 0 保持;成功后清零;两倍充电/安规设置成功后重新置位 |
u32_ems_inv_comm_tick | 几乎所有收帧成功的函数 | 行 5459 通信丢失判定 | 任何一帧收发成功即刷新,等效"心跳" |
u8_inv_parameter_init_flag | 行 119、5112、3659、4424 | 5104、2632、2439、3852 | 开机与安规变更时置位;system_start_first_setting() 成功后清零 |
u8_set_inv_start_stop_flag | 行 129、550 | 5157 | data_check 检测到启停模式变化 |
u8_ems_set_safety_actpower_setting_flag / u8_ems_get_safety_actpower_setting_flag | data_check 未直接写 set;get 由 699、153、2924、3661 写入 | 5293 / 5375 | 安规解析不一致或安规写成功后触发全量重读 |
s_u8_config_save_flag | 行 702、1196、3642 | 5428 | 任何"解析结果与配置不一致"的场合,统一在 comm 末尾落盘 |
g_t_inv_info.t_run_info.u8_inverter_comm_lost_flag | 行 1032(清)、5461(置) | 5686、外部 HMI/告警 | 收帧成功清、30 s 无帧置 |
u8_inverter_poweron_mode_cnt | 行 5688、5693、5698 | 同处 | DSP 连续上报上电模式,>10 次即重初始化通信 |
g_t_logic_info.u8_bat_adapt_inv_flag | 行 1172/1176 | send_bat_info_to_inv 3728 | 由逆变器 Modbus 协议版本 > V1.00 决定是否走电池自适应新方案 |
g_t_inv_info.t_safty_info.* | 行 1972-2035(读)、1545-1771(写) | 全局 | u8_ems_get_self_data_flag 驱动的读—改—写回环 |
4.10 AFCI 分支
AFCI(电弧故障检测)板与逆变器共用 uart2,因此其协议也由本文件承载物理层:
alphaess_afci_comm_function(行 5045-5081):依次处理使能下发、故障使能下发、自检(afci_self_check_condition()四条件同时满足才afci_self_check_handle())、告警清除、u8_ems_set_inv_afci_log_flag触发afci_fault_log_data_handle()、升级后 50 s 回读软件版本。afci_self_check_condition(行 4996-5009):u8_afci_self_check_flag && u8_quary_afci_enable && u8_afci_fault_enable && u8_config_data.u8_afci_enable && AFCI_RUN_MODE_ALLOW(u8_run_mode)。alphaess_afci_data_check(行 5478-5520):监测u32_inv_warning2.bit.u8_afci_wraning跳变;持续 10 s 仍为 TRUE 则置u8_afci_clear_warning_info_flag自动清除(行 5484-5494)。配置使能与 DSP 回读使能不一致时置两个下发标志(行 5496-5506)。检测到u32_inv_fault2.bit.u8_afci_fault且已使能、且未处理过,则置u8_ems_set_inv_afci_log_flag记录日志(行 5509-5514)——注释明确说明"拉弧报错后逆变器停机且不会自清除,需售后上门重启"。
5. 对外接口
5.1 本文件导出的函数(非 static)
| 函数 | 声明位置 | 实际调用方 |
|---|---|---|
alphaess_comm_init | .h:718 | midware/inverter/inverter.c:89、midware/inverter/alphaess/alphaess_upgrade.c:533,582、本文件 5462、5691 |
alphaess_write_data | .h:720 | midware/afci/afci_comm.c:67,109,763、midware/afci/afci_upgrade.c:102,204,231、本文件全部发送路径 |
alphaess_recv_data | .h:721 | midware/afci/afci_upgrade.c:127、本文件全部接收路径 |
alphaess_inverter_comm_usart | .h:723 | midware/inverter/inverter.c:1116 |
alphaess_inverter_data_check | .h:724 | midware/inverter/inverter.c:1117 |
alphaess_get_self_test_data | .h:725 | midware/inverter/inverter.c:308 |
alphaess_get_single_phase_self_test_data | 无任何头文件声明 | 无调用方(死代码) |
alphaess_set_safety_actpower_setting | 无头文件声明 | 仅本文件 5295 |
alphaess_restart_dsp | 无头文件声明 | 仅本文件 5220 |
alphaess_overload_recovery | 无头文件声明 | 仅本文件 5225 |
alphaess_set_generator_flag | 无头文件声明 | 仅本文件 5230 |
alphaess_set_grid_forming_flag | 无头文件声明 | 仅本文件 5235 |
alphaess_set_bb_enable | 无头文件声明 | 仅本文件 5245 |
alphaess_set_mppt_enable | 无头文件声明 | 仅本文件 5250 |
alphaess_set_pv_charger_mode | 无头文件声明 | 仅本文件 5255 |
alphaess_set_quiescent_volt_reactpower_support | 无头文件声明 | 仅本文件 5300 |
alphaess_set_pu_mode_active_response_3tau | 无头文件声明 | 仅本文件 5305 |
alphaess_set_pe_loss_check_flag | 无头文件声明 | 仅本文件 5265 |
alphaess_set_phase_negation | 无头文件声明 | 仅本文件 5329 |
alphaess_set_bat_ac_out | 无头文件声明 | 仅本文件 5312 |
alphaess_set_inv_operation_mode_alphaess | 无头文件声明 | 仅本文件 5334 |
alphaess_set_inv_parallel | 无头文件声明 | 仅本文件 5260 |
5.2 本文件导出的全局变量
| 变量 | 说明 |
|---|---|
g_t_alphaess_comm_info | 行 36 定义;.h:715 声明 extern。被 alphaess_comm_can.c、alphaess_upgrade.c、midware/afci/afci_comm.c、midware/afci/afci_upgrade.c、midware/interface/modbus/modbus.c、sunspec_business.c、sunspec_modbus.c、midware/inverter/inverter.c 读取 |
phase_base[3] | 行 42,未加 static,符号对全工程可见(虽然当前只有本文件使用) |
5.3 本文件调用的外部函数与变量
| 来源模块 | 符号 | 用途 |
|---|---|---|
hardware/usart2/usart2.c | usart2_init、usart2_clear_buffer、usart2_send_data、usart2_is_recv_async_data、usart2_get_data_len、usart2_read_data_async | uart2 物理层收发 |
common/crc.c | GetCrcCode_Modbus | Modbus CRC16 |
data/data.c | g_t_inv_info(含 t_run_info/t_safty_info/t_safty_tset_info/t_config_data/t_control_cmd/t_control_parameter/t_afci_info/t_debug_log)、g_t_bat_info、g_t_meter、g_t_system_base_info、SYSTEM_DATETIME、ems_set_fault_bit | 主数据结构与故障置位 |
logic/logic.c | g_t_logic_info(t_config_data.PV_Capacity_Storage、u8_max_feedin_percent、u8_bat_adapt_bat_flag、u8_bat_adapt_inv_flag) | 能量调度配置 |
midware/inverter/inverter.c | get_inverter_sub、inverter_read_safety、inverter_read_grid_freq、inverter_get_parallel_mode、inverter_reset、is_inverter_firm_download_finished、PF_001_TO_01 | 机型/安规/并机查询与复位 |
midware/bms/bms.c | bms_get_ready_enable | BMS 就绪判定 |
midware/pvcharger | pvcharger_read_bat_work_state、pvcharger_read_bat_charge_cut_off_volt、pvcharger_read_bat_dischg_cut_off_volt、pvcharger_read_bat_discharge_pro_cur_step_1、pvcharger_read_bat_charge_pro_cur_step_1、pvcharger_read_bat_rated_volt_instant、pvcharger_read_bat_model、pvcharger_read_bat_series、pvcharger_read_bat_rated_volt、pvcharger_read_bat_max_charge_power、pvcharger_read_bat_max_dischg_power、pvcharger_read_machine_mode | 电池与 PVCharger 参数 |
logic/parallel 或 generator.c | parallel_read_gc_control_en | 油机使能来源 |
data/system_config.c | save_job_post、Set_Setup_Config_Status、Set_Setup_Config_Extend2_Status、set_info_status、get_board_type、get_ems_hard_version、VERSION_INV_HARD | 配置落盘与版本 |
midware/inverter/alphaess/alphaess_upgrade.c/.h | alphaess_upgrade_handle、alphaess_get_upgrade_finish_tick | 逆变器固件升级 |
midware/inverter/alphaess/alphaess_comm_can.c/.h | alphaess_comm_init_can、ALPHAESS_POWER_ON_E、ALPHAESS_POWER_ON_E_2 | CAN 侧初始化与运行模式枚举 |
midware/afci/afci_comm.c/.h、afci_upgrade.c、afci_download.c | set_afci_fac_mode、afci_log_init、query_afci_software_version、afci_self_check_handle、send_afci_clear_warning_message、afci_fault_log_data_handle、is_afci_firm_download_finished、afci_upgrade_handle、AFCI_SLAVR_ADDRESS、AFCI_UPGRADE_ADDRESS、DEBUG_ALPHAESS_AFCI | AFCI 板通信、自检、升级 |
midware/inverter/inv_download.c、midware/bms/bms_download.c、midware/afci/afci_download.c | include 但本文件未直接调用(由 include 传递依赖) | 固件下载 |
net/ | include ems.h | 云端状态上报 |
| uCOS-II | OSTimeGet、OSTimeDlyHMSM | 时基与阻塞延时 |
6. 依赖关系
依赖(include 列表,行 13-32)
alphaess_comm_usart.h(自身)、alphaess_comm_can.h、alphaess_upgrade.h、inverter.h、bms.h、meter.h、usart2.h、data.h、logic.h、generator.h、system_config.h、wireless_driver.h、ems.h、inv_download.h、bms_download.h、crc.h、board_init.h、afci_comm.h、afci_download.h、afci_upgrade.h。
被依赖
midware/inverter/inverter.c(主调用方,行 1116-1117、308、89)midware/inverter/alphaess/alphaess_upgrade.c(行 533、582 调alphaess_comm_init)midware/afci/afci_comm.c、midware/afci/afci_upgrade.c(复用 uart2 物理层)alphaess_comm_usart.h的消费者:alphaess_comm_can.c、midware/interface/modbus/*- 所有读取
g_t_alphaess_comm_info的模块(HMI、Modbus 从站、云端上报)
7. 备注与风险点
缓冲区越界风险(高)
alphaess_recv_data中读应答分支(行 381-382)用buf[buf[2]+4]、buf[buf[2]+3]计算 CRC 位置,完全信任对方报文的字节数字段buf[2],既不检查buf[2]是否与请求的寄存器数一致,也不检查l_u16_len是否足够。s_u8_recv_buf为 256 字节,若 DSP 或总线噪声导致buf[2]被读成较大值,会越界读。升级分支(行 322、327)同样在未验证l_u16_len ≥ 8/6的情况下直接读buf[7]/buf[5]。alphaess_set_bat_ac_out(行 4504-4520)在l_u8_tx_buf[128]中拼 14 字节,安全;但ems_send_ctrl_data_to_inv_alphaess的l_u8_tx_buf[128]在len_buff == 200(ALPHAESS_MAX_REGISTER_NUM*2)时理论上会写入7 + 200 = 207 > 128。当前无调用方传 >102 字节,但长度检查只校验len_buff <= 100*2,未校验缓冲区本身尺寸,属于潜在溢出。query_inv_cei_self_checking_data_alphaess依赖响应长度校验buf[2] == 81*2 = 162,之后最高访问147 + 2*6 + 5 = 164,而有效数据区到buf[164](共 165 字节),刚好不越界——但这是隐性耦合,若phase_base或off公式调整会立即越界。
逻辑可疑/错误
- 表达式优先级错误(行 2641、2647):
u16_rev_machine_rate = ((s_u8_recv_buf[3] << 8) | (s_u8_recv_buf[4]) * 6);— 按 C 优先级等价于(buf[3] << 8) | (buf[4] * 6),而非注释意图的((buf[3]<<8)|buf[4]) * 6。行 2687、2663 也有同类(...)) * 6但括号位置正确的写法,说明此处就是漏括号。 - 重复赋值/错位赋值:
parse_inv_err_msg_alphaess行 726 与 773 都把u8_output_overload写同一个位,前者被覆盖。parse_inv_warning_msg_alphaess行 804-805 连续两行都写u8_bat_low,明显是把另一个位写错。
query_inv_operation_mode_alphaess的长度校验用了别的宏(行 4627):s_u8_recv_buf[2] == ALPHAESS_NUM_SET_PHASE_NEGATION * 2,应为ALPHAESS_NUM_INV_MODE_CMD * 2。当前两者数值都为 2 才没出问题。- DSP 主/从版本号取的是同一段字节(行 1141-1149),
u8_master_ver与u8_slave_ver内容必然相同,从机版本实际未单独解析。 - "失败 3 次即当成功"的语义(见 4.6 节):
query_inv_afci_fault_enable/query_inv_afci_enable在计数超限时仍然执行buf[3..4]赋值(行 4878、4924),而buf此时可能仍是上一帧残留内容或是全零,会把错误值写进g_t_inv_info.t_run_info。这是几条最容易产生静默错误数据的分支。 alphaess_get_single_phase_self_test_data的判定方向值得复核(行 926-936):四个 CEI 返回值全部非零才判"通过(0)"。同时又没有把它与 0x5555 的位图判定统一,且该函数无任何调用方,属死代码。l_u8_error_num计数器在部分函数里被static修饰在函数体内(行 2761、4246、4767、4813、4859、4905),每个函数一份实例,若某次成功后未清零就跨场景复用会串味。目前所有分支都在成功路径清零,尚可。alphaess_afci_data_check的状态机不对称(行 5515-5518):else if ((fault == FALSE) && (u8_ems_set_inv_afci_log_flag == FALSE))才复位l_u8_afci_temp_error_handle,而u8_ems_set_inv_afci_log_flag的清除在afci_fault_log_data_handle()内部(本文件外),若那条链路不执行,l_u8_afci_temp_error_handle会永久保持 TRUE,后续拉弧故障不再记日志。
魔法数字与约定
- 关键魔法数:升级功能码
0x41/0x42/0x43(行 318-348)、send_query_data_to_inv_alphaess里硬编码的0x03(行 456)、alphaess_overload_recovery的0x0d(行 4040)、alphaess_set_bat_ac_out的帧头0x51 0x35与"禁止时写 10000"(行 4504、4493)、奥地利零电流电压1840/115(行 2018-2022)、A 相电压阈值15(行 783-784)、电网频率阈值4500/4000(行 1403、5538)、u_cei_test_res == 0x5555(行 948-950)、曲线上报缩放23/10与*10/23(行 3892-3899、4307-4320)、*6//6的功率比例换算(行 2641、2768、2825)。 set_inv_start_stop的映射(行 2530-2538):s_u8_temp_work_mode为 1 → 命令 1、为 2 → 命令 0。EMS 侧"2 = 运行、1 = 停机"与 DSP 侧"1 = 运行、0 = 停机"是反的,只靠这段 switch 桥接;s_u8_temp_work_mode初值 0x02(行 37)意味着上电默认下发"运行"。误改这里的常量会直接导致逆变器反向动作。u16_ems_change_para_state_time = (bHours << 8) | bMinutes(行 4672)——只记录"时:分",跨天不可区分,且精度只到分钟。
其它
phase_base未加 static(行 42),污染全局命名空间;cei_map/s_u8_recv_buf/s_u8_config_save_flag/s_u8_temp_work_mode都加了 static,此处不一致。- 大量非 static 函数无头文件声明(见 5.1 节表格)。这在 C89/C90 下会导致"隐式声明"或直接被误当作外部符号;当前它们只在本文件内被调用,应改为 static 或补声明。
alphaess_get_single_phase_self_test_data(行 884)完全未被引用;ALPHAESS_ADDR_REG_QUERY_INV_RUNNING_DATA_PARALLEL、ALPHAESS_ADDR_REG_SET_INV_FIRST_ONGRID_TIME、ALPHAESS_ADDR_REG_CLEAR_INV_FAULT也未被本文件使用,属历史遗留。- 三处主动阻塞:
parse_alphaess_inv_safety末尾 1 s(行 705)、set_inv_start_stop成功后 2 s(行 2551)、alphaess_recv_data等待循环(最长 500 ms)。这些 delay 发生在逆变器任务上下文,会推迟同任务内的其它工作;1 s 的 delay 在安规解析路径上尤其值得关注(每次安规回读不一致都会打满 1 s)。 alphaess_set_italian_anti_backflow的调试打印被写死为#if 1(行 3425、3432),无论DEBUG_ALPHAESS_INV如何配置都会向串口输出,属于遗留的临时调试代码。- 行 1376-1401 有一大段被注释掉的 "CAN 协议兼容" 赋值块,行 1259、1272-1273、1752-1753、1762-1763、2014、2334-2335、2370-2371、5553-5559 也有多处注释代码,说明该文件在 SCI 与 CAN 两套协议之间做过多次切换,阅读时需注意哪些是活跃路径。
- 两处除法未做零保护:
200/(((u16)(...))/100)(行 2667、2688)与2000/u16_p_f_over_freq_derating_rate、2000/u16_p_f_under_freq_derating_rate(行 2829-2830、2878-2879)。若 DSP 回读的降载率为 0(未配置或回读失败但长度校验通过),在 Cortex-M4 上整型除零要么产生 UsageFault、要么返回 0 导致下发l_u8_tx_buf[34..35] = 0,两种情况都不可接受。 - 抗干扰能力:
alphaess_recv_data的 1 s 周期回读(行 5202)不论成败都推进时间戳,因此单次丢帧不会立即重试,而是等下一个 1 s 周期;query_inv_device_info_alphaess反而是"不成功就一直重发并阻塞在波特率探测上",两条路径的重试策略不一致。