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

inovance_comm_usart.c

源文件路径:midware/inverter/inovance/inovance_comm_usart.c 所属模块:midware/inverter/inovance(汇川 Inovance 逆变器通信协议) 代码行数:3229

1. 文件职责

本文件是汇川(Inovance)逆变器与 EMS 之间 SCI(RS485 串口,Modbus-RTU)通道 的 EMS 侧实现,与同目录 inovance_comm_can.c(CAN 私有协议通道)构成"双通道"分工:CAN 通道负责高频的有功/无功下发与实时运行数据接收,本文件负责设备识别、参数整定(安规参数整批下发与回读)、电池类型/加热、RTC 校准、启停机、软重启、能量统计、故障码解析,以及故障录波(黑匣子)数据回传。

数据流位置:向上从 g_t_inv_info(inverter.h 的逆变器总表,含 t_config_data/t_safty_info/t_run_info/t_control_cmd)、g_t_bat_info(BMS)、g_t_meter、g_t_logic_info 读取目标值与配置,向下经 usart2 硬件层把 Modbus-RTU 帧发到逆变器;反向把逆变器回读的安规参数、运行数据、故障/告警位写入 g_t_inv_info,并把故障录波写入 g_t_fault_scord_data(位于 SDRAM,供 net/ems.c 上报云端)。

被谁驱动:由 inverter.c:1045 的 uCOS-II 任务 task_inverter() 每个循环依次调用 inovance_inverter_comm()(inverter.c:1132)与 inovance_inverter_data_check()(inverter.c:1134)。初始化入口 inovance_comm_init() 在 inverter.c:102(机型识别后)、inovance_upgrade_init()(本文件 2306)和软重启流程(本文件 412)中被调用。

本文件不创建任务、不使用信号量或消息邮箱,全部以"轮询 + 事件标志位 + OSTimeGet() tick 时间戳 + OSTimeDlyHMSM() 阻塞延时"方式与 uCOS-II 协作。所有收发共用同一个串口 usart2 与同一个接收缓冲区 s_u8_inovance_recv_buf,是"单发单收、一问一答"的同步事务模型。

2. 关键数据结构与宏

2.1 本文件定义的全局对象

名称类型说明
g_t_inovance_comm_infoINOVANCE_TABLE_T(定义于 inovance_comm_usart.h:719)汇川 SCI/CAN 通信总表:事件标志、各周期 tick、故障/告警位域、运行信息、安规使能位域、待存盘标志
g_t_inovance_special_safetyINOVANCE_SPECIAL_SAFETY_TABLE_T(inovance_comm_usart.h:754)特殊安规暂存表:功率调节相关寄存器(0x1600 块)中无对应 EMS 字段的中间量
s_u8_inovance_recv_bufstatic u8[512](本文件 32)全文件唯一的接收缓冲,长度由 INOVANCE_INV_RECV_BUFFER_SIZE 决定

2.2 本文件主要使用的宏

名称类型说明
INOVANCE_INV_DEBUG宏本文件串口收发/解析调试打印总开关,inovance_comm_usart.h:17,默认 0
INOVANCE_SAFETY_DEBUG宏安规参数下发/回读调试打印开关,inovance_comm_usart.h:18,默认 0
INOVANCE_SLAVE_ADDRESS = 0x01宏逆变器 Modbus 从站地址(inovance_comm_usart.h:40)
INOVANCE_FUNC_READ_HOLDING_REGISTER = 0x03宏读保持寄存器功能码(:41)
INOVANCE_FUNC_WRITE_SIGNAL_HOLDING_REGISTER = 0x06宏写单个保持寄存器功能码(:42)
INOVANCE_FUNC_WRITE_MULTIPLE_HOLDING_REGISTER = 0x10宏写多个保持寄存器功能码(:43)
INOVANCE_MAX_REGISTER_NUM = 100宏单次读写寄存器数量上限(:23),用作写帧合法性判据
INOVANCE_INV_RECV_BUFFER_SIZE = 512宏接收缓冲长度(:24)
INOVANCE_DAT_PCK_INTERVAL_INV = 100宏两帧之间的最小间隔(ms),同时作为 usart2_send_data 的超时参数(:25)
INOVANCE_EMS_INV_COMM_LOST_TIME = 30000宏SCI 通讯丢失判据:距上次成功事务超过 30 s(:26)
INOVANCE_INV_INIT_TIME = 2000宏上电初始化阶段查询设备信息的重试周期(:27)
INOVANCE_BLACK_BOX_TIME = 4000宏黑匣子各查询步骤之间的等待时间(:28)
INOVANCE_BLACK_BOX_POINTS_T = 320宏录波总点数(:30)
INOVANCE_BLACK_BOX_POINTS_S = 4宏每帧返回的点数(:31)
INOVANCE_BLACK_BOX_POINTS_NUM = 80宏录波帧数(80 × 4 = 320)(:32)
INOVANCE_BLACK_BOX_DATA_OFFSET = 70宏黑匣子响应帧中每个录波点的字节步长(:33)
MAX_REQUEST_NUM = 30宏黑匣子流程最大请求次数保护阈值(:34)
TOTAL_CHANNELS_16 = 19宏录波 16 位通道数(:35)
TOTAL_CHANNELS_32 = 8宏录波 32 位通道数(:36)
S16_DATA_START_OFFSET = 5 / S32_DATA_START_OFFSET = 43宏录波点内 16/32 位数据起始偏移(:37-38)——定义了但代码中未使用,save_fault_scord() 仍写死 5 和 43
INOVANCE_BBOX_ADDR = 0xFE宏黑匣子模块的 Modbus 从站地址(:144)
FUNC_READ_BBOX = 0x03 / FUNC_READ_BBOX_INDEX = 0x06 / FUNC_READ_BBOX_DATA = 0x16宏黑匣子三个功能码(:145-147)
INOVANCE_ADDR_REGISTER_*宏逆变器保持寄存器地址表,共约 25 个块,见 inovance_comm_usart.h:45-122(详见 4.3 节映射表)
INOVANCE_TYPE_T12/T15/T20/T20_OLD = 1/2/3/52枚举值机型编码(inovance_comm_usart.h:161),query_inv_device_info() 据此选择额定参数与 SUB_* 子机型
INOVANCE_OPERATE_NONE/STOP/START = 0/1/2枚举值启停操作码(inovance_comm_usart.h:171)
INOVANCE_*_VAR_RESPONSE_MODE_E枚举无功响应模式:0 无、1 固定功率因数、2 cosφ(p)、3 固定 Q、4 Q(U) 线性、5 Q(U) 滞环(inovance_comm_usart.h:149),query_inv_safety_reactive_power_data() 据此设置 safty_mode_u.BIT
BLACKBOX_STATE_E枚举黑匣子读取状态机(inovance_comm_usart.h:709):QUERY_BLACK_BOX / WAIT_DIRECTORY_UPLOAD / READ_DIRECTORY_CONTENT / SET_INDEX_NUM / WAIT_FAULTDATA_UPLOAD / READ_DIRECTORY
INVERTER_TYPE = INVERTER_NULL宏编译期机型选择(inverter.h:172),文件末尾黑匣子整段代码被 #if (INVERTER_TYPE == INOVANCE_TYPE) 包裹(2871、3197)

