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

alphaess_comm_usart.c

源文件路径: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_baudstatic行 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_alphaessstatic行 451。组 8 字节读寄存器请求帧(0x03, func, addr, num, CRC)并发出
ems_send_ctrl_data_to_inv_alphaessstatic行 477。组写寄存器请求帧(0x10 多寄存器 / 0x06 单寄存器),含长度合法性检查与 CRC
parse_alphaess_inv_safetystatic行 519。把 DSP 安规码翻译成 EMS 侧 u8_safety/u8_safesub,与配置不一致时回写配置并置位相关回读标志
parse_inv_err_msg_alphaessstatic行 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_alphaessstatic行 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_alphaessstatic行 1014。读 30000+73 设备信息区:型号、SN、安规、额定功率、屏幕类型、DSP 主/从版本、硬件版本、Modbus/CAN 协议版本,并落盘配置
query_inv_running_data_alphaessstatic行 1234。读 30200+115 运行数据区,填充 t_alphaess_run_info 并转发到 g_t_inv_info.t_run_info,最后调用两个 parse 函数
query_inv_running_data_alphaess_extand1static行 1491。读 30331+16 扩展区,取三相无功/视在功率与单相 PV 接入状态
alphaess_set_first_ongrid_pro_valuestatic行 1540。写 42001+4,下发首次并网 OVP/UVP/OFP/UFP 保护值
alphaess_set_ovp_uvp_pro_valuestatic行 1581。写 42005+16,下发三级过压/欠压值、时间(DSP 单位 2 ms,写时 /2)、10 min 过压、恢复值
alphaess_set_ofp_ufp_pro_valuestatic行 1671。写 42021+12,下发三级过频/欠频值与时间(/2)
alphaess_set_self_pro_threshold_valuestatic行 1729。写 42033+15,下发频率变化率保护、ISO/DCI 阈值与时间、HVRT/LVRT 电压、四档 GFCI 阈值
alphaess_set_gfci30ma_pro_valuestatic行 1816。写 42044,单点下发 30 mA GFCI 阈值
alphaess_set_gfci60ma_pro_valuestatic行 1852。写 42045,单点下发 60 mA GFCI 阈值
alphaess_set_gfci150ma_pro_valuestatic行 1888。写 42046,单点下发 150 mA GFCI 阈值
alphaess_set_gfci300ma_pro_valuestatic行 1924。写 42047,单点下发 300 mA GFCI 阈值
query_inv_self_data_alphaessstatic行 1959。读 42001+47 安规参数区,反向填充 g_t_inv_info.t_safty_info(时间 *2、*20,等待/重连时间 /2),并按奥地利安规特殊处理零电流电压
query_inv_cei_self_checking_data_alphaessstatic行 2108。读 42048+81,按 phase_base[] + cei_map[] 三维展开三相 CEI 自检数据与逐项结果位
alphaess_set_function_enablestatic行 2300。写 41000+26(52 字节),一次性下发全部功能使能与保护阈值包
query_inv_function_enable_data_alphaessstatic行 2400。读 41000+26,反向填充功能使能包;成功返回 TRUE
set_inv_snstatic行 2489。写 40202+16,把本机 SN 写入逆变器
set_inv_start_stopstatic行 2524。写 40126,按 s_u8_temp_work_mode 映射启停命令字(1→1 启动,2→0 停止)
alphaess_set_inv_on_offstatic行 2576。写 40127,下发逆变器 ON/OFF(INV_SHUTDOWN 时写 1)
query_inv_safety_actpower_settingstatic行 2618。读 43000+51,解析频率降载(P-f)曲线、P-V 曲线、无功模式等 51 个寄存器
query_inv_safety_over_under_freq_modestatic行 2720。读 43000+51 但只取 43007/43031 两个位,用于过/欠频降载使能回读
alphaess_set_safety_actpower_setting全局行 2759。写 43000+51(102 字节),下发完整 P-f / P-V 降载曲线,含 3 次失败放弃逻辑
set_pv_capacitystatic行 2945。写 40134,下发 PV 装机容量
set_max_feedin_percentstatic行 2983。写 40135,下发最大馈网功率比例
set_bat_chg_cut_voltstatic行 3021。写 41111,下发充电截止电压
set_bat_dischg_cut_voltstatic行 3060。写 41108,下发放电截止电压
set_bat_adapt_typestatic行 3099。写 41106,仅下发"并联/串联"自适应类型
set_bat_typestatic行 3144。写 41106,按电池型号映射成 96 V/150 V/300 V/9640-9650/DCDC/0xFF 工厂值下发
set_bat_heat_cut_voltstatic行 3265。写 41134+2,下发电池加热电压(0.1 V)与加热电流(0.01 A)
set_bat_heat_cmdstatic行 3305。写 41028,下发电池加热指令
set_bat_heat_relay_stastatic行 3340。写 41140,下发电池加热继电器状态
alphaess_set_dc_double_pchargestatic行 3375。写 41141,下发"两倍电池充电功率"使能;成功后置 u8_query_inv_device_info_flag 触发重新读取设备信息
alphaess_set_italian_anti_backflowstatic行 3411。写 41031,下发意大利防逆流使能(注释标记 //bufan)
alphaess_inverter_energy_clearstatic行 3446。写 40102+5(值为交替 0/1),清除逆变器各项发电量
alphaess_inverter_safety_setstatic行 3490。把 EMS 侧 u8_safety/u8_safesub 反译成 DSP 安规码写 42000;成功后再触发一轮参数回读
system_start_first_settingstatic行 3685。开机首次参数序列:依次回读功能使能、安规有功设置、静态无功支撑,任一失败返回 FALSE
send_bat_info_to_invstatic行 3722。电池参数下发总控:按"电池+逆变器是否都支持自适应"分流到自适应新方案或旧方案,再下发充/放电截止电压
alphaess_restart_dsp全局行 3794。写 40128,复位 DSP
query_inv_quiescent_volt_reactpower_supportstatic行 3829。读 44000+26,解析无功模式位图、cosφ(P) 五点曲线、Q(U) 四点曲线与回差
query_inv_pu_mode_active_response_3taustatic行 3946。读 44034+2,解析 P-V 模式使能与 3τ 响应时间
query_inv_pe_loss_check_flagstatic行 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_negationstatic行 4534。读 40156,回读相序自适应使能
alphaess_set_inv_operation_mode_alphaess全局行 4576。写 40130,下发逆变器运行模式
query_inv_operation_mode_alphaessstatic行 4613。读 40130,回读运行模式
alphaess_set_inv_parallel全局行 4655。写 40151,整体下发并机配置字节;成功后记录 u16_ems_change_para_state_time
alphaess_set_inv_bypass_modestatic行 4692。写 40161,下发 Bypass 模式使能
alphaess_set_bat_adapt_enstatic行 4727。写 41136,下发电池自适应使能(入参决定开或关)
send_inv_afci_enablestatic行 4765。写 41023,下发 AFCI 使能,含 3 次失败放弃逻辑
send_inv_afci_fault_enablestatic行 4811。写 40166,下发 AFCI 报错使能,含 3 次失败放弃逻辑
query_inv_afci_fault_enablestatic行 4857。读 40166,回读 AFCI 报错使能,含 3 次失败放弃逻辑
query_inv_afci_enablestatic行 4903。读 41023,回读 AFCI 使能,含 3 次失败放弃逻辑
alphaess_set_bat_adapt_protect_parastatic行 4949。写 41137+3,下发电池自适应保护参数(瞬时额定电压、放电/充电电流)
afci_self_check_conditionstatic行 4996。AFCI 自检前置条件判定:自检标志、回读使能、配置使能、运行模式四者同时满足
is_ready_to_query_inv_self_datastatic行 5017。判断当前是否允许发起安规参数回读(无正在进行的安规写操作时才允许)
alphaess_afci_comm_functionstatic行 5045。AFCI 通信总调度:使能下发、自检、告警清除、故障日志、升级后版本回读
alphaess_inverter_comm_usart全局行 5090。主通信状态机,逐轮推动所有查询/下发/升级/通信丢失检测
alphaess_afci_data_checkstatic行 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 是共享缓冲。

时序:

  1. usart2_is_recv_async_data() 判断是否有异步数据;无数据直接 *len = 0 返回(行 296、435-441)。
  2. 轮询 usart2_get_data_len() 直到 ≥2 字节,每次 OSTimeDlyHMSM(0,0,0,10) 让出 10 ms;超过 500 tick(500 ms) 放弃并返回长度 0(行 298-307)。
  3. 一次性把 l_u16_len 字节读到 buf(行 309-316)。
  4. 按帧头分流做 CRC 校验,只有校验通过才 *len = l_u16_len,否则 *len = 0:
分流条件行号CRC 覆盖范围
buf[0]==0x03 && buf[1]==0x41/0x42/0x43(逆变器升级帧)318-3480x42 → 前 6 字节、CRC 在 buf[6..7];0x41/0x43 → 前 4 字节、CRC 在 buf[4..5]
buf[0]==0x03 && buf[1]==0x10/0x06(写应答回显)349-3770x06 → 前 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 分支)

