前后台 + 状态机架构
既然上面的问题是由于主循环中单个应用逻辑自身执行时间太长导致,那么我们就将其拆分,原本一个逻辑只能一次执行完,现在就拆分成多个步骤,每次执行只运行一个步骤而不是完整的逻辑,再用一个变量去记录当前执行到了哪个步骤,下次进入就执行下一个步骤。
这就是状态机编程(以 do_a 为例,其他主循环逻辑同 do_a ):
<p>void do_a(void) {</p><p> static unsigned char step = 0;</p><p> if (tick % 100 == 0) {</p><p> switch (step) {</p><p> case 0:</p><p> // 执行第一步</p><p> step++;</p><p> break;</p><p> case 1:</p><p> // 执行第二步</p><p> step++;</p><p> break;</p><p> case 2:</p><p> // 执行第三步</p><p> step = 0;</p><p> break;</p><p> default:</p><p> // 未知步骤,归零重来</p><p> step = 0;</p><p> break;</p><p> }</p><p> } else {</p><p> return;</p><p> }</p><p>}</p>
可以看到原本 do_a 我们将它看作一个完整不可分割的逻辑,执行完整个 do_a 才会退出,而现在我们将其拆分成了3个步骤,每执行完一个步骤就会退出 do_a 函数,直到下一次进入才会执行下一个步骤,这样一来就能有效缩短一次 do_a 执行的时间,从而大大降低其一次执行时间会超过所有逻辑中最小周期的可能性。主循环中其他应用逻辑也和 do_a 一样,利用更加细分的状态机模式来加快主循环的响应效率,进一步提高了裸机编程的稳定性和时间可控性。
状态机的加入也使得裸机编程走向了其终极形态,使其能够处理更加复杂的逻辑与应用,与此同时,其代码量和复杂度也极速上升,尤其是当你的主循环中有十几个甚至几十个任务逻辑,此时你就会面临地狱级的编程难度。
|