2.3 位域联合体(故障/告警/标志)

名称类型说明
INOVANCE_ERROR1_U联合体故障字 1(64 位),按 BYTE0~BYTE7 逐位命名(母线过压、PV 反接、IGBT 过温、GFCI、绝缘、EMS SCI/CAN 等),inovance_comm_usart.h:178
INOVANCE_ERROR2_U联合体故障字 2,BYTE0~:电网过流、备电过压/欠压、PV 硬件过压、负载过流、各相零漂故障、加热相关故障;BYTE2 之后为未命名占位位(:275)
INOVANCE_WARNING1_U联合体告警字 1:电网过压/欠压/过频/欠频、电池开断、风扇故障、黑匣子 FLASH、RTC、孤岛、HVRT/LVRT、板温告警(:371)
INOVANCE_WARNING2_U联合体告警字 2,仅保留 word 视图,无逐位定义(:468)
INOVANCE_SAFETY_FUNCTION_ENABLE_U联合体安规功能使能位域(写入寄存器 0x1200/0x1201 两个 16 位字),含 u8_actpowet_control_enable、u8_slope_power_enable、u8_grid_volt_power_reduce_enable、u8_reactive_power_control_enable、u8_lvrt_enable、u8_hvrt_enable、u8_grid_volt_protect_enable、u8_island_detect_enable、u8_dci/iso/gfci_detect_enable 等(:482)
INOVANCE_SCI_FLAG_U联合体本文件的核心事件标志表(u64_sci_flag):BYTE0~BYTE2 为查询类标志(u8_query_*),BYTE5~BYTE7 为设置类标志(u8_set_*),另有 u8_check_inv_info_flag、u8_special_Australia_cec_flag(:579)
INOVANCE_RUN_INFO_T结构体SCI 通道特有的运行信息(与 CAN 通道互补):机温 1~5、机型、额定电压频率、PV 总功率、u8_generator_mode、u8_mppt_scan_enable、u8_grid_forming_enable、u8_bat_type、u8_phase_adaptive_enable、加热使能/电压/电流/继电器状态、6 个 tmp 调试槽(:676)

3. 函数清单

