12故障与调试

波形现象、原因定位与 STM32 排查路径

本模块主旨
把"现象 → 波形 → 中间变量 → 硬件测量"串成证据链——老师傅的排障套路。

学完应能回答

查看完整 Walkthrough(8 步 + 4 误区)

总览
故障调试的目标是把"感觉不对"翻译成"可测、可复现、可修复"。证据链 + 案例库是工程师最值钱的资产。

零基础速入

类比
故障调试像医生看病——不是看症状("电机抖动"),而是要把"症状 → 波形 → 中间变量 → 硬件测量"串成一条证据链。每个故障在波形上都有典型特征,会看波形等于会做诊断。
核心概念
建立"现象库":把 8 类常见故障(过流 / 缺相 / 偏置 / 相序 / 角度 / 振荡 / 饱和 / 启动失败)和它们的波形特征 + 排查步骤 + 修复方案对应起来。

为什么要学

第一手操作
右侧切换"故障类型"试 8 种故障,看 Ia/Ib/Ic/speed 波形特征。每种故障右侧都有"现象 + 原因 + 排查步骤 + 修复建议",这是真实现场的诊断手册。

学习目标

核心概念

公式

调试黄金循环
现象 → 波形 → 中间变量 → 硬件测量 → 假设 → 修改 → 复测

每次只改一个变量,保留复现实验。盲改多个会迷失。

过流判据(软件)
|Ia| > I_OC 或 √(Iα²+Iβ²) > I_OC × 1.15

软件保护 I_OC = 1.2 × I_rated;硬件保护通常 1.5-2 × I_rated 由比较器直接关 PWM。

相序错诊断
正向命令但电机反转 / 同样 Iq 命令转矩偏向反向

换接线两相 / 软件里 swap Ib 与 Ic 即可修复。

工程意义

STM32 移植指南

常见误区

  • 过流后只降 Kp 不查相序和角度。
  • 电压饱和时继续加 Iq 命令(无效且伤管)。
  • 只做软件保护,没硬件兜底——MCU 卡死了保护就没了。
  • 故障日志没保存,每次都凭印象。

调试方法

建议实验

STM32 C 代码骨架

/* ============================================
 * fault.c — 分级故障保护 + 黑匣子快照
 * 硬件保护 < 1μs,软件中断 < 50μs,主循环 < 10ms
 * ============================================ */

typedef enum {
    FAULT_NONE,
    FAULT_OVER_CURRENT,
    FAULT_OVER_VOLTAGE,
    FAULT_UNDER_VOLTAGE,
    FAULT_OVER_TEMP,
    FAULT_PHASE_LOSS,
    FAULT_ENCODER_LOST,
    FAULT_ANGLE_DIVERGENCE,
} fault_code_t;

/* === 黑匣子快照(链接脚本里放在掉电不丢的 RAM 段) === */
typedef struct __attribute__((packed)) {
    uint32_t magic;          // 0xDEADBEEF
    uint32_t timestamp_ms;
    fault_code_t code;
    float ia, ib, ic;
    float id, iq;
    float vd, vq;
    float duty_a, duty_b, duty_c;
    float theta_e;
    float speed_rpm;
    float udc;
    float temp_c;
    uint32_t crc32;
} fault_snapshot_t;

extern fault_snapshot_t __noinit_fault_snap __attribute__((section(".noinit")));

/* === 第一级:硬件保护(< 1μs,不靠 CPU) ===
 *   COMP1 比较 ADC4 (相电流) 和 DAC3 (1.8 × I_rated),
 *   超限 → BKIN_N → TIM1 MOE=0 → PWM 全关。
 *
 * 在 BKIN 的 NMI 中只做:拍快照 + 设置 fault flag */
void NMI_Handler(void) {
    if (TIM1->SR & TIM_SR_BIF) {
        TIM1->SR &= ~TIM_SR_BIF;
        save_snapshot(FAULT_OVER_CURRENT);
        g_state.fault_pending = 1;
    }
}

