虽然单片机的处理能力低下,可是咱们仍是要尽可能榨干它,以最少的资源干更多的事情,因此在单片机上进行多任务处理仍是很常见的事情,任务多了,资源仍是那些,每一个任务获得执行的周期一定拉长,势必会影响任务的实时性。
遇到这种状况,为了保证明时性,都会引入任务调度机制,对于ARM7或更高级的16位或32处理器,咱们能够加入一个RTOS来处理,但RTOS的任务调度和系统开销会占用很大一部分处理器资源的,对于通常的低档8位机显然难以承受。怎么办?想一想,引入RTOS不就是为了实时任务调度么,咱们本身调度一下不就完了嘛,费那事。不过本身调度是挺费事的,不过8位机也不会安排太多任务,下面就介绍一种保证明时性的任务调度方法。
通常无OS的单片机程序都是在初始化后直接进入死循环,几个要执行的任务都放在死循环中去周期循环调用。由于这个循环周期没法保证,因此死循环中每一个任务被调用执行的周期就没法保证,固然具备实时性要求的任务就没法保证在规定时间内获得处理。如今以一个范例来讲明这种任务调度方法,假定为某单片机安排了5个任务用Task1~Task5表示,其各任务的实时性要求和实测得最长执行时间以下表:
Task1
|
Task2
|
Task3
|
Task4
|
Task5
|
|
实时性要求(ms)
|
1
|
2
|
5
|
10
|
100
|
最长执行时间(ms)
|
0.1
|
0.2
|
0.5
|
0.3
|
1.2
|
由上表能够看出,五个任务放在一个死循环中顺序执行,最长的执行周期达到了2.3ms,这对于Task1和Task2来讲是没法忍受的,并且响应系统中断也要花费时间,虽然通常系统中断处理函数都很短。现假设有3个中断处理函数Int1~Int3,其最小中断周期和最长执行时间见下表:
Int1
|
Int2
|
Int3
|
|
最小中断周期(ms)
|
0.2
|
2
|
10
|
最长执行时间(ms)
|
0.02
|
0.05
|
0.05
|
如今我要保证最短的Task1的1ms响应时间,必须使得程序初始化后进入的死循环执行周期在1ms内,因而乎我对某些任务进行如下加工:
Task3拆分红5个最长执行时间为0.1ms的任务Task3.1~Task3.5。
Task5拆分红4个最长执行时间为0.3ms的任务Task5.1~Task5.4。
作完拆分后将这些子任务安排到5个组(Class1~Class5)里,分配以下:
|
Class1
|
Class2
|
Class3
|
Class4
|
Class5
|
任务
|
Task1,Task2
Task3.1,Task4
|
Task1,Task3.2
Task5.1
|
Task1,Task2
Task3.3,Task5.2
|
Task1,Task3.4
Task5.3
|
Task1,Task2
Task3.5,Task5.4
|
最长执行时间(ms)
|
0.7
|
0.5
|
0.7
|
0.5
|
0.7
|
如上表,再算上期间各中断的执行时间,每组的执行时间也不可能超过1ms吧。
好了,将这五个组按顺序放在死循环里,而且保证被拆分的每一个子任务在执行以前都去判断排在它前头的那个子任务是否被执行到,若是被执行过了则本段子任务执行,不然不执行(例Task3.3在执行前要去判断Task3.2是否被执行,并且本段子程序在执行后要给出标志,告知下段子程序Task3.4我执行过了)。这么作看看能不能知足每一个任务要求的实时响应时间?都在容许范围内吧。
若是但愿Task1可以实现精准的1ms定时执行,能够设置一个1ms的定时器来定时顺序切换这5个组。
上面的这种作法也算是实现一种简单的实时任务调度,其优势是:任务调度都在编程时作好了,在程序实际运行过程当中几乎不会占用额外的硬件资源和处理器时间。缺点是:编程麻烦,必须预先算准各任务和拆分的子任务的最长执行时间,不能有误差,并且编写出来的程序可读性差。
总的来讲,这种调度方法对于低档8位单片机来讲仍是一种不错的实时多任务的解决方案,行之有效,就是费点事。