函数名作用域说明
inovance_write_data (72)全局统一串口发送出口:保证两帧最小间隔 timeout ms,再 usart2_clear_buffer() + usart2_send_data()
send_query_data_to_inovance (104)static组读保持寄存器帧(0x03)并发送,8 字节固定长度
ems_send_ctrl_data_to_inovance (129)static组写寄存器帧(0x10 多写 / 0x06 单写)并发送,带长度合法性校验
inovance_recv_data (169)static从 usart2 异步缓冲读出整帧,校验 Modbus CRC、从站地址与功能码,失败置长度为 0
set_inv_rtc_calibration (227)static用 SYSTEM_DATETIME 组 YYMM/DDHH/MMSS 三字写入 0x0500,成功后清 u8_set_inv_rtc_calibration_flag
set_clear_energy (265)static写 0x1000=1 清电量,成功后清 t_control_cmd.u8_clean_energy
set_clear_fault (294)static写 0x1001=1 清故障,成功后清 t_control_parameter.u8_clearing_fault
inovance_set_inv_start_stop (323)全局写 0x1002 启停命令;返回 TRUE 成功 / FALSE 应用层异常回复(长度 5) / 2 无回复(判定在 boot)
inovance_set_inv_on_of (359)全局写 0x1003 逆变器开关机命令,返回值语义同上
set_inv_dsp_restart (395)static写 0x1004=1 软重启;成功后清 t_control_cmd.u8_reset 并重新执行 inovance_comm_init() + inovance_comm_init_can()
set_inv_machine_mode (426)static油机模式设置:先停机 → 延时 500 ms → 写 0x1005 → 延时 200 ms → 重启机
query_inv_machine_mode (460)static读 0x1005 回填 t_run_info.u8_generator_mode
set_inv_mppt_scan_status (487)static写 0x1008 阴影扫描使能
query_inv_mppt_scan_enable (515)static读 0x1008 回填 u8_mppt_scan_enable
set_inv_grid_forming_enable (540)staticgrid-forming 设置:停机 → 延时 500 ms → 写 0x1009 → 延时 200 ms → 重启机
query_inv_grid_forming_enable (572)static读 0x1009 回填 u8_grid_forming_enable
set_inv_phase_adaptive_enable (597)static写 0x100A 相序自适应使能,并置位回读标志
query_inv_phase_adaptive_enable (626)static读 0x100A 回填 u8_phase_adaptive_enable
inovance_set_bat_type (651)static写 0x100B 电池串并类型(源 pvcharger_read_bat_series())
inovance_set_bat_heating_mode (715)static连写 0x100F/0x1010/0x1011 三个寄存器:加热使能 / 加热电压(0.1 V) / 加热电流(0.01 A)
query_inv_bat_heating_enable (752)static读 0x100F~0x1011 三寄存器回填加热使能/电压/电流
inovance_set_bat_heaer_state (781)static写 0x1012 电池加热膜接入状态(1 全部接入 / 2 全部切出)
query_inv_bat_heater_state (812)static读 0x1012 回填 u8_bat_heater_state
set_inv_safety_function_enable (838)static组 64 位安规功能使能位域(同步自 g_t_inovance_comm_info.u_safety_function_enable 后按 EMS 配置覆盖),写 0x1200 起 2 个寄存器
query_inv_safety_function_enable (902)static读 0x1200 起 2 个寄存器,回写 u_safety_function_enable 并同步到 g_t_inv_info.t_safty_info / t_run_info
set_inv_safety (945)static写 0x1400 主安规编号(停机 → 写 → 延时 → 置位 8 个回读标志 → 重启机)
set_inv_safesub (985)static连写 0x1400/0x1401 主安规 + 子安规,并额外置位澳洲 CEC 特殊标志
set_inv_safety_voltage_protect (1029)static组 18 个寄存器写 0x1402:首并网过/欠压过/欠频、OVP3/2/1(时间 ×10)、UVP2/1、10 min 过压
query_inv_safety_voltage_protect (1115)static读 0x1402 起 18 个寄存器回填,时间字段 ÷10 还原
set_inv_safety_frequency_protect (1180)static组 14 个寄存器写 0x1416:OFP3/2/1、UFP3/2/1(时间 ×10)与频率变化保护门限/时间
query_inv_safety_frequency_protect (1250)static读 0x1416 起 14 个寄存器回填,频率变化时间 ÷1000
set_inv_safety_argument1 (1304)static组 5 个寄存器写 0x1426:并网等待/重连时间、ISO 门限、DCI 门限与时间(×1000)
query_inv_safety_argument1 (1346)static读 0x1426 起 5 个寄存器回填,DCI 时间 ÷1000
set_inv_safety_argument2 (1381)static组 8 个寄存器写 0x142D:GFCI 4 档门限、功率因数(×10)、固定无功(×2)、f2 门限、恢复斜率
query_inv_safety_argument2 (1431)static读 0x142D 起 8 个寄存器回填,PF ÷10、固定 Q ÷2
set_inv_safety_argument3 (1471)static组 12 个寄存器写 0x1013:恢复点、过频降额率(×8)、欠频模式、f2(减 1)、欠频降额率(×200)、恢复斜率、P-V 响应时间(×30)、有功斜率使能
query_inv_safety_argument3 (1533)static读 0x1013 起 12 个寄存器回填,各比例因子反向还原
set_inv_safety_power_regulate_data (1582)static组 8 个寄存器写 0x1600:调节率、反向机率、启动机率、P-V 降压使能、P-V 曲线 V3/V4(未映射字段走 g_t_inovance_special_safety)
query_inv_safety_power_regulate_data (1637)static读 0x1600 起 8 个寄存器回填
set_inv_safety_reactive_power_data (1682)static组 17 个寄存器写 0x1700:无功模式、Q(U) 曲线 4 点、P-PF 曲线 4 点、PF5 等
query_inv_safety_reactive_power_data (1781)static读 0x1700 起 17 个寄存器回填,并按模式值把 safty_mode_u.BIT 置一
inovance_parse_inv_err_msg (1863)static把 u64_inv_fault1/2、u64_inv_warning1/2 的原始位域"多对一"翻译为 EMS 统一故障/告警位(g_t_inv_info.t_run_info.u_fault_code 等)
query_inv_device_info (1986)static读 0x0000 起 27 个寄存器:机型、SN、额定功率、软硬件版本;按机型写额定参数并置存盘标志
query_inv_energy_statistics (2094)static读 0x010A 起 2 个寄存器,仅解析 PV 总发电量到 u32_energy_pv_input
query_inv_running_data (2131)static读 0x010C 起 66 个寄存器:机温、PV1~4、三相电网/备电电压电流、无功/视在功率、母线/电池、故障告警 8 个字;并驱动故障录波触发
inovance_upgrade_init (2304)全局升级前初始化:inovance_comm_init() + inovance_comm_init_can(),清通信丢失标记,清零 PV 电压到运行模式之间的运行数据区
inovance_comm_init (2320)全局SCI 通道初始化:usart2_init(115200),置位全部首次查询/下发标志,同步安规主/子编号
inovance_special_Australia_cec (2357)全局AS4777_2(澳洲)特殊处理:强制有功控制使能、无功模式 4、恢复 UVP=2160、AUSTRALIA_C 的 OFP 恢复 5050、NEW_ZEALAND 的 10 min 过压 2580
inovance_inverter_data_check (2392)全局变化检测器:比对安规编号、AC/DC 额定功率、相序自适应、grid-forming、油机模式、启停、开关机、MPPT、RTC、电池类型、电池加热/加热膜、频压曲线使能,按变化置对应下发标志;并触发配置存盘
inovance_inverter_comm (2571)全局本文件主循环:升级分支 → 通讯丢失判定 → 初始化查询分支 → 按标志位顺序执行全部设置/查询 → 500 ms 运行数据、60 s 能量统计、24 h RTC 校准周期任务
send_command_to_blackbox (2878)全局向黑匣子(从站 0xFE)发 6 字节命令 + CRC,共 8 字节
blackbox_recv_data (2903)static黑匣子响应接收与校验(CRC + 地址 + 功能码),失败置长度 0
save_fault_scord_time_code (2961)static解析录波目录帧:故障时间(YYMM/DDHH/MMSS)与故障字 1/2、告警字 1/2 写入 g_t_fault_scord_data
save_fault_scord (3000)static解析一帧 4 个录波点:19 个 16 位通道 + 8 个 32 位通道,写入 s16_channel/s32_channel 对应列
generate_random_digits (3034)全局生成 8 位十进制随机字符串作为录波记录 ID(rand() % 10)
read_blackbox_handle (3053)全局黑匣子读取状态机主函数(停机 → 查目录 → 取目录内容 → 设索引 → 8 s → 逐帧读 80 包录波 → 生成 ID → 恢复运行)