按如下优先级依次尝试,每一轮只推进能成功的那些(每个函数内部自带"发一帧 + 收一帧",所以一轮内实际可能发多帧):

  1. 开机首次参数设置(行 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。
  2. 电池信息下发(行 5127-5131):u8_startingup_check_bat_flag == FALSE 且 pvcharger_read_bat_work_state() != FALSE 时调 send_bat_info_to_inv()。
  3. 电池加热三件套(行 5133-5155):加热指令、加热电压/电流、加热继电器状态,各自用 u8_bat_heat_*_data_flag == FALSE 作为"待发"标志,成功后置 TRUE。
  4. 一批条件触发的单点命令(行 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 容量、最大馈网比例。
  5. 周期回读 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()(时间回绕)则强制同步。

  1. 周期回读 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 回卷保护。
  2. 常驻守护式回读(行 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()。
  3. AFCI 通信(行 5336-5340):仅在"支持 AFCI 且逆变器固件、AFCI 固件都下载完成"时调用 alphaess_afci_comm_function()。

阶段 C:收尾(行 5428-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-5618t_safty_info.u8_safety/u8_safesub 与配置不一致则置 u8_ems_set_inv_safety_arg_flag1
油机5620-5624与 parallel_read_gc_control_en() 比较
Grid-Forming5626-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-5699u16_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-5704u16_n_n_short_value & 0x02 与配置 u8_nn_short_detect_state & 0x02 不一致则置 u8_ems_set_function_enable_flag
逆变器 ON/OFF5706-5710快照与 t_run_info.u8_set_inv_on_off 比较
Bypass 模式5712-5716快照与 t_run_info.u8_inv_bypass_enable 比较
AFCI5718-5721支持 AFCI 时调 alphaess_afci_data_check()

4.5 数据解析与映射

query_inv_device_info_alphaess(行 1014-1225) —— 只在开机时执行一次(成功后清 u8_query_inv_device_info_flag):

query_inv_running_data_alphaess(行 1234-1482) —— 1 s 周期的主遥测通道,长度校验 buf[2]==115*2:

u32_err1_all = (buf[161+32]<<24)|(buf[162+32]<<16)|(buf[159+32]<<8)|(buf[160+32]),即 DSP 按"高字在前"发送。

parse_inv_err_msg_alphaess(行 716-788) —— 纯位对位搬运,约 50 行赋值。两个特殊点:

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)之内。

意大利自检判定:

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_setting2761, 2918-2934达 3 次后清标志、置 u8_ems_get_safety_actpower_setting_flag = TRUE
alphaess_set_quiescent_volt_reactpower_support4246, 4332-4347达 3 次后清标志、置回读标志
send_inv_afci_enable4767, 4777-4801达 3 次后清标志、置 u8_ems_get_inv_afci_enable_flag = TRUE
send_inv_afci_fault_enable4813, 4823-4847达 3 次后清标志、置回读标志
query_inv_afci_fault_enable4859, 4869-4891达 3 次后仍以 buf[3..4] 作为结果写入(buf 可能还是上一帧的内容)
query_inv_afci_enable4905, 4915-4939同上

4.7 安规双向映射

回读方向(parse_alphaess_inv_safety,行 519-707):DSP 的 ALPHAESS_* 码 → EMS 的 u8_safety + u8_safesub。三个国家需要二次判断以区分子标准:

下发方向(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 配合

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、44245104、2632、2439、3852开机与安规变更时置位;system_start_first_setting() 成功后清零
u8_set_inv_start_stop_flag行 129、5505157data_check 检测到启停模式变化
u8_ems_set_safety_actpower_setting_flag / u8_ems_get_safety_actpower_setting_flagdata_check 未直接写 set;get 由 699、153、2924、3661 写入5293 / 5375安规解析不一致或安规写成功后触发全量重读
s_u8_config_save_flag行 702、1196、36425428任何"解析结果与配置不一致"的场合,统一在 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/1176send_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,因此其协议也由本文件承载物理层:

5. 对外接口

5.1 本文件导出的函数(非 static)

函数声明位置实际调用方
alphaess_comm_init.h:718midware/inverter/inverter.c:89、midware/inverter/alphaess/alphaess_upgrade.c:533,582、本文件 5462、5691
alphaess_write_data.h:720midware/afci/afci_comm.c:67,109,763、midware/afci/afci_upgrade.c:102,204,231、本文件全部发送路径
alphaess_recv_data.h:721midware/afci/afci_upgrade.c:127、本文件全部接收路径
alphaess_inverter_comm_usart.h:723midware/inverter/inverter.c:1116
alphaess_inverter_data_check.h:724midware/inverter/inverter.c:1117
alphaess_get_self_test_data.h:725midware/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.cusart2_init、usart2_clear_buffer、usart2_send_data、usart2_is_recv_async_data、usart2_get_data_len、usart2_read_data_asyncuart2 物理层收发
common/crc.cGetCrcCode_ModbusModbus CRC16
data/data.cg_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.cg_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.cget_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.cbms_get_ready_enableBMS 就绪判定
midware/pvchargerpvcharger_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.cparallel_read_gc_control_en油机使能来源
data/system_config.csave_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/.halphaess_upgrade_handle、alphaess_get_upgrade_finish_tick逆变器固件升级
midware/inverter/alphaess/alphaess_comm_can.c/.halphaess_comm_init_can、ALPHAESS_POWER_ON_E、ALPHAESS_POWER_ON_E_2CAN 侧初始化与运行模式枚举
midware/afci/afci_comm.c/.h、afci_upgrade.c、afci_download.cset_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_AFCIAFCI 板通信、自检、升级
midware/inverter/inv_download.c、midware/bms/bms_download.c、midware/afci/afci_download.cinclude 但本文件未直接调用(由 include 传递依赖)固件下载
net/include ems.h云端状态上报
uCOS-IIOSTimeGet、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。

被依赖

7. 备注与风险点

缓冲区越界风险(高)

  1. 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]。
  2. 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,未校验缓冲区本身尺寸,属于潜在溢出。
  3. query_inv_cei_self_checking_data_alphaess 依赖响应长度校验 buf[2] == 81*2 = 162,之后最高访问 147 + 2*6 + 5 = 164,而有效数据区到 buf[164](共 165 字节),刚好不越界——但这是隐性耦合,若 phase_base 或 off 公式调整会立即越界。

逻辑可疑/错误

  1. 表达式优先级错误(行 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 但括号位置正确的写法,说明此处就是漏括号。
  2. 重复赋值/错位赋值:
    • parse_inv_err_msg_alphaess 行 726 与 773 都把 u8_output_overload 写同一个位,前者被覆盖。
    • parse_inv_warning_msg_alphaess 行 804-805 连续两行都写 u8_bat_low,明显是把另一个位写错。
  3. query_inv_operation_mode_alphaess 的长度校验用了别的宏(行 4627):s_u8_recv_buf[2] == ALPHAESS_NUM_SET_PHASE_NEGATION * 2,应为 ALPHAESS_NUM_INV_MODE_CMD * 2。当前两者数值都为 2 才没出问题。
  4. DSP 主/从版本号取的是同一段字节(行 1141-1149),u8_master_ver 与 u8_slave_ver 内容必然相同,从机版本实际未单独解析。
  5. "失败 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。这是几条最容易产生静默错误数据的分支。
  6. alphaess_get_single_phase_self_test_data 的判定方向值得复核(行 926-936):四个 CEI 返回值全部非零才判"通过(0)"。同时又没有把它与 0x5555 的位图判定统一,且该函数无任何调用方,属死代码。
  7. l_u8_error_num 计数器在部分函数里被 static 修饰在函数体内(行 2761、4246、4767、4813、4859、4905),每个函数一份实例,若某次成功后未清零就跨场景复用会串味。目前所有分支都在成功路径清零,尚可。
  8. 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,后续拉弧故障不再记日志。

魔法数字与约定

  1. 关键魔法数:升级功能码 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)。
  2. 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)意味着上电默认下发"运行"。误改这里的常量会直接导致逆变器反向动作。
  3. u16_ems_change_para_state_time = (bHours << 8) | bMinutes(行 4672)——只记录"时:分",跨天不可区分,且精度只到分钟。

其它

  1. phase_base 未加 static(行 42),污染全局命名空间;cei_map/s_u8_recv_buf/s_u8_config_save_flag/s_u8_temp_work_mode 都加了 static,此处不一致。
  2. 大量非 static 函数无头文件声明(见 5.1 节表格)。这在 C89/C90 下会导致"隐式声明"或直接被误当作外部符号;当前它们只在本文件内被调用,应改为 static 或补声明。
  3. 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 也未被本文件使用,属历史遗留。
  4. 三处主动阻塞: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)。
  5. alphaess_set_italian_anti_backflow 的调试打印被写死为 #if 1(行 3425、3432),无论 DEBUG_ALPHAESS_INV 如何配置都会向串口输出,属于遗留的临时调试代码。
  6. 行 1376-1401 有一大段被注释掉的 "CAN 协议兼容" 赋值块,行 1259、1272-1273、1752-1753、1762-1763、2014、2334-2335、2370-2371、5553-5559 也有多处注释代码,说明该文件在 SCI 与 CAN 两套协议之间做过多次切换,阅读时需注意哪些是活跃路径。
  7. 两处除法未做零保护: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,两种情况都不可接受。
  8. 抗干扰能力:alphaess_recv_data 的 1 s 周期回读(行 5202)不论成败都推进时间戳,因此单次丢帧不会立即重试,而是等下一个 1 s 周期;query_inv_device_info_alphaess 反而是"不成功就一直重发并阻塞在波特率探测上",两条路径的重试策略不一致。