在单片机上利用一个定时器和二行代码轻轻松松实现多任务的运行(基于时间片)

因为我常用的是stm32F4系列单片机,所以采用其滴答定时器作为时基定时器(如果你使用的单片机是别款,只要单片机上有个定时器都可以,另外也得有中断处理函数)(另外如果用的是stm32等单片机,片上具有滴答定时器,可以省掉1、2步骤,在HAL库下直接用HAL_GetTick()代替GetCount()即可,其他类似)

1.首先初始化定时器,本人一般设置定时时间为1ms,这个可以是具体情况而定。

2.定义一个全局变量,假设命名为Count,并初始化为0;然后再定时器相关的中断处理函数中进行Count++。

static long long Count = 0;
//定时器初始化,并设定定时时间和中断使能
void TimInit(){
    ...
}
//其相关的中断处理函数
void InterHandle(void){
    ....
    Count ++;
}
//防止外界修改Count
long long GetCount(void){
    return Count;
}

3.在相关的头文件里定义俩个宏,第一行代码中的(num)表示任务上一次的运行时刻,然后通过全局的时钟数减去上一次的运行时刻,再与设定好的时间(ms)进行比较,如果大于等於则表示时间已到可以进行此任务,否则不能进行。当可以进行该任务时,会有num=GetCount()的动作,表示得到当前时间,方便下次判断下次进此任务。举个例子:现在12点整,定个明天12点整的闹钟,每天循环,然后它会显示还有24个小时,然后等它到每天12点就响,也就是进闹钟任务。类比就是num表示当前时间12点整,getCount()就是系统时钟,自定义ms就是那个最大间隔24个小时,然后以此循环。

#define _BEGIN(ms)    static long long num = 0; if(GetCount() - num >= ms)do{ num = GetCount()

#define _END()    }while(0)

4.使用方式,先定义一个任务函数,千万要避免任务函数使用延时函数,不然可能会没效果的。一般一个任务的运行时间最好把控在所设置的最小时钟片内,比如我这定时为1ms,则处理每个任务所花的时间应该比1ms小。如果是在stm32上基本不用过多担心这个问题,只要不是跑什么耗时通信协议就好。那如果是在51上的话,那个最小时钟片还是定大一点比较稳,毕竟51的性能相对32而言是比较低的。

void Task1(void){
    _BEGIN(100);
    
    //doSomeing
    LED1 = ~LED1;//比如让小灯1每隔100ms闪一下
    _END();
}

void Task2(void){
    _BEGIN(150);
    
    //doSomeing
    LED2 = ~LED2;//比如让小灯2每隔150ms闪一下
    _END();
}

5.在主函数的while(1){}里调用任务函数便可简单的实现多任务了

6.总结,由于整体比较简单,自然就会有很多缺点了,比如在一个任务函数里面不能够再次延时和如果在某个任务太占时间会影响其它任务等,还得改进,不过这个已经适用很多情景了。如果处理的任务太过复杂,就可以考虑上os了。学习,共勉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章