完整 56 个函数,无遗漏。文件顶部 37-64 行有一份前向声明列表,声明了其中 26 个 static 函数(含已注释掉的 query_inv_tmp_data)。另有 inovance_get_self_test_data 仅在头文件 782 行声明、全工程无定义。

4. 核心逻辑解析

4.1 传输层:Modbus-RTU 帧格式与收发事务

所有 SCI 通信都建立在 usart2(usart2_init(115200),见 2322 行)之上,采用标准 Modbus-RTU 帧,从站地址固定 0x01。

读请求帧(send_query_data_to_inovance(),104-121 行,固定 8 字节):

偏移012-34-567
含义从站地址 0x01功能码 0x03起始寄存器地址(大端)寄存器数量(大端)CRC 低字节CRC 高字节

写多个寄存器帧(ems_send_ctrl_data_to_inovance(),142-149 行):

012-34-567 ~ 7+N-1末尾 2 字节
0x010x10起始地址寄存器数字节数 N数据域CRC 低/高

写单个寄存器帧(150-154 行):| 0x01 | 0x06 | 地址 | 数据(2B) | CRC |,共 8 字节。

写入前的合法性判据(140 行):register_num <= 100 && len_buff <= 200 && len_buff == register_num * 2,三者同时满足才组帧;否则 l_u8_len 保持 0,inovance_write_data(buf, 0, ...) 实际不会发出有效帧(发送长度 0)。CRC 由 GetCrcCode_Modbus() 计算,按"低字节在前、高字节在后"填入。

接收与校验(inovance_recv_data(),169-219 行):使用 usart2 的异步接收缓冲模型——先 usart2_is_recv_async_data() 判断有无数据,usart2_get_data_len() 取长度,再循环 usart2_read_data_async() 逐字节搬入 s_u8_inovance_recv_buf。校验三项全部通过才认为有效:

  1. CRC:接收帧末两字节(buf[len-1]<<8 | buf[len-2])与 GetCrcCode_Modbus(buf, len-2) 相等;
  2. 首字节等于 INOVANCE_SLAVE_ADDRESS;
  3. 第二字节属于 0x03 / 0x06 / 0x10 之一。

任一项失败或不满足,则 *len = 0。注意:本层不做超时等待,也不重试——它只读取当前已经到达串口缓冲的数据。因此"超时重试"实际上由上层标志位机制实现:设置类函数只有在收到有效响应时才清除 u8_set_xxx_flag,否则该标志保持 TRUE,主循环下一轮会再次下发,形成无限重试。

帧间节流(inovance_write_data(),72-96 行):用静态 s_u32_send_pack_tick 记录上次发送时刻,若与当前 OSTimeGet() 之差小于 timeout(本文件统一传 INOVANCE_DAT_PCK_INTERVAL_INV = 100 ms),则 OSTimeDlyHMSM() 补足差额再发;同时该 timeout 也是 usart2_send_data() 的发送超时。这保证了"每 100 ms 最多一个事务"的节拍。

4.2 主循环与事件标志调度(inovance_inverter_comm(),2571-2868 行)

主循环不维护显式状态机,而是"标志位表驱动":所有行为由 g_t_inovance_comm_info.u64_sci_flag 的位决定是否执行。

if 固件升级完成/服务器已更新 (2575)
    → 一次性 inovance_upgrade_init(),置 u8_run_mode 为 cUpdateMaster/Slave/Arm,调用 inovance_upgrade_handle()
else
    ├─ if (OSTimeGet() - u32_ems_inv_comm_tick) > 30 s → 置 inverter_comm_lost_flag 并 inovance_comm_init() 重新初始化
    ├─ if u8_query_inv_device_info_flag == TRUE   ← 初始化阶段
    │     u8_check_inv_info_flag = FALSE(暂停其他检测)
    │     每 2 s 查询一次 query_inv_device_info(),直到成功(成功后该标志被清)
    └─ else                                        ← 正常运行阶段
          u8_check_inv_info_flag = TRUE(允许数据检测器工作)
          按固定顺序执行 30+ 个 "if(标志) 执行对应函数"
          + 时间驱动:500 ms 运行数据 / 60 s 能量统计 / 24 h RTC 校准

执行顺序(2627-2865 行):安规主/子编号 → 清电量 → 清故障 → DSP 软重启 → 查询油机模式 → MPPT 回读 → grid-forming 回读/下发 → 相序自适应回读/下发 → 油机模式下发 → RTC 校准 → 启停 → 开关机 → MPPT 下发 → 安规功能使能下发/回读 → 电压保护下发/回读 → 频率保护下发/回读 → 参数 1/2/3 下发/回读 → 功率调节下发/回读 → 无功下发/回读 → 电池类型 → 故障录波 → 电池加热下发/回读 → 加热膜状态下发/回读。

设置-回读闭环:几乎所有 set_* 函数在收到有效响应后除了清自己的 u8_set_*_flag,还会把对应的 u8_query_*_flag 置 TRUE(如 878、1081、1221、1410、1508 行等),下一轮主循环再把参数读回写入 g_t_inv_info.t_safty_info,实现"下发 → 逆变器确认 → EMS 侧数据与实际一致"的闭环。set_inv_safety()(945)和 set_inv_safesub()(985)在收到响应后一次性置位 8 个回读标志(963-970、1005-1012 行)。

停机后改参数:set_inv_safety()、set_inv_safesub()、set_inv_machine_mode()、set_inv_grid_forming_enable() 都采用"先 inovance_set_inv_start_stop(INOVANCE_OPERATE_STOP) → OSTimeDlyHMSM(0,0,0,500) → 写寄存器 → 延时 200 ms → 重新启动"的模式(953-972、995-1015、434-446、548-558 行),因为这些参数只能在停机状态下生效。

时间戳/tick 一览:

