三.UC/OS-Ⅱ任务管理
三.UC/OS-Ⅱ任务管理
目录
3. 试写出OSStartHighRdy( )函数的示意代码
1.UC/OS –II中的任务
- uC/OS –II 2.5版本支持64个任务,每个任务一个特定的优先级。数字越小,优先级越高
- 系统总是运行进入就绪态优先级最高的任务
- 任务优先级号就是任务编号(ID).优先级号也被一些内核功能函数调用。如OsTaskChangePrio( )及OsTaskDel( ).
- 系统占用了8个任务,保留优先级为0、1、2、3、OS_LOWEST_PRIO-3、 OS_LOWEST_PRIO-2、 OS_LOWEST_PRIO-1、 OS_LOWEST_PRIO-0
- 即:建议不使用上述最高4个和最低4个优先级,用户任务仍可达56个
UC/OS-II开关中断的方法
UC/OS-II定义了两个宏调用来开关中断:
- OS_ENTER_CRITICAL( ) (禁止中断的宏)
- OS_EXIT_CRITICAL( ) (启用中断的宏)
通常成对出现
2. 任务状态
- 睡眠态(task dormant)
- 就绪态(task ready)
- 运行态(task running)
- 等待状态(task waiting)
- 中断服务态(ISR running)
1.睡眠态又称(休眠状态)(task dormant)
- 指任务驻留在程序空间(ROM或RAM),还没有交给系统来管理的状态
- 任务交给系统通过调用以下函数之一来实现:
OSTaskCreate()
OSTaskCreateExt()
- 告知系统:
- 任务的起始地址
- 任务建立时,用户给任务赋予的优先级
- 任务要使用的栈空间大小等
2.就绪态(task ready)
- 任务一旦创建就进入就绪态,准备运行
- 任务的创建可以是在多任务开始之前,也可以动态地由一个运行着的任务创建
- 若刚创建任务的优先级高于创建它的任务的优先级,它将立即获得cpu的使用权
- 任务可通过OSTaskDel()返回睡眠态;或调用该函数让另一个任务进入睡眠态
3. 运行态(task running)
- 就绪的任务只有当所有优先级高于它的任务都转为等待状态,或被删除后,才能进入运行态
- 任何时刻只有一个任务处于运行态
- 调用OSStart()可以启动多任务。该函数只能在启动时调用一次
- OSStart()运行用户初始化代码中已经建立的、进入就绪态的优先级最高的任务
4.等待状态(task waiting)
- 正在运行的任务可以通过下面的调用进入等待状态。延迟时间到,立即强制执行任务切换,让下一个优先级最高、并进入就绪态的任务执行。
- 等待时间过去后,系统服务(内部)函数OSTimeTick()使延迟了的任务进入就绪态,用户无需在应用程序代码中调用这个函数
- 正在运行的任务可能需要通过调用函数等待某一事件发生。如果该事件并未发生,任务就进入等待状态
5.中断服务态(ISR running)
- 正在执行的任务是可以被中断的,除非该任务将中断关闭,或系统将中断关闭。被中断的任务便进入了中断服务态。
- 响应中断后,正在运行的任务被挂起,中断服务子程序控制了CPU的使用权
- 中断服务子程序可能会报告一个或多个事件的发生,而使一个或多个任务进入就绪态
- 上述情况下,从中断服务子程序返回之前,uC/OS –II 要判定:
当所有的任务都在等待时间发生或等待延迟时间结束时,uC/OS –II 执行被称为空闲任务(Idle Task)的内部函数,即:OSTaskIdle()
任务状态转换图:
3.任务控制块(TCB)
- 任务控制块 OS_TCB是一个数据结构,保存该任务的相关参数,包括任务堆栈指针、状态、优先级、任务表位置、任务链表指针等
- 所有的任务控制块分为两条链表:
空闲链表
使用链表
- 当任务的CPU使用权被剥夺时,系统用它来保存该任务的状态全部驻留在RAM中
typedef struct os_tcb {
OS_STK *OSTCBStkPtr(当前任务堆栈栈顶指针);
#if OS_TASK_CREATE_EXT_EN>0
void *OSTCBExtPtr; (指向用户定义的任务控制块扩展)
OS_STK *OSTCBStkBottom;(指向任务堆栈栈底指针)
INT32U OSTCBStkSize;(存有栈中可容纳的指针元数目)
INT16U OSTCBOpt;
INT16U OSTCBId; (存储任务的识别码ID,备用)
#endif
struct os_tcb *OSTCBNext; (任务控制块OS-TCB双向链表的后链接)
struct os_tcb *OSTCBPrev; (任务控制块OS-TCB双向链表的前链接)
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN
OS_EVENT *OSTCBEventPtr;(指向事件控制块的指针)
#endif
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
void *OSTCBMsg;(指向传递给任务的消息的指针)
#endif
INT16U OSTCBDly;
INT8U OSTCBStat;(任务的状态字)
INT8U OSTCBPrio; (任务的优先级)
INT8U OSTCBX;
INT8U OSTCBY;
INT8U OSTCBBitX;
INT8U OSTCBBitY;
#if OS_TASK_DEL_EN
BOOLEAN OSTCBDelReq;
#endif
} OS_TCB;
Ucos-II任务代码的一般框架
void MyTask( void *pdata )
{
for(;;)
{
可以被中断的用户代码;
OS_ENTER_CRITICAL(); //进入临界段(关中断)
不可以被中断的用户代码;
OS_EXIT_CRITICAL(); //退出临界段(开中断)
可以被中断的用户代码;
}
}
4. 空任务列表
- 所有的任务控制块都被放置在任务控制块列表数组OSTCBTbl[ ]中
- 系统初始化时,所有任务控制块被链接成空任务控制块的单向链表
- 任务建立后,空任务控制块指针OSTCBFreeList指向的任务控制块就赋给了该任务,然后OSTCBFreeList的值调整为指向链表中的下一个空任务控制块
- 任务一旦被删除,任务控制块就还给空任务链表
5.任务级的任务调度--OSSched
- UC/OS是占先式实时多任务内核,优先级最高的任务一旦准备就绪,则拥有CPU的所有权即开始投入运行。
- UC/OS中不支持时间片轮转法,每个任务的优先级要求不一样且是唯一的。因此,任务调度就是:查找准备就绪的最高优先级的任务并进行上下文切换。
- UC/OS任务调度所花的时间为常数,与应用程序中建立的任务数无关。
7.就绪表
根据就绪表确定最高优先级两个关键:
- 优先级数分解为高三位和低三位分别确定
- 高优先级有着小的优先级号
1.根据优先级找到任务在就绪任务表中的位置
把优先级转换为2进制 得到8位二进制数,其中的值表示OSRdyTbl [ n ],
的值表示OSRdyGrp [ n ]。如下图所示:
任务就绪表的三种基本操作包括:插入任务到任务就绪表、从任务就绪表中删除任务和查找最高优先级的就绪任务。
以下是三种基本操作的C代码:
1.入表操作:
在程序中,可以用类似下面的代码把优先级别为prio的任务置为就绪状态:
OSRdyTbl[prio>>3] | = OSMapTbl[prio&0x07];
OSRdyGrp | = OSMapTbl[prio>>3];
2.出表操作:
如果要使一个优先级别为prio的任务脱离就绪状态则可使用如下类似代码:
if((OSRdyTbl[prio>>3] &= ~OSMapTbl[prio&0x07]) == 0)
OSRdyGrp&=~OSMapTbl[prio>>3];
3.查表操作:
在就绪表中计算机查找最高优先级别任务的代码:
y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[y]];
prio = (y<<3) +x;
8.任务调度器(task scheduler)
OSTCBHighRdy 待运行任务控制块OSTCBCur 正在运行的运行任务控制块
9.任务切换的机理
任务切换就是中止正在运行的任务(当前任务),转而去运行另外一个任务的操作,当然这个任务应该是就绪任务中优先级别最高的那个任务
将被挂起的任务寄存器入栈将较高优先级任务的寄存器出栈
任务级的任务切换宏OS_TASK_SW()
OS_TASK_SW()是宏调用,含有微处理器的软中断指令。因为,系统假定任务切换是靠中断级代码完成的。
OS_TASK_SW()将处理器相关的软件中断机制封装起来,便于操作系统移植
10. 调度时机
1.用函数OSTaskCreate( )创建任务
应用程序通过调用OSTaskCreate( ) 函数来创建一个任务,OSTaskCreate( )函数的原型如下:
INT8U OSTaskCreate (
void (*task)(void *pd),//指向任务的指针
void *pdata, //传递给任务的参数
OS_STK *ptos, //指向任务堆栈栈顶的指针
INT8U prio //任务的优先级
)
2.uC/OS-II的任务框架
void task_xxx(void *pdata)
{
/* 该任务的初始化工作 */
……
/* 进入该任务的死循环 */
while(1)
{
……
}
}
或者写作这种形式:
3. 试写出OSStartHighRdy( )函数的示意代码
void OSStartHighRdy() {
调用用户定义的OSTaskSwHook();
OSRuning = TRUE;
得到将要恢复运行任务的堆栈指针: Stack pointer = OSTCBHighRdy->OSTCBStkPtr;
从新任务堆栈中恢复处理器的所有寄存器;
执行中断返回指令;
}
本文来自博客园,作者:种星记,转载请注明原文链接:https://www.cnblogs.com/zhongxingji/p/17697232.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix