drm.c
drm.c:77)4.2 信号采集 drm_get()(drm.c:44)4.3 DRM0 采集、滤波与分档(drm.c:84–107)4.4 模式判定状态机 u8_drm_mode(drm.c:109–150)4.5 德国 RRCR / EZA 馈网限值(drm.c:152–211)4.6 §14a EnWG 使能(drm.c:213–246)4.7 奥地利 KNG WLV 远程功率限制(drm.c:248–277)5. 对外接口本文件导出本文件调用的外部函数 / 变量6. 依赖关系依赖被依赖7. 备注与风险点源文件路径:
midware/interface/drm/drm.c所属模块:midware / interface / drm(DRM 需求响应模式与德国/奥地利电网限制) 代码行数:280
1. 文件职责
本文件实现 DRM(Demand Response Mode,需求响应模式)接口的状态采集与模式判定,是欧盟并网标准(英国 RRCR / G100、德国 VDE-AR-N 4105 §14a EnWG、奥地利 KNG 远程功率限制)在 EMS 侧的落地入口。它每 1 秒读一次硬件 DRM0~DRM4 五个信号(DRM0 走 ADC 模拟量、DRM1~4 走 GPIO 数字量),把结果打包成 4 位半字节状态 u16_drm_state,再翻译成 g_t_logic_info.u8_drm_mode(0~8、16)以及一组馈网/限功率使能与百分比字段。这些字段随后被 logic/logic.c(限功率与馈网计算)、midware/inverter/inverter.c(关机判定)、net/ems.c(云端上报)、midware/inverter/parallel*.c(并机同步)消费。本文件对外只有三个函数,由 midware/interface/interface.c 的 task_interface_parse 任务驱动:上电时调 drm_init(),之后每周期调 drm_mode_judge()(内部自带 1 s 节流)。文件本身没有任务、信号量或消息邮箱,也没有任何通信协议帧格式。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 | |||
|---|---|---|---|---|---|
u16_drm_state | 全局变量(drm.c:21) | DRM 信号打包态。位域布局:`(drm1!=0)<<12 \ | (drm2!=0)<<8 \ | (drm3!=0)<<4 \ | (drm4!=0),即 4 个半字节,取值只能是 0x0000/0x1000/0x0100/0x0010/0x0001 的 16 种组合。初始化 0x0000。**注意:全局导出但全工程无外部引用**,实际只在本文件内被 switch 使用,同时被镜像到 g_t_logic_info.u16_drm_state` |
g_t_logic_info.u8_drm_mode | 外部全局(logic/logic.h:505) | DRM 模式输出:0=DRM0 关断/CSIP 受限、1~4=DRM1~DRM4 半功率级、5~8=DRM1~DRM4 关断级、16=无效/无 DRM | |||
g_t_logic_info.u16_drm_state | 外部全局(logic/logic.h:506) | u16_drm_state 的镜像,供 net/ems.c:829、840 上报云端 | |||
g_t_logic_info.u8_rrcr_feedin_percent | 外部全局(logic.h:507) | RRCR(英式需求响应)生效时的馈网限值百分比,取值来自配置 u8_feedin_percent1~4 或 u8_max_feedin_percent | |||
g_t_logic_info.u8_eza_feedin_percent | 外部全局(logic.h:508) | EZA(德国自用优化)馈网限值百分比 | |||
g_t_logic_info.u8_deu_feedin_enable | 外部全局(logic.h:509) | RRCR/EZA 馈网限制总使能,被 net/ems.c:1125、1475 上报 | |||
g_t_logic_info.u8_14a_enwg_enable | 外部全局(logic.h:601) | §14a EnWG 生效标志,被 logic/logic.c:195 用于 EV/电池功率额度限幅,net/ems.c:1124、1474 上报 | |||
g_t_logic_info.u8_wlv_percent / u8_wlv_enable | 外部全局(logic.h:510-511) | 奥地利 KNG WLV(远程降低功率)限值百分比与使能;logic/logic.c:1136 用 u8_wlv_percent 按比例压低 s32_inv_rated_output_power | |||
RRCR_ENABLE / EZA_ENABLE / ALL_DISABLE | 枚举(logic/logic.h:114–119,RRCR_EZA_STATUS_E) | t_config_data.u8_rrcr_en 的取值:0=ALL_DISABLE、1=RRCR_ENABLE、2=EZA_ENABLE | |||
ENABLE / TRUE / FALSE | 宏(全局,includes.h 链) | 配置项与逻辑标志的通用取值 | |||
| DRM 阈值 800 / 3000 | 魔法数(drm.c:102、104) | ADC 低通滤波值分档门限:<800 → 等级 0,<3000 → 等级 1,≥3000 → 等级 2 | |||
| 低通系数 0.5568 / 0.4432 | 魔法数(drm.c:94–98) | 一阶 IIR 滤波系数,和为 1.0000 | |||
| 节流周期 1000 | 魔法数(drm.c:77) | 单位 tick(OS_TICKS_PER_SEC = 1000),即 1 s |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
drm_init | 全局(drm.c:33,声明 drm.h:21) | 上电初始化,把 u8_drm_mode 复位为 16(无效) |
drm_get | 全局(drm.c:44,声明 drm.h:23) | 读 DRM1~DRM4 四个 GPIO 电平,打包成 u16_drm_state 并镜像到 g_t_logic_info.u16_drm_state |
drm_mode_judge | 全局(drm.c:67,声明 drm.h:22) | 主判定:1 s 节流 → 采集 → DRM0 分档 → 决定 u8_drm_mode → 计算 RRCR/EZA/§14a/WLV 各使能与百分比 |
4. 核心逻辑解析
4.1 调度时序与节流(drm.c:77)
drm_mode_judge() 由 task_interface_parse 每周期调用,但函数开头用 static u32 s_u16_drm_tick 做 1 s 节流:
if (abs(OSTimeGet() - s_u16_drm_tick) < 1000) return;
drm_get();
s_u16_drm_tick = OSTimeGet();
OSTimeGet() 返回 32 位 tick 计数,OS_TICKS_PER_SEC = 1000(UCOSII/uCOS-CONFIG/os_cfg.h:51),所以 1000 tick = 1 s。abs() 包装是为了容忍 tick 回绕。注意变量名 s_u16_drm_tick 前缀是 u16 但类型是 u32,属命名遗留。
4.2 信号采集 drm_get()(drm.c:44)
l_u8_drm_falg[0] = get_drm1_flag(); // GPIOF PIN_10
l_u8_drm_falg[1] = get_drm2_flag(); // GPIOC PIN_1
l_u8_drm_falg[2] = get_drm3_flag(); // GPIOC PIN_4
l_u8_drm_falg[3] = get_drm4_flag(); // GPIOC PIN_5
u16_drm_state = (f0!=0)<<12 | (f1!=0)<<8 | (f2!=0)<<4 | (f3!=0);
g_t_logic_info.u16_drm_state = u16_drm_state;
四个 get_drmx_flag() 定义在 hardware/gpio/gpio.c:1403/1415/1427/1439,都是对 gpio_input_bit_get() 的单次读取,无去抖;去抖完全依赖下面的 ADC 通道低通滤波(但仅对 DRM0 有效)。局部变量名 l_u8_drm_falg 是 flag 的拼写错误。
4.3 DRM0 采集、滤波与分档(drm.c:84–107)
仅当逆变器安规类型属于以下集合时才做 DRM0 判定(drm.c:85):
inverter_read_safety_is_AS4777(...) 为真,或 inverter_read_safety() ∈ {PPDS, TOR_ERZEUGER, VDE4105_11_18, EN50549_NL, C10_C11, NC_RFG}。
(枚举定义见 midware/inverter/inverter.h:194–249。)
命中后:
- 只把 ADC 值放进索引 0,索引 1~4 写 0——注释明确"只用 DRM0"。由于配置集合里没有英国 G100/AS4777 之外的选项,DRM1~DRM4 的 GPIO 采集结果只影响
u16_drm_state的 RRCR/§14a/WLV 分支,不参与u8_drm_mode的生成。 - 五个通道统一跑一阶 IIR:
y = 0.5568*x + 0.4432*y_prev。因为 x[1..4] 恒为 0,s_u16_drm_lpf_buf[1..4]会从 0 开始单调衰减到 0,恒 < 800 →l_u8_singnal_state[1..4]恒为 0。 - 分档:
< 800→ 0;< 3000→ 1;否则 → 2。
4.4 模式判定状态机 u8_drm_mode(drm.c:109–150)
signal[0] >= 2(DRM0 高电平 → 要求关断)
→ u8_drm_mode = 0
signal[0] < 2
任一 signal[1..4] == 2(关断级) → 5 / 6 / 7 / 8(按 DRM1/2/3/4 顺序,先命中先胜)
否则任一 signal[1..4] == 1(半功率级)→ 1 / 2 / 3 / 4(同上)
否则 → 16(无效)
由于 4.3 已使 signal[1..4] 恒为 0,在当前集合的安规下实际只有两条出口:signal[0] >= 2 → 0,否则 16。
CSIP 覆写(drm.c:141–145):若 sys_limited_by_csip_judge() == TRUE(南澳 CSIP-AUS 调度受限,定义于 logic/logic.c:3499)且(u8_opmodenergize != FALSE 或 u8_opmodconnect != FALSE,即逆变器已带电或已并网),无条件把 u8_drm_mode 覆写为 0。
不满足安规集合时(drm.c:147–150):整段跳过,直接 u8_drm_mode = 16。
消费侧:midware/inverter/inverter.c:846 用 u8_drm_mode == 0(本机与并机从机)作为"必须关机"的判据之一;midware/inverter/parallel.c:187、872、887 把它同步进 g_t_host_machine_running_info[0].u8_drm_mode,再经 parallel_can.c:226/838、parallel_sci.c:411/844 在并机总线(CAN/SCI)上传递;net/ems.c:829/840 上报云端。
4.5 德国 RRCR / EZA 馈网限值(drm.c:152–211)
两个分支互斥且都以 inverter_read_safety() == VDE4105_11_18 为前提。
RRCR 分支(u8_rrcr_en == RRCR_ENABLE,drm.c:152):置 u8_deu_feedin_enable = TRUE,然后按 u16_drm_state 映射到 u8_rrcr_feedin_percent:
u16_drm_state | 百分比来源 |
|---|---|
0x1000 0x1100 0x1011 0x1110 0x1101 0x0101 | u8_feedin_percent1 |
0x0100 0x0110 | u8_feedin_percent2 |
0x0010 0x0011 | u8_feedin_percent3 |
0x0001 0x1001 0x0111 | u8_feedin_percent4 |
其余(含 0x0000、0x1111 等) | u8_max_feedin_percent,并置 u8_deu_feedin_enable = FALSE |
EZA 分支(u8_rrcr_en == EZA_ENABLE,drm.c:180):同样置总使能,映射到 u8_eza_feedin_percent:
u16_drm_state | 百分比 |
|---|---|
0x0000 0x1000 | 固定 100 |
0x0100 0x1101 | u8_feedin_percent1 |
0x0010 0x1110 | u8_feedin_percent2 |
0x0001 0x0111 0x0101 0x1011 | u8_feedin_percent3 |
其余(含 0x1111、0x1100、0x0110、0x0011、0x1001) | u8_max_feedin_percent,且 u8_deu_feedin_enable = FALSE |
两个分支都不成立(u8_rrcr_en == ALL_DISABLE 或安规不是 VDE4105_11_18)→ 仅清 u8_deu_feedin_enable = FALSE(drm.c:210),不清 u8_rrcr_feedin_percent / u8_eza_feedin_percent(保留上次值,但下游已由使能位屏蔽)。
4.6 §14a EnWG 使能(drm.c:213–246)
u8_14a_enwg_en 同样是三值枚举,但语义与 RRCR/EZA 表不同:
EZA_ENABLE:以下 6 个组合生效 →u8_14a_enwg_enable = TRUE:0x1000、0x1101、0x1110、0x0101、0x1011(注释写"14a生效")。RRCR_ENABLE:另一组 5 个组合生效 →TRUE:0x1111、0x1100、0x0110、0x0011、0x1001。- 其余所有情况(含
ALL_DISABLE)→FALSE。
u8_14a_enwg_enable 被 logic/logic.c:195 用于 EV/电池功率额度限幅(与 u8_14a_enwg_active 配合)。
4.7 奥地利 KNG WLV 远程功率限制(drm.c:248–277)
条件 t_config_data.u8_kng_wlv_config_en == TRUE(注释"奥地利远程功率限制使能"):
u16_drm_state | u8_wlv_enable | u8_wlv_percent |
|---|---|---|
0x0000 | FALSE | 100 |
0x0100 | TRUE | 30 |
0x1000 | TRUE | 0 |
| 其余 | TRUE | 0 |
不使能时只清 u8_wlv_enable = FALSE,不动 u8_wlv_percent(drm.c:276)。下游在 logic/logic.c:1136 用 u8_wlv_percent 按比例压低逆变器额定输出功率:s32_inv_rated_output_power = parallel_read_system_rated_output_power() * u8_wlv_percent / 100。
5. 对外接口
本文件导出
| 名称 | 类型 | 使用方 |
|---|---|---|
drm_init | 函数(drm.h:21) | midware/interface/interface.c:215 |
drm_mode_judge | 函数(drm.h:22) | midware/interface/interface.c:219 |
drm_get | 函数(drm.h:23) | 仅本文件 drm_mode_judge() 内部调用;头文件对外声明但全工程无外部调用者 |
u16_drm_state | 全局变量(drm.c:21) | 无外部引用(未在 drm.h 中 extern 声明),属事实上的文件私有变量 |
本文件调用的外部函数 / 变量
| 来源 | 名称 |
|---|---|
hardware/gpio/gpio.h:183-187 | get_drm1_flag()~get_drm4_flag()、get_drm0_data()(内部转 get_adc2_in7_data(),见 hardware/gpio/gpio.c:1451) |
midware/inverter/inverter.h | inverter_read_safety()(2084)、inverter_read_safety_is_AS4777()(2258) |
logic/logic.h | sys_limited_by_csip_judge()(707)、g_t_logic_info 及其 t_config_data(u8_rrcr_en、u8_feedin_percent1~4、u8_max_feedin_percent、u8_14a_enwg_en、u8_kng_wlv_config_en) |
| uCOS-II | OSTimeGet() |
| 标准库 | abs() |
6. 依赖关系
依赖
drm.h、gpio.h、logic.h、inverter.h(drm.c:13–16)。其中 inverter.h 的引用是必要的(安规枚举与读取函数),drm.h 仅提供 includes.h 与自身原型。
被依赖
midware/interface/interface.c:215、219:唯一调度者。midware/interface/interface.c、logic/logic.c、net/ems.c、midware/inverter/inverter.c、parallel.c、parallel_can.c、parallel_sci.c:消费g_t_logic_info中的 DRM 相关字段。
7. 备注与风险点
- DRM1~DRM4 的输入在本文件内被实质丢弃:
drm.c:89–92把l_u16_drm_buf[1..4]硬编码为 0,导致l_u8_singnal_state[1..4]恒为 0,因此u8_drm_mode的 1~8 分支(drm.c:117–133)在当前安规集合下永不可达。这些分支与u8_drm_mode = 5/6/7/8、1/2/3/4的语义仍被inverter.c和云端沿用,属历史遗留代码,若后续启用 DRM1~4 数字量判定需一并复核。 drm_get()无去抖:四个 GPIO 单次读取直接进u16_drm_state,而u16_drm_state直接决定 RRCR/EZA/§14a/WLV 的百分比映射。虽然该函数 1 s 才被调一次,但期间任何抖动会立即改变馈网限值。u16_drm_state是导出符号但无extern声明:其他文件若要用只能自己extern,容易与g_t_logic_info.u16_drm_state混用。建议统一走g_t_logic_info。u8_rrcr_feedin_percent/u8_eza_feedin_percent/u8_wlv_percent在失能时不被复位(drm.c:210、276),残留上次值。当前靠u8_deu_feedin_enable、u8_wlv_enable屏蔽,但如果下游有代码只读百分比不看使能位,就会用到过期数据(net/ems.c:1119、1121就是只读百分比)。abs(OSTimeGet() - s_u16_drm_tick) < 1000是带符号回绕技巧(drm.c:77):OSTimeGet()返回INT32U,相减结果被当作有符号解释,在 tick 差距小于 2^31 时成立;写法可读性差但功能正确。- 魔法数密集:ADC 门限 800/3000(
drm.c:102、104)、IIR 系数 0.5568/0.4432(drm.c:94)、WLV 固定 30(drm.c:260)、EZA 的 100(drm.c:186)、节流 1000(drm.c:77)均无宏定义或注释说明来源。 0.5568是浮点运算:s_u16_drm_lpf_buf[0] = 0.5568 * l_u16_drm_buf[0] + s_u16_drm_lpf_buf[0] * 0.4432走软件 double 浮点,GD32F407 无硬件双精度 FPU,在 1 s 周期的任务里开销可接受,但若被移植到更小周期需评估。l_u8_singnal_state拼写错误(signal→singnal,drm.c:69),l_u8_drm_falg亦为flag误拼(drm.c:46)。不影响功能,但会误导检索。u8_drm_mode的隐含依赖:drm.c:109–139的整套判定只在"安规集合命中"分支内;而drm.c:152之后的 RRCR/EZA/§14a/WLV 用同一个u16_drm_state但不受安规集合限制(只受各自配置位限制)。因此当安规为VDE4105_11_18之外的其它安规、而u8_rrcr_en又被误设为RRCR_ENABLE时,RRCR 分支不会执行(有安规判断),但 §14a 与 WLV 分支没有安规判断,会照常依据u16_drm_state动作。- 无通信协议与重试机制:DRM 是本地硬线接口,本文件不涉及帧格式、校验或超时重试。这一节在本文档中按"不适用"处理。