字段更新时机用途
u32_ems_inv_comm_tick每次收到有效响应通讯在线判据(> 30 s 判丢失)
u32_query_inv_device_info_tick每次执行设备信息查询初始化阶段 2 s 节流
u32_query_inv_running_data_tick每次执行运行数据查询500 ms 节流(2818)
u32_query_inv_energy_statistics_tick每次执行能量统计查询60 s 节流(2829)
u32_set_inv_rtc_calibration_tick初始化与每次校准24 h 节流(2852),另在 RTC 故障恢复时归零(2497)

每个节流点都附带 else if (tick > OSTimeGet()) 的回绕保护(2604、2618、2823、2835、2857 行):一旦发现记录的 tick 大于当前 tick(说明系统 tick 计数器回绕),立即把记录值重置为当前值,避免长期不再触发。

4.3 寄存器映射与参数换算

寄存器宏数量方向内容与换算
0x0000QUERY_INV_DEVICE_INFO27读机型(1)、SN(16 B)、额定功率、HW/MASTER/ARM/SLAVE 版本;snprintf 组装 V%d.%d.%d.%d
0x010AQUERY_INV_ENERGY_STATISTICS2读仅取前 4 字节为 PV 总发电量(大端 u32)
0x010CQUERY_INV_RUNNING_DATA66读见 4.5 节偏移表
0x0500SET_INV_RTC_CALIBRATION3写YYMM、DDHH、MMSS 各占一寄存器(十进制打包,如 2025 年 7 月 → 2507)
0x1000SET_INV_CLEAR_ENERGY1写写 1 清电量
0x1001SET_INV_CLEAR_FAULT1写写 1 清故障
0x1002SET_INV_START_STOP1写1 停机 / 2 开机
0x1003SET_INV_ON_OFF1写逆变器开关机
0x1004SET_INV_SOFT_RESTART1写写 1 软重启
0x1005SET_INV_MACHINE_MODE1读写油机模式:1 关 / 2 开
0x1008SET_INV_MPPT_SCAN_ENABLE1读写阴影扫描:1 关 / 2 开
0x1009SET_INV_GRID_FORMING_ENABLE1读写grid-forming:1 关 / 2 开
0x100ASET_INV_GRID_ADAPTIVE_ENABLE1读写相序自适应:1 关 / 2 开
0x100BSET_INV_BAT_TYPE1写电池串并类型
0x100F~0x1011SET_INV_BAT_HEATING3读写加热使能(0/1/2)、电压 0.1 V、电流 0.01 A
0x1012SET_INV_BAT_HEATER_STATE1读写加热膜 1 全部接入 / 2 全部切出
0x1013SET_INV_SAFETY_ARGUMENT312读写见 4.4 节换算表
0x1200/0x1201SET_INV_SAFETY_PROTECT_ARG12读写安规功能使能 64 位位域的低 32 位
0x1400/0x1401SET_INV_SAFETY1 或 2写主安规编号(+ 子安规编号)
0x1402SET_INV_SAFETY_VOLTAGE_PROTECT18读写电压/频率保护点
0x1416SET_INV_SAFETY_FREQUENCY_PROTECT14读写频率保护点
0x1426SET_INV_SAFETY_ARGUMENT15读写并网等待/重连、ISO、DCI
0x142DSET_INV_SAFETY_ARGUMENT28读写GFCI、PF、固定 Q
0x1600SET_INV_SAFETY_POWER_REGULATE8读写有功调节率与 P-V 曲线
0x1700SET_INV_SAFETY_REACTIVE_POWER17读写无功 Q(U)/P-PF 曲线

关键换算(下发 ×,回读 ÷,二者严格互逆):

字段下发回读
OVP2/3 时间、UVP1/2/3 时间×10(1045-1068)÷10(1131-1143)
频率保护 OFP/UFP 时间×10(1187-1208)÷10(1262-1272)
频率变化保护时间原值直传(1211-1212)÷1000(1274)
DCI 保护时间×1000(1317-1318)÷1000(1361)
功率因数 s8_set_power_factor×10(1394)÷10(1446)
固定无功 s16_set_fix_reactive_power×2(1396)÷2(1447)
过频降额率×8(1484)÷8(1548)
欠频 f2 门限-1(1490)+1(1551)
欠频降额率×200(1492)÷200(1552)
P-V 响应时间×30(1496)÷30(1554)
Q-V 响应时间×300(1698)÷300(1811)
P-PF 模式 P2×10(1719)÷10(1822)
PF5×10(1731)÷10(1829)

4.4 运行数据解析与故障码翻译

query_inv_running_data()(2131-2295 行)按固定字节偏移解析 66 个寄存器(132 字节)的响应。响应帧结构为 [addr][func][byteCount][data...][crc][crc],因此数据起始偏移为 3。主要偏移:

偏移长度内容
3-1210 B机温 1~5(s16),并由机温 1 ÷10 得 t_run_info.s8_machine_temp
13-141 寄存器当前安规编号 t_safty_info.u8_safety
17-4024 BPV1~PV4 电压/电流/功率
43-526 B三相电网电流(电压字段被注释,因与 CAN 帧重复,见 2143 行注释)
53-6412 B三相备电电压/电流
65-7612 B三相无功、三相视在功率(并求和得总量,2179、2183 行)
77-8610 B运行功率因数、母线电压、电池电压/电流
87-11832 B故障字 1、故障字 2、告警字 1、告警字 2(各 4 个 16 位字)
131-1321 寄存器子安规编号 u8_safesub

