引入:一个任务的三要素是任务主体函数,任务栈,任务控制块,那么怎样吧这个三要素联系在一起呐?
在UCOSIII中我们通过函数OSTaskCreate()来创建任务。
作用:任务控制块,任务堆栈,任务代码等联系在一起,并初始化控制块的相应字段。
位置:os_task.c中定义原型函数
先不深究源码,先看看怎么用起来。
//任务创建函数入口参数解释 void OSTaskCreate (OS_TCB *p_tcb,//指向任务控制块OS_TCB CPU_CHAR *p_name,//指向任务的名字(字符串类型),每个任务都有不同的名字 OS_TASK_PTR p_task,//执行任务代码,任务函数名 void *p_arg,//传递任务主体函数的参数 OS_PRIO prio,//任务优先级(一般从3开始,不用0/1/2) CPU_STK *p_stk_base,//指向堆栈基地址 CPU_STK_SIZE stk_limit,//任务堆栈的最大深度(堆栈限制) CPU_STK_SIZE stk_size,//任务堆栈的大小 OS_MSG_QTY q_size,//内嵌消息队列,0默认不用 OS_TICK time_quanta,//时间片的长度,0默认时间节数除以10,// 轮转时间=time_quanta*时间长度 void *p_ext,指向用户补充内存区,填0即可 OS_OPT opt,//选项 /*选项: OS_OPT_TASK_NONE //不使用任何选项 OS_OPT_TASK_STK_CHK //检查栈 OS_OPT_TASK_STK_CLR //清除栈 OS_OPT_TASK_SAVE_FP //保存浮点寄存器中的内容 */ OS_ERR *p_err)//错误码
注意:为什么任务优先级一般从3开始
//UCOSIII中以下优先级用户程序不能使用,ALIENTEK
//将这些优先级分配给了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()
//任务优先级 #define START_TASK_PRIO 3 //任务控制块 OS_TCB StartTaskTCB; //任务堆栈大小 #define START_STK_SIZE 512 //任务堆栈 CPU_STK START_TASK_STK[START_STK_SIZE]; //任务函数 void start_task(void *p_arg); int main(void) { OS_ERR err;//定义一个错误码 CPU_SR_ALLOC();//进入临界区,定义临界区需要的变量 //硬件初始化 /* delay_init(); //延时初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置 uart_init(115200); //串口波特率设置 LED_Init(); //LED初始化 */ OSInit(&err); //初始化UCOSIII OS_CRITICAL_ENTER();//进入临界区(关闭中断) //创建开始任务 /* 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(); //退出临界区(开启中断) OSStart(&err); //开启UCOSIII while(1); }
OSTaskDel()函数用来删除当前任务。删除的任务将从所有就绪堵塞挂起和事件列表中删除。
作用: 用来删除任务,当一个任务不需要运行时候可以利用此函数删掉。
位置:os_task.c中定义 函数原型:
void OSTaskDel (OS_TCB *p_tcb,//删除任务TCB,也可以传递NULL指针删除自身函数 OS_ERR *p_err)//返回错误码
eg:
OSTaskDel((OS_TCB*)0,&err); //删除任务自身 OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err); //删除指定任务
实验要求:
1、主函数创建任务1负责创建任务2和任务3执行完函数之后删掉自身。 2、任务2和任务3在任务运行过程中要将自身运行次数通过串口打印。 3、任务2在执行任务超过十次后删除任务3
先准备一个移植好的空白模版:
先定义一下任务1:
在main函数当中根据之前的模版输入
此时在创建任务1的各个入口参数与定义的任务1对应
编写任务1,因为要求我们在任务1中创建任务2任务3
此时任务2任务3还未被定义,返回定义任务1的下方定义任务2任务3 :
编写任务2任务3 函数。
又裸机基础的上边要求的逻辑很好理解,这里就不在解释。
注意:在任务2/3都是运行在while(1)循环当中,要是任务一直在while(1)中没法挂起,退出死循环,那这样就不会进行任务3,所以while(1)中一定要加阻塞。所以用OSTimeDlyHMSM();函数进行延时阻塞。
这样实验就进行成功了查看一下运行结果:
实验源码:
#include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "includes.h" //UCOSIII中以下优先级用户程序不能使用,ALIENTEK //将这些优先级分配给了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() //创建任务1 //定义任务优先级 #define TASK_1_PRIO 3 //定义任务控制块 OS_TCB TASK_1_TCB; //定义任务堆栈大小 #define TASK_1_STK_SIZE 128 //定义任务堆栈 CPU_STK TASK_1_STK[TASK_1_STK_SIZE]; //定义任务函数 void TASK_1(void *arg); //创建任务2 //定义任务优先级 #define TASK_2_PRIO 4 //定义任务控制块 OS_TCB TASK_2_TCB; //定义任务堆栈大小 #define TASK_2_STK_SIZE 128 //定义任务堆栈 CPU_STK TASK_2_STK[TASK_2_STK_SIZE]; //定义任务函数 void TASK_2(void *arg); //创建任务3 //定义任务优先级 #define TASK_3_PRIO 5 //定义任务控制块 OS_TCB TASK_3_TCB; //定义任务堆栈大小 #define TASK_3_STK_SIZE 128 //定义任务堆栈 CPU_STK TASK_3_STK[TASK_3_STK_SIZE]; //定义任务函数 void TASK_3(void *arg); int main(void) { OS_ERR err1;//错误码变量 CPU_SR_ALLOC();//定义临界区需要的变量 //硬件初始化 delay_init(); //延时初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置 uart_init(115200); //串口波特率设置 OSInit(&err1);//初始化UCOSIII OS_CRITICAL_ENTER();//进入临界区代码 //创建开始任务1 OSTaskCreate((OS_TCB * )&TASK_1_TCB, //任务控制块 (CPU_CHAR * )"main TASK1", //任务名字 (OS_TASK_PTR )TASK_1, //任务函数 (void * )0, //传递给任务函数的参数 (OS_PRIO )TASK_1_PRIO, //任务优先级 (CPU_STK * )&TASK_1_STK[0], //任务堆栈基地址 (CPU_STK_SIZE)TASK_1_STK_SIZE/10, //任务堆栈深度限位 (CPU_STK_SIZE)TASK_1_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 * )&err1); //存放该函数错误时的返回值 OS_CRITICAL_EXIT();//退出临界区代码 OSStart(&err1);//开启UCOSIII while(1); } void TASK_1(void *arg) { OS_ERR err2_3;//错误码变量 CPU_SR_ALLOC();//定义临界区需要的变量 OS_CRITICAL_ENTER();//进入临界区代码 //创建开始任务2 OSTaskCreate((OS_TCB * )&TASK_2_TCB, //任务控制块 (CPU_CHAR * )"main TASK2", //任务名字 (OS_TASK_PTR )TASK_2, //任务函数 (void * )0, //传递给任务函数的参数 (OS_PRIO )TASK_2_PRIO, //任务优先级 (CPU_STK * )&TASK_2_STK[0], //任务堆栈基地址 (CPU_STK_SIZE)TASK_2_STK_SIZE/10, //任务堆栈深度限位 (CPU_STK_SIZE)TASK_2_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 * )&err2_3); //存放该函数错误时的返回值 //创建开始任务3 OSTaskCreate((OS_TCB * )&TASK_3_TCB, //任务控制块 (CPU_CHAR * )"main TASK3", //任务名字 (OS_TASK_PTR )TASK_3, //任务函数 (void * )0, //传递给任务函数的参数 (OS_PRIO )TASK_3_PRIO, //任务优先级 (CPU_STK * )&TASK_3_STK[0], //任务堆栈基地址 (CPU_STK_SIZE)TASK_3_STK_SIZE/10, //任务堆栈深度限位 (CPU_STK_SIZE)TASK_3_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 * )&err2_3); //存放该函数错误时的返回值 OS_CRITICAL_EXIT();//退出临界区代码 //任务一执行完函数之后删掉自身 OSTaskDel((OS_TCB *)0,&err2_3); } void TASK_2(void *arg) { int num = 0;//任务2运行次数 OS_ERR err2; while(1) { num++; if(num==10) { OSTaskDel((OS_TCB *)&TASK_3_TCB,&err2); printf("删除任务三\r\n"); } printf("任务2运行次数:%d\r\n",num); OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err2);//延时1S } } void TASK_3(void *arg) { int num = 0;//任务2运行次数 OS_ERR err3; while(1) { num++; printf("任务3运行次数:%d\r\n",num); OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_HMSM_STRICT,&err3);//延时500ms } }