0-1write MC/OS __Basics3

2021-07-23 09:40:45 星期五

七、就绪列表

在μC/OS-III中,任务被创建后,任务的TCB会被放入就绪列表中,表示任务在就绪,随时可能被运行。 就绪列表包含一个表示任务优先级的优先级表,一个存储任务TCB的TCB双向链表。

1、优先级表

优先级表在代码层面上来看,就是一个数组

/* 定义优先级表 */
CPU_DATA   OSPrioTbl[OS_PRIO_TBL_SIZE];

#define OS_PRIO_TBL_SIZE((OS_CFG_PRIO_MAX - 1u) / (DEF_INT_CPU_NBR_BITS) + 1u);//OS_CFG_PRIO_MAX表示支持多少个优先级,DEF_INT_CPU_NBR_BITS定义CPU整型数据有多少位

OS_PRIO_TBL_SIZE的值为1, 即优先级表只需要一个成员即可表示32个优先级。如果要支持64个优先级,即需要两个成员

优先级表时如何跟任务的优先级联系起来的?

优先级表中每个成员类型为32位,可以表示32个优先级。
假如创建一个优先级为3的任务,就将位【31-3】置1,位31表示的是优先级最高的任务,以此递减,位0表示的是最低的优先级。

1.1、优先级表函数讲解

  • OS_PrioInit()

/* 初始化优先级表 */
void OS_PrioInit( void )
{
    CPU_DATA i;

    /* 默认全部初始化为0 */
    for ( i=0u; i<OS_PRIO_TBL_SIZE; i++ )
    {
        OSPrioTbl[i] = (CPU_DATA)0;
    }
}
  • OS_PrioInsert()

/* 置位优先级表中相应的位 */
void  OS_PrioInsert (OS_PRIO  prio)
{
    CPU_DATA  bit;
    CPU_DATA  bit_nbr;
    OS_PRIO   ix;


    /* 求模操作,获取优先级表数组的下标索引 */
    ix             = prio / DEF_INT_CPU_NBR_BITS;//定位prio这个优先级对应优先级表数组的哪个成员,假设prio=3,则ix=0;

    /* 求余操作,将优先级限制在DEF_INT_CPU_NBR_BITS之内 */
    bit_nbr        = (CPU_DATA)prio & (DEF_INT_CPU_NBR_BITS - 1u);

    /* 获取优先级在优先级表中对应的位的位置 */
    bit            = 1u;
    bit          <<= (DEF_INT_CPU_NBR_BITS - 1u) - bit_nbr;//假设prio等于3,那么bit就等于28.

    /* 将优先级在优先级表中对应的位置1 */
    OSPrioTbl[ix] |= bit;
}
  • OS_PrioRemove()

/* 清除优先级表中相应的位 */
void  OS_PrioRemove (OS_PRIO  prio)
{
    CPU_DATA  bit;
    CPU_DATA  bit_nbr;
    OS_PRIO   ix;


    /* 求模操作,获取优先级表数组的下标索引 */
    ix             = prio / DEF_INT_CPU_NBR_BITS;

    /* 求余操作,将优先级限制在DEF_INT_CPU_NBR_BITS之内 */
    bit_nbr        = (CPU_DATA)prio & (DEF_INT_CPU_NBR_BITS - 1u);

    /* 获取优先级在优先级表中对应的位的位置 */
    bit            = 1u;
    bit          <<= (DEF_INT_CPU_NBR_BITS - 1u) - bit_nbr;

    /* 将优先级在优先级表中对应的位清零 */
    OSPrioTbl[ix] &= ~bit;
}
  • OS_PrioGetHighest()

/* 获取最高的优先级 */
OS_PRIO  OS_PrioGetHighest (void)
{
    CPU_DATA  *p_tbl;
    OS_PRIO    prio;


    prio  = (OS_PRIO)0;
    /* 获取优先级表首地址 */
    p_tbl = &OSPrioTbl[0];//从头开始搜索整个优先级表,直到找到最高的优先级。

    /* 找到数值不为0的数组成员 */
    while (*p_tbl == (CPU_DATA)0)
    {
        prio += DEF_INT_CPU_NBR_BITS;
        p_tbl++;
    }

    /* 找到优先级表中置位的最高的优先级 */
    prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl);//
    return (prio);
}