解析完成后:

  1. 调用 inovance_parse_inv_err_msg()(1863-1978 行)把原始位域"多对一"映射为 EMS 统一故障码——例如 PV1~PV4 反接合并为 u8_pv_reverse、四个过温位合并为 u8_over_temperature、逆变器零漂与三相电网/负载零漂共 7 个位合并为 u8_inv_zero_drift_fault、四个风扇故障合并为 u8_fan_abnormal_alarm(1874-1886、1892-1895、1909-1915、1964-1967 行)。映射为单向:EMS 统一码不会反向写回逆变器原始位。
  2. 非 AS4777_2 时强制 u8_safesub = SAFESUB_DEFAULT(2211-2214 行)。
  3. 若读回的安规/子安规编号与 t_config_data 不一致,则回写配置并置 u8_save_config_flag(2216-2222 行)。
  4. 故障录波触发:用两个 static u64 缓存上一拍的故障字 1/2,一旦发生变化且新值非 0,就置位 u8_query_fault_record_flag(2224-2241 行)——即"只在新故障出现时触发录波,故障消失不触发"。原 2235-2240 行"故障清 0 后自动重启机"的逻辑已被注释掉。

4.5 变化检测器(inovance_inverter_data_check(),2392-2564 行)

该函数是"EMS 配置 ↔ 逆变器状态"的差异比较器,运行在主循环的 u8_check_inv_info_flag == TRUE 阶段(即设备信息查询完成之后,2409-2412 行提前返回)。它把"EMS 期望值"与"逆变器当前已知值"比较,不等则更新本地缓存并置对应下发标志:

检测项期望值来源目标值/使能值编码触发标志
安规编号t_config_data.u8_safety/u8_safesub直传u8_set_inv_safety_flag 或 u8_set_inv_safesub_flag(非 AS4777_2 走前者,2417-2424)
AC/DC 额定充放电功率t_run_info.u32_*_rate_*直传u8_save_config_flag(2428-2442)
相序自适应t_config_data.u8_phase_negation_enTRUE→2,FALSE→1u8_set_phase_adaptive_enable_flag(2445-2450)
grid-formingg_t_meter.t_config_data.u8_gridforming_enTRUE→2,FALSE→1u8_set_grid_forming_enable_flag(2453-2458)
油机模式g_t_logic_info.u8_generator_onTRUE→2,FALSE→1u8_set_inv_machine_mode(2461-2466)
启停t_control_cmd.u8_start_stop直传u8_set_inv_start_stop_flag(2469-2473)
开关机t_run_info.u8_set_inv_on_off直传u8_set_inv_on_off_flag(2475-2479)
MPPT 阴影扫描t_config_data.u8_inv_mpptscan_enableTRUE→2,FALSE→1u8_set_mppt_scan_enable_flag(2483-2488)
RTC 故障恢复u64_inv_warning1.bit.u8_rtc_fault 由 1→0—u8_set_inv_rtc_calibration_flag 并把 24 h 计数归零(2491-2501)
电池类型pvcharger_read_bat_model()直传u8_set_bat_type_flag(2504-2508)
电池加热g_t_bat_info.t_run_info.u8_inv_heat_cmdTRUE→2,FALSE→1u8_set_bat_heating_mode_flag(2516-2525)
加热膜状态g_t_bat_info.t_run_info.u8_heat_relay_staTRUE→1,FALSE→2u8_set_bat_heater_state_flag(2527-2533)
频压曲线使能parallel_read_freq_dispatch_en()并机调频时强制 FALSE,否则 TRUEu8_set_inv_safety_function_flag + u8_set_inv_safety_argument3_flag(2536-2563)

存盘:u8_save_config_flag == TRUE 时清标志并 save_job_post(INVERTER_CONFIG_PAGE)(2510-2514 行),即把配置写入掉电保持区。

4.6 黑匣子(故障录波)状态机(read_blackbox_handle(),3053-3196 行)

整段代码由 #if (INVERTER_TYPE == INOVANCE_TYPE) 包裹(2871、3197 行),默认编译配置 INVERTER_TYPE == INVERTER_NULL(inverter.h:172)时不参与编译。

通信协议(黑匣子从站地址 0xFE,帧尾同样为 Modbus CRC 低/高字节,命令帧共 8 字节):

命令内容用途
read_blackboxFE 03 14 1F 00 01触发黑匣子生成本次故障录波
read_catalog_setFE 06 14 3C 00 51设置/读取目录指针
read_catalog_dataFE 16 00 01 00 01读取目录内容(含故障时间与故障/告警字)
read_rundata_indexFE 06 14 1E 00 01设置录波数据索引
read_rundata_setFE 06 14 3C 00 41设置录波数据读取模式
read_rundata_dataFE 16 00 02 00 01读取一帧录波数据,每次发送前把第 5 字节 +1 递增(3159 行)

状态迁移(BLACKBOX_STATE_E s_e_blackbox_read_status,静态变量):

QUERY_BLACK_BOX ──收到响应且 buf[5]!=0──> WAIT_DIRECTORY_UPLOAD
      ↑                                        │ (等待 4 s)
      │                                        ↓
      │                              READ_DIRECTORY_CONTENT ──收到响应──> SET_INDEX_NUM
      │                                        │ 失败                        │ 收到响应
      │                                        └──────────────┐              ↓
      │                                                       │      WAIT_FAULTDATA_UPLOAD
      │                                                       │              │ 收到响应
      │                                                       │              ↓
      │                                                       │        READ_DIRECTORY
      │                                                       │              │ 循环 80 帧
      └───────────────────────────────────────────────────────┴──────────────┘
                        (任一环节无响应/校验失败即回到 QUERY_BLACK_BOX)

进入 QUERY_BLACK_BOX 时先 inovance_set_inv_start_stop(INOVANCE_OPERATE_STOP) 停机并 OSTimeDlyHMSM(0,0,0,500),再 fault_scord_init() 初始化录波缓冲;READ_DIRECTORY 完成 80 帧后 generate_random_digits() 生成 8 位记录 ID 写入 g_t_fault_scord_data.record_id,set_fault_scord_status() 置上报状态,延时 200 ms 后重新开机,清 u8_query_fault_record_flag。

超时保护:s_u8_requst_num 在每次函数调用末尾自增,累加超过 MAX_REQUEST_NUM(30)即强制回 QUERY_BLACK_BOX、清录波标志、开机(3185-3195 行),避免通讯异常时永久卡死。

