UCOSⅢ学习总结1: void OSTaskCreate();

OSTaskCreate 函数

任务的堆栈,任务的函数实体,任务的 TCB 最终需要联系起来才能由系统进行统一调
度。那么这个联系的工作就由任务创建函数 OSTaskCreate 来实现。


/*p_tcb 是任务控制块指针。OS_TCB是一个结构体,是一个任务的身份证,(1)*/

 void  OSTaskCreate ( OS_TCB                 *p_tcb,              
                     OS_TASK_PTR   p_task,   /*p_task 是任务函数名,类型为  typedef
                                            void  (*OS_TASK_PTR)  (void *p_arg);  */                       void          *p_arg,    /*p_arg 是任务形参,用于传递任务参数。
                                                   void 类型以便于参数类型的转换*/
                     CPU_STK       *p_stk_base,  /*p_stk_base 用于指向任务堆栈的起始地
                                                    址。也就是自己创建数组的第0个元素*/
                     CPU_STK_SIZE    stk_size,    /*stk_size 表示任务堆栈的大小。CPU_STK_SIZE    是一个 无符号32位的整型变量,在cpu.h中定义   typedef  unsigned  int     CPU_INT32U;   ypedef  CPU_INT32U  CPU_ADDR;  typedef  CPU_ADDR  CPU_STK_SIZE;*/

                     OS_ERR         *p_err)   (2)    /*p_err 用于存错误码, uC/OS-III 中为函数的返回值预先定义了很多错误码,通过这些错误码我们可以知道函数是因为什么出错。*/
       {                                                                                       //函数主体
             CPU_STK    *p_sp;    //定义一个CPU_STK类型的指针,*p_sp
           p_sp = OSTaskStkInit  (p_task,    /*OSTaskStkInit()是任务堆栈初始化函
                                                 数。 p_sp 指向任务栈顶*/
                                  p_arg,  //p_arg 是任务形参,就是上文函数需要传入的参数
                                 p_stk_base,  //p_stk_base 用于指向任务堆栈的起始址。
                                  stk_size);    (3)  //stk_size 表示任务堆栈的大小。
                                  p_tcb->StkPtr = p_sp;    /*将剩余栈的栈顶指针 p_sp 保存到任务控制块 TCB 的第一个成员StkP中。*/
                                  p_tcb->StkSize = stk_size;   /*将任务堆栈的大小保存到任务控制块 TCB 的成员 StkSize 中。*/
                                   *p_err = OS_ERR_NONE;   /*函数执行到这里表示没有错误,即 OS_ERR_NONE。*/
   }

(1)BCT  结构体:为任务的身份证,如下所示,刚开始我们只在tcb结构体中添加两个成员,之后会慢慢增加。

struct os_tcb
{
        CPU_STK              *StkPtr;            //指向任务栈 栈顶指针。
        CPU_STK_SIZE    StkSize;         //任务堆栈的大小。
};
/***********************************************************************************/
(2)ucos中部分错误代码的定义

    typedef     enum    os_err {
     OS_ERR_NONE                            = 0u,

     OS_ERR_A                                    = 10000u,
     OS_ERR_ACCEPT_ISR            = 10001u,
                                    
     OS_ERR_B                                    = 11000u,

    OS_ERR_C                                     = 12000u,
    OS_ERR_CREATE_ISR             = 12001u,

    /* 篇幅限制,中间部分删除,具体的可查看源码 */

    OS_ERR_X                                 = 33000u,

    OS_ERR_Y                                  = 34000u,
    OS_ERR_YIELD_ISR                = 34001u,

    OS_ERR_Z                                  = 35000u
 }  OS_ERR;
/***********************************************************************************/
(3)OSTaskStkInit()函数的分析    OSTaskStkInit() 是任务堆栈初始化函数。当任务第一次运行的时
候,加载到 CPU 寄存器的参数就放在任务堆栈里面,在任务创建的时候,预先初始化好堆栈。 

/* 任务堆栈初始化 */
 CPU_STK *OSTaskStkInit (OS_TASK_PTR  p_task,       /* p_task 是任务名,指示着任务的入口地址,在任务切换的时候,
                                                                                       需要加载到 R15,即 PC 寄存器,这样 CPU 就可以找到要运行的任务。*/
                                                  void         *p_arg,                    /*p_arg 是任务的形参,用于传递参数,在任务切换的时候,需要
                                                                                                        加载到寄存器 R0。 R0 寄存器通常用来传递参数。*/
                                                  CPU_STK      *p_stk_base,      /*p_stk_base 表示任务堆栈的起始地址下面可用于算出栈顶地址*/
                                                  CPU_STK_SIZE   stk_size)     /*stk_size 表示任务堆栈的大小,数据类型为 CPU_STK_SIZE,在
                                                                                                          Cortex-M3 内核的处理器中等于 4 个字节,即一个字。*/
   {                                                                 //函数主体
    CPU_STK  *p_stk;                                         

    p_stk = &p_stk_base[stk_size];                      /*获取任务堆栈的栈顶地址, ARMCM3 处理器的栈是由高地址向
                                                    低地址生长的。所以初始化栈之前,要获取到栈顶地址,然后栈地址逐一递减即可。*/


/*任务第一次运行的时候,加载到 CPU 寄存器的环境参数我们要
 预先初始化好。 初始化的顺序固定, 首先是异常发生时自动保存的 8 个寄存器,即 xPSR、
R15、 R14、 R12、 R3、 R2、 R1 和 R0。其中 xPSR 寄存器的位 24 必须是 1, R15 PC 指针必
须存的是任务的入口地址, R0 必须是任务形参,剩下的 R14、 R12、 R3、 R2 和 R1 为了调
试方便,填入与寄存器号相对应的 16 进制数。*/

                                                                                     /* 异常发生时自动保存的寄存器        
    *--p_stk = (CPU_STK)0x01000000u;                        /* xPSR的bit24必须置1                                     */
   *--p_stk = (CPU_STK)p_task;                                     /* 任务的入口地址                                         */
    *--p_stk = (CPU_STK)0x14141414u;                        /* R14 (LR)                                               */
    *--p_stk = (CPU_STK)0x12121212u;                        /* R12                                                    */
    *--p_stk = (CPU_STK)0x03030303u;                        /* R3                                                     */
   *--p_stk = (CPU_STK)0x02020202u;                        /* R2                                                     */
   *--p_stk = (CPU_STK)0x01010101u;                        /* R1                                                     */
    *--p_stk = (CPU_STK)p_arg;                              /* R0 : 任务形参                                          */

/*剩下的是 8 个需要手动加载到 CPU 寄存器的参数,为了调试方
便填入与寄存器号相对应的 16 进制数。*/
                                                                           /* 异常发生时需手动保存的寄存器                            */
    *--p_stk = (CPU_STK)0x11111111u;                        /* R11                                                    */
    *--p_stk = (CPU_STK)0x10101010u;                        /* R10                                                    */
   *--p_stk = (CPU_STK)0x09090909u;                        /* R9                                                     */
    *--p_stk = (CPU_STK)0x08080808u;                        /* R8                                                     */
    *--p_stk = (CPU_STK)0x07070707u;                        /* R7                                                     */
    *--p_stk = (CPU_STK)0x06060606u;                        /* R6                                                     */
    *--p_stk = (CPU_STK)0x05050505u;                        /* R5                                                     */
    *--p_stk = (CPU_STK)0x04040404u;                        /* R4                                                     */
    return (p_stk);                  /*返回栈指针 p_stk,这个时候 p_stk 指向剩余栈的栈顶。*/
 }

任务创建好之后,我们需要把任务添加到一个叫就绪列表的数组里面, 表示任务已经
就绪,系统随时可以调度。

 /* 将任务加入到就绪列表 */
  OSRdyList [0].HeadPtr = &Task1TCB;     /*把任务 TCB 指针放到 OSRDYList 数组里面。
            OSRDYList 是一个类型为 OS_RDY_LIST 的全局变量  OS_EXT OS_RDY_LIST           OSRdyList        [OS_CFG_PRIO_MAX];OS_CFG_PRIO_MAX 是一个定义,表示这个系统支持多少个优先级(刚开始暂时不支持多个优先级,往后章节会支持)例如 #define OS_CFG_PRIO_MAX     32u ,      OS_RDY_LIST  是就绪列表的数据类型,在 os.h 中声明*/ (4)

(4) OS_RDY_LIST 里面目前暂时只有两个 TCB 类型的指针,一个是头指针,一个是尾指针

  typedef    struct      os_rdy_list    OS_RDY_LIST; 

  struct os_rdy_list {
     OS_TCB       *HeadPtr;     //TCB 类型的 头指针
     OS_TCB        *TailPtr;        //TCB 类型的 尾指针   指向不同的TCB控制块,实现链表
 };

 

 


在 uC/OS-III 中,将任务添加到就绪列表其实是在 OSTaskCreate()函数中完成的。每当任务创建好就把任务添加到就绪列表,表示任务已经就绪。只是目前这里的就绪列表的实现还是比较简单,不支持优先级,不支持双向链表,只是简单的将任务控制块放到就绪列表的数组里面。
总结:1. 任务创建函数  void  OSTaskCreate (), (内有OSTaskStkInit () 初始化指向栈顶指针

           2.把创建好的任务加入就序列表,OSRdyList [0].HeadPtr = &Task1TCB   就是将 结构体类型的数组 第0个元素内,os_rdy_list 结构体的成员 *HeadPtr    指向创建好的任务。   至此任务创建完成。

 

你可能感兴趣的:(UCOSⅢ学习总结1: void OSTaskCreate();)