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

goodwe_comm.h

源文件路径:midware/inverter/goodwe/goodwe_comm.h 所属模块:midware/inverter/goodwe(古瑞瓦特 GoodWe 逆变器通信) 代码行数:417

1. 文件职责

本头文件是 GoodWe(古瑞瓦特)逆变器 Modbus-RTU 通信模块的对外契约,集中定义 EMS 与逆变器交互所需的全部寄存器地址常量、协议功能码、型号/安规枚举和故障/告警位域联合体。它把逆变器寄存器手册里的地址表原样搬进代码,使 goodwe_comm.c 的每个查询/下发函数都能用语义化宏(如 ADDR_REGISTER_QUERY_INV_RUNNING_DATA)代替裸数字。文件中定义的 GOODWE_TABLE_T 是模块唯一的运行时状态表,通过 extern GOODWE_TABLE_T g_t_goodwe_comm_info; 暴露给 inverter.c 等上层模块做标志位设置与状态读取。同时它只导出 5 个函数原型,是 inverter.c 调用本模块的全部入口面。

2. 关键数据结构与宏

名称类型说明
GOODWE_TABLE_T结构体模块全局状态表(goodwe_comm.h:350)。15 个 u8_*_flag 触发标志 + 8 个 u32_*_tick 周期时间戳 + 若干 u16 回读缓存 + u8_inv_device_type[10] + u8_inv_model_sub + 两个联合体实例
GOODWE_ERROR_U联合体(位域)u32_all 与 4 字节 32 个故障位共用(goodwe_comm.h:263);byte4(bit24~31)在源码中被整段注释,实际不可用
GOODWE_WARNNING_U联合体(位域)u16_all 与 2 字节 16 个告警位共用(goodwe_comm.h:321)
GOODWE_POWER_MODE_E枚举写入 47511 的功率模式字:AUTO=0x0001、CHARGE_PV、DISCHARGE_PV、IMPORT_AC、EXPORT_AC、CONSERVE、OFF_GRID、BATTERY_STANBY、BUY_POWER、SELL_POWER、CHARGE_BAT、DISCHARGE_BAT、STOP=0x00FF
GOODWE_LED_DISPLAY_E枚举LED 语义:LED_OFF=0x01、LED_ON、LED_FLASH_1X、LED_FLASH_2X、LED_FLASH_4X(goodwe_comm.h:164)
GOODWE_OPERATION_MODE_E枚举逆变器上报运行态:WAIT_E=0、ON_GRID_E、OFF_GRID_E、FAULT_E、FLASH_E、CHECK_E(goodwe_comm.h:173)
GOODWE_SAFETY_COUNTRY_E枚举GoodWe 安规国家码,GW_ITALY=0 顺序递增到 GW_AUSTRALIA_P_C,另有跳跃值 GW_UL1741=0x61、GW_PR_240VAC=0x77(goodwe_comm.h:183)
GOODWE_INV_DEBUG宏(0),总调试开关,控制本模块所有 printf
MAX_REGISTER_NUM宏100,单帧读写寄存器数上限,ems_send_ctrl_data_to_inv 的入参校验上界
INV_RECV_BUFFER_SIZE宏256,UART4 收帧缓冲长度
GOODWE_DAT_PCK_INTERVAL_INV宏100(ms),两次 Modbus 发送的最小间隔
GOODWE_SLAVE_ADDRESS宏0xF7,Modbus 从站地址
FUNC_READ_HOLDING_REGISTER宏0x03 读保持寄存器
FUNC_WRITE_SIGNAL_HOLDING_REGISTER宏0x06 写单个保持寄存器
FUNC_WRITE_MULTIPLE_HOLDING_REGISTER宏0x10 写多个保持寄存器
ALPHA_SAFETY / GOODWE_SAFETY宏0 / 1,parse_goodwe_safety() 的方向选择
INV_TYPE_ALPHA宏10,写入 47011 把系统类型标为 Alpha
GW_ABP_SOC_PROTECT宏95,离网充电截止 SOC 上限
ON / OFF宏1 / 0
ADDR_REGISTER_QUERY_INV_DEVICE_INFO + NUM_QUERY_INV_DEVICE_INFO宏35000 + 21,设备信息区
ADDR_REGISTER_QUERY_INV_RUNNING_DATA + NUM_QUERY_INV_RUNNING_DATA宏35100 + 122,运行数据区(本模块最大的单次读取)
ADDR_REGISTER_QUERY_INV_ENERGY_DATA + NUM_QUERY_INV_ENERGY_DATA宏35191 + 21,能量数据区(本版本未被使用)
ADDR_REGISTER_QUERY_INV_ARC_MODULE + NUM_QUERY_INV_ARC_MODULE宏36067 + 2,ARC 模块版本
ADDR_REGISTER_CLEAR_ENERGY_INV + NUM_CLEAR_ENERGY_INV宏45217 + 1,清除电量统计
ADDR_REGISTER_RESET_INV宏45220,复位逆变器(写 0x01 0x69)
ADDR_REGISTER_RESET_SPS宏45221,复位 SPS(本版本未被使用)
ADDR_REGISTER_SET_INV_SAFETY + NUM_SET_INV_SAFETY宏45244 + 1,安规设置
ADDR_REGISTER_SET_ISO_LIMIT + NUM_SET_ISO_LIMIT宏45245 + 1,ISO 绝缘阻抗限值
ADDR_REGISTER_SET_LVRT + NUM_SET_LVRT宏45246 + 1,低电压穿越(本版本未被使用)
ADDR_REGISTER_QUERY_DETAILED_MSG + NUM_QUERY_DETAILED_MSG宏45250 + 12,详细报文(本版本未被使用)
ADDR_REGISTER_BACKUP_ENABLE + NUM_BACKUP_ENABLE宏45252 + 1,备份/备电使能
ADDR_REGISTER_SET_OFFGRID_AUTOSTART + NUM_SET_OFFGRID_AUTOSTART宏45253 + 1,离网自启动
ADDR_REGISTER_SET_AFCI_ENABLE宏45270,AFCI(电弧故障)使能
ADDR_REGISTER_SET_ONGRID_DELAY + NUM_SET_ONGRID_DELAY宏45276 + 1,并网延时
ADDR_REGISTER_SET_MICRO_GRID_ENABLE宏45280,微网(GridForming)使能(本版本未被使用,改为写电表配置)
ADDR_REGISTER_READ_BAT_PARA + NUM_READ_BAT_PARA宏45350 + 9,电池参数
ADDR_RESITER_SET_MICRO_GRID_SOC_PROTECT + NUM_SET_MICRO_GRID_SOC_PROTECT宏45387 + 1,离网充电截止 SOC 保护
ADDR_RESITER_SAFETY_DATA + NUM_READ_SAFETY_DATA宏45400 + 28,安规阈值区 1
ADDR_RESITER_SET_POWER_FACTOR + NUM_SET_POWER_FACTOR宏45443 + 1,功率因数(本版本未被使用)
ADDR_RESITER_SET_MICRO_GRID_FREQ_PROTECT + NUM_SET_MICRO_GRID_FREQ_PROTECT宏45446 + 1,微网频率保护
ADDR_RESITER_SET_QU_CURVE + NUM_SET_QU_CURVE宏45456 + 1,Q-U 曲线(本版本未被使用)
ADDR_RESITER_SAFETY_DATA2 + NUM_READ_SAFETY_DATA2宏45495 + 4,安规阈值区 2(OVP3/UVP3)
ADDR_REGISTER_LED_TEST + NUM_LED_TEST宏47008 + 1,LED 测试(本版本未被使用)
ADDR_REGSITER_INV_SYSTEM_TYPE + NUM_INV_SYSTEM_TYPE宏47011 + 1,逆变器系统类型
ADDR_REGISTER_WIFI_LED / ADDR_REGISTER_COM_LED宏47013 / 47014,WIFI、通信指示灯
ADDR_REGISTER_SOC1_LED + NUM_SOC_LED宏47020 + 4,4 段 SOC 指示灯
ADDR_REGISTER_BAT_LED / ADDR_REGISTER_SYS_LED / ADDR_REGISTER_FAULT_LED宏47024 / 47025 / 47026,电池、系统、故障指示灯
ADDR_REGISTER_LED_CONTORL + NUM_LED_CONTROL宏47028 + 1,LED 控制解锁(写 0xA5 0x67)
ADDR_REGISTER_STOP_SOC_PROTECT + NUM_STOP_SOC_PROTECT宏47500 + 2,停机 SOC 保护(本版本未被使用)
ADDR_REGISTER_CTRL_INV_FEEDIN + NUM_CTRL_INV_FEEDIN宏47509 + 2,馈电使能 + 馈电功率
ADDR_REGISTER_SET_INV_POWER_MODE + NUM_SET_INV_POWER_MODE宏47511 + 2,功率模式字 + 功率值(最核心的控制寄存器)
ADDR_REGISTER_SET_BAT_PROTOCOL + NUM_SET_BAT_PROTOCOL宏47514 + 1,电池协议(写 0x011F 锂电协议)
ADDR_REGISTER_SEND_BMS_DATA + NUM_SEND_BMS_DATA宏47900 + 16,EMS 向逆变器下发 BMS 汇总数据(32 字节)
ADDR_REGISTER_EBMS_COMM_LOSS_ENABLE + NUM_EBMS_COMM_LOSS_ENABLE宏47916 + 1,EBMS 通信丢失告警使能