按照从高位到低位的顺序查找第一个置1的位的方法是通过计算前导0函数CPU_CntLeadZeros()来实现的。 从高位开始找1叫计算前导0,从低位开始找1叫计算后导0。
调用CPU_CntLeadZeros()可以计算出OSPrioTbl[0]第一个置1的位前面有3个0,那么这个3就是我们要查找的最高优先级, 至于后面还有多少个位置1我们都不用管,只需要找到第一个1即可。
CPU_CntLeadZeros()函数可由汇编或者C来实现,如果使用的处理器支持前导零指令CLZ,可由汇编来实现,加快指令运算,如果不支持则由C来实现。
Cortex-M系列处理器自带CLZ指令,所以CPU_CntLeadZeros()函数默认由汇编编写。


2、就绪列表

准备好运行的任务的TCB都会被放到就绪列表中,系统可随时调度任务运行。就绪列表在代码的层面上看就是一个 OS_RDY_LIST数据类型的数组OSRdyList[],数组的大小由宏OS_CFG_PRIO_MAX决定,支持多少个优先级, OSRdyList[]就有多少个成员。任务的优先级与OSRdyList[]的索引一一对应,比如优先级3的任务的TCB会被放到OSRdyList[3]中。

/* 就绪列表定义 */
OS_EXT    OS_RDY_LIST    OSRdyList[OS_CFG_PRIO_MAX];
typedefstruct  os_rdy_list         OS_RDY_LIST;

struct os_rdy_list {
    OS_TCB        *HeadPtr;
    OS_TCB        *TailPtr;
    OS_OBJ_QTY    NbrEntries;//表示OSRdyList[]同一个索引下有多少个任务。
};
//OSRdyList[]的成员与任务的优先级一一对应, 同一个优先级的多个任务会以双向链表的形式存在OSRdyList[]同一个索引下,那么HeadPtr就用于指向链表的头节点, TailPtr用于指向链表的尾节点,//该优先级下的索引成员的地址则称为该优先级下双向链表的根节点, 知道根节点的地址就可以查找到该链表下的每一个节点。

2.1、就绪列表函数讲解


在实现就绪列表相关函数之前,我们需要在结构体os_tcb中添加Prio、NextPtr和PrevPtr这三个成员, 然后在os.h中定义两个全局变量OSPrioCur和OSPrioHighRdy

struct os_tcb {
    CPU_STK         *StkPtr;
    CPU_STK_SIZE    StkSize;

    /* 任务延时周期个数 */
    OS_TICK         TaskDelayTicks;

    /* 任务优先级 */
    OS_PRIO         Prio;

    /* 就绪列表双向链表的下一个指针 */
    OS_TCB          *NextPtr;
    /* 就绪列表双向链表的前一个指针 */
    OS_TCB          *PrevPtr;
};

/* 在os.h中定义 */
OS_EXT    OS_PRIO  OSPrioCur;       /* 当前优先级 */
OS_EXT    OS_PRIO  OSPrioHighRdy;   /* 最高优先级 */
  • OS_RdyListInit()

void OS_RdyListInit(void)//将就绪列表OSRdyList[]初始化为空
{
    OS_PRIO i;
    OS_RDY_LIST *p_rdy_list;

    /* 循环初始化,所有成员都初始化为0 */
    for ( i=0u; i<OS_CFG_PRIO_MAX; i++ ) {
        p_rdy_list = &OSRdyList[i];
        p_rdy_list->NbrEntries = (OS_OBJ_QTY)0;
        p_rdy_list->HeadPtr = (OS_TCB *)0;
        p_rdy_list->TailPtr = (OS_TCB *)0;
    }
}
  • OS_RdyListInsertHead()

