加热器软件 PWM 设计

Babel36acl 嵌入式实战 无~ 6 次阅读 预计阅读时间: 17 分钟 发布于 1 天前 最后更新于 1 小时前 3636 字


嵌入式功率控制体系:加热 PWM、DC 电机驱动与统一限幅框架

关键词:STM32F103、IR2104 H-Bridge、NMOS 继电器、软件 PWM、packer_power_limit、FreeRTOS、功率管理框架

flowchart TB
    subgraph TASK[packer_heater_task_once]
        T1[读取目标温度]
        T2{PID 计算}
        T2 -->|需加热| T3[翻转 GPIO]
        T2 -->|关闭| T4[GPIO 低]
    end
    subgraph PWM[软件 PWM]
        P1[100ms 周期]
        P2[占空比调节]
    end
    TASK --> PWM -->|TIM5 CH1 已禁用| GPIO[加热继电器]
    style TASK fill:transparent,stroke:#8dc7ff,color:#eaf4ff
    style PWM fill:transparent,stroke:#8dc7ff,color:#eaf4ff

1. 背景:为什么需要统一功率控制?

在 DEVICE_CO 的 INDL_CONTROLLER 系列工业控制器中,一块控制板上同时存在多种功率负载:大功率阻性加热器、两台有刷直流电机、散热风扇、料斗输送电机等。早期版本中,每个负载的启动和关闭是分散处理的——上层应用直接调用 GPIO 操作或继电器驱动。这种架构在功能简单时足够,但一旦需要引入过流保护、功率统计和动态限流时,问题立刻暴露:没有一个统一的入口点可以拦截和控制所有功率操作

加热器使用电磁继电器(非固态继电器,无硬件 PWM 能力),最初尝试用 TIM5 CH1 硬件 PWM 直接驱动,结果继电器机械吸合/释放时间远超 PWM 载波周期,导致触点抖动、电弧、寿命急剧缩短,并产生严重的 EMI 干扰。

DC 电机方面,系统使用 IR2104 半桥驱动芯片驱动 4 个 NMOS 构成全 H 桥,需要在 BSP 层精确控制启动时序、停止时序、方向切换。每类负载有自己的硬件特性和安全约束,但又共享同一电源总线——因此需要一个统一的功率管理框架来协调。

这就是本文要阐述的三层体系:加热器软件 PWM、DC 电机 BSP 驱动、统一功率限幅框架 packer_power_limit


2. 硬件基础

2.1 负载总览

整个系统包含 6 类功率负载,每类通过独立硬件通道控制:

负载类型 数量 驱动方式 GPIO / 定时器
DC 电机 1 (MOTOR_1) 1 IR2104 H-Bridge (TIM1 CH1/CH1N) INH/INL/SD + 互补 PWM
DC 电机 2 (MOTOR_2) 1 IR2104 H-Bridge (TIM8 CH1/CH1N) INH/INL/SD + 互补 PWM
加热器 (Heater) 1 NMOS 继电器 (PA0) GPIO 电平翻转
散热风扇 (Fan) 1 NMOS 继电器 (PA1) GPIO 电平翻转
料斗输送 (Hopper Conveyor) 1 NMOS 继电器 (PA6) GPIO 电平翻转
备用继电器 (Spare) 1 NMOS 继电器 (PB1) GPIO 电平翻转

2.2 GPIO 映射

所有 GPIO 来自 STM32CubeMX 生成的 main.h 宏定义,BSP 层只引用宏、不硬编码引脚值:

/* 继电器 GPIO 资源表(静态表驱动) */
static const relay_gpio_t s_relay_gpios[RELAY_COUNT] = {
    [RELAY_HEATER]  = { .port = GPIOA, .pin = GPIO_PIN_0 },
    [RELAY_FAN]     = { .port = GPIOA, .pin = GPIO_PIN_1 },
    [RELAY_HOPPER]  = { .port = GPIOA, .pin = GPIO_PIN_6 },
    [RELAY_SPARE]   = { .port = GPIOB, .pin = GPIO_PIN_1 },
};

2.3 DC 电机 IR2104 H-Bridge 硬件拓扑

每路电机采用 IR2104 半桥驱动 + 4 个 NMOS 构成全 H 桥。IR2104 使用 3 线控制:INH(高侧输入)、INL(低侧输入)、SD(关断/使能)。STM32 输出经 IR2104 转换为高侧/低侧栅极信号。TIM1/TIM8 输出互补 PWM(含死区插入)。

