【UCOSIII】【基本任务操作总结】任务创建、删除、挂起、恢复 ,以及 3种任务调度器(时间片轮转调度)

时间:2022-01-05 00:45:37

任务创建、删除、挂起、恢复

OS_TCB	Task1_TaskTCB;            //OS_TCB任务控制块
void task1_task(void *p_arg);    //入口函数
#define TASK1_TASK_PRIO	5        //优先级
#define TASK1_STK_SIZE	64        //堆栈长度
CPU_STK	TASK1_TASK_STK[TASK1_STK_SIZE];    //堆栈数组
OSTaskCreate                                    //创建
OSTaskDel((OS_TCB*)0,&err);                    //删除    start_task任务自身
OSTaskSuspend((OS_TCB*)&Task2_TaskTCB,&err);    //挂起
OSTaskResume((OS_TCB*)&Task2_TaskTCB,&err);      //恢复


一、UCOSIII启动与初始化:三步

1.初始化UCOSIII

OSInit(&err);		//1初始化UCOSIII

2.创建开始任务

 只创建一个start_task任务,其余在start_task这个任务里面创建

①进入临界区

②创建任务

③退出临界区

OS_CRITICAL_ENTER();//2进入临界区
	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
				 (CPU_CHAR	* )"start task", 		//任务名字
                 (OS_TASK_PTR )start_task, 			//任务函数
                 (void		* )0,					//传递给任务函数的参数
                 (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                 (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                 (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                 (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                 (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void   	* )0,					//用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR 	* )&err);				//存放该函数错误时的返回值
OS_CRITICAL_EXIT();	//4退出临界区

3.开启UCOSIII

OSStart(&err);  //5开启UCOSIII

【UCOSIII】【基本任务操作总结】任务创建、删除、挂起、恢复 ,以及 3种任务调度器(时间片轮转调度)

【UCOSIII】【基本任务操作总结】任务创建、删除、挂起、恢复 ,以及 3种任务调度器(时间片轮转调度)

	OSInit(&err);		//1初始化UCOSIII
	OS_CRITICAL_ENTER();//2进入临界区
	//3创建开始任务 只创建一个start_task任务,其余在start_task这个任务里面创建
	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
				 (CPU_CHAR	* )"start task", 		//任务名字
                 (OS_TASK_PTR )start_task, 			//任务函数
                 (void		* )0,					//传递给任务函数的参数
                 (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                 (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                 (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                 (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                 (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void   	* )0,					//用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR 	* )&err);				//存放该函数错误时的返回值
	OS_CRITICAL_EXIT();	//4退出临界区	 
	OSStart(&err);  //5开启UCOSIII


二、创建任务:

任务控制块OS_TCB  用来保存任务的信息

【UCOSIII】【基本任务操作总结】任务创建、删除、挂起、恢复 ,以及 3种任务调度器(时间片轮转调度)

任务堆栈CPU_STK  用来在切换和调用其它函数的时候保存现场 

                             其实 CPU_STK就是 CPU_INT32,因此 任务的 实际堆栈大小应该为我们定义任务的 4倍

【UCOSIII】【基本任务操作总结】任务创建、删除、挂起、恢复 ,以及 3种任务调度器(时间片轮转调度)

任务优先级   优先级位 映射表OSPrioTbl[] 管理优先级位

                    一个优先级可以有多个任务,由就绪任务列表管理 OSRdyList[]

 //UCOSIII中以下优先级用户程序不能使用
//将这些优先级分配给了UCOSIII的5个系统内部任务
//优先级0:中断服务服务管理任务 OS_IntQTask()
//优先级1:时钟节拍任务 OS_TickTask()
//优先级2:定时任务 OS_TmrTask()
//优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
//优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()

                    总优先级数定义:OS_CFG_PRIO_MAX

【UCOSIII】【基本任务操作总结】任务创建、删除、挂起、恢复 ,以及 3种任务调度器(时间片轮转调度)

//开始任务函数
void start_task(void *p_arg)
{
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;

	CPU_Init();

	OS_CRITICAL_ENTER();	//进入临界区
	//TCB 名字 函数入口
	//优先级 堆栈
		 OSTaskCreate((OS_TCB 	* )&Task1_TaskTCB,		
				 (CPU_CHAR	* )"task1 task", 		
                 (OS_TASK_PTR )task1_task, 			
                 (void		* )0,					
                 (OS_PRIO	  )TASK1_TASK_PRIO,     
                 (CPU_STK   * )&TASK1_TASK_STK[0],	
                 (CPU_STK_SIZE)TASK1_STK_SIZE/10,	
                 (CPU_STK_SIZE)TASK1_STK_SIZE,		
                 (OS_MSG_QTY  )0,					
                 (OS_TICK	  )0,					
                 (void   	* )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);	
				 	
	OS_CRITICAL_EXIT();	//进入临界区
	OSTaskDel((OS_TCB*)0,&err);//删除start_task任务自身
	printf("创建完任务1、任务2, 并删除start_task任务自身\n");

}


三、任务调度与切换

UCOSIII可剥夺、可抢占式的

任务调度器:

1、任务级调度器:不同优先级的任务 

2、中断级调度器:

3、时间片轮转调度:相同优先级的任务

/*任务级切换函数*/
void  OSSched (void)
{
    CPU_SR_ALLOC();

	//(1)检查本函数是否在中断函数中被调用,因为任务级调度器不能用于中断级任务调度
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* ISRs still nested?                                     */
        return;                                             /* Yes ... only schedule when no nested ISRs              */
    }
	//(2)检查调度器是否加锁,加锁了就不能做任务调度和切换
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {        /* Scheduler locked?                                      */
        return;                                             /* Yes                                                    */
    }
	//(3)关中断
    CPU_INT_DIS();
	//(4)获取 任务就续表中 已就绪的最高优先级任务
    OSPrioHighRdy   = OS_PrioGetHighest();                  /* Find the highest priority ready                        */
	//(5)获取该优先级下的任务列表中的第一个任务的OS_TCB
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
	//(6)判断该任务是否已经是正在运行的任务,是就不用再任务切换了
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                   /* Current task is still highest priority task?           */
        CPU_INT_EN();                                       /* Yes ... no need to context switch                      */
        return;
    }

	//(7)真正执行 任务切换	:宏定义函数
    OS_TASK_SW();                                           /* Perform a task level context switch                    */
	//(8)开中断
    CPU_INT_EN();
}

/*中断级切换函数*/
void  OSIntExit (void)
{
    CPU_SR_ALLOC();


	//(1)判断UCOSIII是否运行,否,则退出
    if (OSRunning != OS_STATE_OS_RUNNING) {                 /* Has the OS started?                                    */
        return;                                             /* No                                                     */
    }
	//关中断
    CPU_INT_DIS();
	//OSIntNestingCtr中断嵌套计数器,记录中断嵌套次数
	//进入中断服务函数,调用OSIntEnter()函数,OSIntNestingCtr++;
	//退出中断服务函数时 调用OSIntExit(),OSIntNestingCtr--
	//检查OSIntNestingCtr是否为0,确保退出中断服务函数时调用OSIntExit() 不会等于负数
    if (OSIntNestingCtr == (OS_NESTING_CTR)0) {             /* Prevent OSIntNestingCtr from wrapping                  */
        CPU_INT_EN();
        return;
    }
	//退出中断服务函数时 调用OSIntExit(),OSIntNestingCtr--
    OSIntNestingCtr--;
	//如果OSIntNestingCtr还大于0,说明还有其他中断发生,就跳回中断服务程序,不需要做任务切换
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* ISRs still nested?                                     */
        CPU_INT_EN();                                       /* Yes                                                    */
        return;
    }
	//检查调度器是否加锁,加锁就直接跳出,不需要做任务切换
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {        /* Scheduler still locked?                                */
        CPU_INT_EN();                                       /* Yes                                                    */
        return;
    }
	//获取 任务就续表中 已就绪的最高优先级任务
    OSPrioHighRdy   = OS_PrioGetHighest();                  /* Find highest priority                                  */
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;     /* Get highest priority task ready-to-run                 */
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                   /* Current task still the highest priority?               */
        CPU_INT_EN();                                       /* Yes                                                    */
        return;
    }

	//调用中断级任务切换函数
    OSIntCtxSw();                                           /* Perform interrupt level ctx switch                     */
    CPU_INT_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();


	//时间片轮转调度en 是否允许
    if (OSSchedRoundRobinEn != DEF_TRUE) {                  /* Make sure round-robin has been enabled                 */
        return;
    }
	
    CPU_CRITICAL_ENTER();
	//获取某一优先级下就绪任务列表中的第一个任务
    p_tcb = p_rdy_list->HeadPtr;                            /* Decrement time quanta counter                          */
	//如果p_tcb为空,即没有任务就绪,就直接退出,返回了
    if (p_tcb == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        return;
    }
	//如果p_tcb里只有系统设定的空闲任务,那么也可以退出返回了
    if (p_tcb == &OSIdleTaskTCB) {
        CPU_CRITICAL_EXIT();
        return;
    }
	//TimeQuantaCtr 当前任务时间片的剩余时间
    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {
        p_tcb->TimeQuantaCtr--;
    }
	//当前任务时间片还没用完,就不能任务切换,直接返回
    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {                /* Task not done with its time quanta                     */
        CPU_CRITICAL_EXIT();
        return;
    }
	//当前优先级下的任务数量,任务太少,小于2,即1个就不需要做任务切换,直接返回
    if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {           /* See if it's time to time slice current task            */
        CPU_CRITICAL_EXIT();                                /* ... only if multiple tasks at same priority            */
        return;
    }
	//调度器是否上锁,上锁就无法任务切换,直接返回
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {        /* Can't round-robin if the scheduler is locked           */
        CPU_CRITICAL_EXIT();
        return;
    }
	//双向链表
	//改变p_rdy_list->头指针 指向 该优先级下的 下一个OS_TCB任务,
	//现在已经执行完的OS_TCB任务指针移到队尾
    OS_RdyListMoveHeadToTail(p_rdy_list);                   /* Move current OS_TCB to the end of the list             */
    //指向了下一个OS_TCB
	p_tcb = p_rdy_list->HeadPtr;                            /* Point to new OS_TCB at head of the list                */
	//如果TimeQuanta=0,就TimeQuantaCtr = 默认时间片值
    if (p_tcb->TimeQuanta == (OS_TICK)0) {                  /* See if we need to use the default time slice           */
        p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta; //默认值是20
    } else {
        p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;           /* Load time slice counter with new time                  */
    }
    CPU_CRITICAL_EXIT();
}


四、任务删除

OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err);


五、任务挂起与恢复

OSTaskSuspend((OS_TCB*)&Task2_TaskTCB,&err);

OSTaskResume((OS_TCB*)&Task2_TaskTCB,&err);