void  OS_RdyListInsertHead (OS_TCB  *p_tcb)
{
    OS_RDY_LIST  *p_rdy_list;
    OS_TCB       *p_tcb2;

    /* 获取链表根部 */
    p_rdy_list = &OSRdyList[p_tcb->Prio];

    /* CASE 0: 链表是空链表 */
    if (p_rdy_list->NbrEntries == (OS_OBJ_QTY)0) {
        p_rdy_list->NbrEntries =  (OS_OBJ_QTY)1;
        p_tcb->NextPtr         =  (OS_TCB   *)0;
        p_tcb->PrevPtr         =  (OS_TCB   *)0;
        p_rdy_list->HeadPtr    =  p_tcb;
        p_rdy_list->TailPtr    =  p_tcb;
    }
    /* CASE 1: 链表已有节点 */
    else {
        p_rdy_list->NbrEntries++;
        p_tcb->NextPtr         = p_rdy_list->HeadPtr;
        p_tcb->PrevPtr         = (OS_TCB    *)0;
        p_tcb2                 = p_rdy_list->HeadPtr;
        p_tcb2->PrevPtr        = p_tcb;
        p_rdy_list->HeadPtr    = p_tcb;
    }
}
  • OS_RdyListInsertTail()

void  OS_RdyListInsertTail (OS_TCB  *p_tcb)
{
    OS_RDY_LIST  *p_rdy_list;
    OS_TCB       *p_tcb2;


    /* 获取链表根部 */
    p_rdy_list = &OSRdyList[p_tcb->Prio];

    /* CASE 0: 链表是空链表 */
    if (p_rdy_list->NbrEntries == (OS_OBJ_QTY)0) {
        p_rdy_list->NbrEntries  = (OS_OBJ_QTY)1;
        p_tcb->NextPtr          = (OS_TCB   *)0;
        p_tcb->PrevPtr          = (OS_TCB   *)0;
        p_rdy_list->HeadPtr     = p_tcb;
        p_rdy_list->TailPtr     = p_tcb;
    }
    /* CASE 1: 链表已有节点 */
    else {
        p_rdy_list->NbrEntries++;
        p_tcb->NextPtr          = (OS_TCB   *)0;
        p_tcb2                  = p_rdy_list->TailPtr;
        p_tcb->PrevPtr          = p_tcb2;
        p_tcb2->NextPtr         = p_tcb;
        p_rdy_list->TailPtr     = p_tcb;
    }
}
  • OS_RdyListInsert()

OS_RdyListInsert()用于将任务的TCB插入就绪列表,插入的时候分成两步,第一步是根据优先级将优先级表中的相应位置位, 这个调用OS_PrioInsert()函数来实现,第二步是根据优先级将任务的TCB放到OSRdyList[优先级]中, 如果优先级等于当前的优先级则插入链表的尾部,否则插入链表的头部

/* 在就绪链表中插入一个TCB */
void  OS_RdyListInsert (OS_TCB  *p_tcb)
{
    /* 将优先级插入优先级表 */
    OS_PrioInsert(p_tcb->Prio);

    if (p_tcb->Prio == OSPrioCur)
    {
        /* 如果是当前优先级则插入链表尾部 */
        OS_RdyListInsertTail(p_tcb);
    }
    else
    {
        /* 否则插入链表头部 */
        OS_RdyListInsertHead(p_tcb);
    }
}
  • OS_RdyListMoveHeadToTail()

用于将节点从链表头部移动到尾部,移动的时候分四种情况,第一种是链表为空,无事可做; 第二种是链表只有一个节点,也是无事可做;第三种是链表只有两个节点;第四种是链表有两个以上节点

