os_task.c

  定位到uCOS-II/Source/os_task.c,该文件是任务的相关操作:

1. 修改任务优先级函数OSTaskChangePrio()

  OSTaskChangePrio()适用于用户动态改变一个任务的优先级,但新的优先级必须符合要求。

#if OS_TASK_CHANGE_PRIO_EN > 0u
INT8U  OSTaskChangePrio (INT8U  oldprio, INT8U  newprio)
{
#if (OS_EVENT_EN)               /* 事件控制块配置宏 */
    OS_EVENT  *pevent;
#if (OS_EVENT_MULTI_EN > 0u)    /* 多事件控制块配置宏 */
    OS_EVENT **pevents;
#endif
#endif

    OS_TCB    *ptcb;
    INT8U      y_new;
    INT8U      x_new;
    INT8U      y_old;
    OS_PRIO    bity_new;
    OS_PRIO    bitx_new;
    OS_PRIO    bity_old;
    OS_PRIO    bitx_old;

#if OS_CRITICAL_METHOD == 3u    
    OS_CPU_SR  cpu_sr = 0u;     //为CPU状态寄存器分配存储器
#endif

#if OS_ARG_CHK_EN > 0u          //允许参数检查

    //旧优先级数值不合法
    if (oldprio >= OS_LOWEST_PRIO) {
        if (oldprio != OS_PRIO_SELF) {
            return (OS_ERR_PRIO_INVALID);
        }
    }

    //新优先级不合法
    if (newprio >= OS_LOWEST_PRIO) {
        return (OS_ERR_PRIO_INVALID);
    }
#endif
    OS_ENTER_CRITICAL();            //进入临界区
    if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) { //不等于0说明已经存在优先级跟新优先级一样的任务了
        OS_EXIT_CRITICAL();
        return (OS_ERR_PRIO_EXIST);
    }

    //要改变优先级的任务是任务自己本身
    if (oldprio == OS_PRIO_SELF) { //OS_PRIO_SELF虽为0xff,但它指代任务自己
        oldprio = OSTCBCur->OSTCBPrio;  
    }

    //获取旧的优先级的任务的TCB
    ptcb = OSTCBPrioTbl[oldprio];

    //旧优先级的任务的TCB为空
    if (ptcb == (OS_TCB *)0) {
        OS_EXIT_CRITICAL(); 
        return (OS_ERR_PRIO);
    }

    //旧优先级的任务的TCB已经被保留/占领
    if (ptcb == OS_TCB_RESERVED) {
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_NOT_EXIST);
    }
#if OS_LOWEST_PRIO <= 63u
    y_new                 = (INT8U)(newprio >> 3u);     //通过优先级数值得到优先级组,即OSRdyTbl[]的下标Y
    x_new                 = (INT8U)(newprio & 0x07u);   //通过优先级数值得到OSRdyTbl[Y]成员的具体哪一位X
#else
    y_new                 = (INT8U)((INT8U)(newprio >> 4u) & 0x0Fu);
    x_new                 = (INT8U)(newprio & 0x0Fu);
#endif

    bity_new              = (OS_PRIO)(1uL << y_new);    //bity_new和bitx_new目的方便在就绪表中登记就绪
    bitx_new              = (OS_PRIO)(1uL << x_new);    //两个数值替代了稍微老点的版本的OSMapTbl[]表格

    OSTCBPrioTbl[oldprio] = (OS_TCB *)0;    /* 旧优先级的TCB不再使用,置空 */

    /* 将任务放在newprio指定的TCB中 */
    OSTCBPrioTbl[newprio] =  ptcb; 

    /* 更改任务的优先级相关的参数 */
    y_old                 =  ptcb->OSTCBY;
    bity_old              =  ptcb->OSTCBBitY;
    bitx_old              =  ptcb->OSTCBBitX;
    if ((OSRdyTbl[y_old] &   bitx_old) != 0u) { //若旧优先级的任务为就绪态
         OSRdyTbl[y_old] &= (OS_PRIO)~bitx_old;    //设置旧优先级的任务为非就绪态。(这步很重要,因为就旧任务的TCB已经为空了,
                                                //若不更改为非就绪态,那么它将会得到系统的调度,一旦被调度就运行出错了)
         if (OSRdyTbl[y_old] == 0u) {           //设置旧优先级的任务的任务组
             OSRdyGrp &= (OS_PRIO)~bity_old;
         }

         //既然旧优先级的任务原先就处于就绪态,那么更改完优先级后还是还原其为就绪态
         OSRdyGrp        |= bity_new;                       /* Make new priority ready to run          */
         OSRdyTbl[y_new] |= bitx_new;
    }

