4. 软件框架设计:主循环架构、状态机设计、任务调度与优先级
好,咱们进入实战环节的骨架部分——软件框架。很多同学拿到一个FOC项目,上来就写算法,写到一半发现逻辑乱成一锅粥。我早期也犯过这个错,后来被一个老工程师点醒:先搭框架,再填肉。今天这章,我就把在线校准这套框架怎么搭,掰开了讲给你听。
4.1 主循环架构:别让CPU闲着
嵌入式系统里,主循环就是心脏。我习惯把主循环分成三个层级:
- 硬实时层:电流环、速度环,必须用定时器中断触发,1kHz~20kHz不等。
- 软实时层:状态机轮询、通讯处理、校准逻辑,放在主循环里跑。
- 后台层:日志输出、参数保存、看门狗喂食,优先级最低。
在线校准属于软实时层。为什么?因为校准过程中,你不需要每微秒都去调整零位偏移,但也不能拖太久——电机可能还在转呢。
核心原则:主循环不能阻塞。校准过程中如果遇到通讯等待或EEPROM写入,必须拆成状态机片段,否则电流环一断,电机就抖。
我见过一个项目,工程师在校准函数里直接用了HAL_Delay(100),结果电机直接啸叫。嗯,从那以后,我所有校准逻辑都改成了非阻塞状态机。
4.2 状态机设计:三个状态走天下
在线校准的状态机,说白了就三个状态:空闲、校准中、校准完成。你想想看,再多就乱了。
| 状态 | 触发条件 | 主要动作 | 退出条件 |
|---|---|---|---|
| 空闲 | 系统初始化完成 / 校准完成 | 等待上位机指令或自动触发条件 | 收到校准开始指令 |
| 校准中 | 进入校准流程 | 执行旋转/对齐/采样/计算 | 零位偏移计算完成 |
| 校准完成 | 偏移值已写入 | 保存参数、切换回正常FOC | 系统复位或重新触发校准 |
这里有个坑——校准中状态内部其实还有子状态。我一般会再拆成:
- 子状态1:准备——关闭速度环,切换到开环电流模式。
- 子状态2:对齐——给d轴注入电流,让转子锁到已知位置。
- 子状态3:采样——读取编码器值,记录原始数据。
- 子状态4:计算——做平均或滤波,算出零位偏移。
- 子状态5:验证——再转一圈,确认偏移值正确。
小技巧:每个子状态都设一个超时计数器。我曾经遇到过电机负载太大,转子没锁住就采样,结果偏移值差了30度。加个超时保护,至少不会让系统死在那。
4.3 任务调度与优先级:谁先谁后要拎清
在线校准不是孤立的任务,它要和电流环、通讯、故障检测抢CPU。我常用的调度策略是:
- 电流环中断:最高优先级,谁都不能打断。校准期间电流环照常跑,只是目标值变了。
- 校准状态机:主循环中轮询,每次只执行一个子状态的一小步。
- 通讯任务:中等优先级,用环形缓冲区收数据,主循环里解析。
- 故障检测:每10ms检查一次过流、过温,发现异常立刻强制退出校准。
我个人习惯用时间片轮询+状态机的组合。不用RTOS,因为很多低成本MCU跑不了。代码结构大概这样:
void main_loop(void)
{
while(1)
{
// 1. 通讯解析(非阻塞)
comm_process();
// 2. 校准状态机(每次只跑一步)
calib_state_machine();
// 3. 故障检测(每10ms一次)
if(time_elapsed_ms >= 10)
{
fault_check();
time_elapsed_ms = 0;
}
// 4. 后台任务(日志、参数保存)
background_tasks();
}
}
你看,校准状态机只是主循环里的一个函数,每次调用只执行一个子状态的一小段代码。这样即使校准过程需要几秒钟,电流环也不会断。
注意:校准过程中如果检测到电机堵转或过流,必须立即强制退出校准状态,回到空闲状态,并置故障标志。我曾经在实验室里忘了加这个保护,结果校准到一半电机卡住,电流飙升到10A,差点烧了驱动板。
4.4 整体框架图:一张图看懂所有
下面这张SVG图,把主循环、状态机、任务优先级的关系画清楚了。你可以把它贴在开发板旁边,写代码时对照着看。
4.5 避坑指南:我踩过的几个坑
框架搭好了,但实际跑起来还是会遇到问题。我挑几个典型的说说:
- 坑1:校准过程中看门狗超时——校准如果涉及EEPROM写入,可能耗时几十毫秒。我习惯在校准子状态里手动喂狗,或者把写入操作拆成多次。
- 坑2:通讯干扰导致误触发校准——曾经有个项目,上位机误发了校准指令,电机在高速运转时突然进入校准模式,直接飞车。后来我在空闲状态加了速度阈值判断:电机转速超过5%额定转速时,忽略校准指令。
- 坑3:校准完成后的参数切换时机——零位偏移算出来后,不能直接在中断里修改。我一般会在主循环里设一个
pending_update标志,等电流环进入安全窗口(比如过零点)再切换。
我的习惯:每个状态切换都打印一条调试日志,包括时间戳和当前状态ID。这样出了问题,翻日志就能定位到是哪个子状态卡住了。别问我怎么知道的——调了三天三夜的教训。