void  OS_RdyListMoveHeadToTail (OS_RDY_LIST  *p_rdy_list)
{
    OS_TCB  *p_tcb1;
    OS_TCB  *p_tcb2;
    OS_TCB  *p_tcb3;

    switch (p_rdy_list->NbrEntries) {
    case 0:
    case 1:
    break;

    case 2:
        p_tcb1              = p_rdy_list->HeadPtr;
        p_tcb2              = p_rdy_list->TailPtr;
        p_tcb1->PrevPtr     = p_tcb2;
        p_tcb1->NextPtr     = (OS_TCB *)0;
        p_tcb2->PrevPtr     = (OS_TCB *)0;
        p_tcb2->NextPtr     = p_tcb1;
        p_rdy_list->HeadPtr = p_tcb2;
        p_rdy_list->TailPtr = p_tcb1;
    break;

    default:
        p_tcb1              = p_rdy_list->HeadPtr;
        p_tcb2              = p_rdy_list->TailPtr;
        p_tcb3              = p_tcb1->NextPtr;
        p_tcb3->PrevPtr     = (OS_TCB *)0;
        p_tcb1->NextPtr     = (OS_TCB *)0;
        p_tcb1->PrevPtr     = p_tcb2;
        p_tcb2->NextPtr     = p_tcb1;
        p_rdy_list->HeadPtr = p_tcb3;
        p_rdy_list->TailPtr = p_tcb1;
    break;
    }
}
  • OS_RdyListRemove()

用于从链表中移除一个节点,移除的时候分为三种情况,第一种是链表为空,无事可做; 第二种是链表只有一个节点;第三种是链表有两个以上节点

void  OS_RdyListRemove (OS_TCB  *p_tcb)
{
    OS_RDY_LIST  *p_rdy_list;
    OS_TCB       *p_tcb1;
    OS_TCB       *p_tcb2;

    p_rdy_list = &OSRdyList[p_tcb->Prio];

    /* 保存要删除的TCB节点的前一个和后一个节点 */
    p_tcb1     = p_tcb->PrevPtr;
    p_tcb2     = p_tcb->NextPtr;

    /* 要移除的TCB节点是链表中的第一个节点 */
    if (p_tcb1 == (OS_TCB *)0)
    {
        /* 且该链表中只有一个节点 */
        if (p_tcb2 == (OS_TCB *)0)
        {
            /* 根节点全部初始化为0 */
            p_rdy_list->NbrEntries = (OS_OBJ_QTY)0;
            p_rdy_list->HeadPtr    = (OS_TCB   *)0;
            p_rdy_list->TailPtr    = (OS_TCB   *)0;

            /* 清除在优先级表中相应的位 */
            OS_PrioRemove(p_tcb->Prio);
        }
        /* 该链表中不止一个节点 */
        else
        {
            /* 节点减1 */
            p_rdy_list->NbrEntries--;
            p_tcb2->PrevPtr        = (OS_TCB   *)0;
            p_rdy_list->HeadPtr    = p_tcb2;
        }
    }
    /* 要移除的TCB节点不是链表中的第一个节点 */
    else
    {
        p_rdy_list->NbrEntries--;
        p_tcb1->NextPtr = p_tcb2;

        /* 如果要删除的节点的下一个节点是0,即要删除的节点是最后一个节点 */
        if (p_tcb2 == (OS_TCB *)0)
        {
            p_rdy_list->TailPtr = p_tcb1;
        }
        else
        {
            p_tcb2->PrevPtr     = p_tcb1;
        }
    }

    /* 复位从就绪列表中删除的TCB的PrevPtr和NextPtr这两个指针 */
    p_tcb->PrevPtr = (OS_TCB *)0;
    p_tcb->NextPtr = (OS_TCB *)0;
}

八、支持多优先级

在此之前,OS只支持两个任务互相切换,还没有到优先级,
现在开始往任务中加入优先级的功能。数字优先级越小,逻辑优先级越高。

1、定义优先级相关全局变量

/* 当前优先级 */
OS_EXT            OS_PRIO                OSPrioCur;
/* 最高优先级 */
OS_EXT            OS_PRIO                OSPrioHighRdy;

2、修改OSInit()函数