信号 电机 1 电机 2 定时器
PWM (CH1/CH1N) TIM1 CH1 / CH1N TIM8 CH1 / CH1N 互补输出 + 死区
INH (GPIO) GPIO 输出 GPIO 输出 高侧逻辑输入
INL (GPIO) GPIO 输出 GPIO 输出 低侧逻辑输入
SD (GPIO) GPIO 输出 GPIO 输出 关断信号,低电平有效

3. 加热器软件 PWM —— 继电器 + 100ms 窗口翻转

3.1 为什么不用硬件 PWM

加热器执行机构为一枚普通电磁继电器。早期版本错误地使用 TIM5 CH1 硬件 PWM 输出模式直接驱动——继电器触点的机械动作时间约为 5~10ms,远高于 PWM 载波周期(~1ms),高频开关只会导致触点抖动、电蚀、电磁干扰,最终烧毁继电器和保温层。

正确方案:废除 TIM5 的 PWM 配置,改为 GPIO 电平翻转 + 软件窗口计时,以 100ms 为基准窗口做 ON/OFF 分配。这才是本文所谓"软件 PWM"的本质。

3.2 基本参数

参数 说明
基准周期 100ms(可运行时配置) 软件窗口总时长
最小 ON 宽度 1ms 零占空比保护
占空比上限 200‰(20.0%) 硬编码安全限幅——不可逾越
任务周期 10ms HeaterTask 专用任务

3.3 HeaterTask 独立任务

加热器控制由一个独立的 FreeRTOS 任务 HeaterTask 负责,运行周期固定为 10ms。该任务不与执行机构(actuator)混合在同一循环中,保证了加热控制的实时性不受其他逻辑拖累。

同期在同一任务中还处理了 散热风扇控制,通过跨任务标志位 indl_controller_heater_fan_request() 驱动。

3.4 窗口化 PWM 计算算法

核心思想:将一个完整的 PWM 周期(例如 100ms)等分为 10ms 窗口,在每个窗口决定是否输出 ON。使用累加器进行滚动判断,无浮点运算,适合嵌入式环境:

static uint8_t compute_target_output(uint16_t duty_per_mille,
                                     uint16_t period_ms)
{
    uint16_t on_window_ms;
    static uint16_t acc_window_ms = 0;

    /* 限幅:不超过 200‰ */
    if (duty_per_mille > HEATER_MAX_DUTY_PER_MILLE) {
        duty_per_mille = HEATER_MAX_DUTY_PER_MILLE;
    }

    /* 计算 ON 时间(ms),最小 1ms 保护 */
    on_window_ms = (period_ms * duty_per_mille) / 1000;
    if (on_window_ms == 0 && duty_per_mille > 0) {
        on_window_ms = 1;
    }

    /* 窗口滚动判断 */
    if (acc_window_ms < on_window_ms) {
        acc_window_ms += HEATER_TASK_PERIOD_MS; /* 10ms */
        return 1; /* ON */
    } else {
        acc_window_ms += HEATER_TASK_PERIOD_MS;
        if (acc_window_ms >= period_ms) {
            acc_window_ms = 0; /* 周期复位 */
        }
        return 0; /* OFF */
    }
}

3.5 20% 安全限幅的来历

RCFG_ID_HEATER_DUTY_PER_MILLE 的取值范围为 0~200,超过 200 的值会被 硬编码限幅 到 200(即 20.0%)。该限幅来自一次真实现场事故——因配置错误导致 100% 占空比持续加热,继电器粘连、保温层烧穿、机台起火。此后所有产品强制上限为 20.0%。

安全限幅必须硬编码,不可由运行时参数覆盖。一次真实起火事故让整个产品线加上了 HEATER_MAX_DUTY_PER_MILLE 这个不可逾越的上限。

3.6 跨任务标志与临界区

风扇请求、强制加热等信号来自其他任务(如通信任务、状态机任务),通过 volatile 全局标志 + 临界区保护 传入 HeaterTask:

/* 跨任务标志定义 */
static volatile uint8_t heater_fan_request;
static volatile uint8_t heater_force_on;

/* 临界区访问 */
void indl_controller_heater_fan_request(void)
{
    taskENTER_CRITICAL();
    heater_fan_request = 1;
    taskEXIT_CRITICAL();
}

uint8_t indl_controller_heater_fan_consume(void)
{
    uint8_t ret;
    taskENTER_CRITICAL();
    ret = heater_fan_request;
    heater_fan_request = 0;
    taskEXIT_CRITICAL();
    return ret;
}

