【19】从0到1教你写uC/OS-III————>时间片

  1. 简述:
    1. 我们让OS支持同一个优先级下,可以有多个任务的功能;
    2. 为同优先级任务可以分配不同的时间片;
    3. 当任务时间片用完的时候,任务会从 链表的头部移动到尾部;
    4. 让下一个任务共享时间片,以此循环;
    5. 修改之前编写的如下几个函数:
  2. 例程
    1. 任务控制块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;      
      };

       

    2. 增加  时间片调度函数
       /*********************************************************
       * 函数名:void OS_SchedRoundRobin(OS_RDY_LIST *p_rdy_list);
       * 描述  :
                  1、时间片是个可选的功能,由OS_CFG_SCHED_ROUND_ROBIN_EN控制
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
      
      void OS_SchedRoundRobin(OS_RDY_LIST *p_rdy_list)
      {
          OS_TCB  *p_tcb;
          
          //保存当前中断状态
          CPU_SR_ALLOC(); 
          //进入临界段
          CPU_CRITICAL_ENTER();
          
          p_tcb = p_rdy_list->HeadPtr;    //获取链表的第一个节点
          
          //如果TCB节点为空,则退出
          if(p_tcb == (OS_TCB *)0)
          {
              CPU_CRITICAL_EXIT();
              return;
          }
          //如果是空闲任务,也退出
          if(p_tcb == &OSIdleTaskTCB)
          {
              CPU_CRITICAL_EXIT();
              return;
          }
          
          //如果不是空闲任务,时间片自减
          if(p_tcb->TimeQuantaCtr > (OS_TICK)0)
          {
              p_tcb->TimeQuantaCtr--;
          }
          
          //时间片没有用完,则退出
          if(p_tcb->TimeQuantaCtr > (OS_TICK)0)
          {
              CPU_CRITICAL_EXIT();
              return;
          }
          
          //如果当前优先级只有一个任务,则退出
          if(p_rdy_list->NbrEntries < (OS_OBJ_QTY)2)
          {
              CPU_CRITICAL_EXIT();
              return;
          }
          //时间片耗完,将任务放到链表的最后一个节点
          OS_RdyListMoveHeadToTail(p_rdy_list);
          //重新获取任务节点a
          p_tcb = p_rdy_list->HeadPtr;
          
          //重载默认的时间片计数值
          p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;
          
          //退出临界段
          CPU_CRITICAL_EXIT(); 
      }
      #endif  //#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u

       

    3. 修改OSTimeTick函数
      /*********************************************************
       * 函数名:OSTimeTick(void)
       * 描述  :调用任务调度函数
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      void OSTimeTick(void)
      {
          OS_TickListUpdate();    //更新时基列表
          
      #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
          //时间片调度
          OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
          
      #endif    
          
          OSSched();  //任务调度
      }

       

    4. 修改OSTaskCreate函数
      /*********************************************************
       * 函数名:
                   void OSTaskCreate ( OS_TCB          *p_tcb,             //任务控制块指针
                                      OS_TASK_PTR     p_task,               //任务函数名
                                      void            *parg,              //形参,用于传递参数
                                      OS_PRIO         prio,               //任务优先级
                                      CPU_STK         *p_stk_base,        //指向任务堆栈的起始地址
                                      CPU_STK_SIZE    stk_size,           //任务堆栈的大小
                                      OS_ERR          *p_err              //错误码
                                      );
       * 描述  :创建任务
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      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_TICK         time_quanta,        //时间片在任务创建的时候由函数形参time_quanta指定
                          OS_ERR          *p_err              //错误码
                          )
      {
          CPU_STK     *p_sp;
          
          //保存CPU中断前的状态
          CPU_SR_ALLOC();
          
          //初始化TCB为默认值
          OS_TaskInitTCB(p_tcb);
          
          //初始化堆栈
          p_sp = OSTaskStkInit(  p_task,     //任务堆栈初始化
                                  p_arg,
                                  p_stk_base,
                                  stk_size
                              );
          p_tcb->Prio = prio;
          
          p_tcb ->StkPtr = p_sp;      //将剩余栈的栈顶指针p_sp保存到任务控制块TCB的第一个成员StkPtr中;
          p_tcb ->StkSize = stk_size; //任务堆栈大小保存到任务控制块TCB成员的StkSize中;
          
          //时间片相关初始化
          p_tcb->TimeQuanta   =   time_quanta;    //该变量表示任务能享有的最大的时间片是多少,该值一旦初始化后就不改变,除非认为修改
      #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
          p_tcb->TimeQuantaCtr = time_quanta;     //每经过一个系统时钟周期,该值会递减,如果该值为0,则表示时间片耗完
      #endif
          
          //进入临界段
          OS_CRITICAL_ENTER();
          
          //将任务添加到就绪列表
          OS_PrioInsert(p_tcb->Prio);
          OS_RdyListInsertTail(p_tcb);
          
          //退出临界段
          OS_CRITICAL_EXIT();
          
          *p_err = OS_ERR_NONE;       //函数执行到此表示无错误,返回OS_ERR_NONE;
      }

       

    5. 修改OS_IdleTaskInit函数
       /*********************************************************
       * 函数名:OS_IdleTaskInit(OS_ERR  *p_err);                    
       * 描述  :空闲任务初始化,放在系统初始化中
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      void    OS_IdleTaskInit(OS_ERR  *p_err)
      {
          //初始化空闲任务计数器,设置为0
          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_TICK     )0,
                          (OS_ERR     *)p_err
                      );
          
      }

       

  3. 总结
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值