10. 插补周期定时器:硬件定时器配置、软件定时器使用、周期抖动控制
插补周期,说白了就是运动控制的心脏跳动。你想想看,一个插补算法算得再漂亮,如果定时器不准,那输出到电机上的轨迹就是歪的。我在做多轴联动项目时,就吃过这个亏——算法仿真完美,一上机就跑偏,查了三天才发现是定时器抖动在作怪。
今天咱们就把这个「心脏」拆开来看。我会从硬件定时器配置讲起,再聊软件定时器的灵活用法,最后重点说说周期抖动怎么控制。嗯,这部分内容,我个人觉得是RTOS运动控制里最容易被忽视,但又最关键的一环。
10.1 硬件定时器配置:选型与初始化
硬件定时器,是RTOS里最可靠的时钟源。它直接挂在CPU的时钟树上,不受任务调度影响。我习惯用芯片的通用定时器(比如STM32的TIM、NXP的PIT)来做插补周期基准。
配置时要注意几个关键参数:
- 时钟源:一般选内部高速时钟,别用外部晶振分频,容易受干扰
- 预分频系数:决定了定时器的计数精度。我一般设到能让计数器在1us内计数一次
- 自动重装载值:这个值直接决定了插补周期。比如1ms周期,就设1000
- 中断优先级:必须设为最高优先级,不能被其他任务打断
核心原则:硬件定时器的中断服务函数里,只做最轻量级的工作——比如设置一个信号量或者触发一个任务。千万别在里面做插补计算!
我曾经在一个项目中,把插补计算直接放在定时器中断里。结果呢?计算时间稍微超了一点,下一个周期就错过了,整个运动轨迹开始抖动。后来改成中断里只发信号,计算交给高优先级任务,问题就解决了。
10.2 软件定时器使用:灵活但需谨慎
软件定时器,是RTOS提供的一种「软时钟」。它基于系统滴答(SysTick)实现,可以动态创建、删除、修改周期。相比硬件定时器,它更灵活,但精度差一些。
在运动控制里,我一般这样用软件定时器:
- 非实时性任务:比如状态监控、日志记录、参数更新
- 辅助定时:比如插补开始前的延时、加减速阶段的过渡等待
- 看门狗:监控硬件定时器是否正常工作
但要注意,软件定时器的精度受系统滴答影响。如果系统滴答是1ms,那软件定时器的周期误差就在±1ms。对于插补周期来说,这个误差太大了。所以,主插补周期必须用硬件定时器,软件定时器只能打辅助。
我的习惯:硬件定时器负责「节拍」,软件定时器负责「节奏」。节拍必须精准,节奏可以稍微灵活。
10.3 周期抖动控制:从根源解决问题
周期抖动,就是实际定时周期和理论周期之间的偏差。你想想看,如果理论是1ms,实际有时候0.9ms,有时候1.1ms,那插补出来的轨迹能平滑吗?
抖动的来源主要有三个:
- 中断延迟:高优先级中断打断了定时器中断
- 任务抢占:其他任务占用了CPU,导致定时器任务不能及时执行
- 计算超时:插补计算本身耗时太长,超过了周期时间
针对这些,我总结了一套「三板斧」:
| 抖动来源 | 控制方法 | 优先级 |
|---|---|---|
| 中断延迟 | 关闭其他中断,或降低其优先级 | 高 |
| 任务抢占 | 插补任务设为最高优先级,且不可被抢占 | 中 |
| 计算超时 | 优化算法,或拆分为多个周期执行 | 高 |
嗯,这里要特别说一下「计算超时」。我曾经在一个五轴联动项目里,插补周期设了1ms,但算法算一次要1.2ms。结果就是每5个周期就丢一个,电机嗡嗡响。后来我把算法拆成两步:第一步在周期内算完粗插补,第二步在下一个周期开始前算完精插补。这样虽然增加了代码复杂度,但抖动问题彻底解决了。
避坑指南:我曾经在FreeRTOS里直接用vTaskDelayUntil()做周期控制,以为很准。结果发现任务被挂起后,再恢复时周期就乱了。后来改用硬件定时器+二值信号量,才真正做到了微秒级精度。
10.4 实战:一个稳定的插补周期实现
下面是我在项目中常用的实现框架。核心思路是:硬件定时器产生周期中断,中断里释放信号量,插补任务等待信号量后执行计算。
// 硬件定时器中断服务函数
void TIM_IRQHandler(void) {
if (TIM_GetITStatus(TIMx, TIM_IT_Update)) {
TIM_ClearITPendingBit(TIMx, TIM_IT_Update);
// 释放信号量,通知插补任务
xSemaphoreGiveFromISR(interp_sem, NULL);
}
}
// 插补任务
void InterpolationTask(void *pvParameters) {
while (1) {
// 等待信号量,超时设为最大值
xSemaphoreTake(interp_sem, portMAX_DELAY);
// 执行插补计算
// 注意:这里必须保证计算时间 < 插补周期
InterpolationStep();
// 输出到驱动器
DriveOutput();
}
}
这个框架的好处是:定时器中断只做最轻量的事,插补计算在任务里执行,不会被其他中断打断。而且,如果计算超时了,信号量会累积,下一个周期会连续执行两次——虽然不完美,但至少不会丢步。
10.5 周期抖动的测量与优化
怎么知道你的定时器抖不抖?我建议用示波器量一个GPIO的翻转。在插补任务开始和结束时翻转GPIO,看波形就能直观看到抖动情况。
如果发现抖动,按这个顺序排查:
- 先看中断优先级:定时器中断是不是最高?
- 再看任务优先级:插补任务是不是最高?
- 然后看计算时间:有没有超过周期?
- 最后看系统负载:其他任务是不是太占CPU?
我记得有一次,抖动始终在±50us左右,怎么优化都降不下去。后来发现是DMA传输占用了总线,导致定时器读取计数值时被延迟。解决办法是把DMA优先级降低,或者用双缓冲技术。嗯,这种问题,不实际调一调,光看代码是看不出来的。
总结一下:插补周期定时器,硬件是骨架,软件是血肉,抖动控制是灵魂。三者缺一不可。
这张图把咱们今天讲的内容串起来了。硬件定时器是基础,软件定时器是补充,抖动控制是保障。三者配合好了,你的运动控制才算真正「稳」了。
最后一个小建议:如果你刚开始做运动控制,先别追求极致精度。把硬件定时器配好,插补任务跑起来,用示波器看看抖动。等你能把抖动控制在±10us以内,再考虑优化算法。一步一步来,别急。