void OSInit (OS_ERR *p_err)
{
    /* 配置OS初始状态为停止态 */
    OSRunning =  OS_STATE_OS_STOPPED;

    /* 初始化两个全局TCB,这两个TCB用于任务切换 */
    OSTCBCurPtr = (OS_TCB *)0;
    OSTCBHighRdyPtr = (OS_TCB *)0;

    /* 初始化优先级变量 */
    OSPrioCur                       = (OS_PRIO)0;     //将1中新添加的优先级相关的全部变量,在OSInit()函数中进行初始化
    OSPrioHighRdy                   = (OS_PRIO)0;

    /* 初始化优先级表 */
    OS_PrioInit();

    /* 初始化就绪列表 */
    OS_RdyListInit();

    /* 初始化空闲任务 */
    OS_IdleTaskInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
}

3、修改任务控制块TCB

struct os_tcb {
    CPU_STK         *StkPtr;
    CPU_STK_SIZE    StkSize;

    /* 任务延时周期个数 */
    OS_TICK         TaskDelayTicks;

    /* 任务优先级 */
    OS_PRIO         Prio;     //在任务控制块中,加入优先级字段Prio。数据类型为OS_PRIO, 宏展开后是8位的整型,所以只支持255个优先级。

    /* 就绪列表双向链表的下一个指针 */
    OS_TCB          *NextPtr;
    /* 就绪列表双向链表的前一个指针 */
    OS_TCB          *PrevPtr;
};

4、修改OSTaskCreate()函数

void OSTaskCreate (OS_TCB        *p_tcb,
                OS_TASK_PTR   p_task,
                void          *p_arg,
                OS_PRIO       prio,//加入优先级字段。
                CPU_STK       *p_stk_base,
                CPU_STK_SIZE  stk_size,
                OS_ERR        *p_err)
{
    CPU_STK       *p_sp;
    CPU_SR_ALLOC();//定义一个局部变量,用来存CPU关中断前的中断状态,因为接下来将任务添加到就绪列表这段代码属于临界短代码,需要关中断。

    /* 初始化TCB为默认值 */
    OS_TaskInitTCB(p_tcb);

    /* 初始化栈 */
    p_sp = OSTaskStkInit( p_task,
                        p_arg,
                        p_stk_base,
                        stk_size );

    p_tcb->Prio = prio;//将形参传进来的优先级存到任务控制块TCB的优先级字段。

    p_tcb->StkPtr = p_sp;
    p_tcb->StkSize = stk_size;

    /* 进入临界段 */
    OS_CRITICAL_ENTER();

    /* 将任务添加到就绪列表,需要分成两步来实现:1、根据优先级置位优先级表中的相应位置; 2、将任务TCB放到OSRdyList[优先级]中,如果同一个优先级有多个任务,那么这些任务的TCB就会被放到OSRdyList[优先级]串成一个双向链表。*/
    OS_PrioInsert(p_tcb->Prio);
    OS_RdyListInsertTail(p_tcb);

    /* 退出临界段 */
    OS_CRITICAL_EXIT();(7)

    *p_err = OS_ERR_NONE;
}

5、修改OS_IdleTaskInit()函数

修改OS_IdleTaskInit()函数,是因为该函数调用了任务创建函数OSTaskCreate(),OSTaskCreate()我们刚刚加入了优先级, 所以这里我们要跟空闲任务分配一个优先级

/* 空闲任务初始化 */
void  OS_IdleTaskInit(OS_ERR  *p_err)
{
    /* 初始化空闲任务计数器 */
    OSIdleTaskCtr = (OS_IDLE_CTR)0;

    /* 创建空闲任务 */
    OSTaskCreate( (OS_TCB     *)&OSIdleTaskTCB,
                (OS_TASK_PTR )OS_IdleTask,
                (void       *)0,
                (OS_PRIO)(OS_CFG_PRIO_MAX - 1u),//设置空闲任务的优先级最低
                (CPU_STK    *)OSCfg_IdleTaskStkBasePtr,
                (CPU_STK_SIZE)OSCfg_IdleTaskStkSize,
                (OS_ERR     *)p_err );
}

6、修改OSStart()函数

加入优先级之后,OSStart()函数需要修改,具体哪一个任务最先运行,由优先级决定