录波点解析(save_fault_scord(),3000-3026 行):一帧含 4 个点(INOVANCE_BLACK_BOX_POINTS_S),点号基址 u16_point_num = frame_num * 4,点内字节步长 INOVANCE_BLACK_BOX_DATA_OFFSET = 70:

g_t_fault_scord_data 类型为 FAULT_SCORD_T(net/ems.h:454-456):s16_channel[19][320] + s32_channel[8][320],共 320 个点,与"80 帧 × 4 点 = 320"一致,下标不会越界。目录帧解析(save_fault_scord_time_code(),2961-2991 行)从偏移 6 开始取 YYMM/DDHH/MMSS,再取故障字 1 的 4 个字、故障字 2 的第 1 个字、告警字 1 的前 2 个字(其余字段已注释)。

4.7 澳洲 CEC 特殊处理

inovance_special_Australia_cec()(2357-2385 行)由标志 u8_special_Australia_cec_flag 触发(该标志在 set_inv_safesub() 成功后置位,1013 行)。当 t_safty_info.u8_safety == AS4777_2 时:

4.8 与 uCOS-II 的协作方式

5. 对外接口

5.1 本文件导出的函数(声明于 inovance_comm_usart.h:775-781)

导出函数调用方
inovance_write_data本文件内部;inovance_upgrade.c(升级握手帧复用同一串口出口)
inovance_set_inv_start_stop本文件黑匣子流程、inovance_upgrade.c:486(升级前停机)、inovance_upgrade.c:828(升级后开机)
inovance_set_inv_on_of本文件主循环(2699)
inovance_inverter_comminverter.c:1132(task_inverter)
inovance_inverter_data_checkinverter.c:1134
inovance_comm_initinverter.c:102、本文件 412(软重启)、2306(升级初始化)
inovance_upgrade_init本文件 2580(升级开始)
inovance_special_Australia_cec本文件主循环(2864)
read_blackbox_handle本文件主循环(2794)
send_command_to_blackbox本文件黑匣子流程(6 处)
generate_random_digits本文件黑匣子流程(3171)

5.2 本文件导出的全局变量

变量声明位置外部使用者
g_t_inovance_comm_infoinovance_comm_usart.h:772inovance_comm_can.c(CAN 通道共用标志与 u16_inv_type)、inverter.c 等
g_t_inovance_special_safetyinovance_comm_usart.h:773目前仅本文件内部使用

5.3 本文件调用的外部函数/变量

来源模块使用内容
hardware/usart2/usart2.husart2_init、usart2_clear_buffer、usart2_send_data、usart2_read_data_async、usart2_get_data_len、usart2_is_recv_async_data
common/crc.hGetCrcCode_Modbus
inverter.hg_t_inv_info(t_run_info / t_config_data / t_safty_info / t_control_cmd / t_control_parameter)、INVERTER_CONTROL_CMD_TABLE_T、SUB_T12/T15/T20/NULL、SAFESUB_DEFAULT、AS4777_2、AUSTRALIA_C、NEW_ZEALAND、INV_STARTUP、cUpdateMaster/Slave/Arm
inovance_comm_can.hinovance_comm_init_can
inovance_upgrade.hinovance_read_upgrade_flag_master/slave/fpga、inovance_upgrade_handle
logic.hg_t_logic_info.u8_generator_on
system_config.hSYSTEM_DATETIME(RTC 时间)、save_job_post(INVERTER_CONFIG_PAGE)
ems.hSet_Setup_Config_Status、g_t_fault_scord_data、fault_scord_init、set_fault_scord_status、FAULT_SCORD_T
inv_download.his_inverter_firm_download_finished
upd_download.hGet_Status_Is_Updated_From_Server(UPDT_INV3)
meter.hg_t_meter.t_config_data.u8_gridforming_en
pvcharger.hpvcharger_read_bat_series、pvcharger_read_bat_model
parallel.hparallel_read_freq_dispatch_en
bms.hg_t_bat_info.t_run_info(u8_inv_heat_cmd、u16_heat_volt、u16_heat_current、u8_heat_relay_sta)
generator.h / pcf8563.h随 includes.h 引入,本文件未直接调用其符号
Keil C 库memcpy、memcmp、memset、snprintf、printf、abs、rand、size_t

6. 依赖关系

依赖(本文件 include / 使用)

被依赖(谁会用到它)

