任务创建、删除、挂起、恢复
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
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 用来保存任务的信息
任务堆栈CPU_STK 用来在切换和调用其它函数的时候保存现场
其实 CPU_STK就是 CPU_INT32,因此 任务的 实际堆栈大小应该为我们定义任务的 4倍
任务优先级 优先级位 映射表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
//开始任务函数
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);