#if (OS_EVENT_EN)           /事件控制使能
    pevent = ptcb->OSTCBEventPtr;
    if (pevent != (OS_EVENT *)0) {  //若pevent等于0说明原优先级的任务跟event没有关联,即没有等待信号量、Mutex那些
                                    //反之,将旧优先级的任务的pevent迁移到新优先级的任务的pevent
        //清空
        pevent->OSEventTbl[y_old] &= (OS_PRIO)~bitx_old;    /* Remove old task prio from wait list     */
        if (pevent->OSEventTbl[y_old] == 0u) {
            pevent->OSEventGrp    &= (OS_PRIO)~bity_old;
        }

        //迁移
        pevent->OSEventGrp        |= bity_new;              /* Add    new task prio to   wait list     */
        pevent->OSEventTbl[y_new] |= bitx_new;
    }
#if (OS_EVENT_MULTI_EN > 0u)
    //一个任务可以等待多个事件,将这些事件放在一起,用OSTCBEventMultiPtr指向它们
    if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) {
        pevents =  ptcb->OSTCBEventMultiPtr;
        pevent  = *pevents;
        while (pevent != (OS_EVENT *)0) {
            pevent->OSEventTbl[y_old] &= (OS_PRIO)~bitx_old;   /* Remove old task prio from wait lists */
            if (pevent->OSEventTbl[y_old] == 0u) {
                pevent->OSEventGrp    &= (OS_PRIO)~bity_old;
            }
            pevent->OSEventGrp        |= bity_new;          /* Add    new task prio to   wait lists    */
            pevent->OSEventTbl[y_new] |= bitx_new;
            pevents++;
            pevent                     = *pevents;
        }
    }
#endif
#endif
    ptcb->OSTCBPrio = newprio;                              /* Set new task priority                   */

    //更新任务的TCB中与优先级相关的就绪表坐标参数
    ptcb->OSTCBY    = y_new;
    ptcb->OSTCBX    = x_new;
    ptcb->OSTCBBitY = bity_new;
    ptcb->OSTCBBitX = bitx_new;
    OS_EXIT_CRITICAL();
    if (OSRunning == OS_TRUE) {
        OS_Sched();    /* 优先级发生改变,自然需要重新调度 */
    }
    return (OS_ERR_NONE);
}
#endif

2. 创建任务函数OSTaskCreate()

  uCOS-II支持动态创建和静态创建任务:
  (1) 静态创建:在应用程序调用OSStart()之前创建好所有任务,OSStart()函数将全局变量OSRunning置一后系统开始调度
  (2) 动态创建:在OSStart()之后创建任务

  一般我们使用的是静态创建任务的方式。uCOS-II是一款RTOS,为保证实时性,不可在ISR中创建任务。

  uCOS-II是通过任务控制块TCB来管理任务的,所以创建一个任务的工作实质上是创建一个TCB,并通过TCB将任务代码和任务堆栈关联起来形成一个完整的任务。当然还要将被创建的任务为就绪态并引发一次调度。

#if OS_TASK_CREATE_EN > 0u
INT8U  OSTaskCreate (void   (*task)(void *p_arg),   //指向任务代码
                     void    *p_arg,                //传递给任务代码的参数
                     OS_STK  *ptos,                 //指向任务堆栈的栈顶
                     INT8U    prio)                 //任务的优先级
{
    OS_STK     *psp;
    INT8U       err;
#if OS_CRITICAL_METHOD == 3u 
    OS_CPU_SR   cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508          //IEC61508是标准,主要与风险和安全相关,不细究
    if (OSSafetyCriticalStartFlag == OS_TRUE) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return (OS_ERR_ILLEGAL_CREATE_RUN_TIME);
    }
#endif

#if OS_ARG_CHK_EN > 0u          //参数合法性判断使能
    if (prio > OS_LOWEST_PRIO) {
        return (OS_ERR_PRIO_INVALID);
    }
#endif
    OS_ENTER_CRITICAL();
    if (OSIntNesting > 0u) { //不可在中断ISR中创建任务
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_CREATE_ISR);
    }
    if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //不等于0表示已经存在任务,其优先级与要创建的任务的优先级一致。
                                             //等于0说明不存在
        OSTCBPrioTbl[prio] = OS_TCB_RESERVED; //先RESERVED任务控制块,RESERVED即占领

        //占领了位置了,下来可以放心操作该任务的相关设置
        OS_EXIT_CRITICAL();                          //进入临界区
        psp = OSTaskStkInit(task, p_arg, ptos, 0u);  //初始化栈
        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u);  //初始化该任务的TCB
        if (err == OS_ERR_NONE) {
            if (OSRunning == OS_TRUE) { //如果os已经在运行了,引发调度
                OS_Sched();
            }   //如果os还没运行呢?这里并没有这个else。不必着急,等下APP调用OSStart()时候会开启调度,这是系统的首次调度
        } else {        //创建任务失败,让出占领TCB的位置
            OS_ENTER_CRITICAL();
       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值