3.7 强制加热与预热逻辑

工业流程中某些步骤需要在开始前将温度快速提升到目标值(预热),此时 PWM 算法的渐近调功不适用。为此设计了跨任务强制加热机制,可在任意任务中调用 indl_controller_heater_force_on_now(),立即全功率输出,无需等待 PWM 周期对齐。

3.8 功率限制门控

继电器输出受 功率限制门控 控制。当系统处于功率限制模式(如电源过载、紧急降功率),即使 PWM 计算结果为 ON,实际也不允许吸合继电器:

static void write_relay(uint8_t target_on)
{
    /* 功率限制门控 */
    if (indl_controller_power_limit_request_relay_read()) {
        GPIO_ResetBits(HEATER_RELAY_GPIO_PORT, HEATER_RELAY_PIN);
        return;
    }

    /* 系统状态检查:ERROR / RESET 时自动关闭 */
    if (sys_state == SYS_STATE_ERROR ||
        sys_state == SYS_STATE_RESET) {
        GPIO_ResetBits(HEATER_RELAY_GPIO_PORT, HEATER_RELAY_PIN);
        return;
    }

    if (target_on) {
        GPIO_SetBits(HEATER_RELAY_GPIO_PORT, HEATER_RELAY_PIN);
    } else {
        GPIO_ResetBits(HEATER_RELAY_GPIO_PORT, HEATER_RELAY_PIN);
    }
}

4. DC 电机 BSP 驱动 —— IR2104 H-Bridge + NMOS Relay

4.1 IR2104 前级反相特性(最容易踩坑的地方)

IR2104 的输入逻辑是 反相的:MCU 输出 HIGH 到 IR2104 的 INH/INL 引脚时,IR2104 实际输出 LOW 给 MOS 管栅极(即关断)。反之,MCU 输出 LOW 时,IR2104 才输出 HIGH 开启 MOS 管。

关键推论:当 MCU 将 INH 和 INL 都置为 HIGH 时,IR2104 两侧均输出 LOW → H 桥上下管全部关闭 → 安全状态。不仅如此,这种状态还允许自举电容充电,为下次 PWM 启动做准备。这就是 "Pre-stage HIGH is safe + bootstrap charge" 的设计原则。

4.2 停止时序 (Stop Sequence)

正确的停止顺序分为三步:

1. 停止 PWM 输出                → TIM_Cmd(TIMx, DISABLE)
2. 拉低 SD 引脚                 → GPIO_ResetBits(SD_PORT, SD_PIN)
3. 将 INH 和 INL 均置 HIGH     → 进入安全状态 + 自举充电

为什么先停 PWM 再拉 SD? 如果先拉 SD 再停 PWM,在 SD 拉低到 PWM 停止的间隙内,IR2104 可能处于不确定状态,导致 MOS 管直通(shoot-through)。严格时序:PWM 停止 → SD 拉低 → 强制 INH/INL HIGH。

4.3 启动时序 (Start Sequence)

正转 (Forward):

1. INL 强制 HIGH(MCU) = IR2104 INL LOW  → 低侧 MOS 关断
2. INH 输出 PWM 波形                   → IR2104 INH 跟随 PWM
3. SD 置 HIGH(使能)                   → 启动 TIM CH1N 互补通道
→ 电流路径:电源 → 高侧 MOS → 电机 → 低侧 MOS (通过另一侧半桥)

反转 (Reverse):

1. INH 强制 HIGH(MCU) = IR2104 INH LOW  → 高侧 MOS 关断
2. INL 输出 PWM 波形                   → IR2104 INL 跟随 PWM
3. SD 置 HIGH(使能)                   → 启动 TIM CH1 主通道
→ 电流路径反向

4.4 PWM 占空比限制 —— 96% 上限

IR2104 使用自举电容为上管驱动供电。当占空比接近 100% 时,自举电容没有足够的充电时间,导致上管驱动电压不足而关断。实际限制:PWM 占空比上限为 96%,下限取决于开关频率和死区。在驱动层通过 __HAL_TIM_SET_COMPARE() 之前对占空比进行钳位。

任何时候都不应输出 0% 或 100% 的占空比。0% 意味着长期无 PWM 翻转,自举电容放电殆尽;100% 意味着无低侧导通时间,无法充电。

4.5 方向切换 —— Stop-Then-Start

方向切换 不允许直接反转。必须执行完整的 Stop Sequence → 等待安全状态 → 再执行新方向的 Start Sequence:

bsp_dc_motor_stop(motor_id);
delay_ms(5);           /* 等待 MOS 完全关断 + 自举充电 */
bsp_dc_motor_start(motor_id, direction, speed);

这 5ms 的延迟窗口确保了 H 桥不会出现瞬间直通。

4.6 继电器重复写入抑制

继电器写入函数实现了 重复写入抑制 机制,使用 8-bit 位掩码 s_relay_active_mask 实时记录各继电器当前状态,重复写入时直接返回 OK:

static int relay_write_checked(uint8_t relay_id, uint8_t state)
{
    /* 重复抑制:检查当前状态是否已经是目标状态 */
    uint8_t current = (s_relay_active_mask >> relay_id) & 0x01U;
    if (current == state)
        return BSP_DC_MOTOR_OK;   /* 跳过 GPIO 写入 */

    /* 更新屏蔽字并写入 GPIO */
    if (state) {
        s_relay_active_mask |=  (1U << relay_id);
        GPIO_SetBits(s_relay_gpios[relay_id].port, s_relay_gpios[relay_id].pin);
    } else {
        s_relay_active_mask &= ~(1U << relay_id);
        GPIO_ResetBits(s_relay_gpios[relay_id].port, s_relay_gpios[relay_id].pin);
    }
    return BSP_DC_MOTOR_OK;
}

4.7 停止策略:两种 Stop API

API 停止内容 继电器状态 使用场景
stop_all() 所有电机 + 所有继电器 全部关闭 紧急停止、系统复位
stop_all_motors() 仅停止电机 保持当前状态 工艺暂停、轻故障恢复

5. 统一功率限幅框架 —— packer_power_limit

5.1 框架定位

packer_power_limit 框架的核心思路:给所有功率操作加一个统一的前置评估层。所有电机启动和继电器写入都必须经过 packer_power_limit_request_* 系列函数,没有任何旁路路径。

框架定义了 6 种负载类型,每种独立跟踪功率:

typedef enum {
    LOAD_DC_MOTOR1  = 0,
    LOAD_DC_MOTOR2  = 1,
    LOAD_HEATER     = 2,
    LOAD_FAN        = 3,
    LOAD_HOPPER_CONVEYOR = 4,
    LOAD_RELAY4     = 5,
    LOAD_TYPE_COUNT = 6
} load_type_t;

5.2 核心数据流:measure → predict → latch → limit

框架采用四段式流水线架构:

ADC 采样 → 滑动平均滤波 → 实测功率更新
                    │
         预测功率 = 当前值 + 新负载增量
         (饱和加法)
                    │
          ┌──────────────────────────┐
          │  是否超过动态限值?        │
          │  (measured > dynamic_limit)│
          └─────────────┬────────────┘
                    │
            是 ────┴──── 否
          ┌─────────┐   ┌─────────┐
          │ 触发锁存  │   │ 正常通过  │
          │ latched=1│   │ latch不变│
          └─────────┘   └─────────┘

5.3 测量链路

  • ADC 通道:ADC1_IN4(PA4 引脚),分流电阻上的压降 → 差分放大 → ADC 采样
  • 4 点滑动平均滤波器:ADC 读数经过 4 点滑动平均滤波去噪。4 点的选择是典型的实时性与平滑度的折中——太长会延迟过流响应,太短则噪声抑制不足
  • 饱和安全加法:功率预计算使用饱和加法,避免意外溢出导致错误判断:static uint32_t sat_add(uint32_t a, uint32_t b) { uint32_t sum = a + b; if (sum < a) sum = UINT32_MAX; return sum; }

5.4 锁存机制与迟滞

锁存(latch)一旦触发,不会在功率回落到阈值以下时立即释放。它使用迟滞(hysteresis)

  • 触发阈值dynamic_limit_mw(动态限值)
  • 释放阈值dynamic_limit_mw × 0.8(80% 回退)
  • 锁定标记load_power_state_t.latched
  • 只有滤波后的功率低于释放阈值时,锁存才会清除

这种设计防止了在阈值边界处反复触发/释放的"抖动"问题,是工业控制中标准做法。

5.5 动态限值:按流程类型切换

不同工作流程有不同的功率预算:

typedef enum {
    FLOW_TYPE_BAG       = 0,   /* 灌装流程 */
    FLOW_TYPE_SELF_CHECK = 1,  /* 自检流程 */
    FLOW_TYPE_SEAL      = 2,   /* 封口流程 */
    FLOW_TYPE_RESET     = 3,   /* 复位流程 */
    FLOW_TYPE_COUNT     = 4
} flow_type_t;

