1-任务创建和删除

UCOSIII 任务创建和删除

 

这篇总结只是概述任务的创建和删除,至于系统的原理、前后台系统的区别、系统移植、系统初始化配置等以后会用专门的文章来总结。

系统初始化大概流程

  1. 各个外设的初始化
  2. 系统初始化,其实就是调用一个系统初始化函数就好 OSInit()
  3. 进入临街代码保护 OS_CRITICAL_ENTER()
  4. 创建任务 OSTaskCreate()
  5. 退出临界代码保护 OS_CRITICAL_EXIT()
  6. 启动系统 OSStart()

 

看起来好像挺简单的,但是其中有些地方还是要注意的。比如在创建任务的时候一般都不希望被中断打断,所以就需要对这部分代码进行保护,让这部分代码能够连续执行,所以就需要调用临界代码保护的函数对代码临界保护。这个是参考原子的代码,这两个函数在UCOS作者的书中特别说明用户是不能调用的,而且UCOS给用户的API接口函数中也没有这两个函数,但是在UCOS源码中这两个函数也是当普通函数用的。

这几个步骤中,创建任务这步是比较关键的,函数原型和入口参数解释如下;

函数原型;

void  OSTaskCreate (OS_TCB        *p_tcb,

                    CPU_CHAR      *p_name,

                    OS_TASK_PTR    p_task,

                    void          *p_arg,

                    OS_PRIO        prio,

                    CPU_STK       *p_stk_base,

                    CPU_STK_SIZE   stk_limit,

                    CPU_STK_SIZE   stk_size,

                    OS_MSG_QTY     q_size,

                    OS_TICK        time_quanta,

                    void          *p_ext,

                    OS_OPT         opt,

                    OS_ERR        *p_err)

参数解释;

OS_TCB        *p_tcb,

这个是任务控制块,里面记载着本任务的各种信息,有点像其他语言里面的句柄吧。

CPU_CHAR      *p_name,

可以给任务起一个名字,用上位机调试的时候可以看到,但是如果不用上位机调式的话好像没啥用

OS_TASK_PTR    p_task,

这是任务函数的函数名,本任务要做的事情都放在这个任务函数里

void          *p_arg,

可以给任务函数传递入口参数

OS_PRIO        prio,

设定本任务的优先级,这里用的是原子的demo,原子的基本工程里0-2,最后的两个优先级已经使用了,所以我们不能使用这几个优先级,如果开启了时间片轮转调度的话不同的任务可以使用相同的优先级,但是我还是喜欢每个任务单独占用一个优先级。优先级的数字越低优先级越高,第5级优先级比第6级优先级高。

CPU_STK       *p_stk_base,

任务堆栈基地址,任务切换的时候要把当前状态备份到这个堆栈里,就像中断的压栈PUSH。等到恢复这个任务的时候再把堆栈里的状态数据恢复到相关寄存器,相当于中断里的出栈POP。

CPU_STK_SIZE   stk_limit,

这个堆栈也是有大小的,为了防止堆栈溢出,这里对堆栈进行限位检测,一般为10%吧,但是系统检测到堆栈到达限位时不知道系统会怎么处理

CPU_STK_SIZE   stk_size,

这个就是堆栈的总大小了,其实就是堆栈数组的长度。但是这个大小和CPU_STK_SIZE的数据类型有关,如果是8位的话堆栈长度10就是10个字节,如果是32位的话堆栈长度10就是40个字节,依次类推

OS_MSG_QTY     q_size,

如果使能了内部消息队列功能的话,这个参数就是用来确定可用消息长度的,如果设置为0则代表禁止该任务接收消息队列

OS_TICK       time_quanta,

UCOSIII支持同一个优先级下有多个任务,这个参数就是确定本任务所占用的时间片的个数,如果设置为0则代表一个时间片,每个时间片的长度由系统决定

void          *p_ext,

任务扩展TCB用的,其实我没用过

OS_OPT         opt,

这个选项有5个可选项;如果想多选的话用与连接就好

OS_OPT_TASK_NONE 表示没有任何选项

OS_OPT_TASK_STK_CHK 指定是否允许检测任务的堆栈,当然是允许啊

OS_OPT_TASK_STK_CLR 指定是否需要清零该任务的堆栈,在新建任务的时候清空下堆栈比较好

OS_OPT_TASK_SAVE_FP 指定是否保存浮点运算寄存器,有浮点运算的CPU才会用到,最起码M3是没有的

