【20】从0到1教你写uC/OS-III————>任务的挂起和恢复

  1. 简述
    1. uc/OS的任务支持挂起和恢复功能
    2. 挂起相当于暂停,暂停后从就绪列表中移除
    3. 恢复即重新将任务插入到就绪列表
    4. 一个任务挂起多少次就要被恢复多少次才能重新运行
  2. 例程代码
    1. 自定义任务的状态
      /*
      ************************************************************************************************************************
      *                                              任务状态
      ************************************************************************************************************************
      */  
      #define     OS_STATE_OS_STOPPED             (OS_STATE)(0u)
      #define     OS_STATE_OS_RUNNING             (OS_STATE)(1u)
      
                                                                      /* ------------------- TASK STATES ------------------ */
      #define  OS_TASK_STATE_BIT_DLY               (OS_STATE)(0x01u)  /*   /-------- SUSPENDED bit                          */
                                                                      /*   |                                                */
      #define  OS_TASK_STATE_BIT_PEND              (OS_STATE)(0x02u)  /*   | /-----  PEND      bit                          */
                                                                      /*   | |                                              */
      #define  OS_TASK_STATE_BIT_SUSPENDED         (OS_STATE)(0x04u)  /*   | | /---  Delayed/Timeout bit                    */
                                                                      /*   | | |                                            */
                                                                      /*   V V V                                            */
      
      #define  OS_TASK_STATE_RDY                    (OS_STATE)(  0u)  /*   0 0 0     Ready                                  */
      #define  OS_TASK_STATE_DLY                    (OS_STATE)(  1u)  /*   0 0 1     Delayed or Timeout                     */
      #define  OS_TASK_STATE_PEND                   (OS_STATE)(  2u)  /*   0 1 0     Pend                                   */
      #define  OS_TASK_STATE_PEND_TIMEOUT           (OS_STATE)(  3u)  /*   0 1 1     Pend + Timeout                         */
      #define  OS_TASK_STATE_SUSPENDED              (OS_STATE)(  4u)  /*   1 0 0     Suspended                              */
      #define  OS_TASK_STATE_DLY_SUSPENDED          (OS_STATE)(  5u)  /*   1 0 1     Suspended + Delayed or Timeout         */
      #define  OS_TASK_STATE_PEND_SUSPENDED         (OS_STATE)(  6u)  /*   1 1 0     Suspended + Pend                       */
      #define  OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED (OS_STATE)(  7u)  /*   1 1 1     Suspended + Pend + Timeout             */
      #define  OS_TASK_STATE_DEL                    (OS_STATE)(255u)

       

    2. 修改任务控制块TCB
      /*
      ************************************************************************************************************************
      *                                              OS_TCB 任务控制块
      ************************************************************************************************************************
      */    
      struct os_tcb
      {
          CPU_STK         *StkPtr;
          CPU_STK_SIZE    StkSize;
          
          //任务延时周期个数
          OS_TICK         TaskDelayTicks;
          
          //任务优先级
          OS_PRIO         Prio;
          
          //就绪列表的下一个指针
          OS_TCB          *NextPtr;
          //就绪列表的上一个指针
          OS_TCB          *PrevPtr;
          
          //时基列表相关字段
          OS_TCB          *TickNextPtr;       //指向链表中的下一个节点
          OS_TCB          *TickPrevPtr;       //指向链表中的上一个节点
          OS_TICK_SPOKE   *TickSpokePtr;      //每个被插入到链表的TCB都包含一个字段TickSpokePtr,用于回指到链表的根部
          
          //TickCtrMatch的值等于时基计数器OSTickCtr的值加上TickRemain的值,当TickCtrMatch的值等于OSTickCtr值的时候,表示等待到期,
          //TCB会从链表中删除
          OS_TICK         TickCtrMatch;       
          OS_TICK         TickRemain;         //设备任务还需要等待多少个时钟周期,每到来一个时钟周期,该值会递减
          
          //时间片相关字段
          OS_TICK         TimeQuanta;         //表示任务需要多少个时间片,单位为系统时钟周期Tick
          //表示任务还剩下多少个时间片,每到来一个系统时钟周期,TimeQuanCtr 会减1
          //当TimeQuantaCtr == 0,表示时间片用完,任务的TCB会从就绪列表链表的头部移动到尾部
          //好让下一个任务共享时间片
          OS_TICK         TimeQuantaCtr;     
      
          //任务状态
          OS_STATE        TaskState;
      #if OS_CFG_TASK_SUSPEND_EN  > 0u
          
          //任务挂起函数OSTaskSpuend()计数器
          //任务每挂起一次,SuspendCtr递增一次,一个任务挂起多少次,就要恢复多少次才能运行
          OS_NESTING_CTR  SuspendCtr; 
      
      #endif
      };

       

    3. 挂起函数OSTaskSuspend()
      /*********************************************************
       * 函数名:
                  void OSTaskSuspend(OS_TCB   *p_tcb, OS_ERR *p_err);    
       * 描述  :任务挂起函数
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      #if OS_CFG_TASK_SUSPEND_EN > 0u
      void OSTaskSuspend(OS_TCB   *p_tcb, OS_ERR *p_err)
      {
          //保存当前中断状态
          CPU_SR_ALLOC();
          //进入临界段
          OS_CRITICAL_ENTER();
          
          //是否挂起自己
          if(p_tcb == (OS_TCB *)0)
          {
              p_tcb = OSTCBCurPtr;
          }
          //如果挂起的是自己,判断调度器是否锁住,
          if(p_tcb == OSTCBCurPtr)
          {
              //如果调度器锁住则不能挂起自己
              if(OSSchedLockNestingCtr > (OS_NESTING_CTR)0)
              {
                  CPU_CRITICAL_EXIT();
                  *p_err = OS_ERR_SCHED_LOCKED;
                  return;
              }
          }
          
          *p_err = OS_ERR_NONE;
          
          //根据任务的状态来决定挂起的动作
          switch(p_tcb->TaskState)
          {
              case OS_TASK_STATE_RDY:
                      OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
                      p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
                      p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
                      OS_RdyListRemove(p_tcb);
                      OS_CRITICAL_EXIT_NO_SCHED();
                  break;
              case OS_TASK_STATE_DLY:
                      p_tcb->TaskState = OS_TASK_STATE_DLY_SUSPENDED;
                      p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
                      CPU_CRITICAL_EXIT();
                  break;
              case OS_TASK_STATE_PEND:
                      p_tcb->TaskState = OS_TASK_STATE_PEND_SUSPENDED;
                      p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
                      CPU_CRITICAL_EXIT();
                  break;
              case OS_TASK_STATE_PEND_TIMEOUT:
                      p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED;
                      p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
                      CPU_CRITICAL_EXIT();
                  break;
              case OS_TASK_STATE_SUSPENDED:
              case OS_TASK_STATE_DLY_SUSPENDED:
              case OS_TASK_STATE_PEND_SUSPENDED:
              case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                      p_tcb->SuspendCtr++;
                      CPU_CRITICAL_EXIT();
                  break;
              default:
                      CPU_CRITICAL_EXIT();
                      *p_err = OS_ERR_STATE_INVALID;
                  break;
          }
          
          //任务切换
          OSSched();
          
      }    
      #endif

       

    4. 恢复函数OSTaskResume()
      /*********************************************************
       * 函数名:
                  void OSTaskResume(OS_TCB    *p_tcb, OS_ERR  *p_err);    
       * 描述  :任务恢复
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      #if OS_CFG_TASK_SUSPEND_EN > 0u
      void OSTaskResume(OS_TCB    *p_tcb, OS_ERR  *p_err)
      {
          CPU_SR_ALLOC();
      
          *p_err  = OS_ERR_NONE;
      	/* 根据任务的状态来决定挂起的动作 */
          switch (p_tcb->TaskState) 
      	{
              case OS_TASK_STATE_RDY:
              case OS_TASK_STATE_DLY:
              case OS_TASK_STATE_PEND:
              case OS_TASK_STATE_PEND_TIMEOUT:
                   CPU_CRITICAL_EXIT();
                   *p_err = OS_ERR_TASK_NOT_SUSPENDED;
                   break;
      
              case OS_TASK_STATE_SUSPENDED:
                   OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
                   p_tcb->SuspendCtr--;
                   if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
                       p_tcb->TaskState = OS_TASK_STATE_RDY;
                       OS_TaskRdy(p_tcb);
                   }
                   OS_CRITICAL_EXIT_NO_SCHED();
                   break;
      
              case OS_TASK_STATE_DLY_SUSPENDED:
                   p_tcb->SuspendCtr--;
                   if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
                       p_tcb->TaskState = OS_TASK_STATE_DLY;
                   }
                   CPU_CRITICAL_EXIT();
                   break;
      
              case OS_TASK_STATE_PEND_SUSPENDED:
                   p_tcb->SuspendCtr--;
                   if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
                       p_tcb->TaskState = OS_TASK_STATE_PEND;
                   }
                   CPU_CRITICAL_EXIT();
                   break;
      
              case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                   p_tcb->SuspendCtr--;
                   if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
                       p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
                   }
                   CPU_CRITICAL_EXIT();
                   break;
      
              default:
                   CPU_CRITICAL_EXIT();
                   *p_err = OS_ERR_STATE_INVALID;
                   return;
          }
      
      	/* 任务切换 */
          OSSched();
      }
      #endif

       

  3. 总结
    1. 实验现象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值