static uint32_t get_flow_limit_mw(flow_type_t flow) {
    static const uint32_t limits[FLOW_TYPE_COUNT] = {
        [FLOW_TYPE_BAG]       = 500000,  /* 500W */
        [FLOW_TYPE_SELF_CHECK] = 500000, /* 500W */
        [FLOW_TYPE_SEAL]      = 500000,  /* 500W */
        [FLOW_TYPE_RESET]     = 500000,  /* 500W */
    };
    return limits[flow];
}

5.6 "阈值全部设为最大值,当前表现为直通模式"——先搭骨架,再校准

这是整个框架最令人玩味的地方。当前配置中:

参数 当前值 备注
各流程动态限值 500W 远超实际负载功率(直通模式)
各负载 profile 值 100W 仅为占位符
告警触发 已定义但从不触发 APP_ALARM_POWER_OVER_LIMIT (0x0E)

这种"先上线、后校准"的策略在工业项目中很常见,原因如下:

  1. 功能完整性优先:先确保评估引擎、锁存机制、日志记录等所有功能链路完整跑通
  2. 避免回归风险:阈值设得太小会意外触发保护,干扰功能测试
  3. 数据驱动的校准:先用直通模式跑一段时间,收集实际功率数据,再据此设定合理阈值
  4. 渐进式部署:第一阶段做计量(accounting),第二阶段做警告(warning),第三阶段做硬限流(hard limit)

5.7 决策快照 —— 为审计做准备

框架为每次请求生成了完整的决策快照(decision snapshot)

typedef struct {
    load_type_t load;
    flow_type_t flow;
    uint32_t    predicted_power_mw;
    uint32_t    current_limit_mw;
    bool        would_exceed;
    bool        latched;
    uint32_t    timestamp_ms;
} power_decision_snapshot_t;

这意味着即使现在是直通,未来某天阈值调小后,可以回查历史记录,分析哪些操作"本应被阻止"——设计上已经做好了审计准备


6. 集成:加热器、DC 电机、继电器如何统一经过 power_limit

6.1 分层架构

整个功率控制体系分为三个清晰的层次:

┌─────────────────────────────────────────────────────┐
│                  Application Layer                   │
│     (bag filling / self-check / seal / reset)        │
└────────────┬───────────────────────────────┬─────────┘
             │ start_motor_X()              │ relay_write()
             ▼                              ▼
┌──────────────────────────────────────────────────────┐
│             packer_power_limit_request_*()            │ ← 统一入口
│                                                       │
│  ┌──────────────┐  ┌─────────────┐  ┌───────────┐   │
│  │ Measurement   │→ │ Limit       │→ │ Policy    │   │
│  │ (ADC filter)  │  │   Eval      │  │ Latch     │   │
│  └──────────────┘  └─────────────┘  └───────────┘   │
└──────────────────────────┬───────────────────────────┘
                           ▼
┌──────────────────────────────────────────────────────┐
│           BSP Layer (bsp_dc_motor)                    │
│  GPIO / PWM / Relay / Motor Driver Operations        │
└──────────────────────────────────────────────────────┘

关键设计点:所有电机启动和继电器写入都必须经过 packer_power_limit_request_* 系列函数,BSP 层只负责"能否执行",不关心"应该执行多少功率"。

6.2 集成流程示例

以加热器 PWM 驱动为例,完整的调用链:

/* HeaterTask 每 10ms 执行一次 */
void heater_task_once(void)
{
    /* 1. 强制加热? */
    if (indl_controller_heater_force_on_consume()) {
        /* 通过 power_limit 检查 */
        if (packer_power_limit_request_relay_write(
                LOAD_HEATER, current_flow, HEATER_PROFILE_MW) == POWER_LIMIT_OK) {
            write_relay(1);
        }
        return;
    }

    /* 2. 读取运行时参数 → 窗口 PWM 计算 */
    uint16_t duty = rcfg_read_u16(RCFG_ID_HEATER_DUTY_PER_MILLE);
    uint16_t period = rcfg_read_u16(RCFG_ID_HEATER_PWM_PERIOD_MS);
    uint8_t target = compute_target_output(duty, period);

    /* 3. 通过 power_limit 检查后写继电器 */
    if (target) {
        if (packer_power_limit_request_relay_write(
                LOAD_HEATER, current_flow, HEATER_PROFILE_MW) == POWER_LIMIT_OK) {
            write_relay(1);
        } else {
            write_relay(0);
        }
    } else {
        write_relay(0);
    }
}

