uC/OS-II 任务相关常用API使用

1、任务的创建、调度、其他任务管理API

这些API都在os_task.c中实现。

1.1 任务的创建

任务的创建其实质是创建一个任务控制块,并把它与任务程序代码(C函数)任务堆栈(私有堆栈)关联起来形成一个完整的任务;并使刚刚创建的任务进入就绪状态,引发一次任务调度

INT8U  OSTaskCreate (void   (*task)(void *p_arg), void    *p_arg,OS_STK  *ptos,NT8U    prio)

这个函数用于创建一个任务。

创建任务的时机:1、在多任务系统启动前创建;2、由一个运行的任务创建

注意:任务不能由中断服务程序ISR创建。

分析各个参数:task  是一个指向任务程序代码,程序代码类型 void taskFun(void *p_arg);

p_arg 是一个指向在任务首次执行时传递给任务的参数area区域;

ptos    是一个指向任务堆栈栈顶。如果OS_STK_GROWTH设置为1,则栈是向下生长的,ptos就指向内存的最高地址;如果OS_STK_GROWTH设置为0,则栈是向上生长的,ptos指向内存的最低地址。

prio  是任务的优先级。唯一的优先级,数字越小,优先级越高。

返回值:成功则返回OS_ERR_NONE

失败则根据不同失败的原因有不同的返回值:

优先级已经存在——OS_PRIO_EXIT;   

优先级无效——OS_ERR_PRIO_INVALID

从中断中创建任务——OS_ERR_TASK_CREATE_ISR        

 OSTaskCreate 这个任务创建函数内部逻辑: 检查任务的优先级是否合法-->检查优先级表看该优先级是否被使用。如果没被使用,初始化任务堆栈,获得并初始化任务控制块----》上述均没有问题后,就在任务计数器加1,如果多任务调度(uC/OS-II的核存于运行状态)已经开始,则进行一次任务调度。

先初始化堆栈,再err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u);

任务控制块--->私有堆栈----->任务代码

私有堆栈初始化,我们看看堆栈里存了什么数据

OS_STK *OSTaskStkInit(void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)

如果使用了FPU的话就保存FPU寄存器,否则只保存通用寄存器。注意入栈顺序

如果开启了FPU并且使用Lazy Stacking特性,首先把FPSCR S0~S15 入栈;再把xPSR PC LR R12 R0~R3入栈;接着是是剩下的S16~S31入栈,最后R4~R11手动入栈。

再来看看扩展版本的创建任务----这和OSTaskCreate功能很类似,只是需要指定额外的任务信息。

INT8U  OSTaskCreateExt (void   (*task)(void *p_arg),void    *p_arg,OS_STK  *ptos,INT8U    prio,
                       
INT16U   id,OS_STK  *pbos,INT32U   stk_size,void    *pext,INT16U   opt)

多指定了 任务的标识;任务堆栈栈底的指针;任务堆栈的容陵;指向附加数据域的指针;用于设定操作的选项 

红色部分就是与OSTaskCreate相比要多指定的任务参数。

操作的选项有

OS_TASK_OPT_STK_CHK----为任务检查堆栈

OS_TASK_OPT_STK_CLR-----当任务创建时清除堆栈

OS_TASK_OPT_SAVE_FP-----任务切换时保存FPU的寄存器的值。

1.2 任务的挂起和恢复

挂起任务——就是停止这个任务的运行,使得任务切换到等待状态。

恢复任务——就是使任务恢复到就绪状态。

下面是uC/OS-II实时系统中任务挂起、恢复、运行三态的转移关系的示意图。

 

在uC/OS-II实时系统中,用户任务可以通过调用系统提供的OSTaskSuspend()函数来挂起自己或者是除空闲任务之外的其他任务。

被OSTaskSuspend()挂起的任务,只能在其他任务中通过调用恢复函数OSTaskResume()使其恢复为就绪状态。 

1.2.1 挂起任务API

INT8U  OSTaskSuspend (INT8U prio)

这个API用来挂起任务,通过传递的参数优先级prio来挂起指定优先级prio的任务;或者挂起任务本身OS_PRIO_SELF。

参数prio:待挂起的任务的优先级,挂起自身就指定参数为OS_PRIO_SELF.

返回值: 成功挂起----OS_ERR_NONE

不允许挂起空闲任务-----OS_ERR_TASK_SUSPEND_IDLE

指定的优先级无效------OS_ERR_PRIO_INVALID

想挂起的任务不存在------OS_ERR_TASK_SUSPEND_PRIO

想挂起的任务指定了互斥锁----OS_ERR_TASK_NOT_EXITS

挂起任务实质上:对于挂起的是任务本身,则必须删除任务在就绪表的就绪标志,并在任务控制块成员OSTCBState中做挂起记录,再引发一次任务调度,以使CPU去运行其他任务

对于挂起的是其他任务时,只需要删除任务就绪表中被挂起任务的就绪标志,并在任务控制块成员OSTCBStat中做挂起记录。

1.2.2 恢复任务 

INT8U  OSTaskResume (INT8U prio)

根据优先级prio确定这是一个已存在的挂起任务,同时它不是一个等待任务(任务控制块成员OSTCBDly=0)时,就清除任务控制块成员OSTCBStat中的挂起记录并使任务就绪,最后调用调度器OSSched()进行一次任务调度,成功则返回OS_NO_ERR。

挂起任务恢复时,确保它不是处于阻塞态,否则不会从等待态转为就绪态。

1.3 任务优先级切换

INT8U  OSTaskChangePrio (INT8U  oldprio,INT8U  newprio)

