OSCurTCB和OSNewTCB分别是当前运行任务的堆栈指针和要运行的新任务的堆栈指针。

  下一步是任务的创建了,任务是如何创建的。每个任务都有自己的堆栈空间,像是单独占用CPU一样,所以创建任务还需完成任务堆栈的初始化。

  需要知道CPU是如何出栈压栈的,保存了哪些寄存器,顺序是什么,堆栈的增长方向是什么。参考《cortexM3权威指南》,书中有详细的介绍。

  以下是c语言写的任务堆栈的初始化函数,位于文件OS_CPU.c中,如果需要移植,除了汇编部分OS_CPU_A.asm文件修改外,OS_CPU.c和OS_TYPE.h等文件也需要修改。仅这几个文件。

  OS_STK实际上是int32,因为stm32上堆栈指针是32位长度。第一个参数是任务的地址,即函数的地址,第二个参数是任务的堆栈指针。

OS_STK *OSTaskStkInit (void (*task),OS_STK *ptos)
{
    OS_STK *stk;
    stk    = ptos;                          /* get stack point       */
    *(stk)    = (uint32)0x01000000L;        /* xPSR                  */
    *(--stk)  = (uint32)task;               /* Entry Point           */
    *(--stk)  = (uint32)0xFFFFFFFEL;        /* R14 (LR)              */
    *(--stk)  = (uint32)0x12121212L;        /* R12                   */
    *(--stk)  = (uint32)0x03030303L;        /* R3                    */
    *(--stk)  = (uint32)0x02020202L;        /* R2                    */
    *(--stk)  = (uint32)0x01010101L;        /* R1                    */
    *(--stk)  = (uint32)0;                  /* R0 : argument         */
                                            /* Remaining registers   */
    *(--stk)  = (uint32)0x11111111L;        /* R11                   */
    *(--stk)  = (uint32)0x10101010L;        /* R10                   */
    *(--stk)  = (uint32)0x09090909L;        /* R9                    */
    *(--stk)  = (uint32)0x08080808L;        /* R8                    */
    *(--stk)  = (uint32)0x07070707L;        /* R7                    */
    *(--stk)  = (uint32)0x06060606L;        /* R6                    */
    *(--stk)  = (uint32)0x05050505L;        /* R5                    */
    *(--stk)  = (uint32)0x04040404L;        /* R4                    */
    return (stk);
}

/*
 * 创建新的任务
*/
TCB*  OSTaskCreate(void* task, OS_STK *stack,PRIO_TYPE prio)
{
 TCB *pTCB;
 OS_CPU_SR  cpu_sr = 0;
 
 OS_ENTER_CRITICAL();
 
 pTCB = OSGetFreeTCB(prio);
 if (NULL == pTCB)
 {
  OS_EXIT_CRITICAL();
  return NULL;
 }
 pTCB->pStackTop = OSTaskStkInit(task, stack);
 pTCB->CurPriority = prio;
 pTCB->TCBDelay = 0;
 
 TaskNUM++;
 OS_EXIT_CRITICAL();
 return pTCB;
}

  创建新任务函数很简单,只要懂了OSGetFreeTCB(prio);这个函数没啥问题。创建的任务,是一个有序的表,是一个存储元素为

  TCB类型的数组TCB  OSTCBTable[MAX_TASK_NUM];在这个数组中,先在OSTCBTable[0]中创建一个任务,如果再创建一个任务,这个任务比上个任务的优先级高,那么OSTCBTable[0]中存储优先级高的任务,那个之前先创建的低优先级的任务搬移到OSTCBTable[1]中。如果再创建一个任务,任务优先级会与前两个任务对比,若比前两个都低,放在第三个位置OSTCBTable[2]中,否则重新排序,总之,使OSTCBTable数组中的任务始终是按优先级从高到低的顺序排列。

  以下是这种思想实现的OSGetFreeTCB(prio)函数:

/*在TCB表中取一个空闲的节点,给新任务使用*/
/*对OSTCBTable表这个有序表进行插入排序*/
/*将优先级高的任务放在前面*/
TCB* OSGetFreeTCB(PRIO_TYPE prio)
{
 TCB *pTCB;
 int32 index=0,orgIndex;
 pTCB = &(OSTCBTable[0]);
 for (index = 0;index < TaskNUM+1;index++)
 {
  pTCB = OSTCBTable+index;
  /*已经是空闲TCB了,直接使用*/
  if (NULL == pTCB->pStackTop)
  {
   return (TCB*)pTCB;
  }
  /*若新任务优先级比较低或相等,则向后继续找*/
  if (pTCB->CurPriority >= prio)
  {
   continue;
  }
  else /*pTCB->CurPriority < prio 找到了该插入的位置了*/
  {
   /*保存当前位置*/
   orgIndex = index;
   /*从当前节点遍历到后一个使用了的节点*/
   for( index = TaskNUM ; index > orgIndex ; index-- )
   {
    pTCB = OSTCBTable+index;
    /*将前一个节点的数据,保存到当前节点*/
    _mem_copy((uint8 *)(pTCB),(uint8 *)(pTCB-1),sizeof(TCB));
   }
   _mem_clr((uint8 *)(pTCB-1),sizeof(TCB))  ;
  
   return (TCB*)(pTCB-1);
  }
 }
 return (TCB*)NULL;
}