MCU状态机设计,其实有的时候用的还是少,不过有些也会有一些使用,MCU做状态机,这话问到我心坎上了,状态机在MCU开发里那可是重中之重,逻辑要是乱了,整个项目都得跟着遭殃。我这一路走过来,在状态机设计上可没少折腾,有自己摸索出来不一样的好招式,也有被状态跳错整到心态爆炸的时候。
之前有个项目,是个智能小车的控制系统。我设计了挺复杂的状态机来控制小车的各种动作,像前进、后退、转弯、避障啥的。状态机里设置了好多状态,像待机状态、巡航状态、避障状态、充电状态等等,每个状态之间还有特定的跳转条件。
本来测试的时候好好的,可到了实际运行,小车突然就不听使唤了。一会儿该转弯的时候不转,一会儿又莫名其妙地进入充电状态。一会在地上跑的时候好像被烫到了,在那里不听使唤,好像那些四条腿走路不和的样子,我排查了好半天,才发现是状态跳转条件出了问题。有个状态跳转的逻辑判断写错了,导致小车在不该跳转的时候跳到了其他状态,整个控制逻辑全乱了。那几天我天天对着代码和状态图,眼睛都快看瞎了,心态也崩得不行,感觉自己之前的努力都白费了。
不过,经过每次教训,我也总结出了不少状态机设计的好方法。我最常用的就是画状态图,和流程图法,在开始写代码之前,我会先花时间把状态机的所有状态和跳转条件都画在纸上,就像画一幅地图一样。每个状态用一个方框表示,状态之间的跳转用箭头连接,箭头上还标注着跳转条件。这样,整个状态机的逻辑就一目了然了。在写代码的时候,我就对着这张状态图来写。每写一个状态的处理函数,我就看看状态图上这个状态有哪些输入和输出,以及它和其他状态之间的关系。这样写出来的代码,逻辑清晰,不容易出错。而且,在后期调试和修改的时候,这张状态图也能帮我快速定位问题。要是发现状态跳转有问题,我就看看状态图上对应的跳转条件是不是写错了,或者是不是漏掉了某些条件。 其实除了画状态图,我还喜欢用枚举和switch - case语句来实现状态机。
像下面的代码: typedef enum {
STATE_IDLE,
STATE_CRUISE,
STATE_AVOID,
STATE_CHARGE
} State;
或者在主循环里,用一个变量来保存当前的状态,再用switch - case语句来根据当前状态执行相应的操作和处理跳转条件。 State currentState = STATE_IDLE;
while (1) {
switch (currentState) {
case STATE_IDLE:
if (满足条件) {
currentState = STATE_CRUISE;
}
break;
case STATE_CRUISE:
if (障碍物) {
currentState = STATE_AVOID;
}
break;
}
}
这些都是我之前用过的,不过现在网上很多这些方法了。
|