时间片+状态机实现裸机伪多任务
注:上述伪多任务是按个人理解命名的,实际上在裸机中跑的还是单线程,只是效果看上去是多线程。
时间片轮询方式是把MCU的执行时间划分为一块一块的,然后根据自己的需求去分配这一块一块的时间,而当你的任务(在时间片轮询方法中实现的任务)的执行时间足够短的时候可以实现多线程的现象,效果如下图所示:
而当你的任务所需要的的时间不能在一个时间片的情况下完成时,此时就会出现一直在执行某一个任务,而现象则是跟裸机大循环(前后台系统)类似的现象出现,如下图所示:
出现此现象的原因跟时间片轮询调度的机制有关(可参考我的另一篇文章时间片轮询系统学习),因为每一次调度(即进入时间心跳定时中断进行调度)如果你的上一次任务并没有完成的话,在退出调度(即退出中断以后)会接着执行上一次未完成的任务,而出现大循环。
那我们如何实现裸机长任务的调度呢?既然任务太长导致无法及时完成,那么我们便用状态机的方式将一个长任务分割成一个个状态,每一次调度只要完成其中一个状态(在此之中不能用类似延时的方式将执行时间拖长到比时间片还长,只能执行短暂的小于时间片的延时),那么就可以将CPU的执行时间重新划分为一块一块,每一块都有对应的状态需要去完成,而且执行状态时间足够短,那么便可以实现多任务的效果啦。
附上伪代码:(时间片轮询调度请参考我的另一份文章,这里只提供调用状态机的任务情况,这个项目实现的效果是上电:①动态扫描数码管②RGB呼吸灯,①和②需要有同时执行的现象)
void task_schedule(void)//任务调度函数
{
for (uint8_t i=0; i<TASKS_MAX; i++) // 逐个任务时间处理,TASKS_MAX有多少个任务
{
if (mytask_list[i].timer) // 时间不为0
{
mytask_list[i].timer--; // 减去一个节拍
if (mytask_list[i].timer == 0) // 时间减完了
{
mytask_list[i].timer = mytask_list[i].interval_time; // 恢复计时器值,从新下一次
mytask_list[i].run = 1; // 任务可以运行
}
}
}
}
void task_process(void)//任务执行函数
{
for (uint8_t i=0; i<TASKS_MAX; i++) // 逐个任务时间处理
{
if(mytask_list[i].enable_flag) //任务允许被运行
{
if (mytask_list[i].run) // 时间不为0
{
mytask_list[i].run = 0; // 标志清0
mytask_list[i].mytask(); // 运行任务
}
}
}
}
void digital_task(void)//动态数码管显示,任务1
{
digital_fsm();
}
void led_breath_task(void)//呼吸灯,任务2
{
led_breath_fsm();
}
以上纯属个人见解,有误之处还望大家指正。