generator.c
get_time_control_mark()4.3 主状态机 generator_logic()4.4 通信协议帧格式4.5 定时/调度时序与 uCOS-II 配合4.6 关键全局变量的读写5. 对外接口6. 依赖关系7. 备注与风险点源文件路径:
logic/generator.c所属模块:logic(能量调度核心) 代码行数:372
1. 文件职责
本文件实现储能 EMS 的柴油发电机(油机 / Generator,代码里也叫 GC = Generator Control)启停控制逻辑,主要服务于离网(backup)场景:市电缺失时由电池支撑负载,当电池 SOC 过低或到达设定的时间窗时启动柴油机补电。它对外提供一组「状态查询」函数(并网状态、油机运行标志、油机控制标志、油机启动标志、油机功率),并把最终的启停命令写入全局标志 g_t_logic_info.u8_generator_on,由 midware/interface/dry_node/dry_node.c 驱动干接点继电器 DRY_NODE1 实际合闸/分闸。它处在数据流的「决策 → 干接点输出」中间环节:输入是电表电压/频率采样(meter_read_*)、电池 SOC(t_logic_control_parameter.u16_bat_soc_low)、RTC 时间(SYSTEM_DATETIME)和用户配置(t_config_data.Generator/GeneratorMode/GCSOC*/GCTime*)。驱动方是 logic/logic.c 的 task_system_logic_control 任务,在每个调度周期内调用 generator_logic()(logic.c:2930,位于并网/离网分支判断之前的公共段)。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
GENERATOR_MODE_E | 枚举(定义于 generator.h) | 油机工作模式:NONE_MODE = 0、SOC_MODE = 1、TOU_MODE = 2、MANUAL_MODE = 4(注意 3 被跳过,NONE_MODE 在本文件未被任何 case 处理) |
s_u8_generator_on | 文件级 static u8(generator.c:22) | 本文件的「期望输出状态」内部变量,即油机应开/应关的即时决策结果;由 get_generator_start_flag() 导出给逆变器侧使用 |
g_t_logic_info.u8_generator_on | 全局 u8(logic.h:588) | 对外生效的油机运行标志,被干接点、并机、逆变器协议(如 inovance_comm_usart.c 转成 enable=2/1)、上报等消费 |
g_t_logic_info.s32_generator_run_power | 全局 s32(logic.h:589) | 油机运行功率(取逆变器 Grid 侧总功率 s32_pgridt),供能量统计与云端上报 |
g_t_logic_info.t_config_data.Generator | 全局 u8 | 油机功能总使能,FALSE 时本文件所有函数走「关闭」分支 |
g_t_logic_info.t_config_data.GeneratorMode | 全局 u8 | 工作模式,取 GENERATOR_MODE_E 值 |
g_t_logic_info.t_config_data.GCSOCStart / GCSOCEnd | 全局 u8 | SOC 模式的启停 SOC 阈值,单位为 1%(使用时 *10 换算成 0.1% 单位) |
g_t_logic_info.t_config_data.GCTimeStart / GCTimeEnd | 全局 u8 | TOU 模式的启停小时阈值(仅小时,使用时 *60 换算成「当日分钟数」) |
g_t_logic_info.t_config_data.u8_gcats_en | 全局 u8 | 「油机/市电接入点(GCATS)」使能;为 TRUE 时并网判据改用干接点 DI_1_ACCESS_POINT 而不是电表采样 |
DI_1_ACCESS_POINT | 宏(midware/interface/dry_node/dry_node.h:24) | 展开为 di0_input_bit_get(),读 DI0 接入点干接点状态,FALSE 表示接入点闭合(市电存在) |
GRID_METER / PHASE_A/B/C / PHASE_ALL | 枚举(midware/meter/meter.h、inverter.h) | 电网侧电表位置与相序标识 |
METER_SAMPLING | 枚举(meter.h:184,METER_SAMPLING_TYPE_E) | 电表采样类型,只有处于该类型才认为电压采样有效 |
SYSTEM_DATETIME | 全局结构体 struct RTC_DateTime(hardware/pcf8563/pcf8563.h) | RTC 时间,本文件读取 bHours / bMinutes 换算当日分钟数 |
OSTimeGet() | uCOS-II API | 返回 32 位毫秒系统滴答(OS_TICKS_PER_SEC = 1000),本文件所有滞回计时基准 |
FALSE / TRUE | 宏 | 1 / 0 语义的布尔宏 |
本文件没有定义结构体、联合体、位域,也没有自定义阈值宏——所有时间与功率阈值都以字面量出现在表达式中。
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
get_grid_state | static(前置声明于 27 行) | 判定市电/电网是否接入(TRUE 并网、FALSE 离网),支持电表采样与 GCATS 干接点两套判据 |
get_time_control_mark | static(前置声明于 28 行) | 判定当前 RTC 时间是否落在 GCTimeStart~GCTimeEnd 时间窗内(按当日分钟数比较,支持跨天) |
get_offgrid_mode_grid_state | 全局 | 离网模式专用的并网状态查询,比 get_grid_state() 多了一层 Generator 使能与 u8_generator_on 判断 |
get_offgrid_mode_gc_power | 全局 | 返回油机运行功率(取逆变器 Grid 侧总功率),并同时写回 g_t_logic_info.s32_generator_run_power |
get_offgrid_mode_gc_charge_power | 全局 | 返回油机给电池充电的功率(取逆变器 INV 侧总有功 inverter_read_inv_actpower(PHASE_ALL)) |
get_generator_control_flag | 全局 | 判定是否进入「油机控制(GC)序控模式」:油机使能 + 逆变器并网态 + 实际离网 |
get_generator_running_flag | 全局 | 返回对外生效的油机运行标志 g_t_logic_info.u8_generator_on |
get_generator_start_flag | 全局 | 返回本文件内部的期望启动标志 s_u8_generator_on |
generator_logic | 全局 | 油机启停主逻辑:按模式(SOC / TOU / 手动)与强充条件决策,含滞回与三相关机仲裁 |
共 9 个函数(2 个 static、7 个全局),无函数指针、无回调。
4. 核心逻辑解析
4.1 并网/离网判据
get_grid_state()(static,仅在文件内使用)提供两套互斥判据:
u8_gcats_en == TRUE :
并网 = (DI_1_ACCESS_POINT == FALSE) && (u16_fgrid > 4000)
u8_gcats_en == FALSE :
并网 = ((Ua > 1000) || (Ub > 1000) || (Uc > 1000))
&& (meter_get_meter_or_ct(GRID_METER) == METER_SAMPLING)
&& (u16_fgrid > 4000)
1000对应 100.0 V(电表电压量纲 0.1 V),只要任一相超过 100 V 即认为有市电;4000对应 40.00 Hz(频率量纲 0.01 Hz,即 50 Hz → 5000),作为频率有效门限;- GCATS 使能时用接入点干接点,避免依赖电表通讯是否在线;未使能时必须同时满足「有电压 + 电表处于 METER_SAMPLING 采样模式 + 频率正常」,是一组与条件(
&&),任一不成立就判为离网。
get_offgrid_mode_grid_state() 是它的「对外版本」,语义差异明显:
t_config_data.Generator | u8_gcats_en | 返回值 |
|---|---|---|
FALSE | 任意 | 恒 TRUE(并网)——油机未使能时直接认为市电正常 |
TRUE | TRUE | (DI_1_ACCESS_POINT == FALSE) && (u16_fgrid > 4000) |
TRUE | FALSE | (g_t_logic_info.u8_generator_on == FALSE) && (u16_fgrid > 4000) |
最后一行是本文件最关键的语义:「油机正在运行」被等价视为「离网」。因为油机启动后会给逆变器的 Grid 侧供电,u16_fgrid 会重新变成 50 Hz,如果只看频率会误判成市电恢复了,所以用 u8_generator_on == FALSE 把油机自身的输出排除在「市电存在」之外。该函数被 midware/meter/meter.c 的三处电表失连告警判断调用(meter.c:626、3652、5460),用于「离网模式未接市电不报电表失连」。
4.2 时间窗判定 get_time_control_mark()
l_system_tick = SYSTEM_DATETIME.bHours*60 + SYSTEM_DATETIME.bMinutes; // 当日分钟数
l_tim1_start_tick = GCTimeStart*60;
l_tim1_end_tick = GCTimeEnd*60;
三分支:
| 条件 | 结果 |
|---|---|
start == end | l_u8_res = 2 → 返回 FALSE(窗口视为无效,不进 TOU 启动) |
start < end(不跨天) | start <= now < end → l_u8_res = 0;否则 1 |
start > end(跨天) | now < start && now >= end → l_u8_res = 1;否则 0 |
返回语句是 return (l_u8_res == 0);,也就是「在时间窗内 → TRUE(启动油机)、不在窗内 → FALSE(关闭油机)」。跨天场景实测行为:GCTimeStart=22、GCTimeEnd=6 时,23:00 与 02:00 都返回 TRUE(窗外 12:00 返回 FALSE),即跨天时间窗是被正确支持的(与函数内第 89 行注释「跨天在时间段内无效」不符,见备注 1)。由于只取到「小时 × 60」粒度,分钟级起停时间无法配置,最小粒度是 1 小时。
4.3 主状态机 generator_logic()
调用点:logic/logic.c:2930,位于 task_system_logic_control 每个调度周期内、并网/离网分支之前的公共段。它使用两个函数级 static 计时变量:s_u32_start_gc_tick(最近一次启动时刻)与 s_u32_close_gc_tick(最近一次关闭时刻),单位为 ms 滴答。
第 0 步:功能未使能(Generator == FALSE)
s_u8_generator_on = FALSE;同步 g_t_logic_info.u8_generator_on;并把两个计时变量都刷新为 OSTimeGet();直接 return。
第 1 步:启动判定(两个互斥入口)
入口 A —— 电池强充 + 离网(欠压保护性启动):
if (u8_bat_force_charge != FALSE) && (get_grid_state() == FALSE)
若 |OSTimeGet() - s_u32_close_gc_tick| >= 10*1000 (距上次关闭 ≥10 s)
s_u32_start_gc_tick = OSTimeGet(); s_u8_generator_on = TRUE;
这是所有模式里优先级最高的启动条件:即使处于手动/TOU 之外,只要电池强充且离网就直接启机。
入口 B —— 按 GeneratorMode 分派(switch,没有 default):
| 模式 | 启动条件 | 关闭条件 |
|---|---|---|
SOC_MODE(GCSOCStart < GCSOCEnd) | u16_bat_soc_low < GCSOCStart*10 且 s_u8_generator_on == FALSE 且 u16_fgrid < 4000(无市电/油机未建频)且距上次启动 ≥30 s | u16_bat_soc_low >= GCSOCEnd*10 且 s_u8_generator_on == TRUE 且 u16_fgrid > 4000(油机已建频)且距上次启动 ≥30 s |
SOC_MODE(GCSOCStart >= GCSOCEnd,配置非法) | 不启动 | 仅执行关闭:s_u8_generator_on == TRUE 且 u16_fgrid > 4000 且距上次启动 ≥30 s |
TOU_MODE | get_time_control_mark() == TRUE 且 s_u8_generator_on == FALSE 且 u16_fgrid < 4000 且距上次启动 ≥30 s | get_time_control_mark() == FALSE 且 s_u8_generator_on == TRUE 且 u16_fgrid > 4000 且距上次启动 ≥30 s |
MANUAL_MODE | 无条件 s_u8_generator_on = TRUE(每个周期都强制置位) | 本 case 内无关闭逻辑 |
| 其它值(0/3/≥5) | 无 case 命中,本周期不做任何启停动作 | 同上 |
注意 SOC_MODE 里 SOC 阈值的使用:GCSOCStart / GCSOCEnd(单位 1%)先 *10 扩到 0.1%(与 u16_bat_soc_low 同量纲)再比较;启动走 u16_fgrid < 4000(确认逆变器尚未被油机建频)、关闭走 u16_fgrid > 4000(确认油机已建频),两者互补,构成「先看频率有没有油机输出、再看 SOC」的两段式判断。
第 2 步:并网强制关闭
if (u8_grid_status != FALSE) && (get_grid_state() == TRUE) // 逆变器并网 + 市电确实存在
if (s_u8_generator_on == TRUE || g_t_logic_info.u8_generator_on == TRUE)
若距上次启动 ≥30 s
s_u32_close_gc_tick = OSTimeGet();
s_u8_generator_on = FALSE;
g_t_logic_info.u8_generator_on = FALSE; // 并网下认为油机空载,直接关
这里同时改写内部标志与全局标志,是唯一「绕过第 3 步仲裁」的关闭路径。
第 3 步:关机仲裁(防止带载切机)
if ((g_t_logic_info.u8_generator_on == TRUE) && (s_u8_generator_on == FALSE))
若 pinva > -(system_self_consumption + 50)
且 pinvb > -(system_self_consumption + 50)
且 pinvc > -(system_self_consumption + 50)
则 g_t_logic_info.u8_generator_on = s_u8_generator_on; // 真正关闭
// 任一相不满足 → 不赋值,全局标志保持 TRUE(油机继续运行)
else
g_t_logic_info.u8_generator_on = s_u8_generator_on; // 开启或状态未变,直接同步
含义:当决策由「开」变为「关」时,必须三相同步确认逆变器各相功率都已回到「不低于 −(系统自耗 + 50)」的水平(即没有相还在大功率输出/带载),才允许把关闭命令传导出去,否则继续让油机带载运行,避免突然卸载。50 是余量偏置。
第 4 步(时序号汇总)
| 时刻 | s_u8_generator_on(内部) | g_t_logic_info.u8_generator_on(对外) |
|---|---|---|
| 功能未使能 | 每周期清 FALSE | 同步 FALSE |
| 强充 + 离网启机 | 立即 TRUE | 直接同步 TRUE |
| SOC/TOU 启机 | 距上次启动 ≥30 s 后 TRUE | 同步 TRUE |
| SOC/TOU/时间窗到期要求关闭 | FALSE | 需三相关机仲裁通过后才 FALSE,否则维持 TRUE |
| 并网强制关闭 | FALSE(同时把全局也置 FALSE) | FALSE |
| 手动模式 | 每周期无条件 TRUE | 同步 TRUE(若同时并网,见备注 5) |
4.4 通信协议帧格式
本文件不涉及任何通信收发的帧格式、校验或超时重试。它对协议的介入只有两处间接引用:
meter_read_voltage()/meter_get_meter_or_ct()(midware/meter)——电表侧 Modbus 采样结果;inverter_read_inv_actpower(PHASE_ALL)(midware/inverter)——逆变器侧采样结果。
4.5 定时/调度时序与 uCOS-II 配合
- 时基:
OSTimeGet(),32 位 ms 滴答(OS_TICKS_PER_SEC = 1000u,见UCOSII/uCOS-CONFIG/os_cfg.h:51),约 49.7 天回绕一次。 - 三处滞回常数:强充启动「距上次关闭 ≥ 10 s」;SOC/TOU 的启动与关闭、以及并网强制关闭统一使用「距上次启动 ≥ 30 s」(等价于最小运行时间 30 s)。
- 调度来源:
task_system_logic_control(user/main.c静态创建),本文件没有任何任务、信号量、事件标志或消息邮箱操作,也不阻塞(无OSTimeDly);整个函数是「一进一出」的纯计算 + 标志赋值。 - 由于
generator_logic()每个周期都跑,而switch里的滞回判断依赖s_u32_start_gc_tick,实际启动/关闭的响应延迟为「滞回时间 + 一个调度周期」。
4.6 关键全局变量的读写
| 变量 | 读/写 | 触发条件 |
|---|---|---|
g_t_logic_info.u8_generator_on | 读+写 | 读:get_offgrid_mode_grid_state()、get_offgrid_mode_gc_power()、get_offgrid_mode_gc_charge_power()、第 3 步仲裁入口;写:第 0 步(未使能清 0)、第 2 步(并网强制关)、第 3 步(仲裁同步) |
g_t_logic_info.s32_generator_run_power | 写 | 仅 get_offgrid_mode_gc_power():条件满足时写 t_logic_control_parameter.s32_pgridt,否则写 0 |
g_t_logic_info.t_config_data.Generator | 读 | 本文件所有函数的分支总开关 |
g_t_logic_info.t_config_data.GeneratorMode | 读 | generator_logic() 第 1 步 switch |
g_t_logic_info.t_config_data.GCSOCStart / GCSOCEnd | 读 | SOC_MODE 的启停阈值(*10) |
g_t_logic_info.t_config_data.GCTimeStart / GCTimeEnd | 读 | get_time_control_mark()(*60) |
g_t_logic_info.t_config_data.u8_gcats_en | 读 | get_grid_state()、get_offgrid_mode_grid_state() 选择判据 |
t_logic_control_parameter.u16_bat_soc_low | 读 | SOC_MODE 启停判断 |
t_logic_control_parameter.u8_bat_force_charge | 读 | 第 1 步入口 A(强充启机) |
t_logic_control_parameter.u16_fgrid | 读 | 并网判据、SOC/TOU 启停的辅判据 |
t_logic_control_parameter.u8_grid_status | 读 | 第 2 步「逆变器处于并网模式」判断 |
t_logic_control_parameter.s32_pinva/b/c | 读 | 第 3 步三相关机仲裁 |
t_logic_control_parameter.s32_system_self_consumption | 读 | 仲裁阈值基数 |
t_logic_control_parameter.s32_pgridt | 读 | get_offgrid_mode_gc_power() 功率来源 |
SYSTEM_DATETIME | 读 | get_time_control_mark() 取 bHours / bMinutes |
s_u8_generator_on(文件内 static) | 读+写 | 第 0/1/2/3 步;同时被 get_generator_start_flag() 导出 |
s_u32_start_gc_tick / s_u32_close_gc_tick(函数内 static) | 读+写 | 各滞回判断与刷新点 |
5. 对外接口
导出(供外部调用)——均通过 generator.h 声明:
| 函数 | 调用者 | 用途 |
|---|---|---|
generator_logic() | logic/logic.c:2930 | 在 task_system_logic_control 中每周期执行油机启停决策 |
get_offgrid_mode_grid_state() | midware/meter/meter.c:626、3652、5460 | 离网模式判据,用于抑制电表失连告警 |
get_generator_running_flag() | midware/inverter/parallel.c:667、787、958、145(被注释掉的旧代码) | 并机场景判断油机是否运行(并写入 u8_gc_control_en) |
get_generator_control_flag() | logic/logic.c:2193 | 为 TRUE 时把 u8_sequencecontrol_mode 置为 GC_CECONTROL(油机充电序控模式) |
get_generator_start_flag() | logic/logic.c:2094、midware/inverter/inverter.c:1014 | 油机尚未启动时清零逆变器额定输入功率与充电限值(logic.c:2094);判断油机启停边沿以切换 P-V / P-F down-load 标志(inverter.c:1014,inverter_generator_mode_handle()) |
get_offgrid_mode_gc_power() | data/resume_data/flash/flash_data_store.c:670、net/ems.c:540、1431、midware/auxiliary/system_aux.c:268、270 | 断点续传数据快照(s32_gc_power)、云端上报(GCPower)、油机发电量统计 |
get_offgrid_mode_gc_charge_power() | midware/auxiliary/system_aux.c:300 | 油机给电池充电的功率统计(所在函数 generator_charge_energy_statistics() 当前被 #if 0 屏蔽,属未启用路径) |
GENERATOR_MODE_E 枚举 | hmi/key.c(菜单选择)、hmi/ui/ui_setting_user_func_generator_mode*.c | 用户菜单设置油机模式 |
导出变量:本文件不导出全局变量(仅有一个文件级 static u8 s_u8_generator_on,通过 get_generator_start_flag() 间接暴露)。
被调用(外部依赖):
| 名称 | 来源模块 |
|---|---|
meter_read_voltage()、meter_get_meter_or_ct() | midware/meter/meter.c(meter.h) |
DI_1_ACCESS_POINT / di0_input_bit_get() | midware/interface/dry_node/dry_node.c(宏定义于 dry_node.h) |
inverter_read_inv_actpower() | midware/inverter/inverter.c |
OSTimeGet() | uCOS-II(经 includes.h 引入) |
abs() | C 标准库 stdlib.h |
SYSTEM_DATETIME | midware/auxiliary/system_aux.h(定义于 hardware/pcf8563/pcf8563.h) |
TRUE / FALSE、u8 / u16 / s32 / u32 | includes.h → chip.h 链条 |
反向的写入方(本文件之外修改 g_t_logic_info.u8_generator_on 的地方,会影响本文件读到的初值):
midware/interface/dry_node/dry_node.c:1787——关闭油机功能时清零;midware/interface/interface.c:188——EPO 关机流程中清零;midware/interface/dry_node/dry_node.c:1828——某些条件下直接把t_config_data.Generator置FALSE(会连带使本文件走「未使能」分支)。
6. 依赖关系
依赖(include 列表,generator.c:13-18):
logic/generator.h——GENERATOR_MODE_E与自身原型;logic/logic.h——g_t_logic_info、t_logic_control_parameter;midware/meter/meter.h——GRID_METER、PHASE_A/B/C、METER_SAMPLING、电表读取函数;midware/interface/dry_node/dry_node.h——DI_1_ACCESS_POINT/di0_input_bit_get();midware/auxiliary/system_aux.h——SYSTEM_DATETIME;midware/inverter/inverter.h——PHASE_ALL、inverter_read_inv_actpower();- 间接依赖
UCOSII/uCOS-CONFIG/includes.h(generator.h:13引入)与system/sys/chip.h。
被依赖(include generator.h 的全部文件):
logic/logic.c:16、data/resume_data/flash/flash_data_store.c:31、hmi/key.c:29、hmi/ui/ui_setting_user_func_generator_mode.c:4、hmi/ui/ui_setting_user_func_generator_mode_select.c:3、midware/auxiliary/system_aux.c:26、midware/inverter/inverter.c:32、midware/inverter/parallel.c:26、midware/inverter/alphaess/alphaess_comm_usart.c:22、midware/inverter/inovance/inovance_comm_usart.c:24、midware/meter/meter.c:24、net/ems.c:38,以及 logic/generator.c:13 自身。跨模块耦合面较广(logic / data / hmi / midware / net 五个模块)。
7. 备注与风险点
get_time_control_mark()的注释与实现相反:第 89 行注释写「跨天在时间段内无效」,但代码实际是「跨天时间窗有效」(22:00→06:00 场景下,23:00 与 02:00 都返回TRUE)。注释误导后续维护者,若按注释「修正」代码会直接破坏跨天启机功能。另外l_u8_res用 0/1/2 三态编码布尔值、返回时靠== 0收窄,可读性差,l_u8_res = 2与l_u8_res = 1在返回值上完全等价,属冗余分支。switch (GeneratorMode)没有default分支:GENERATOR_MODE_E里NONE_MODE = 0且枚举值 3 被跳过,只有 1(SOC)、2(TOU)、4(MANUAL)有case。如果 Flash 中保存的配置值是 0 或 3(例如旧版本固件写入、或本产品以外的机型默认值),油机在非强充分支下永远不会启动也不会关闭——s_u8_generator_on保持上一拍的残留值,且没有任何日志或告警。建议补default并把NONE_MODE显式处理。MANUAL_MODE与并网强制关闭互相打架:case MANUAL_MODE:每周期无条件把s_u8_generator_on置TRUE;随后第 2 步的「逆变器并网 + 市电存在」分支又会把它连同全局标志一起置FALSE。结果是同一次调用内s_u8_generator_on先TRUE后FALSE(对外最终为FALSE,因此干接点不会抖动),但get_generator_start_flag()读到的是这一刻的瞬时值,而它被task_inverter上下文(inverter.c:1014的inverter_generator_mode_handle())跨任务读取——两个任务不同步,逆变器侧可能观测到「已启动」的假边沿并切换 P-V/P-F down-load 标志。这是一处真实的跨任务竞态(见备注 8)。s_u32_close_gc_tick只写不读的错位感:该变量在 SOC/TOU/并网的三个关闭分支里被赋值,但唯一读取点是强充分支的 10 s 判据(第 259 行);而关闭分支自身用的是s_u32_start_gc_tick(30 s 判据,语义是「最小运行时间」)。两组变量名与用途交叉,极易误读为 bug,实际功能上成立(一个是最小停机时间、一个是最小运行时间),但建议改名或在注释里写明。- 第 0 步持续刷新计时器带来的「首次启动延迟」:功能未使能时每个周期都把
s_u32_start_gc_tick与s_u32_close_gc_tick都刷新为当前时刻,因此当用户刚开启油机功能(或 Flash 中Generator由 0 变 1)时,两个差值都约等于 0,守卫会先失败,导致首次启动至少要等到开启后 30 s(SOC/TOU 模式)或 10 s(强充离网模式)。行为上可接受,但不是显式设计意图,文档与 UI 均无说明。 abs()作用在无符号减法结果上:abs(OSTimeGet() - s_u32_start_gc_tick)中减法是u32运算,结果作为u32传入接收int的abs()。滴答回绕时差值本身是正确的(模 2^32),但当差值 ≥ 2^31(约 24.8 天)时,u32 → int转换为负值再被abs()取正,语义侥幸仍然正确。这种「有符号/无符号混用 + abs」的写法对编译器的实现定义行为有依赖,建议改为显式的「毫秒差」辅助函数(项目内system_aux.c已有手动处理回绕的写法可复用)。MANUAL_MODE无法自动关闭:该分支没有关闭条件,唯一能关掉它的路径是「逆变器并网 + 市电存在」的强制关闭。若油机在离网下被手动模式启动,而市电一直没有回来、SOC 已满,油机会一直运行;同时GCSOCEnd在手动模式下完全不生效(这与用户对「手动」的预期一致,但配置界面若不提示,容易造成油机长时间空转耗油)。建议在 UI 或文档中明确。- 跨任务可见性/一致性:
g_t_logic_info.u8_generator_on与s_u8_generator_on的赋值序列(第 2 步中先s_u8_generator_on = FALSE;再g_t_logic_info.u8_generator_on = FALSE;)不是原子的,写入方在task_system_logic_control,读取方包括task_inverter(inverter.c:1014)、dry_node干接点任务、并机逻辑与 net 上报任务。读取方可能看到中间态(内部已关、全局仍开,或反之),进而产生「逆变器按油机在运行切 P-V 曲线、干接点却已断开」的短暂不一致。建议对这类跨任务标志加临界区或改成「单点写、单点读」的邮箱/标志传递。 get_offgrid_mode_gc_power()有隐藏副作用:函数名是get_...,但内部会写全局g_t_logic_info.s32_generator_run_power。它被flash_data_store.c、net/ems.c、system_aux.c多处调用,每次调用都会刷新该全局量;此外get_offgrid_mode_gc_power()在三处被连续调用两次(如system_aux.c:268与270),重复执行了同样的条件判断与赋值,属可优化点。get_offgrid_mode_gc_charge_power()的注释与量纲存疑:第 178 行注释「柴油机开启情况下禁止馈网,逆变器逆变功率等于柴油机给电池充电功率」,直接取inverter_read_inv_actpower(PHASE_ALL)作为充电功率。这与符号约定强相关(若逆变器侧功率为负表示取电充电,则此处应为-actpower),代码里没有取反或符号说明,容易在换机型时出现充电量统计符号反了的问题。该函数当前唯一调用者所在的统计函数已被#if 0屏蔽,属于「死代码但仍在编译单元里」的状态。- 魔法数字集中:
4000(40.00 Hz)、1000(100.0 V)、10*1000(10 s)、30*1000(30 s)、*10(SOC 单位换算)、+50(仲裁余量)、0(未使能时清零)。这些常量既无宏也无注释,且4000在「并网判据」与「SOC 模式启停辅判据」两处复用同一含义(频率有效/油机已建频),语义叠加后容易误改。 get_grid_state()与get_offgrid_mode_grid_state()职责高度重叠:两个函数都叫「grid state」但语义不同(一个纯粹看电气量,一个还掺入配置使能与油机运行标志),且后者在Generator == FALSE时无条件返回TRUE。调用方(meter.c三处)如果误用成get_grid_state(),会丢失「油机在跑就不算并网」的保护。g_t_logic_info.u8_generator_on被多处外部代码直接赋值(dry_node.c:1787/1828、interface.c:188),本文件又在第 0/2/3 步改写它,形成「多写者共享变量」。第 0 步在Generator == FALSE时会把外部设的值清掉,属有意为之;但当dry_node.c:1828改动t_config_data.Generator时,本文件的缓存判断只滞后一个调度周期,这期间干接点输出与配置可能短暂不一致。- 头文件
generator.h与本文件存在冗余:generator.h的@brief为空、无版本信息;NONE_MODE定义了却没有任何使用点;get_offgrid_mode_gc_charge_power()的唯一调用路径被#if 0屏蔽,属事实上的未使用接口。