这个API可以用来动态切换任务的优先级。注意新的任务优先级必须可用 

返回值: OS_ERR_NONE----切换成功

OS_ERR_PRIO_INVALID---指定的优先级无效

OS_ERR_PRIO_EXIST----新的优先级已经存在了

OS_ERR_PRIO-----OLD任务不存在

OS_ERR_TASK_NOT_EXIST---该任务已经加了线程锁

1.4 查询任务的信息

INT8U  OSTaskQuery (INT8U    prio,  //待查询任务的优先级

OS_TCB  *p_task_data                      //存储任务信息的结构

)

在应用程序运行过程中需要了解一个任务的指针、堆栈等信息,调用上述API函数OSTaskQuery()来获取选定的任务信息 ---任务控制块的指针,成功则返回OS_NO_ERR。

1.5 任务删除

所谓删除一个任务,就是把该任务置于睡眠状态。具体而言,就是把被删除任务的任务控制块从任务控制块链表中删除,并归还给空任务控制块链表,然后在任务就绪表中把该任务的就绪状态位置0,这样该任务鱼就不能再被调度器所调用。即任务的身份证被吊销了。

INT8U  OSTaskDel (INT8U prio)

参数prio-----是待删除任务的优先级;

如果在运行的任务中去删除其他任务,有可能其他任务还占用了一些动态分配的内存或信号量之类的资源,这样可能导致内存泄露。

因此比较安全的做法是 提出删除任务请求的任务   和 删除任务本身两者之间通过删除任务的任务控制块成员OSTCBDelReq作为双方的联络新信号,同时给出双方都能调用的函数-------请求删除任务函数OSTaskDelReq(INT8U prio)

OSTaskDelReq(INT8U prio)中根据信号OSTCBDelReq的状态 提出删除任务请求的任务   和 删除任务本身要有不同的行为。

删除任务本身调用请求删除任务函数时,参数为OS_PRIO_SELF对自己做删除信号请求,从而获取OSTCBDelReq成员的状态;

提出删除任务请求的任务调用请求删除任务函数时,参数为要删除任务的优先级,如果该优先级的任务存在(除空闲任务外),则将要删除任务的任务控制块的OSTCBDelReq置为OS_TASK_DEL_REQ;

在删除任务本身通过OSTaskDelReq(INT8U prio)查询到OSTCBDelReq==OS_TASK_DEL_REQ,即其他任务已经发送要任务在合适的时候删除本身,此时可以调动资源释放函数和OSTaskDel (OS_PRIO_SELF)对自己进行删除。

因此更加合适的接口时

INT8U OSTaskDelReq(INYuU prio); //待删除任务的优先级

1.6uC/OS-II的初始化和任务的启动

1.6.1 uC/OS-II的初始化

要想用uC/OS-II的所有服务之前,第一步必须调用uC/OS-II的初始化函数OSInit(),对uC/OS-II自身的运行环境进行初始化。看看代码.

void  OSInit (void)
{
    OSInitHookBegin();       /* Call port specific initialization code   */

    OS_InitMisc();           /* Initialize miscellaneous variables       */

    OS_InitRdyList();        /* Initialize the Ready List                */

    OS_InitTCBList();        /* Initialize the free list of OS_TCBs      */

    OS_InitEventList();      /* Initialize the free list of OS_EVENTs    */

#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
    OS_FlagInit();           /* Initialize the event flag structures     */
#endif

#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u)
    OS_MemInit();            /* Initialize the memory manager            */
#endif

#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u)
    OS_QInit();             /* Initialize the message queue structures  */
#endif

    OS_InitTaskIdle();     /* Create the Idle Task                     */
#if OS_TASK_STAT_EN > 0u
    OS_InitTaskStat();     /* Create the Statistic Task                */
#endif

#if OS_TMR_EN > 0u
    OSTmr_Init();          /* Initialize the Timer Manager             */
#endif

    OSInitHookEnd();      /* Call port specific init. code            */

#if OS_DEBUG_EN > 0u
    OSDebugInit();
#endif
}

根据注释,俺们知道OSInit() 完成了就绪表、空白任务控制块链表、空白事件链表、其他全局变量进行初始化。还根据配置初始化事件标志结构体变量、初始化内存管理、初始化信息队列;并创建空闲任务OSTaskIdle(),并赋之以最低优先级和永久的就绪状态。还根据需要创建优先级为OS_LOWEST_PRIO-1的统计任务。初始化定时器管理。

系统任务初始化,主要还是全局变量和数据结构初始化;

全局变量: OSPrioCur-----当前运行任务的优先级;

OSPrioHighRdy----就绪表中具有最高优先级的优先级;

OSTCBCur----指向正在运行任务的任务控制

OSRunning-----uC/OS-II核是否正在运行的标志。

数据结构:5个空数据缓冲区-------空白任务控制块链表、任务就绪表OSRdyTbl[] OSRdyGrp、OSTCBPrioTbl[]数组等。

uC/OS-II自身的运行环境

1.6.2 uC/OS-II的启动

uC/OS-II进行任务的管理由调用启动函数OSStart()开始,在此之前,必须先至少创建一个用户任务。uC/OS-II立即进入了多任务管理阶段。

void  OSStart (void)
{
    if (OSRunning == OS_FALSE) {
        OS_SchedNew();                               /* Find highest priority's task priority number   */
        OSPrioCur     = OSPrioHighRdy;
        OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run    */
        OSTCBCur      = OSTCBHighRdy;
        OSStartHighRdy();                            /* Execute target specific code to start task     */
    }
}

调用OSStart()之后,各个变量的变化。

 

 

 

©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值