多任务创建的分类
1 万事具备只欠东风
在main函数中将硬件初始化,RTOS系统初始化,所有需要创建的任务都创建好,最后就是启动RTOS的调度器开始任务调度。
2 以一带多
在main函数中把硬件初始化,RTOS系统初始化好,然后创建一个启动任务,启动调度器,在这个启动任务中创建各种任务,在所有任务创建好之后,调用OSTaskDly()
删除自身。
这两者没有很大的区别,但是我个人来说比较喜欢第二种,我觉得这样的代码更有模块化。
实验要求
LED1亮1s,LED2亮5秒,LED3亮10秒。它们的优先级都是3,启动任务的优先级是2。
头文件 app_cfg.h
//定义任务堆栈的大小
#define APP_TASK_START_STK_SIZE 128
#define APP_TASK_LED1_STK_SIZE 512
#define APP_TASK_LED2_STK_SIZE 512
#define APP_TASK_LED3_STK_SIZE 512
//定义任务的优先级
#define APP_TASK_START_PRIO 2
#define APP_TASK_LED1_PRIO 3
#define APP_TASK_LED2_PRIO 3
#define APP_TASK_LED3_PRIO 3
函数的主体app.c
#include "os.h"
#include "app_cfg.h"
#include "bsp.h"
static OS_TCB AppTaskStartTCB; //定义任务控制块
static OS_TCB AppTaskLED1TCB; //定义任务控制块LED1
static OS_TCB AppTaskLED2TCB; //定义任务控制块LED2
static OS_TCB AppTaskLED3TCB; //定义任务控制块LED3
/**定义任务堆栈**/
static CPU_STK AppTaskStartSTK[APP_TASK_START_STK_SIZE];
static CPU_STK AppTaskLED1STK[APP_TASK_LED1_STK_SIZE];
static CPU_STK AppTaskLED2STK[APP_TASK_LED2_STK_SIZE];
static CPU_STK AppTaskLED3STK[APP_TASK_LED3_STK_SIZE];
/*任务函数的声明*/
static void AppTaskStart(void * parm);
static void AppTaskLED1(void * parm);
static void AppTaskLED2(void * parm);
static void AppTaskLED3(void * parm);
//启动函数的函数体
static void AppTaskStart(void * parm)
{
OS_ERR err;// 错误的返回
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
(void)parm;
/* Initialize BSP functions */
BSP_Init();
CPU_Init();
/* Determine SysTick reference freq. */
cpu_clk_freq = BSP_CPU_ClkFreq();
/* Determine nbr SysTick increments */
cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;
/* Init uC/OS periodic time src (SysTick). */
OS_CPU_SysTickInit(cnts);
/* Initialize Memory Management Module */
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
/* Compute CPU capacity with no task running */
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
/**创建三个任务**/
/*Tast LED1*/
OSTaskCreate( (OS_TCB *)&AppTaskLED1TCB,/* Create the Led1 task */
(CPU_CHAR *)"AppTaskLED1",
(OS_TASK_PTR ) AppTaskLED1,
(void *) 0,
(OS_PRIO ) APP_TASK_LED1_PRIO,
(CPU_STK *)&AppTaskLED1STK[0],
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
/*Task LED2*/
OSTaskCreate( (OS_TCB *)&AppTaskLED2TCB,/* Create the Led1 task */
(CPU_CHAR *)"AppTaskLED2",
(OS_TASK_PTR ) AppTaskLED2,
(void *) 0,
(OS_PRIO ) APP_TASK_LED2_PRIO,
(CPU_STK *)&AppTaskLED2STK[0],
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
/*Task LED3*/
OSTaskCreate( (OS_TCB *)&AppTaskLED3TCB,/* Create the Led1 task*/
(CPU_CHAR *)"AppTaskLED3",
(OS_TASK_PTR ) AppTaskLED3,
(void *) 0,
(OS_PRIO ) APP_TASK_LED3_PRIO,
(CPU_STK *)&AppTaskLED3STK[0],
(CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskDel(0,&err);
}
int main(void)
{
OS_ERR err;
BSP_Init ();
OSInit(&err); //初始化
//创建启动任务
OSTaskCreate((OS_TCB *)&AppTaskStartTCB,/* Create the Led1 task */
(CPU_CHAR *)"AppTaskStart",
(OS_TASK_PTR )AppTaskStart,
(void *) 0,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartSTK[0],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSStart(&err); //启动任务,开调度
}
/*Task LED1*/
static void AppTaskLED1(void * parm)
{
OS_ERR err;
(void )parm;
while(1)
{
LED1_TOGGLE;
OSTimeDly(1000,OS_OPT_TIME_DLY,&err);//实现毫秒级别的延时1000ms = 1s
}
}
/*Task LED2*/
static void AppTaskLED2(void * parm)
{
OS_ERR err;
(void )parm;
while(1)
{
LED2_TOGGLE;
OSTimeDly(5000,OS_OPT_TIME_DLY,&err);
}
}
/*Task LED3*/
static void AppTaskLED3(void * parm)
{
OS_ERR err;
(void )parm;
while(1)
{
LED3_TOGGLE;
OSTimeDly(10000,OS_OPT_TIME_DLY,&err);
}
}
总结创建多任务和单任务没有大的区别
1 在main函数中创建一个启动任务。
2 在启动任务中创建三个任务,分别是用来启动LED1,LED2,LED3
。
3 在创建完三个任务后调用OSTaskDly()
删掉启动任务。
uCOS-III的启动过程
1 上电复位后
2 执行Reset_Handle
3 执行__main
4 来到main
(由汇编转入C语言的世界)
uCOS-III的任务是相互独立互不干扰的,各有各自独立的内存。
任务的数量是任意的(物理限制除外,内存的限制)。
可以多个任务具备同样的优先级,使用时间片轮转的方法调度。
任意时刻只有一个任务在执行(单核)。调度器永远是优先选择就绪态下优先级别最高的任务。