ucOS是一个抢占式多任务操作系统,其核心就是人物调度机制,该机制保证了多个任务在一个MCU上并发执行。
关于多任务实现我们就不得不谈一谈一段程序运行的上下文。所谓程序运行的上下文就是指一段代码(一般以函数为基本单位)运行过程中需要使用到的资源,这个资源被我称之为上下文。这些资源包括当前系统的基本工作寄存器,函数使用到的零时变量,全局变量等等。当这些资源被给定后我们无论在何时去执行一个给定的地址开始的代码都将得到完全相同的结果。下边以具体代码为例讲解该过程,以下代码get_val为一个计算1到10累加和的函数,C代码如下:
unsigned char get_val(void)
{
unsigned char i = 0;
unsigned char temp = 0;
for(i = 0; i < 10; i++)
temp += i;
return temp;
}
要了解上下文信息我们需要查看汇编代码,汇编代码如下:
get_val:
C:0x0003 E4 CLR A
C:0x0004 FF MOV R7,A
C:0x0005 FE MOV R6,A
C:0x0006 EF MOV A,R7
C:0x0007 2E ADD A,R6
C:0x0008 FE MOV R6,A
C:0x0009 0F INC R7
C:0x000A BF0AF9 CJNE R7,#0x0A,C:0006
C:0x000D AF06 MOV R7,0x06
C:0x000F 22 RET
查看汇编代码我们发现该函数使用的系统资源仅仅为累加器A,寄存器R7,R6。因此在任何时间我们离开该函数,只要在重新执行函数时恢复离开时的上下文,那么函数执行完毕都能够得到正确的结果。例如当执行到C:0x0008处(0008指令还没有被执行),此时我们由于某种原因改变了PC的值指向了代码段Q(操作系统称这一过程为任务切换),当Q代码段执行完毕后再次返回到0008处执行,此时如果恢复R7,R6,和A那么我们将得到一致的结果。
操作系统就是通过在改变PC时保存当前上下文并装载目标PC处的上下文的方式实现了多任务并发执行。当然,操作系统所进行的上下文保存就并不只是保存R6,R7了,它不会根据哪个具体的任务是用了哪些具体资源而保存这个任务,它会采用一个统一的方式把任何任务可能是用到的任何资源都保存起来,虽然这样浪费了系统的存储空间但是它缺保持了任务切换的统一性和简单性。
在保存上下文时有几个需要注意的问题:
1.是否保存独占资源的上下文?比如系统当前一共有20个任务,只有任务8使用定时器2,那么在保存上下文时需要保存定时器2的相关配置么?
2.保存上下文时不会保存全局变量,因为全局变量本身就是用来传递信息用的,允许在其他地方被改变从而带给当前程序信息。
3.函数内部的零时变量不需要保存上下文,因为该变量时被存储到函数自身的栈上的。
这样系统根据某一种机制在特定时刻保存当前上下文切换的目标代码执行实现了多任务,这种机制被称为任务调度算法。 ucOS通过两种途径实现任务调度:中断和任务调用等待函数。 中断又包括系统tick中断和其他任务中断。