/* 启动RTOS,将不再返回 */
void OSStart (OS_ERR *p_err)
{
if ( OSRunning == OS_STATE_OS_STOPPED ) {
#if 0
        /* 手动配置任务1先运行 */
        OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;
#endif
        /* 寻找最高的优先级 */
        OSPrioHighRdy   = OS_PrioGetHighest();//(1)
        OSPrioCur       = OSPrioHighRdy;

        /* 找到最高优先级的TCB */
        OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;//(2)
        OSTCBCurPtr     = OSTCBHighRdyPtr;

        /* 标记OS开始运行 */
        OSRunning       = OS_STATE_OS_RUNNING;

        /* 启动任务切换,不会返回 */
        OSStartHighRdy();

        /* 不会运行到这里,运行到这里表示发生了致命的错误 */
        *p_err = OS_ERR_FATAL_RETURN;
    } else {
        *p_err = OS_STATE_OS_RUNNING;
    }
}

7、修改PendSV_Handler()函数

PendSV_Handler()函数中添加了优先级相关的代码

;*******************************************************************
;                          PendSVHandler异常
;*******************************************************************

OS_CPU_PendSVHandler_nosave

; OSPrioCur   = OSPrioHighRdy
    LDR     R0, =OSPrioCur
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

; OSTCBCurPtr = OSTCBHighRdyPtr
LDR     R0, = OSTCBCurPtr
LDR     R1, = OSTCBHighRdyPtr
LDR     R2, [R1]
STR     R2, [R0]

LDR     R0, [R2]
LDMIA   R0!, {R4-R11}

MSR     PSP, R0
ORR     LR, LR, #0x04
CPSIE   I
BX      LR


NOP

ENDP

8、修改OSTimeDly()函数

任务调用OSTimeDly()函数之后,任务就处于阻塞态,需要将任务从就绪列表中移除

/* 阻塞延时 */
void  OSTimeDly(OS_TICK dly)
{
#if 0
    /* 设置延时时间 */
    OSTCBCurPtr->TaskDelayTicks = dly;

    /* 进行任务调度 */
    OSSched();
#endif

    CPU_SR_ALLOC();//(1)定义一个局部变量,用来存CPU关中断前的中断状态,因为接下来将任务从就绪列表移除这段代码属于临界短代码,需要关中断。

    /* 进入临界区 */
    OS_CRITICAL_ENTER();//(2)

    /* 设置延时时间 */
    OSTCBCurPtr->TaskDelayTicks = dly;

    /* 从就绪列表中移除 */
    //OS_RdyListRemove(OSTCBCurPtr);
    OS_PrioRemove(OSTCBCurPtr->Prio);//(3)

    /* 退出临界区 */
    OS_CRITICAL_EXIT();//(4)

    /* 任务调度 */
    OSSched();
}
//将任务从就绪列表移除, 这里只需将任务在优先级表中对应的位清除即可,暂时不需要把任务TCB从OSRdyList[]中移除, 因为接下来OSTimeTick()函数还是通过扫描OSRdyList[]来判断任务的延时时间是否到期。当我们加入了时基列表之后, 当任务调用OSTimeDly()函数进行延时,就可以把任务的TCB从就绪列表删除,然后把任务TCB插入时基列表, OSTimeTick()函数判断任务的延时是否到期只需通过扫描时基列表即可,时基列表在下一个代码实例中实现。

9、修改OSSched()函数

任务调度函数OSSched()不再是之前的两个任务轮流切换,需要根据优先级来调度

void OSSched(void)
{

CPU_SR_ALLOC();//(1)

/* 进入临界区 */
OS_CRITICAL_ENTER();//(2)

/* 查找最高优先级的任务 */
OSPrioHighRdy   = OS_PrioGetHighest();
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;

/* 如果最高优先级的任务是当前任务则直接返回,不进行任务切换 */
if (OSTCBHighRdyPtr == OSTCBCurPtr)
{
    /* 退出临界区 */
    OS_CRITICAL_EXIT();

    return;
}
/* 退出临界区 */
OS_CRITICAL_EXIT();//(5)

/* 任务切换 */
OS_TASK_SW();//(6)

}

10、修改OSTimeTick()函数

