uC/OS-III 任务详解(四)

放肆的年华 提交于 2019-11-30 19:42:29

uC/OS系统的任务一般都放在最开始介绍,我放在第四章主要是对模糊的概念作清晰的讲解。

从用户的角度来看,uC/OS-III 中的任务可以分为5 种状态,分别是休眠态、就绪态、运行态、挂起态和中断态,如下表所示。

 

 

 任务状态之间的具体切换情况如下图所示。

 

 

也就是说,任务有五个状态,分别是休眠态、就绪态、运行态、等待态、中断服务态。即任务还没使用函数OSTaskCreate()创建时就是属于休眠态,而一但使用函数OSTaskCreate()创建了任务,并且函数OSStart()之前已经被执行的话,那么任务就属于就绪态了。然后系统会根据就绪表里任务的优先级来只执行最高的任务,而这个被执行的任务也从就绪态变为运行态,这个时刻就是这个优先级最高的任务的CPU独享moment(也就是独自拥有CPU的使用权),直到这个任务被被切换成其他状态(使用OSTimeDly()、OSSemPend()等函数能将运行态的函数变为等待态),那么就绪表里优先级最高的任务就会得到CPU的使用权执行任务,依次循环。

所以我这么分类,如果一个正在执行的任务M(即正在执行优先级最高的任务),它就只有两种情况,A.一直循环执行下去   B.改变自己任务状态。 改变状态也分为     b1.自己任务调用延时类函数或者等待信号值类函数的主动改变;    b2.被一个优先级更高的就绪任务H打断的被动改变(也就是只要有优先级更高的就绪任务,那么在下一个时钟节拍到来的的时候,任务H就会剥夺任务1的CPU)。

主动改变的话可以是除运行态之外的任意状态,被动改变就是任务变为挂起态。

还有一种情况就是当两个任务的优先级一样怎么办?这里使用的是时间片轮转调度,就要在文件中使能  OSSchedRoundRobinCfg(DEF_ENABLED,1,&err)  函数,如下图所示。

 

 

 

 

 

 然后在app.C文件的初始函数中初始化OSSchedRoundRobinCfg(DEF_ENABLED,1,&err) ,这个1代表1*5ms的时间,意思是相同的最高优先级时每个任务轮流运行5ms。

例子如下:

#define LED0_TASK_PRIO          4                   //任务优先级;
#define LED0_STK_SIZE           128                 //任务堆栈大小,实际大小是:128*4字节
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];               //任务堆栈;
OS_TCB Led0TaskTCB;                                 //任务控制块;
//声明任务函数(一般将一个任务写成一个函数):
void Led0_task(void *p_arg);                        //注:“p_arg”这个参数基本用不上,但必须得写上

#define LED1_TASK_PRIO          4                   //任务优先级;
#define LED1_STK_SIZE           128                 //任务堆栈大小,实际大小是:128*4字节
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];               //任务堆栈;
OS_TCB Led1TaskTCB;                                 //任务控制块;
//声明任务函数(一般将一个任务写成一个函数):
void Led1_task(void *p_arg);                        //注:“p_arg”这个参数基本用不上,但必须得写上


//任务创建函数,注:一般将其它任务的创建放到一个专门创建任务的函数中;
void start_task(void *p_arg)
{
    OS_ERR err;
    CPU_SR_ALLOC();
    p_arg = p_arg;      //故意使用一下这个参数,否则编译器会警告说此参数没有使用

    CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);      //统计任务
#endif
    
#ifdef CPU_CFG_INT_DIS_MEAS_EN        //如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();
#endif
    
#if    OS_CFG_SCHED_ROUND_ROBIN_EN     //当使用时间片轮转的时候
    
    //使能时间片轮转调度功能,时间片长度为:1*5=5ms
    OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif
    
    OS_CRITICAL_ENTER();            //进入临界区
    //创建LED0任务:
    OSTaskCreate(   (OS_TCB *)      &Led0TaskTCB,
                    (CPU_CHAR *)    "led0 task",
                    (OS_TASK_PTR)   Led0_task,
                    (void *)        0,
                    (OS_PRIO)       LED0_TASK_PRIO,
                    (CPU_STK *)     &LED0_TASK_STK[0],
                    (CPU_STK_SIZE)  LED0_STK_SIZE/10,
                    (CPU_STK_SIZE)  LED0_STK_SIZE,
                    (OS_MSG_QTY)    0,
                    (OS_TICK)       2,              //时间片长度,启用时间片轮转调度时有用,这个参数用来设置此任务时间片长度
                    (void *)        0,
                    (OS_OPT)        OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                    (OS_ERR *)      &err
                );
                 
    //创建LED1任务:
    OSTaskCreate(   (OS_TCB *)      &Led1TaskTCB,
                    (CPU_CHAR *)    "led1 task",
                    (OS_TASK_PTR)   Led1_task,
                    (void *)        0,
                    (OS_PRIO)       LED1_TASK_PRIO,
                    (CPU_STK *)     &LED1_TASK_STK[0],
                    (CPU_STK_SIZE)  LED1_STK_SIZE/10,
                    (CPU_STK_SIZE)  LED1_STK_SIZE,
                    (OS_MSG_QTY)    0,
                    (OS_TICK)       2,              //时间片长度,启用时间片轮转调度时有用,这个参数用来设置此任务时间片长度
                    (void *)        0,
                    (OS_OPT)        OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                    (OS_ERR *)      &err
                );
    //OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);        //挂起"start_task"任务
    OS_CRITICAL_EXIT();    //退出临界区
    OSTaskDel((OS_TCB *)0,&err);//删除任务自身;(第一个参数填写0,就是删除任务自身,要是填写别的任务的控制块,那就是删除别的任务)
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!