7. 备注与风险点

  1. 写帧缓冲区存在溢出隐患。ems_send_ctrl_data_to_inovance() 使用 u8 l_u8_tx_buf[128](131 行),而合法性判据允许 register_num 最大 100、len_buff 最大 200(140 行)。当 register_num = 100 时 l_u8_len = 7 + 200 = 207,memcpy(l_u8_tx_buf + 7, tx_buff, 200) 会越界约 79 字节,覆盖栈上其他局部变量。当前所有调用点最大只用 18 个寄存器(l_u8_len = 43),所以尚未触发,但该函数是 public static 风格的通用组帧工具,接口本身不安全。
  2. 文件头注释与实际文件名/内容不一致。第 2 行 @file :inovance_comm.c,实际文件名为 inovance_comm_usart.c;且注释仍保留 2017 年的初版信息。
  3. S16_DATA_START_OFFSET / S32_DATA_START_OFFSET 定义了但从未使用(inovance_comm_usart.h:37-38)。save_fault_scord() 的 3009/3017 行仍硬编码偏移 5 和 43,注释里也写着"原硬编码5/43"——常量集中化的重构只做了一半,后续若表结构变化容易改漏。
  4. 录波点字节步长与通道数据极可能重叠。INOVANCE_BLACK_BOX_DATA_OFFSET = 70,而 32 位通道取的最后一个字节是 data_ptr[46 + 7*4] = data_ptr[74],已越过 70 字节的步长边界,会读到下一个点的数据。需要与汇川黑匣子协议文档核对:要么步长应为 ≥ 75,要么 32 位通道实际只有部分有效。
  5. blackbox_recv_data() 的功能码校验形同虚设(2936-2939 行):判据写成 buf[1] == command[1] || buf[1] == command[2] || buf[1] == command[3],而 command[2]/[3] 是命令帧的数据字节(如 0x14、0x1F、0x3C),不是功能码。这使校验失去意义,理论上可能把不相关帧当作有效响应。
  6. read_blackbox_handle() 在任务上下文长时间阻塞。READ_DIRECTORY 分支(3151-3179)在单次调用内循环 80 次收发,每次受 inovance_write_data() 的 100 ms 帧间隔约束,累计约 8 s,期间 task_inverter 无法处理其他逆变器事务;函数头部还有 500 ms 停机延时。整体流程会让逆变器通信停滞十余秒。
  7. s_u8_requst_num 的计数语义可疑(3066、3185-3195 行)。它在每次函数调用结束时都自增,只在 READ_DIRECTORY 成功完成时被清零;而 MAX_REQUEST_NUM 的判定被放在 switch 之后、对所有状态生效。这意味着进入黑匣子流程后,只要 30 次调用内没走完整个状态机(正常流程需要 4 次 4 s 等待 + 80 帧读取,远超 30 次调用),就会被强制中断退出。
  8. read_blackbox_handle() 中 time_delay 变量几乎无用(3065 行):QUERY_BLACK_BOX 分支给它赋值(3082),但后续所有等待判据用的是 s_u32_time_delay,属于遗留/冗余变量。
  9. generate_random_digits() 的随机性不可靠(3034-3046 行)。使用 rand() 但全文件未见 srand() 调用,若启动时未播种,每次上电会生成同一序列,8 位"故障识别码"可能重复,削弱"同一故障录波数据一致"的设计意图。
  10. set_inv_safety_function_enable() 与 query_inv_safety_function_enable() 中残留无条件 printf(881-891、932-934 行)。文件头定义 INOVANCE_SAFETY_DEBUG 期望用宏开关控制打印,但这两处的 #if/#endif 已被注释掉,导致每次下发/回读安规功能使能都会向串口输出十几行调试信息,与"调试宏默认关闭"的意图相悖。
  11. set_inv_safety_voltage_protect() 的收发字段长度不自洽(1029-1074 行)。代码只填充了 l_u8_tx_buf[0..33](含两行被注释的 34/35),但调用时声明寄存器数 18、长度 36,l_u8_tx_buf[34]/[35] 未赋值即随帧发出(栈上残留值)。同时 1057-1064 行把 u16_uvp2_value/time 连续写了两遍,u16_uvp3_value/u16_uvp3_time(g_t_inv_info 中存在该字段)的下发被漏掉,而回读侧(1138-1139)却会解析 UVP3,形成"下发不含 UVP3、回读含 UVP3"的不对称。
  12. query_inv_device_info() 的 AC 功率字段解析明显可疑(2009-2010 行):u32_ac_rate_charge_power 与 u32_ac_rate_discharge_power 取自完全相同的两个字节 [37]/[38],两者恒等。而 inovance_inverter_data_check() 又用"AC 额定充放电功率是否变化"判定配置存盘(2428-2442),此处赋值错误可能掩盖放电功率的变化检测。
  13. u8_generator_mode 被当作 u16 使用(431-432、546-547、602-603、786-787 等行)。INOVANCE_RUN_INFO_T.u8_generator_mode 声明为 u8,但代码一律按 >> 8 / & 0xFF 的两字节大端方式组帧,高位恒为 0;读回时(470 行)又按两字节拼回 u8,属于命名与用法不一致的遗留写法,本身不致命但容易误读。
  14. u16_inv_type(u16)与 INOVANCE_TYPE_E 枚举值比较(2014-2036 行)依赖隐式类型提升,且 SUB_NULL 分支把最大充放电电流置 0(2042-2044),若读到未知机型会直接让 EMS 侧限流为 0。属预期降级行为,但值得在机型兼容性变更时复核。
  15. inovance_write_data() 的 abs() 节流对 tick 回绕处理不完整(77-81 行)。abs(OSTimeGet() - s_u32_send_pack_tick) 在 uCOS-II tick 回绕(OSTime 为 32 位、每 tick 1 ms 时约 49.7 天)瞬间会产生巨大差值,可能跳过或错误插入延时。相比之下主循环中的节流点都有专门的 else if (tick > OSTimeGet()) 回绕保护分支,此处没有。
  16. inovance_get_self_test_data 声明无定义(inovance_comm_usart.h:782)。全工程仅此一处出现,属于残留接口声明,链接不会报错(无人调用),但会误导后续开发者。
  17. 大量寄存器宏已无引用:INOVANCE_ADDR_REGISTER_SET_INV_WEAK_POWER_GRID(0x100C)、SET_INV_BAT_AWAKE(0x1007)、SET_INV_PARALLEL_MODE(0x1006)、SET_INV_ZERO_DRIFT(0x100D)、SET_INV_EMS_RAMP_STATE(0x101E)、QUERY_INV_ERROR_MSG(0x0136)、QUERY_INV_PARALLEL_RUNNING_DATA(0x0400)、EMS_INV_ID_CODE("ALPHAESS") 在本文件均无使用(SET_INV_ZERO_DRIFT 仅出现在被注释的 inovance_zero_drift_type() 中,685-705 行)。另外 INOVANCE_WARNING2_U 无逐位定义、INOVANCE_ERROR2_U 的 bit20~bit63 为未命名占位,说明协议表尚未完整建模。
  18. 故障录波相关代码在默认编译配置下完全不生效。文件末尾黑匣子整段(2871-3197)及主循环调用点(2791-2796)均被 #if (INVERTER_TYPE == INOVANCE_TYPE) 包裹,而 inverter.h:172 中 INVERTER_TYPE 默认为 INVERTER_NULL。因此该功能只在显式选择汇川机型编译时才存在,阅读时勿按"已生效"理解。
  19. save_fault_scord() 内有无条件 printf(3014 行),每次解析一点都打印一行;80 帧 × 4 点 = 320 行日志,且不受 INOVANCE_INV_DEBUG 控制,会显著拖慢录波流程。