OS_OPT_TASK_NO_TLS 这个选项在工程里面有,但是UCOS 的书上却没有解释

OS_ERR        *p_err

这个参数返回一个错误码,不同的错误码代表不同的错误类型,UCOS作者强烈建议检查这个错误码,但是事实上因为程序空间不够或者其他原因(懒),很多时候是不检测的。

  

 

关于任务函数,每个任务的函数都是一个无限循环的函数,至于什么原因在UCOS原理章节解释吧,反正按照这个格式写就对了,举个栗子;

void uartTask_1_Func()

{

         OS_ERR myErr;

         while(1)//死循环

         {

                   OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&myErr);//延时1秒

                   printf("Im uart task 1 \r\n");//串口输出信息

         }

}

这个函数的功能是每隔1秒就用串口向电脑发送一些信息,函数内部是一个死循环。这里有个要注意的地方,在死循环的内部一定要调用可以引起任务切换的函数,不然程序会一直运行这个任务而不能切换到其他任务运行。能引起任务切换的函数有以下几个;

OSFlagPend()

OSMutexPend();

OSPendMulti()

OSQPend()

OSSemPend()

OSTimeDly()

OSTimeDlyHMSM()

OSTaskQPend()

OSTaskSemPend()

OSTaskSuspend()

OSTaskDel()

................暂时想到这几个,应该还有其他的函数可以引起任务切换。

 

下面来个完整的栗子吧,在main函数里创建一个任务star task,这个任务只是用来创建led task、uart task 1 和uart task 2这三个任务,在创建完这三个任务后star task就把自己给删除掉,然后系统就循环运行led task、uart task 1 和uart task 2这三个任务了。其中led task这个任务每隔100毫秒翻转一个LED灯,指示系统正在运行;uart task 1这个任务每隔1秒向串口输出一串信息,uart task 2这个任务每隔1.5秒向串口输出一串信息,在电脑的串口助手可以看到uart task 1 和uart task 2这两个任务的运行情况。虽然我用的是原子的代码,但是用的却是STM32的最小系统板,这也是为什么用串口输出来查看任务的原因,在学习UCOS部分估计都会用最小系统来测试代码,至于代码里出现的正点原子相关的信息,因为用的是正点原子的工程,所以有些信息保留了下来,当是尊重版权吧。主要代码如下;

Main.c文件
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "includes.h"