OSTimeTick()函数在SysTick中断服务函数中被调用,是一个周期函数,具体用于扫描就绪列表OSRdyList[], 判断任务的延时时间是否到期,如果到期则将任务在优先级表中对应的位置位

void  OSTimeTick (void)
{
    unsigned int i;
    CPU_SR_ALLOC();//(1)

    /* 进入临界区 */
    OS_CRITICAL_ENTER();//(2)

/* 扫描就绪列表中所有任务的TaskDelayTicks,如果不为0,则减1 */
#if 0
    for (i=0; i<OS_CFG_PRIO_MAX; i++)
    {
        if (OSRdyList[i].HeadPtr->TaskDelayTicks > 0)
        {
            OSRdyList[i].HeadPtr->TaskDelayTicks --;
        }
    }
#endif

    for (i=0; i<OS_CFG_PRIO_MAX; i++) //(3)
    {
        if (OSRdyList[i].HeadPtr->TaskDelayTicks > 0)
        {
            OSRdyList[i].HeadPtr->TaskDelayTicks --;
            if (OSRdyList[i].HeadPtr->TaskDelayTicks == 0)
            {
                /* 为0则表示延时时间到,让任务就绪 */
                //OS_RdyListInsert (OSRdyList[i].HeadPtr);
                OS_PrioInsert(i);
            }
        }
    }

    /* 退出临界区 */
    OS_CRITICAL_EXIT();//(4)

    /* 任务调度 */
    OSSched();
}

11、main()函数

int main(void)
{
    OS_ERR err;


    /* CPU初始化:1、初始化时间戳 */
    CPU_Init();

    /* 关闭中断 */
    CPU_IntDis();

    /* 配置SysTick 10ms 中断一次 */
    OS_CPU_SysTickInit (10);

    /* 初始化相关的全局变量 */
    OSInit(&err);//(1)

    /* 创建任务 */
    OSTaskCreate( (OS_TCB*)&Task1TCB,
                (OS_TASK_PTR )Task1,
                (void *)0,
                (OS_PRIO)1,//(2)
                (CPU_STK*)&Task1Stk[0],
                (CPU_STK_SIZE)  TASK1_STK_SIZE,
                (OS_ERR *)&err );

    OSTaskCreate( (OS_TCB*)&Task2TCB,
                (OS_TASK_PTR )Task2,
                (void *)0,
                (OS_PRIO)2,//(3)
                (CPU_STK*)&Task2Stk[0],
                (CPU_STK_SIZE)  TASK2_STK_SIZE,
                (OS_ERR *)&err );

    OSTaskCreate( (OS_TCB*)&Task3TCB,
                (OS_TASK_PTR )Task3,
                (void *)0,
                (OS_PRIO)3,//(4)
                (CPU_STK*)&Task3Stk[0],
                (CPU_STK_SIZE)  TASK3_STK_SIZE,
                (OS_ERR *)&err );
#if 0
/* 将任务加入到就绪列表 将任务插入就绪列表这部分功能由OSTaskCreate()实现,这里通过条件编译屏蔽掉。*/
    OSRdyList[0].HeadPtr = &Task1TCB;
    OSRdyList[1].HeadPtr = &Task2TCB;
#endif

    /* 启动OS,将不再返回 */
    OSStart(&err);
}

/*
*******************************************************************
*                              函数实现
*******************************************************************
*/
/* 软件延时 */
void delay (uint32_t count)
{
    for (; count!=0; count--);
}



void Task1( void *p_arg )
{
    for ( ;; ) {
        flag1 = 1;
        OSTimeDly(2);
        flag1 = 0;
        OSTimeDly(2);
    }
}

void Task2( void *p_arg )
{
    for ( ;; ) {
        flag2 = 1;
        OSTimeDly(2);
        flag2 = 0;
        OSTimeDly(2);
    }
}

void Task3( void *p_arg )
{
    for ( ;; ) {
        flag3 = 1;
        OSTimeDly(2);
        flag3 = 0;
        OSTimeDly(2);
    }
}
posted @ 2021-11-30 20:31  cswft  Views(87)  Comments(0Edit  收藏  举报