DC 电机同理:

/* 启动电机前必须先经过 power_limit */
packer_power_limit_result_t result;
result = packer_power_limit_request_start_motor(
             LOAD_DC_MOTOR1, current_flow, MOTOR1_PROFILE_MW);

if (result == POWER_LIMIT_OK) {
    bsp_dc_motor_start(MOTOR_1, DIR_FORWARD, speed);
} else {
    /* 被限流阻止,记录告警 */
    app_alarm_trigger(APP_ALARM_POWER_OVER_LIMIT);
}

6.3 BSP 层的纯正性

功率限制逻辑在 BSP 层之外实现,位于上层的 packer_actuator / packer_heater 模块。这种设计保持了 BSP 层的纯正性——BSP 只提供原子化的硬件控制原语(start / stop / set_duty),上层策略层组合这些原语实现功率管理、安全联锁、工艺时序。


7. 设计经验与教训

决策 方案 理由
加热器控制方式 GPIO 翻转(非硬件 PWM) 继电器机械特性不适用高频 PWM
加热 PWM 实现 窗口累加算法 简单可靠,无浮点运算
最大占空比(加热器) 硬编码 200‰ 防止配置错误导致的起火事故
DC 电机方向切换 Stop-Then-Start 防止 H 桥直通(shoot-through)
PWM 占空比(电机) 96% 上限 IR2104 自举电容充电需求
功率评估策略 先直通、后校准 功能完整性优先,避免回归风险
锁存释放 80% 回退迟滞 防止阈值边界抖动
跨任务通信 volatile + 临界区 轻量级,适用于标志类信号
功率门控 独立函数层 统一处理所有输出抑制场景
最小 ON 时间 1ms 避免零占空比导致的除零异常
继电器写入 重复写入抑制 减少 GPIO 总线访问,延长继电器寿命

7.1 教训一:不要因为 MCU 有硬件 PWM 就想当然地用它驱动继电器

继电器是机电元件,不是功率 MOSFET。100ms 级别的软件翻转才是正确的打开方式。

7.2 教训二:安全限幅必须硬编码

安全限幅必须硬编码,不可由运行时参数覆盖。一次真实起火事故让整个产品线加上了 HEATER_MAX_DUTY_PER_MILLE 这个不可逾越的上限。

7.3 教训三:IR2104 的前级反相特性必须在 BSP 层显式建模

"Pre-stage HIGH is safe + bootstrap charge" 是设计原则。初始化、停止、方向切换前的过渡状态,均保持 INH = INL = HIGH。在任何代码审查中,只要看到 INH 或 INL 直接接地而没有经过逻辑转换,就需要打上红色标记。

7.4 教训四:框架的价值在于为未来铺好轨道

packer_power_limit 框架的真正价值不在于它现在保护了什么,而在于它为未来的保护铺好了所有轨道。当实际负载数据收集完成、阈值校准后,只需修改几个 #define 就能从"计量"切换到"保护"模式——而代价是零代码重构。

7.5 预热阶段的价值

预热阶段的强制加热 API 是流程控制的关键接口。在批量生产中,预热时间每优化 1 秒都有商业价值——但前提是安全限幅不能被 bypass。


8. 结语

本文介绍的三层功率控制体系已在 DEVICE_CO 的 INDL_CONTROLLER 系列产品上稳定运行多个版本。从加热器用 100ms 窗口做正确的事(继电器 ON/OFF),到 DC 电机用 IR2104 严格时序确保 H 桥安全,再到 packer_power_limit 用"先搭骨架、再校准"的架构给所有功率操作加上统一的前置评估层——这套体系经过了真实现场故障的检验:

  • 硬件 PWM 误用 → 起火事故 → 限幅硬编码 → 跨任务预热接口
  • IR2104 前级反相踩坑 → Pre-stage HIGH 安全原则 → Stop-Then-Start 方向切换
  • 功率管理分散 → packer_power_limit 统一入口 → 直通模式收集数据 → 未来校准

核心思路可以概括为一句话:用正确的时机做正确的事,用硬编码的安全上限兜住失控的配置,用分层架构隔离关注点。


—— DEVICE_CO 嵌入式团队,技术博客系列 · 功率控制专题

此作者没有提供个人介绍。
最后更新于 2026-05-30