/* === 第二级:软件保护(PWM 中断尾部,< 50μs) === */
void check_software_faults(void) {
    /* 过流(含限幅前的瞬时电流) */
    float i_mag = sqrtf(g_state.ialpha * g_state.ialpha
                       + g_state.ibeta * g_state.ibeta);
    if (i_mag > I_OC_SOFT) {
        save_snapshot(FAULT_OVER_CURRENT);
        TIM1->BDTR &= ~TIM_BDTR_MOE;     // 软关 PWM
        g_state.fault_pending = 1;
    }
    /* 母线电压窗口 */
    if (g_state.udc > UDC_MAX) save_snapshot(FAULT_OVER_VOLTAGE);
    if (g_state.udc < UDC_MIN) save_snapshot(FAULT_UNDER_VOLTAGE);
    /* 相电流和检测缺相 */
    if (fabsf(g_state.ia + g_state.ib + g_state.ic) > 1.5f)
        save_snapshot(FAULT_PHASE_LOSS);
}

/* === 第三级:主循环(10 ms) === */
void fault_handler_task(void) {
    if (!g_state.fault_pending) return;
    /* 显示故障码、点亮 LED、发 CAN 报警、写 Flash 长期日志 */
    led_blink(g_snap.code);
    can_send_fault_msg(&__noinit_fault_snap);
    flash_log_append(&__noinit_fault_snap);
    /* 解锁条件(PWM 关 + 故障源消失 + 用户复位)*/
}

/* === 工程套路 ===
 * 1. 上电先读 __noinit_fault_snap,CRC 通过 = 上次复位前有故障,回放给用户
 * 2. 黑匣子触发要快,避免现场被破坏
 * 3. 永远不在中断里做 printf / Flash 写 / Delay
 */

下一步

随堂题

硬件过流保护和软件过流保护的关键区别?
  1. 硬件更慢
  2. 硬件直接关 PWM,不依赖 CPU 状态;软件靠中断 (正确)
  3. 软件更准
  4. 硬件成本高
提示:硬件比较器 → BKIN → 直接关 PWM 输出,CPU 卡死也救得了。软件保护需要中断响应(≥10μs)甚至更长,关键时刻可能来不及。两者必须并存。
调试时电机不正向转、反向反而正常,最可能的原因?
  1. Kp 太大
  2. 相序错(接线 swap 了任意两相,或软件 Ib/Ic 颠倒) (正确)
  3. 编码器坏
  4. 过流
提示:相序决定旋转磁场方向。两相互换 = 磁场反转 = 电机反转。修复办法:硬件 swap 任意两根线,或软件里把 Ib 和 Ic 的 ADC 通道互换。
示波器看到 Ia 一直比 Ib、Ic 高 1.5A 的固定偏移,最可能的原因?
  1. 过流
  2. Ia 通道 ADC 偏置未校准 (正确)
  3. 相序错
  4. PWM 频率漂移
提示:ADC 偏置每路独立。开机时电机不通电,理想 Ia=Ib=Ic=0,但 ADC 读数有几十 mV 偏差对应几百 mA。必须做"零电流采样平均"求出 offset,运行时减掉。
电流环 Iq 阶跃响应有 50% 超调,但稳态后 Iq 就稳。最可能的修复?
  1. 加大 Ki
  2. 减小 Kp 或加大限幅 (正确)
  3. 增大母线
  4. 换电机
提示:Kp 过大 → 阶跃瞬间过冲。如果 Kp 不能再减小(影响响应速度),可加大限幅减小积分饱和的释放冲击。Ki 与超调关系小。
黑匣子快照 (fault snapshot) 放在哪种内存最合适?
  1. 普通 RAM
  2. 链接脚本指定的 .noinit 段(复位不清零的 RAM) (正确)
  3. Flash
  4. EEPROM
提示:复位时普通 RAM 被清零,故障信息就丢了。.noinit 段在复位时不被 startup 代码清,下次开机能读出来。掉电场景再加 EEPROM/Flash 长期备份。