3. 函数清单

本文件为头文件,不含函数定义,共声明 5 个对外函数原型(goodwe_comm.h:412-416):

函数名作用域说明
set_inv_feedin全局(导出声明)下发馈电使能与馈电功率(u8 status, s16 power)
set_inv_wait_mode全局(导出声明)使逆变器进入待机,返回是否收到应答
goodwe_comm_init全局(导出声明)复位触发标志并恢复安规缓存
goodwe_inverter_comm全局(导出声明)通信主调度入口(含升级分支)
goodwe_inverter_data_check全局(导出声明)一致性维护与配置落盘触发

模块导出的全局变量 1 个:

名称类型说明
g_t_goodwe_comm_infoGOODWE_TABLE_Tgoodwe_comm.h:410 声明 extern,实例定义在 goodwe_comm.c:30

4. 核心逻辑解析

头文件本身无执行逻辑,本节说明它承载的三类「隐性协议约定」——这些约定决定了 goodwe_comm.c 的行为,改动时必须同步。

4.1 寄存器地址表的组织规律

地址表按 GoodWe 逆变器的 Modbus 地址手册分段,可归为 5 个区段:

区段地址范围用途
输入/只读信息区35000 ~ 36067设备信息、运行数据、能量统计、ARC 版本,由 0x03 读取
系统/安规配置区45217 ~ 45495清能量、复位、安规、ISO、AFCI、微网保护、电池参数、安规阈值
LED 区47008 ~ 470286 类指示灯 + 控制解锁字
控制区47500 ~ 47514馈电、功率模式、电池协议
EMS→逆变器数据区47900 ~ 47916BMS 汇总数据推送、EBMS 通信丢失使能

