- 简述:
- 我们让OS支持同一个优先级下,可以有多个任务的功能;
- 为同优先级任务可以分配不同的时间片;
- 当任务时间片用完的时候,任务会从 链表的头部移动到尾部;
- 让下一个任务共享时间片,以此循环;
- 修改之前编写的如下几个函数:
- 例程
- 任务控制块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; };
- 增加 时间片调度函数
/********************************************************* * 函数名: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
- 修改OSTimeTick函数
/********************************************************* * 函数名:OSTimeTick(void) * 描述 :调用任务调度函数 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :内部调用 **********************************************************/ void OSTimeTick(void) { OS_TickListUpdate(); //更新时基列表 #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u //时间片调度 OS_SchedRoundRobin(&OSRdyList[OSPrioCur]); #endif OSSched(); //任务调度 }
- 修改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; }
- 修改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 ); }
- 任务控制块TCB
- 总结
【19】从0到1教你写uC/OS-III————>时间片
最新推荐文章于 2022-01-09 18:26:22 发布