csip_aus.c
csip_aus_der_control_process()(:365)4.2 状态机总览4.3 事件轮询:csip_aus_check_and_trigger_events()(:510)4.4 过渡路径与 3 秒等待机制4.5 斜坡速率算法:csip_aus_calculate_ramp_rate()(:885)4.6 斜坡完成判定:csip_aus_check_ramp_complete()(:970)4.7 控制超时:csip_aus_update_control_timeout()(:1037)4.8 参数同步:csip_aus_data_sync()(:154)4.9 斜坡超时估算:csip_aus_calculate_ramp_timeout()(:1191)4.10 电网状态处理4.11 取值接口与安全钳位(:1311-1367)4.12 关键全局变量的读写4.13 定时与 uCOS-II 配合4.14 通信协议5. 对外接口6. 依赖关系7. 备注与风险点源文件路径:
logic/csip_aus.c所属模块:logic(能量调度核心 —— 澳大利亚 CSIP-AUS v1.2 DER 控制) 代码行数:1368
1. 文件职责
本文件实现澳大利亚 CSIP-AUS v1.2 标准下的 DER(分布式能源)远程控制:接收电网运营商通过 SunSpec/CSIP 下发的四类功率限制(OpModExpLimW 馈网、OpModGenLimW 发电、OpModImpLimW 取电、OpModLoadLimW 负载)以及斜坡速率与过渡时间,把它们从"当前值/默认值"三组快照中算出目标变化量,包装成逆变器可执行的斜坡速率下发,并在通信超时、电网丢失、模式切回 NORMAL 时按规范回落到安全默认值。控制的方法是"EMS 计算斜坡速率、逆变器内部执行斜率",因此 g_t_csip_aus_run_data 里的斜坡功率字段被废弃,真正的输出是 s32_ramp_rate_w_per_sec 与 u8_ramp_enable。它由一个 4 态 × 8 事件的状态机组织(IDLE / CONTROL / DEFAULT / TRANSITION),由 logic 任务在 dnsp_ramp_control_handle() 内每控制周期(约 20 ms)调用一次 csip_aus_der_control_process()(logic/logic.c:1035)驱动;限制值与斜坡使能结果被 logic/logic.c 与 midware/inverter/inverter.c 读走用于约束充放电与馈网。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
CSIP_AUS_DER_CONTROL_T / g_t_csip_aus_der_control | 结构体 / 全局变量 | 主参数表,本文件 :23 定义(未显式初始化,按 C 标准全 0) |
CSIP_AUS_RUN_DATA_T / g_t_csip_aus_run_data | 结构体 / 全局变量 | 斜坡运行数据,本文件 :24 定义(未初始化) |
g_u8_csip_aus_ramp_rate_calculated | 全局变量 | 本文件 :25 定义,初值 FALSE;防止同一周期重复计算斜坡速率 |
CSIP_AUS_STATE_E | 枚举 | CSIP_AUS_STATE_IDLE(0)、_CONTROL(1)、_DEFAULT(2)、_TRANSITION(3) |
CSIP_AUS_EVENT_E | 枚举 | NORMAL(0)、DEFAULT_ENTER(1)、DEFAULT_EXIT(2)、CONTROL_ENTER(3)、CONTROL_EXIT(4)、TIMEOUT(5)、GRID_LOSS(6)、GRID_RESTORE(7);后三者中 _DEFAULT_EXIT/_CONTROL_EXIT 无触发点,_GRID_RESTORE 有触发点无处理分支 |
CSIP_AUS_DER_MODE_NORMAL / _CONTROL / _DEFAULT | 宏 | 0 / 1 / 2,与 logic.h 的 DER_NORMAL/DER_CONTROL/DER_CONTROL_DEFAULT 数值一一对应,两侧互相直接赋值 |
CSIP_AUS_RAMP_MIN_TIMEOUT_MS / MAX_TIMEOUT_MS / MAX_TIMEOUT_FACTOR | 宏 | 5000 / 400000 / 12,斜坡超时下限/上限(ms)与倍率因子 |
CSIP_AUS_DEBUG | 宏 | 本文件 :27 定义,值 0。门控约 20 处调试打印与 csip_aus_print_status() 的全部内容 |
CSIP_AUS_DEBUG_LOG | 宏 | 本文件 :28 定义,值 0。门控主循环里每 1 秒一次的周期打印 |
DER_NORMAL | 枚举(logic/logic.h:73) | 来自 logic.h 的 DER 模式 0,本文件在 :421、:424 与 CSIP_AUS_DER_MODE_NORMAL 混用 |
TRUE / FALSE | 宏 | includes.h |
3. 函数清单
本文件共 30 个函数定义:14 个 static、16 个全局。另有 2 个在 csip_aus.h 声明的函数(csip_aus_set_soft_ramp_rate、csip_aus_print_run_data)没有实现。
| 函数名 | 作用域 | 说明 |
|---|---|---|
inverter_set_softgradw | static(:58) | 按逆变器型号把软启动斜坡速率下发(SET 用 inverter_set_dnsp_regulation_rate;AlphaESS/INOVANCE 用速率 ×6 调 inverter_set_rev_machine_rate/inverter_set_regulation_rate) |
inverter_der_enable | static(:91) | 按逆变器型号/子型号判决是否支持 DER 控制(SET 需 SUB_S5/SUB_S5_II/SUB_M10;AlphaESS、INOVANCE 直接 TRUE) |
csip_aus_handle_mode_change | static(:119) | 检测 u8_der_control_mode 变化并按新模式的对应事件调用状态机 |
csip_aus_data_sync | static(:154) | 首次初始化 + 每周期把 g_t_logic_info 的外部参数同步进本模块,并做模式变化前后的旧值保存 |
csip_aus_der_control_process | 全局(:365) | 主处理入口,被 logic 任务每周期调用 |
csip_aus_state_machine_handle | 全局(:474) | 按 u8_current_state 分派事件到四个状态处理器;未知状态回落 transition_to_default() |
csip_aus_check_and_trigger_events | static(:510) | 轮询三类事件触发条件并调用状态机 |
csip_aus_state_idle_handle | static(:570) | IDLE 态:CONTROL_ENTER → 进控制;DEFAULT_ENTER → 进默认;GRID_LOSS → 空实现 |
csip_aus_state_default_handle | static(:601) | DEFAULT 态:进控制/返正常需并网;TIMEOUT → 返正常;GRID_LOSS → 留在默认 |
csip_aus_state_control_handle | static(:641) | CONTROL 态:DEFAULT_ENTER/GRID_LOSS → 进默认;TIMEOUT → 改写模式为 DEFAULT 并进默认 |
csip_aus_state_transition_handle | static(:681) | TRANSITION 态:按事件重定向;末尾若斜坡已结束则按模式落状态 |
csip_aus_transition_to_default | 全局(:736) | 过渡到 DEFAULT;离网时直接落状态不走斜坡;斜坡未使能时先使能并挂起等待 |
csip_aus_transition_to_control | 全局(:811) | 过渡到 CONTROL;重置 u32_control_remaining;挂起等待同 transition_to_default |
csip_aus_transition_to_normal | 全局(:864) | 置模式 NORMAL、状态 IDLE、刷新 state_enter_tick |
csip_aus_calculate_ramp_rate | static(:885) | 计算斜坡速率 s32_ramp_rate_w_per_sec(W/s),下限钳 11 |
csip_aus_check_ramp_complete | 全局(:970) | 仅在 TRANSITION 态按 500 ms 周期检查斜坡是否超时,超时即清斜坡标志并落状态 |
csip_aus_update_control_timeout | static(:1037) | 每秒递减 u32_control_remaining,到 0 触发 csip_aus_handle_control_timeout() |
csip_aus_handle_grid_status_change | 全局(:1088) | 电网连接状态变化时发 GRID_LOSS / GRID_RESTORE 事件 |
csip_aus_handle_control_timeout | 全局(:1116) | 保存当前限制为旧值后向状态机发 TIMEOUT |
csip_aus_update_grid_status | 全局(:1135) | 从 g_t_logic_info.t_logic_control_parameter.u8_grid_status 刷新电网状态 |
csip_aus_print_status | 全局(:1147) | 打印状态/限制/斜坡信息;整体被 #if (CSIP_AUS_DEBUG) 包裹,CSIP_AUS_DEBUG=0 时是空函数 |
csip_aus_calculate_ramp_timeout | static(:1191) | 按四类限制的最大变化量与斜坡速率估算超时,乘 1.2 后钳到 [5000, 400000] ms |
csip_aus_common_transition_setup | static(:1247) | 通用过渡收尾:确保斜坡使能、算速率、算超时、进 TRANSITION 态 |
csip_aus_der_control_mode_to_state | static(:1292) | 用 u8_der_control_mode 查 3 元素表映射到状态,并置 u8_just_transitioned 保护 |
csip_aus_get_ramp_enable | 全局(:1311) | 读 u8_ramp_enable |
csip_aus_get_ramp_rate | 全局(:1316) | 读 s32_ramp_rate_w_per_sec |
csip_aus_get_exp_limit | 全局(:1321) | 读馈网限制;DEFAULT 模式返回 default_opmod_explimw |
csip_aus_get_imp_limit | 全局(:1330) | 读取电限制;下限钳 10;单相系统(inverter_get_phase_number() == 1)再 ×3 |
csip_aus_get_gen_limit | 全局(:1345) | 读发电限制;DEFAULT 模式返回 default_opmod_genlimw |
csip_aus_get_load_limit | 全局(:1354) | 读负载限制;下限钳 10 |
4. 核心逻辑解析
4.1 主处理流程:csip_aus_der_control_process()(:365)
调用者:logic/logic.c:1035(在 dnsp_ramp_control_handle() 中),节拍约 20 ms。执行顺序如下,多处是早期 return,顺序不可调整:
1. g_u8_csip_aus_ramp_rate_calculated = FALSE; // 重置"已算速率"标志
2. csip_aus_data_sync(); // 参数同步 + 模式变化检测
3. if (u8_ramp_enable_pending) { // 斜坡使能延时闸门
elapsed = OSTimeGet() - u32_ramp_enable_set_tick;
if (elapsed >= 3000) { 清 pending 三字段; 按 u8_pending_transition_type 执行
1 → transition_to_control(); 2 → transition_to_default(); }
else return; // 等待期间直接返回
}
4. if ((inverter_read_safety_is_AS4777(inverter_read_safety()) != TRUE) ||
(u8_der_control_enable == FALSE) ||
((g_t_logic_info.u8_dercontrol == DER_NORMAL) && (u8_der_control_mode != CSIP_AUS_DER_MODE_NORMAL)))
{ csip_aus_transition_to_normal(); g_t_logic_info.u8_dercontrol = DER_NORMAL; return; }
5. if (u8_setsoftgradw_set_flag == TRUE) { inverter_set_softgradw(u16_setsoftgradw); u8_setsoftgradw_set_flag = FALSE; }
6. csip_aus_update_grid_status(); // 发 GRID_LOSS / GRID_RESTORE
7. csip_aus_check_and_trigger_events(); // 状态机核心
8. if (g_u8_csip_aus_ramp_rate_calculated == FALSE) csip_aus_calculate_ramp_rate();
9. csip_aus_update_control_timeout(); // 每秒递减剩余时间
10. csip_aus_check_ramp_complete(); // TRANSITION 态超时判定
11. #if (CSIP_AUS_DEBUG_LOG) 每 1000 ms 打一次 csip_aus_print_status(); #endif
步骤 3 的 3 秒闸门是设计上的关键:切换模式前必须先让逆变器收到"斜坡使能",因此第一次调用 transition_to_control()/transition_to_default() 时不切换,只置 u8_ramp_enable_pending = TRUE + u8_pending_transition_type,等 3 秒后再真正切换。注意该闸门在安全检查(步骤 4)之前 return,因此等待期间不做 AS4777 判定、不更新电网状态——见备注 4。
步骤 4 的三重前置条件(:419-426):
| 条件 | 含义 |
|---|---|
inverter_read_safety_is_AS4777(inverter_read_safety()) != TRUE | 安全规约非 AS4777(澳洲并网标准)→ CSIP-AUS 不适用,强制 NORMAL |
u8_der_control_enable == FALSE | 当前逆变器型号不支持 DER 控制(inverter_der_enable() 判定) |
u8_dercontrol == DER_NORMAL 但内部模式已非 NORMAL | 云端已撤销控制 → 回 NORMAL |
三者任一成立即 csip_aus_transition_to_normal() 并把 g_t_logic_info.u8_dercontrol 强制写回 DER_NORMAL。
4.2 状态机总览
四个状态 × 已接线的 5 个事件的转移矩阵(csip_aus.c:570-724):
| 当前状态 | NORMAL | DEFAULT_ENTER | CONTROL_ENTER | TIMEOUT | GRID_LOSS |
|---|---|---|---|---|---|
IDLE | 无分支 | transition_to_default() | transition_to_control() | 无分支 | 空实现(:584-587 被注释掉) |
DEFAULT | 若并网 → transition_to_normal() | 无分支 | 若并网 → transition_to_control() | transition_to_normal() | transition_to_default() |
CONTROL | 无分支 | transition_to_default() | 若并网 → transition_to_control() | 置 u8_der_control_mode = DEFAULT、同步 g_t_logic_info.u8_dercontrol、Set_Setup_Config_Extend2_Status(FALSE)、transition_to_default() | transition_to_default() |
TRANSITION | 被注释掉(:692-695) | 若模式 ≠ DEFAULT → transition_to_default() | 若模式 ≠ CONTROL → transition_to_control() | 同 CONTROL 的 TIMEOUT 处理 | transition_to_default() |
| 其他 | — | — | — | — | csip_aus_state_machine_handle 的 default → transition_to_default() |
TRANSITION 态的处理器末尾(:719-723)还有一条独立收尾:
if (g_t_csip_aus_run_data.u8_ramp_active == FALSE) csip_aus_der_control_mode_to_state();
即"斜坡已结束(由 check_ramp_complete 或事件处理器清标志)"时,按当前 u8_der_control_mode 落到 IDLE/CONTROL/DEFAULT 稳态。
4.3 事件轮询:csip_aus_check_and_trigger_events()(:510)
if (u8_der_control_mode == CSIP_AUS_DER_MODE_NORMAL) { // NORMAL:不动斜坡
u8_ramp_enable = FALSE; u8_ramp_active = FALSE;
}
if (u8_just_transitioned) { // 转换后 2 秒防抖
if ((OSTimeGet() - u32_transition_tick) < 2000) return;
u8_just_transitioned = FALSE; u32_transition_tick = 0;
}
switch (u8_der_control_mode) {
case NORMAL: if (u8_current_state != IDLE) 状态机(NORMAL); break;
case DEFAULT: if (u8_current_state != DEFAULT) 状态机(DEFAULT_ENTER); break;
case CONTROL: if (u32_control_remaining == 0) 状态机(TIMEOUT);
else if (u8_current_state != CONTROL) 状态机(CONTROL_ENTER); break;
}
这就是"轮询式状态机"的核心:没有事件队列,每个周期按当前模式与状态推导"应该发生的事件",再交给 csip_aus_state_machine_handle()。两点设计细节:
u8_just_transitioned+ 2000 ms 防抖避免状态刚落地就被再次触发(csip_aus_der_control_mode_to_state()会置该标志)。u32_control_remaining == 0优先于"状态不是 CONTROL",所以 CONTROL 模式一旦剩余时间耗尽,即使已经在 CONTROL 态也会发TIMEOUT。
4.4 过渡路径与 3 秒等待机制
csip_aus_transition_to_control()(:811)与 csip_aus_transition_to_default()(:736)结构对称,都是"两段式":
if (u8_ramp_enable_pending && u8_pending_transition_type == 本次类型) return; // 已在等同类转换
if (!u8_ramp_enable) { // 斜坡还没使能 → 先使能并挂起
u8_ramp_enable = TRUE; u8_ramp_active = TRUE;
g_t_inv_info.t_control_parameter.u8_csip_aus_data_flag = FALSE; // 让逆变器下次重新收参数
u8_ramp_enable_pending = TRUE; u32_ramp_enable_set_tick = OSTimeGet();
u8_pending_transition_type = 1 或 2;
return;
}
// 斜坡已使能 → 真正切换
u8_der_control_mode = CONTROL 或 DEFAULT;
[CONTROL 额外] u32_control_remaining = u32_durationtime;
csip_aus_common_transition_setup(u16_ramptms 或 0);
transition_to_default() 前面还有一条离网快路径(:739-758):u8_grid_connected == FALSE 时直接置模式 DEFAULT、清 u8_ramp_enable/u8_ramp_active/u8_ramp_enable_pending(连同 u32_ramp_enable_set_tick、u8_pending_transition_type)、调 csip_aus_der_control_mode_to_state() 后 return——离网不走斜坡,立即落稳态,因为离网时 EMS 不参与爬坡(注释 :744"确保电网恢复 EMS 不参与爬坡")。
csip_aus_common_transition_setup()(:1247):
// if (u8_current_state == CSIP_AUS_STATE_TRANSITION) return; ← 被 #if 0 风格注释掉(:1249-1252)
if (!u8_ramp_enable) { u8_ramp_enable = TRUE; u8_ramp_active = TRUE;
g_t_inv_info.t_control_parameter.u8_csip_aus_data_flag = FALSE; }
u16_ramptms = ramp_tms_value;
csip_aus_calculate_ramp_rate();
g_u8_csip_aus_ramp_rate_calculated = TRUE; // 阻止主流程重复计算
if (ramp_tms_value > 0) u32_ramp_timeout_ms = ramp_tms_value * CSIP_AUS_RAMP_MAX_TIMEOUT_FACTOR;
else u32_ramp_timeout_ms = csip_aus_calculate_ramp_timeout();
g_t_inv_info.t_control_parameter.u8_csip_aus_data_flag = FALSE;
u8_current_state = CSIP_AUS_STATE_TRANSITION;
u32_state_enter_tick = OSTimeGet();
被注释掉的"已在 TRANSITION 就不重入"守卫说明作者曾想避免重复过渡,但当前版本每次调用都会重设 u32_state_enter_tick——这意味着斜坡计时会被同一周期内的多次过渡调用反复重置。
4.5 斜坡速率算法:csip_aus_calculate_ramp_rate()(:885)
第一步,算四类限制的变化量:
| 模式 | 目标值 | 起点 |
|---|---|---|
DEFAULT | s32_default_opmod_*limw | s32_old_opmod_*limw |
| 其他(CONTROL/NORMAL) | s32_opmod_*limw | s32_old_opmod_*limw |
第二步,按当前潮流方向挑主变化量:
if (actual_meter_power < 0) power_diff = export_diff; // 卖电(s32_pgrid_metert < 0)
else power_diff = import_diff; // 买电
if (power_diff == 0) power_diff = (actual_inv_power > 0) ? gen_diff : load_diff;
if (power_diff == 0) power_diff = rated_power / 10; // 兜底:额定功率的 10%
第三步,算速率:
s32 target_ramp_rate = rated_power / 100; // 默认 1%/s
if (u8_der_control_mode == CSIP_AUS_DER_MODE_CONTROL) {
if (ramp_tms > 0) target_ramp_rate = (power_diff * 100) / ramp_tms; // 由过渡时间反推
else if (setgradw > 0) target_ramp_rate = (setgradw * rated_power) / 10000; // 由 0.01%/s 换算
} else {
if (setgradw > 0) target_ramp_rate = (setgradw * rated_power) / 10000;
}
s32_ramp_rate_w_per_sec = target_ramp_rate;
if (s32_ramp_rate_w_per_sec < 11) s32_ramp_rate_w_per_sec = 11; // 最小速率
公式校验:
(setgradw * rated_power) / 10000:setgradw单位 0.01%/s,故setgradw/10000是"每秒变化的比例",乘额定功率得 W/s。✔(power_diff * 100) / ramp_tms:u16_ramptms单位 1/100 秒,故ramp_tms/100是秒数,power_diff / 秒数得 W/s。✔
rated_power / 100 = 1%/s 是标准允许的最慢默认速率,当既无 ramptms 也无 setgradw 时兜底;:952 的 < 11 下限(W/s)防止速率过小导致斜坡永远走不完。
4.6 斜坡完成判定:csip_aus_check_ramp_complete()(:970)
static u32 s_l_u32_last_check_tick = 0;
if (u8_current_state != CSIP_AUS_STATE_TRANSITION) { s_l_u32_last_check_tick = 0; return; }
if (s_l_u32_last_check_tick == 0) { s_l_u32_last_check_tick = OSTimeGet(); return; } // 首次只记录
delta = OSTimeGet() - s_l_u32_last_check_tick;
if (delta < 500) return; // 节流到 500 ms
ramp_elapsed_ms = OSTimeGet() - u32_state_enter_tick;
if (ramp_elapsed_ms >= u32_ramp_timeout_ms) { // 超时 → 视为完成
u8_ramp_enable = FALSE; u8_ramp_active = FALSE;
csip_aus_der_control_mode_to_state();
return;
}
s_l_u32_last_check_tick = OSTimeGet();
关键事实:函数名为 "check_ramp_complete",但只做超时判定,从不比较 s32_ramp_current 与 s32_ramp_target(这两个字段全工程无读写点)。也就是说"斜坡是否走完"完全由时间推算,没有基于实际功率的闭环确认。加上首次调用只记录 tick(return)以及 500 ms 节流,从进入 TRANSITION 到最早可能判定完成至少要 1000 ms。
4.7 控制超时:csip_aus_update_control_timeout()(:1037)
static u32 s_last_timeout_tick = 0;
now = OSTimeGet();
if (s_last_timeout_tick == 0) { s_last_timeout_tick = now; return; }
elapsed_sec = (now - s_last_timeout_tick) / 1000;
if (elapsed_sec == 0) return; // 未满 1 秒
s_last_timeout_tick = now;
if (u8_der_control_mode == CSIP_AUS_DER_MODE_CONTROL) {
if (u32_control_remaining > elapsed_sec) u32_control_remaining -= elapsed_sec;
else { u32_control_remaining = 0; csip_aus_handle_control_timeout(); }
}
仅在 CONTROL 模式下递减。csip_aus_handle_control_timeout()(:1116)先把四类 opmod_* 快照进 old_*(为回落斜坡算变化量),再向状态机发 TIMEOUT。函数头注释写的 @Name : csip_aus_update_control_timeout(u32 delta_time_ms) 与实际无参签名不符,且实现是内部自己取 OSTimeGet() 而非接收 delta_time——注释里的"避免重复计算"设计未落地。
4.8 参数同步:csip_aus_data_sync()(:154)
这是本文件最复杂的函数,分四段。
(1) 首次初始化(static u8 s_initialized,:160-215) 从 g_t_logic_info 拉取全部初值:四类限制的当前值/默认值、old_* 取默认值、u16_setgradw/u16_setsoftgradw/u16_ramptms、u8_der_control_mode = g_t_logic_info.u8_dercontrol(:188,未做范围校验)、u32_durationtime、状态置 IDLE、u8_setsoftgradw_set_flag = TRUE、各类标志清零。
(2) 模式变化前的旧值保存(:217-250)
u8 old_mode = u8_der_control_mode, new_mode = g_t_logic_info.u8_dercontrol;
u8 is_mode_changing = (old_mode != new_mode);
if (is_mode_changing && new_mode != NORMAL && save_limit_changed) {
if (old_mode == CONTROL) old_* = opmod_*; // 从控制态切走:保存控制值
else if (old_mode == DEFAULT) old_* = default_*; // 从默认态切走:保存默认值
else { // 从 NORMAL 切入:用实时测得值
s32_old_opmod_explimw = (s32_pgrid_metert >= 0) ? 0 : abs(s32_pgrid_metert);
s32_old_opmod_genlimw = s32_pinvt;
s32_old_opmod_implimw = (s32_pgrid_metert <= 0) ? 0 : s32_pgrid_metert;
s32_old_opmod_loadlimw = -s32_pinvt;
}
save_limit_changed = FALSE;
}
save_limit_changed 是 static,置 FALSE 后只在 !is_mode_changing 时恢复 TRUE(:351-354)——即连续多周期都处于"模式变化中"时,旧值只会保存一次。
(3) 四个宏完成的限制值同步(:252-314) 用 token-pasting 宏把源字段(无下划线,如 s32_opmodexplimw)与目标字段(带下划线,如 s32_opmod_explimw)配对:
#define SYNC_DEFAULT_LIMIT(param) if (g_t_logic_info.s32_default_opmod##param##limw != s32_default_opmod_##param##limw) { ... }
#define SYNC_CONTROL_LIMIT(param) if (g_t_logic_info.s32_opmod##param##limw != s32_opmod_##param##limw) { ... }
#define SYNC_NORMAL_LIMIT(param) ...
在 CONTROL 模式下且外部 u8_dercontrol 也是 CONTROL 时,若四类 opmod_* 任一发生变化,先把全部 opmod_* 存进 old_*(:279-282),再用 SYNC_CONTROL_LIMIT 逐项同步并置 s_limit_changed_in_control = TRUE(该标志会在 :344-349 触发一次 csip_aus_transition_to_control() 重新拉斜坡)。非 CONTROL 模式用 SYNC_NORMAL_LIMIT 只同步不更新旧值。
(4) 斜坡参数与时长同步(:317-337) u16_ramptms、u16_setgradw 单向同步;u16_setsoftgradw 变化时额外置 u8_setsoftgradw_set_flag = TRUE(让主循环重新下发);u32_durationtime 变化时同步并把 u32_control_remaining 重置为该值。
(5) 模式变化处理(:339-354) is_mode_changing 时调 csip_aus_handle_mode_change(new_mode);否则若处于 CONTROL 态且 s_limit_changed_in_control,触发 csip_aus_transition_to_control()。
csip_aus_handle_mode_change()(:119)只在 u8_der_control_mode != new_mode 时动作,按新模式的 0/1/2 分别发 NORMAL/DEFAULT_ENTER/CONTROL_ENTER。注意它不更新 u8_der_control_mode——真正的更新发生在 transition_to_*() 内部。
4.9 斜坡超时估算:csip_aus_calculate_ramp_timeout()(:1191)
// 1) 取四类变化量(DEFAULT 模式用 default_* 重算一次)
// 2) max_diff = max(export_diff, gen_diff, import_diff, load_diff);
// 若为 0 → max_diff = s32_inv_rated_output_power / 10;
// 3) if (s32_ramp_rate_w_per_sec > 0)
// estimated_time_ms = (u32)((s64)max_diff * 1000 / s32_ramp_rate_w_per_sec);
// else
// estimated_time_ms = CSIP_AUS_RAMP_MIN_TIMEOUT_MS;
// 4) estimated_time_ms = estimated_time_ms * CSIP_AUS_RAMP_MAX_TIMEOUT_FACTOR / 10; // ×1.2
// 5) 钳到 [CSIP_AUS_RAMP_MIN_TIMEOUT_MS, CSIP_AUS_RAMP_MAX_TIMEOUT_MS]
这里用了 (s64) 强制提升再乘 1000,是全文件唯一一处防溢出的乘法(对比 csip_aus_calculate_ramp_rate 的 (power_diff * 100) / ramp_tms 与 (setgradw * rated_power) / 10000 都是纯 s32,见备注 6)。
4.10 电网状态处理
csip_aus_update_grid_status()(:1135)→ csip_aus_handle_grid_status_change()(:1088):
u8 old_status = u8_grid_connected;
u8_grid_connected = grid_connected;
if (old_status != grid_connected) {
u8_grid_status_change = TRUE; // 置位后从不清零
if (grid_connected == FALSE)
csip_aus_state_machine_handle(CSIP_AUS_EVENT_GRID_LOSS); // 只有 IDLE 的空实现、DEFAULT/CONTROL/TRANSITION 会响应
else csip_aus_state_machine_handle(CSIP_AUS_EVENT_GRID_RESTORE); // 四个状态处理器都没有这个 case
}
4.11 取值接口与安全钳位(:1311-1367)
| 接口 | 返回 | 钳位/特例 |
|---|---|---|
csip_aus_get_ramp_enable | u8_ramp_enable | — |
csip_aus_get_ramp_rate | s32_ramp_rate_w_per_sec | — |
csip_aus_get_exp_limit | DEFAULT 模式 → default_opmod_explimw,否则 opmod_explimw | 无下限钳位 |
csip_aus_get_imp_limit | DEFAULT 模式 → default_opmod_implimw,否则 opmod_implimw | 下限钳 10;单相系统(inverter_get_phase_number() == 1)再 ×3 |
csip_aus_get_gen_limit | DEFAULT 模式 → default_opmod_genlimw,否则 opmod_genlimw | 无下限钳位 |
csip_aus_get_load_limit | DEFAULT 模式 → default_opmod_loadlimw,否则 opmod_loadlimw | 下限钳 10(钳位后不再乘相数) |
csip_aus_get_imp_limit() 的 ×3 是"单相系统三相合计取电能力"的经验修正,:1342 的写法把相数判断内联在返回表达式里,读起来容易忽略。
4.12 关键全局变量的读写
| 变量 | 写者 | 读者 |
|---|---|---|
g_t_csip_aus_der_control.* | 本文件(data_sync、transition_to_*、common_transition_setup、mode_to_state、handle_control_timeout) | 本文件;外部只经 6 个 csip_aus_get_*() |
g_t_csip_aus_run_data.u8_ramp_enable / u8_ramp_active | 本文件 6 处 | csip_aus_get_ramp_enable() → logic.c(12 处)、inverter.c:2312/2387 |
g_u8_csip_aus_ramp_rate_calculated | 本文件(主流程置 FALSE、common_transition_setup 置 TRUE) | 本文件主流程判定 |
g_t_logic_info.u8_dercontrol | :424 强制 DER_NORMAL;:661/:707 写入 u8_der_control_mode(TIMEOUT 时置 DEFAULT) | logic.c:863/1038/1057-1060/2794-2799、ems.c:1068/2242、modbus.c:3675 |
g_t_logic_info.u16_ramptms / u16_setgradw / u16_setsoftgradw / u32_durationtime / s32_opmod*limw / s32_default_opmod*limw | 只读(本文件从它们同步进模块) | — |
g_t_logic_info.t_logic_control_parameter.s32_pgrid_metert / s32_pinvt | 只读(算变化量与潮流方向) | — |
g_t_logic_info.t_logic_control_parameter.u8_grid_status | 只读 | — |
g_t_inv_info.t_control_parameter.u8_csip_aus_data_flag | 写 FALSE(4 处::775、:828、:1259、:1279),提示逆变器重新接收 CSIP 参数 | midware/inverter 内 |
4.13 定时与 uCOS-II 配合
| 机制 | 说明 |
|---|---|
| 调用节拍 | 由 logic 任务驱动(logic.c:2912 的 OSFlagPend(..., 20, ...),约 20 ms 一次),csip_aus_der_control_process() 每周期执行一次 |
| 任务创建 | 本文件不建任务、不使用信号量、不使用消息邮箱 |
| 时间基准 | 全部 OSTimeGet(),单位 ms(OS_TICKS_PER_SEC = 1000) |
| 文件内时间常量 | 3 秒(斜坡使能等待,:380)、2 秒(状态转换防抖,:521)、500 ms(斜坡检查节流,:994)、1000 ms(超时递减粒度,:1051)、1000 ms(调试打印周期,:454) |
| 状态机的"事件"来源 | 无队列,全部由 csip_aus_check_and_trigger_events() 按模式/状态轮询推导 |
4.14 通信协议
本文件不实现帧收发。它消费的是 net/server.c:5142(JSON u8_dercontrol 等字段)与 midware/interface/modbus/modbus.c:6327(SunSpec Modbus 写点)落进 g_t_logic_info 的四类限制值,并通过 midware/interface/modbus/modbus.c:3675 把 u8_dercontrol 回读给 SunSpec 点表。本文件不含起始码/长度/命令字/校验等任何帧层逻辑,也没有超时重传——"超时"在这里只有 u32_control_remaining 与 u32_ramp_timeout_ms 两个业务计时的含义。
5. 对外接口
导出(供外部使用):
| 名称 | 类型 | 调用方 |
|---|---|---|
csip_aus_der_control_process | 函数 | logic/logic.c:1035(唯一调用点) |
csip_aus_get_ramp_enable | 函数 | logic/logic.c:757/871/924/1084/1086/2781/3126/3142/3158/3218/3234/3250、midware/inverter/inverter.c:2312/2387 |
csip_aus_get_exp_limit | 函数 | logic/logic.c:1065 |
csip_aus_get_gen_limit | 函数 | logic/logic.c:1070/1072 |
csip_aus_get_load_limit | 函数 | logic/logic.c:865/866 |
csip_aus_get_imp_limit | 函数 | logic/logic.c:1094/1095 |
csip_aus_get_ramp_rate | 函数 | logic/logic.c:1078/1080 |
g_t_csip_aus_der_control / g_t_csip_aus_run_data / g_u8_csip_aus_ramp_rate_calculated | 全局变量 | 外部无直接访问 |
csip_aus_transition_to_default / _control / _normal、csip_aus_state_machine_handle、csip_aus_check_ramp_complete、csip_aus_handle_grid_status_change、csip_aus_handle_control_timeout、csip_aus_update_grid_status、csip_aus_print_status | 函数 | 无外部调用方,全部内部使用 |
被调用(本文件引用的外部符号):
| 符号 | 来源 |
|---|---|
OSTimeGet、printf | UCOSII/uCOS-II、C 运行库 |
inverter_read_safety、inverter_read_safety_is_AS4777、inverter_get_type(get_inverter_type)、get_inverter_sub、inverter_get_phase_number、inverter_set_dnsp_regulation_rate、inverter_set_rev_machine_rate、inverter_set_regulation_rate、SET_TYPE、ALPHAESS_TYPE、INOVANCE_TYPE、SUB_S5、SUB_S5_II、SUB_M10 | midware/inverter/inverter.h |
g_t_inv_info.t_control_parameter.u8_csip_aus_data_flag | midware/inverter/inverter.h:1867 |
g_t_logic_info(s32_opmod*limw、s32_default_opmod*limw、u16_ramptms、u16_setgradw、u16_setsoftgradw、u32_durationtime、u8_dercontrol、u8_dnsp_maxfeedin_priority_flag 等) | logic/logic.h |
DER_NORMAL | logic/logic.h:73 |
Set_Setup_Config_Extend2_Status | net/ems.h:512 |
abs、memset、NULL(未见) | C 运行库 / includes.h |
TRUE、FALSE | includes.h |
6. 依赖关系
依赖(csip_aus.c:13-19):csip_aus.h、logic.h、ac_control.h、dispatch.h、data.h、inverter.h、ems.h。
被依赖:
logic/logic.c:26includecsip_aus.h,并调用csip_aus_der_control_process()与 6 个csip_aus_get_*()。midware/inverter/inverter.c:35includecsip_aus.h,只调用csip_aus_get_ramp_enable()(:2312、:2387)。- 无其他文件 include 本头文件。
7. 备注与风险点
#if (CSIP_AUS_DEBUG)打开会编译失败::955-957的调试打印引用了未定义标识符invpower_diff(该变量在函数里不存在)。:1009-1013、:1018-1022也有可疑打印。这意味着CSIP_AUS_DEBUG这个开关实际上不可用——一旦置 1 就会编译报错,调试能力被事实性封死。同理csip_aus_print_status()(:1147)的全部内容都在该宏内,CSIP_AUS_DEBUG=0时它是一个空函数体,被logic.c调用也毫无输出。csip_aus_check_ramp_complete()名不符实,且超时打印重复:函数只做超时判定(:1001-1016),从不比较s32_ramp_target与s32_ramp_current(两个字段全文件无读写点)。:1018-1022还有一段在return之后的调试打印,被#if包裹但位置在return之外、break逻辑之内——它是同一段打印的重复粘贴,且照原样打开会打印误导性内容(把"未超时"的情形也打上"ramp timeout"字样)。mode_to_state数组用云端可控的值做索引,无边界检查:csip_aus_der_control_mode_to_state()(:1292-1308)
static const u8 mode_to_state[] = { CSIP_AUS_STATE_IDLE, CSIP_AUS_STATE_CONTROL, CSIP_AUS_STATE_DEFAULT };
u8 new_state = mode_to_state[g_t_csip_aus_der_control.u8_der_control_mode];
g_t_logic_info.u8_dercontrol 由云端 JSON(net/server.c:5142,(u8)l_u32_json_value1)与 Modbus(modbus.c:6327)直接写入,没有取值校验。它在 csip_aus_data_sync() 首次初始化时被原样赋给 u8_der_control_mode(:188),之后 csip_aus_handle_mode_change() 只处理 0/1/2 不会引入越界值。因此唯一但真实的越界路径是:"云端写入 u8_dercontrol >= 3 → 复位/首次进入 CSIP-AUS → data_sync 首次初始化把它放进 u8_der_control_mode → 任一路径调用 mode_to_state() → 数组越界读"。建议在 :188 加范围钳位。
- 3 秒斜坡等待期间跳过全部安全检查:
csip_aus_der_control_process()的 pending 闸门(:375-416)在安全检查之前return,因此等待的 3 秒内不会调csip_aus_update_grid_status(),电网丢失事件不会被发出;也不会重新评估 AS4777 与u8_der_control_enable。若在等待窗口内发生离网,transition_to_default()的离网快路径(:740)也无法被执行,只能等 3 秒后u8_pending_transition_type == 2的分支(此时u8_grid_connected是 3 秒前的旧值)或下一周期刷新后才纠正。 CSIP_AUS_EVENT_GRID_RESTORE发得出无人接、_DEFAULT_EXIT/_CONTROL_EXIT无触发点::1105发出GRID_RESTORE,但四个state_*_handle都没有该case,全部落到default。这意味着电网恢复后状态机不会主动离开 DEFAULT——要靠check_and_trigger_events()下一轮按u8_der_control_mode(此时已被置为 DEFAULT)再发DEFAULT_ENTER。整个 "电网恢复" 语义是空转的。- 多处
s32乘法无溢出保护:csip_aus_calculate_ramp_rate()的(power_diff * 100)(:939)与(setgradw * rated_power)(:941、:946)。rated_power是s32_inv_rated_output_power(并机系统的额定输出功率,多机并机时可能上万 W),setgradw上限未定;setgradw * rated_power超过2^31/10000 ≈ 214748就会溢出。对比csip_aus_calculate_ramp_timeout()的(s64)max_diff * 1000(:1223)——同一个文件里一处做了提升、另两处没做,标准不一致。 u16_ramptms被两处写入、语义不同:csip_aus_common_transition_setup()每次都执行u16_ramptms = ramp_tms_value(:1263)——transition_to_default()传0(:792),transition_to_control()传g_t_logic_info.u16_ramptms(:847)。因此每次切到 DEFAULT 都会把u16_ramptms清 0,随后csip_aus_calculate_ramp_rate()就走到setgradw分支或rated/100兜底,csip_aus_calculate_ramp_timeout()也就再也拿不到ramp_tms>0的路径。这可能是刻意(DEFAULT 用速率而非过渡时间),但u16_ramptms同时又是从g_t_logic_info同步来的参数(:317-320),被本地清除后下一个周期data_sync又会从外部同步回来——两个方向来回覆盖,行为取决于时序。inverter_set_softgradw()里的数值 ×6 是未解释的换算::71、:78都用u16 rate = setsoftgradw * 6。u16_setsoftgradw的单位在头文件里写的是 0.01%/s,而inverter_set_rev_machine_rate()/inverter_set_regulation_rate()的单位在inverter.h里没有说明,×6的来历无从判断(可能是 %/s ↔ 0.01%/s 加某个机型系数)。注意(u16)(setsoftgradw * 6)与inverter_set_dnsp_regulation_rate(setsoftgradw)(:63,未乘 6)对同一种量用了两种换算,SET 与 AlphaESS/INOVANCE 的口径不一致。inverter_set_softgradw()的注释是错的::57写"暂时未实现的函数,留待后续补充",但函数体完整;:51与:85的@Name两处都写成static u8 inverter_der_enable(void)(复制粘贴),与其真实函数名不符。csip_aus_data_sync()的save_limit_changed逻辑脆弱:该static标志在保存旧值后置FALSE,只在!is_mode_changing时才恢复TRUE(:351-354)。若模式切换跨多个周期(这在 3 秒 pending 等待的机制下很可能发生),旧值只保存一次,后续周期不再保存——而csip_aus_calculate_ramp_rate()又依赖old_*算变化量,可能把已被覆盖的old_*当作起点。u8_grid_status_change置位后永不清零(:1095):无消费者,功能上无害,但属于"永远为真"的陷阱字段。g_t_csip_aus_der_control/g_t_csip_aus_run_data未显式初始化::23、:24都是裸定义,没有= {0}(对比dispatch.c:31的s_t_agingmode_data_temp = {0}与self_test.c:25的= {0})。按 C 标准全局对象零初始化,功能正确,但u16_ramptms、u32_ramp_timeout_ms等字段在首次data_sync之前为 0,若在这之前有调用者读csip_aus_get_*()会拿到 0——logic.c:865的csip_aus_get_load_limit()+s32_pbackupt就是这种情况,此时get_load_limit的< 10钳位起到了兜底作用。Set_Setup_Config_Extend2_Status(FALSE)的副作用未在本文件注释::662、:708在控制超时时调用(实现在net/ems.c),语义是清除"扩展配置 2"的生效状态。本文件没有说明它具体清什么,从调用位置看是"控制超时后撤销 CSIP 配置的生效标记"。建议补注释。csip_aus_get_exp_limit()/csip_aus_get_gen_limit()无下限钳位:对比get_imp_limit/get_load_limit都有< 10 → 10的保护。若云端下发 0(而非负值),logic.c:1065的l_s32_maxfeedin_power = min(..., 0) = 0会把馈网功率锁死到 0;如果 0 是"未配置"而非"禁止馈网",就是一次静默的过保守行为。- 注释与实现不符的两处:
csip_aus_update_control_timeout()的@Name写(u32 delta_time_ms)、@Note写"使用主函数传入的 delta_time,避免重复计算",实际是无参函数且内部自取OSTimeGet()(:1027-1032vs:1037)。CSIP_AUS_RAMP_MAX_TIMEOUT_FACTOR的注释"最大超时倍数:1.2倍计算时间"是对的(:1231用×12/10),但同一宏在:1272被用作ramp_tms_value * 12——因为那里的输入单位是 1/100 秒,×12恰好等于"换算成毫秒后再 ×1.2",两处用法单位基准不同、都正确,但完全没有注释说明,极易在维护时改错。 CSIP_AUS_DEBUG/CSIP_AUS_DEBUG_LOG用#define硬编码在.c内(:27-28):无法通过编译器-D覆盖(会触发宏重定义告警),也不能按机型分别开启。建议改为#ifndef ... #define ... #endif。csip_aus_state_transition_handle()的NORMAL分支被注释掉(:692-695):TRANSITION 态收到NORMAL事件时不回到正常,只能依赖csip_aus_der_control_process()顶部的安全闸门(:419)兜底。属版本遗留。u8_previous_state只写不读::1302写入后全工程无读取点(csip_aus_print_status()也不打它),属于为调试预留但未接线的字段。