4. 运动控制中断源分析:编码器反馈中断、PWM定时器中断、限位开关中断、急停中断

做运动控制这么多年,我越来越觉得——中断管理是RTOS的灵魂。你想想看,电机转得快不快、停得准不准,全靠中断在背后撑着。今天咱们就来拆解四个最核心的中断源:编码器反馈、PWM定时器、限位开关、急停。每一个我都踩过坑,咱们一个一个说。

4.1 编码器反馈中断:位置闭环的“眼睛”

编码器中断,说白了就是告诉CPU:“电机转了多少步,现在在哪个位置。” 我最早做伺服驱动时,用的就是增量式编码器,每转一圈发几百个脉冲。每个脉冲都会触发一次中断,CPU得赶紧把位置值累加一下。

这里有个关键点:中断频率不能太高。我记得有一次,客户要求电机跑到3000转,编码器是2500线,算下来每秒钟要处理125000个中断。我的天,CPU直接跑满了,其他任务全被饿死。

核心要点:编码器中断的优先级要设得高,但中断服务函数(ISR)要写得极短。只做位置累加,别在里面算PID。

我个人的习惯是:在ISR里只放一个计数器累加,然后把位置数据扔到一个环形缓冲区里。主循环或者另一个中等优先级的任务再去算速度、做滤波。这样既保证了实时性,又不阻塞系统。

// 编码器中断服务函数(精简版)
void Encoder_ISR(void) {
    static int32_t pulse_count = 0;
    if (GPIO_ReadInputDataBit(ENC_PORT, ENC_PIN_A)) {
        pulse_count++;  // 正转
    } else {
        pulse_count--;  // 反转
    }
    // 把数据推入环形缓冲区,不在这里做任何计算
    RingBuf_Push(&encoder_buf, pulse_count);
}

嗯,这里要注意:编码器中断的抖动问题。我遇到过机械振动导致编码器信号毛刺,一个脉冲被误读成好几个。后来加了硬件滤波和软件去抖,才算稳定下来。

4.2 PWM定时器中断:速度控制的“心跳”

PWM定时器中断,是运动控制里最常用的定时中断。它决定了电机的换相频率和速度环的更新率。说白了,就是每隔固定时间触发一次,告诉系统:“该算下一拍的速度了。”

我一般把PWM中断的频率设在1kHz到20kHz之间。太低的话,电机噪音大、响应慢;太高的话,CPU负担重。你想想看,20kHz就是每50微秒一次中断,ISR里要是敢放个浮点运算,系统直接崩给你看。

PWM频率 中断周期 适用场景 我的建议
1 kHz 1 ms 步进电机、低速直流电机 适合简单控制,CPU负担低
5 kHz 200 μs 通用伺服、无刷电机 我常用的频率,平衡性好
20 kHz 50 μs 高速高精度伺服 小心CPU过载,建议用DMA
小技巧:PWM中断里不要直接修改占空比寄存器。我习惯用影子寄存器(shadow register)或者双缓冲机制,等PWM周期结束再更新,避免产生不完整的脉冲。

我曾经在一个项目里,PWM中断和编码器中断抢CPU时间,导致速度环抖动。后来我把PWM中断优先级设得比编码器低一级,同时在PWM中断里只做速度环计算,位置环放到任务里做。问题就解决了。

4.3 限位开关中断:安全的“最后一道防线”

限位开关中断,是运动控制里最不能省的中断。它负责在机械行程到达极限时,立刻停止电机。我见过太多因为限位失效导致撞机的事故了。

限位开关中断有几个特点:

  • 优先级必须最高——比编码器和PWM都高。因为这是安全相关的。
  • ISR里只做一件事——立即停止PWM输出,切断电机驱动使能。
  • 硬件和软件双重保护——我习惯在硬件上直接串联一个急停继电器,软件中断只是辅助。
警告:千万不要在限位中断里做复杂的逻辑判断!比如“先减速再停止”这种想法很危险。机械撞击就在毫秒之间,必须立刻切断动力。

我记得有一次调试三轴平台,Z轴限位开关的线被运动部件磨破了,偶尔短路一下。结果系统误触发限位中断,机器频繁急停。排查了两天才找到原因。后来我学乖了:限位开关的线一定要用屏蔽线,而且要走独立的线槽

// 限位开关中断服务函数(标准写法)
void LimitSwitch_ISR(void) {
    // 立即停止PWM输出
    TIM_Cmd(PWM_TIM, DISABLE);
    // 关闭电机使能
    GPIO_ResetBits(MOTOR_EN_PORT, MOTOR_EN_PIN);
    // 设置紧急停止标志
    g_emergency_stop = 1;
    // 通知RTOS任务(用信号量,不要在ISR里做复杂操作)
    xSemaphoreGiveFromISR(limit_sem, NULL);
}

4.4 急停中断:比限位更“狠”的存在

急停中断和限位开关中断有点像,但更彻底。限位开关是“到边界了,停一下”,急停是“不管什么情况,立刻、马上、全部停止”。

急停中断通常接一个物理按钮,按下后直接触发CPU的不可屏蔽中断(NMI)或者最高优先级的外部中断。我个人的做法是:急停中断里直接调用系统复位,或者切断整个驱动板的电源

你可能会问:“为什么不用软件慢慢停?” 我告诉你,急停场景下,往往是操作员已经看到危险了,比如机械臂要打到人了。这时候任何软件逻辑都是多余的,必须物理断电。

设计原则:急停中断的ISR里,不要依赖RTOS的任何服务。因为RTOS可能已经跑飞了。直接操作硬件寄存器,切断PWM、关闭驱动、拉低使能引脚。

我曾经在一个协作机器人项目里,把急停信号同时接到了两个地方:一个是CPU的中断引脚,另一个是驱动器的使能引脚(硬件直连)。这样即使CPU死机了,按下急停按钮也能直接切断电机动力。这叫“硬件冗余”,做运动控制一定要有这个意识。

4.5 四种中断的优先级与协作策略

好了,四种中断都讲完了。那它们之间怎么配合呢?我画了一张图,你看一眼就明白了。

运动控制中断优先级与协作关系图 优先级从高到低 急停中断(最高优先级) 物理断电 / 系统复位 / 不可屏蔽中断 限位开关中断(高优先级) 立即停止PWM / 关闭电机使能 / 设置急停标志 编码器反馈中断(中优先级) 位置累加 / 数据入队 / 不计算PID PWM定时器中断(低优先级) 速度环计算 / 占空比更新 / 影子寄存器 可抢占 可抢占 可抢占

从图里能看出来:急停 > 限位 > 编码器 > PWM。这个顺序是我多年实践总结出来的。急停和限位是安全相关的,必须最高;编码器是位置反馈,丢了脉冲就丢了位置;PWM是执行层,慢一点没关系,但不能丢。

避坑指南:我曾经把编码器中断优先级设得比限位还高,结果限位触发了,编码器还在抢CPU,电机多转了半圈才停下来。就这半圈,撞坏了夹具。从那以后,安全中断的优先级我再也没敢降过。

好了,四种中断源的分析就到这儿。记住一句话:中断优先级的设计,本质上是安全与性能的权衡。安全第一,性能第二,这个顺序不能乱。