命名上有两类拼写残留需注意:读类宏用 ADDR_REGISTER_*,而一部分写类宏用 ADDR_RESITER_*(RESITER 为 REGISTER 的笔误,见 goodwe_comm.h:83、86、92、95、98),以及 ADDR_REGISTER_LED_CONTORL(control 拼错,goodwe_comm.h:125)。这些错拼已成为跨文件引用的既成事实,重命名会影响 goodwe_comm.c 与文档一致性。

4.2 功能码与「读写方向」约定

功能码值帧长使用场景
FUNC_READ_HOLDING_REGISTER0x038 字节请求全部 query_* 函数
FUNC_WRITE_SIGNAL_HOLDING_REGISTER0x068 字节请求在 ems_send_ctrl_data_to_inv 中支持,但本模块所有调用都走 0x10,0x06 分支实际未被使用
FUNC_WRITE_MULTIPLE_HOLDING_REGISTER0x1013+N 字节请求全部 set_* 函数,即使只写 1 个寄存器也走 0x10

这一点值得注意:写单个寄存器时协议上本应可省 4 字节(0x10 需额外的寄存器数 2 字节 + 字节计数 1 字节 + 首部差异),本模块统一使用 0x10,是对逆变器固件行为的适配(该型号对 0x06 支持不完整)。

4.3 三个枚举的语义边界

4.4 GOODWE_TABLE_T 的字段分组与并发语义

结构体虽为一个整体,但字段按用途分为三层,三种访问模式必须清楚区分:

  1. 触发标志层(u8_*_flag,共 15 个):由外部模块(inverter.c、HMI、服务器命令)置 TRUE,由 goodwe_comm.c 中的执行函数在收到有效应答后清除。这是一种单生产者-单消费者的「命令邮箱」,但因为读-改-写不加锁,task_inverter 与 HMI/网络任务同时访问时存在丢失更新(lost update)的理论竞态。inverter.c:4056 直接写 g_t_goodwe_comm_info.u8_set_iso_limit_flag = TRUE; 就是这种跨任务写入。
  2. 时间戳层(u32_*_tick,共 8 个):只有 task_inverter 读写,无跨任务共享问题;但所有时间戳都依赖 OSTimeGet() 的毫秒回绕,因此 goodwe_inverter_comm 对每处比较都补了「记录值 > 当前值则重置」的分支。u32_ems_inv_comm_tick 是唯一被多个函数写入的心跳字段。
  3. 数据缓存层(u16_* / u8_* 数组、两个联合体):由 query_* 函数写入、由 inverter.c / net 读取。u8_inv_device_type[10] 是定长 10 字节的无 NUL 保证数组,外部若按 C 字符串使用有越界读风险。

4.5 故障/告警位域的排布约束