#include "task.h"
/************************************************
 ALIENTEK战舰STM32开发板UCOS实验
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

//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()
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com  
//广州市星翼电子科技有限公司  
//作者:正点原子 @ALIENTEK


//*****************************************************************
//开始任务
OS_TCB  starTaskTCB;	//任务控制块
#define STAR_TASK_PRIO      3		//任务优先级
#define STAR_TASK_STK_SIZE  128	//任务堆栈总大小
CPU_STK STAR_TASK_STK[ STAR_TASK_STK_SIZE ];	//任务堆栈数组


int main()
{
	OS_ERR myErr;			//os的错误码
	CPU_SR_ALLOC();	//使用临街保护就得添加这玩意,不然会报错
	
	delay_init();  //时钟初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
	uart_init(115200);   //串口初始化
	LED_Init();        	 //LED初始化	
	
	OSInit(&myErr);				 //os初始化
	
	//创建任务的时候进入临街保护比较好,但是这个函数非用户的API函数,用户使用是否合适以后再讨论
	OS_CRITICAL_ENTER(); 
	
	//创建开始任务,在开始任务里创建其他任务,为每个函数入口参数都强制转换类型吧,以防万一
	OSTaskCreate (		(OS_TCB       *)&starTaskTCB,						//任务控制块,
                    (CPU_CHAR     *)"star task",						//任务名字
                    (OS_TASK_PTR   )starTaskFunc,						//任务函数
                    (void         *)0,											//任务函数入口参数
                    (OS_PRIO       )STAR_TASK_PRIO,					//任务优先级
                    (CPU_STK      *)&STAR_TASK_STK[0],			//堆栈数组基地址
                    (CPU_STK_SIZE  ) STAR_TASK_STK_SIZE/10,	//堆栈溢出限位
                    (CPU_STK_SIZE  ) STAR_TASK_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       *)&myErr);								//错误码
	
 OS_CRITICAL_EXIT();	//任务创建完了就该退出临界保护了									
 OSStart(&myErr);				//任务创建完成后就该运行了
 while(1);						//运行系统后就一直在系统里面跑了,应该运行不到这里
}


Task.c文件
#include "task.h"
#include "sys.h"
#include "led.h"
#include "includes.h" //想要使用UCOS系统,得包含这个头文件



//LED秒闪任务,提示系统正在运行
OS_TCB  ledTaskTCB;
#define LED_TASK_PRIO 4
#define LED_TASK_STK_SIZE 128
CPU_STK LED_TASK_STK[LED_TASK_STK_SIZE];

//串口输出任务1
OS_TCB  uartTask_1_TCB;
#define UART_TASK_1_PRIO 5
#define UART_TASK_1_STK_SIZE 128
CPU_STK UART_TASK_1_STK[ UART_TASK_1_STK_SIZE ];


//串口输出任务2
OS_TCB  uartTask_2_TCB;
#define UART_TASK_2_PRIO 6
#define UART_TASK_2_STK_SIZE 128
CPU_STK UART_TASK_2_STK[ UART_TASK_2_STK_SIZE ];

void starTaskFunc()
{	
	OS_ERR myErr;
	
	OSTaskCreate (	  (OS_TCB       *)&ledTaskTCB,
                    (CPU_CHAR     *)"led task",
                    (OS_TASK_PTR   )ledTaskFunc,
                    (void         *)0,
                    (OS_PRIO       )LED_TASK_PRIO,
                    (CPU_STK      *)&LED_TASK_STK[0],
                    (CPU_STK_SIZE  ) LED_TASK_STK_SIZE/10,
                    (CPU_STK_SIZE  ) LED_TASK_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       *)&myErr);

										
	OSTaskCreate (	  (OS_TCB       *)&uartTask_1_TCB,
                    (CPU_CHAR     *)"uart task 1 ",
                    (OS_TASK_PTR   )uartTask_1_Func,
                    (void         *)0,
                    (OS_PRIO       )UART_TASK_1_PRIO,
                    (CPU_STK      *)&UART_TASK_1_STK[0],
                    (CPU_STK_SIZE  ) UART_TASK_1_STK_SIZE/10,
                    (CPU_STK_SIZE  ) UART_TASK_1_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       *)&myErr);

										
	OSTaskCreate (	  (OS_TCB       *)&uartTask_2_TCB,
                    (CPU_CHAR     *)"uart task 2 ",
                    (OS_TASK_PTR   )uartTask_2_Func,
                    (void         *)0,
                    (OS_PRIO       )UART_TASK_2_PRIO,
                    (CPU_STK      *)&UART_TASK_2_STK[0],
                    (CPU_STK_SIZE  ) UART_TASK_2_STK_SIZE/10,
                    (CPU_STK_SIZE  ) UART_TASK_2_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       *)&myErr);
	
//这个任务只是用来创建其他任务的,其他任务创建完成了这个任务也就没用了,删除掉		
	OSTaskDel((OS_TCB*)0,&myErr);
}	

//LED任务的任务函数
//LED每隔500ms翻转一次,提示系统正在运行
void ledTaskFunc()
{
	OS_ERR myErr;
	while(1)		//注意,每个任务都是一个死循环
	{
		OSTimeDlyHMSM (		 (CPU_INT16U  ) 0,		//时
											 (CPU_INT16U  ) 0,		//分
											 (CPU_INT16U  ) 0,		//秒
											 (CPU_INT32U  ) 100,	//毫秒
											 (OS_OPT      ) OS_OPT_TIME_HMSM_STRICT,	//选项
											 (OS_ERR      *)&myErr);	//错误码
		LED = !LED;	//LED状态翻转
	}	
}

//串口任务1的任务函数
//功能;每隔1秒向电脑串口助手发送一次数据
void uartTask_1_Func()
{
	OS_ERR myErr;
	while(1)
	{
		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&myErr);//延时1秒
		printf("Im uart task 1 \r\n");
	}
}


//串口任务2的任务函数
//功能;每隔1.5秒向电脑串口助手发送一次数据
void uartTask_2_Func()
{
	OS_ERR myErr;
	while(1)
	{
		OSTimeDlyHMSM(0,0,1,500,OS_OPT_TIME_HMSM_STRICT,&myErr);//延时1.5秒
		printf("Im uart task 2 \r\n");
	}
}
		
Task.h文件
#ifndef __TASK_H
#define __TASK_H	 

	 				    
void starTaskFunc();	
void ledTaskFunc();
void uartTask_1_Func();
void uartTask_2_Func();
							
#endif



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值