a) (Os_cpu_c.c文件中的OSTaskStkInit()函数)μC/OS-Ⅱ中每个任务都有自己的堆栈,新建立一个任务时,必须初始化该任务的上下文,这些被初始化的上下文放在该任务的堆栈中(任务建立时堆栈中除了放初始化的上下文,还会放其他东西,后边会讲到),将会在任务开始运行时从堆栈中弹出来放到对应的寄存器中。但由于任务未曾运行过,所以一般情况下,除了状态寄存器(它的中断位决定着任务开始运行时中断是否开启)和程序计数器(放置任务的起始地址)必须认真设置之外,任务的上下文被初始化成什么值是无所谓的。但是由于μC/OS-Ⅱ会给新建立的任务传递一个参数,而有的编译器会把前几个参数通过寄存器传递,所以也会涉及到上下文的初始化。
b) (Os_cpu_a.asm文件中的OSStartHighRdy ()函数)μC/OS-Ⅱ总是运行当前处于就绪状态的最高优先级的任务(Highest Priority Task,后边简称为HPT)。系统启动时,需要运行第一个任务,这个任务也必须是当前的HPT,而启动这个HPT的工作是由函数OSStart()执行的。
OSStart()函数先找出当前的HPT,再调用OSStartHighRdy (),在OSStartHighRdy ()中把HPT的上下文从HPT的堆栈中弹出到对应的寄存器中,以启动HPT的运行,即μC/OS-Ⅱ中第一个运行的任务。
c) (Os_cpu_a.asm文件中的OSCtxSw()函数)这个函数执行任务切换的工作,函数中先把当前任务的上下文保存到该任务的堆栈中,再把HPT的上下文弹出到对应的寄存器中,任务切换就完成了。
d) (所有的中断服务函数,即ISR(Interrupt Service Routine))中断处理过程中:○1先保存当前运行任务A的上下文,○2进行具体的中断处理,○3把HPT的上下文弹出到对应的寄存器中,以转入任务HPT运行【注意当A是当前最高优先级任务时,A和HPT是相同的】。
e) (Os_cpu_a.asm文件中的OSIntCtxSw ()函数)这个函数是第(3)点中的○3处调用的,用来检查A是否HPT:○1如果A不是HPT就把HPT的上下文弹出到对应的寄存器中,以转入HPT运行;○2如果A是HPT就返回调用处(即ISR中),在ISR中会把A的上下文弹出到对应的寄存器中,以转入任务A运行。
四、让μC/OS-Ⅱ在MSP430上的移植支持用C语言编写中断处理程序
MSP430的一大特色是对C语言的支持相当好,连中断处理函数也能用C语言方便地实现,很多地方C编译器都已经帮用户做好。可惜的是μC/OS-Ⅱ在MSP430F149上的官方移植程序的中断处理函数必须用汇编语言才能编写,但移植μC\OS-II的其中一个目的就是为了更方便的编写程序,这样就与初衷有所矛盾。虽然也可以用C语言编写函数做中断处理的工作,然后再由汇编语言编写ISR对这个C函数进行调用,但对于一些并不熟悉汇编的用户而言,也是比较麻烦的,特别是当需要向C函数传递参数或获取返回值时,还得清楚从汇编向C函数传递参数的具体规则。所以我决定想办法改变移植的程序,使其在C语言中也能直接编写ISR。我使用的集成开发环境是官方网站提供的CCSv4.0(Code Composer Studio Version 4.0)。
/*
**************************************************************************************************************
* MAIN
*
* Note(s): 1) You SHOULD use OS_TASK_STK_SIZE (see OS_CFG.H) when setting OSTaskStkSize prior to calling
* OSInit() because OS_TASK_IDLE_STK_SIZE and OS_TASK_STAT_STK_SIZE are set to this value in
* OS_CFG.H.
**************************************************************************************************************
*/
void main (void)
{
/*---- Any initialization code prior to calling OSInit() goes HERE --------------------------------*/
/* IMPORTANT: MUST be setup before calling 'OSInit()' */
OSTaskStkSize = OS_TASK_STK_SIZE; /* Setup the default stack size */
OSTaskHardStkSize = OS_TASK_HARD_STK_SIZE; /* Setup the default hardware stack size */
OSInit(); /* Initialize "uC/OS-II, The Real-Time Kernel" */
/*---- Any initialization code before starting multitasking ---------------------------------------*/
OSTaskStkSize = OS_TASK_START_STK_SIZE; /* Setup the total stack size */
OSTaskHardStkSize = OS_TASK_START_HARD_STK_SIZE; /* Setup the hardware stack size */
OSTaskCreate(AppTaskStart, (void *)0, (OS_STK *)&AppTaskStartStk[OSTaskStkSize - 1], 0);
/*---- Create any other task you want before we start multitasking --------------------------------*/
OSStart(); /* Start multitasking (i.e. give control to uC/OS-II) */
}
/*
*********************************************************************************************************
* STARTUP TASK
*
* Description : This is an example of a startup task. As mentioned in the book's text, you MUST
* initialize the ticker only once multitasking has started.
*
* Arguments : p_arg is the argument passed to 'AppStartTask()' by 'OSTaskCreate()'.
*
* Notes : 1) The first line of code is used to prevent a compiler warning because 'p_arg' is not
* used. The compiler should not generate any code for this statement.
*********************************************************************************************************
*/
while (TRUE) { /* Task body, always written as an infinite loop. */
LED_Toggle(1);
OSTimeDly(OS_TICKS_PER_SEC / 10);
}
}
/*
*********************************************************************************************************
* CREATE APPLICATION TASKS
*
* Description : This function creates the application tasks.
*
* Arguments : p_arg is the argument passed to 'AppStartTask()' by 'OSTaskCreate()'.
*
* Notes : 1) The first line of code is used to prevent a compiler warning because 'p_arg' is not
* used. The compiler should not generate any code for this statement.
*********************************************************************************************************
*/