GOODWE_ERROR_U 的位域按 little-endian 位序排列:u8_gfci_device_check_failure 是 u32_all 的 bit0,u8_pv_over_voltage 是 bit15,u8_internal_communication_failure 是 bit31。这要求编译器把位域从 LSB 开始分配(ARM/Keil 默认满足),换编译器或加 --pcc 类选项会整体错位。

同时 byte4(bit24~31)在头文件里被整段注释(goodwe_comm.h:310-317),原意是 PV1/PV2/BAT 过流、Bus 过压、R/S/T 逆变过流、电池继电器故障共 8 位;注释掉后 u32_all 仍然完整接收 32 位数据,只是这 8 位不做任何语义解释。parse_inv_err_msg() 因此丢掉了这批故障信息。

GOODWE_WARNNING_U 是 16 位,u16_all 由 goodwe_comm.c:676 一次性填入,但没有任何一位被逐个解析,仅整字转存到 u16_dsp_debug[4]。也就是说这些告警名目前只是文档用途。

5. 对外接口

本文件导出

本文件引用的外部头文件

6. 依赖关系

依赖:includes.h(基础类型)、goodwe_upgrade.h(升级接口)。头文件使用 __GOODWE_COMM_H__ 作为 include guard(goodwe_comm.h:9-10)。

被依赖:

7. 备注与风险点

  1. 注释头与实际文件名/内容不符(goodwe_comm.h:2):@file :mdsp_com.h、@brief 为空,说明本文件是从 mdsp_com.h 复制改造而来,头部注释未同步。
  2. 大量未使用的寄存器宏:ADDR_REGISTER_QUERY_INV_ENERGY_DATA、ADDR_REGISTER_RESET_SPS、ADDR_REGISTER_SET_LVRT、ADDR_REGISTER_QUERY_DETAILED_MSG、ADDR_REGISTER_SET_MICRO_GRID_ENABLE、ADDR_RESITER_SET_POWER_FACTOR、ADDR_RESITER_SET_QU_CURVE、ADDR_REGISTER_LED_TEST、ADDR_REGISTER_STOP_SOC_PROTECT 在本版本 goodwe_comm.c 中均无调用点。保留它们可以认为是为后续机型适配预留,也让「哪些能力真的实现了」变得难以判断。
  3. ON / OFF 宏的全局污染(goodwe_comm.h:33-34):在头文件中定义如此通用的名字,任何 include 本头文件的翻译单元都会受影响,一旦与其它模块(如 UCOSII 的 OS_OFF、HAL 的位定义)冲突会出现难以定位的编译错误。工程内目前靠命名差异规避。
  4. GOODWE_INV_DEBUG 与 GOODWE_INV_UPGRADE_DEBUG 双开关:通信调试在 goodwe_comm.h:17,升级调试在 goodwe_upgrade.h:14,两者独立;goodwe_comm.c 中还存在 #if (GOODWE_INV_DEBUG) 与 #if (GOODWE_INV_DEBUG == 1) 两种写法混用,把宏改为其它真值会导致部分调试段失效。
  5. u8_inv_device_type[10] 没有长度/终止符约束:从寄存器 memcpy 10 字节原始数据后直接当作型号字符串用(goodwe_comm.c:579 用 %s 打印),若逆变器返回的内容不含 \0 会越界读。
  6. GOODWE_ERROR_U.byte4 被注释(goodwe_comm.h:310-317):这批故障位(PV1/PV2/BAT 过流、Bus 过压、R/S/T 逆变过流、电池继电器故障)在 EMS 侧永久丢失,服务器看不到。若 GoodWe 固件确实会上报这些位,属于功能缺失而非有意裁剪。
  7. INV_TYPE_ALPHA = 10 与 GOODWE_SAFETY_COUNTRY_E 中的 GW_AUSTRALIAN(9) 等值无关联:两个枚举都是裸数字,容易与安规码混淆;实际作用不同(前者写 47011 系统类型,后者写 45244 安规),代码里没有任何注释区分。
  8. MAX_REGISTER_NUM = 100 与实际调用规模不匹配:本模块所有写操作最多 16 个寄存器,MAX_REGISTER_NUM 的上界形同虚设,反而放大了 goodwe_comm.c 中 128 字节栈缓冲被越界的可能(详见 goodwe_comm.c 备注第 1、2 条)。
  9. 错拼的宏名:ADDR_RESITER_*(5 处)与 ADDR_REGISTER_LED_CONTORL 会长期污染代码搜索与自动补全;重构时建议保留旧名做别名而非直接改名。
  10. STOP = 0x00FF 使枚举失去可递推性:任何「模式值 ≤ 某枚举」的判断都不成立,必须逐值 switch;当前代码遵守了这一约定,但缺少注释警示。