实验3 任务的基本管理.docx
《实验3 任务的基本管理.docx》由会员分享,可在线阅读,更多相关《实验3 任务的基本管理.docx(17页珍藏版)》请在冰豆网上搜索。
实验3任务的基本管理
实验3任务的基本管理
1实验目的
✓理解任务管理的基本原理,了解任务的各个基本状态及其变迁过程;
✓掌握µC/OS-II中任务管理的基本方法(创建、启动、挂起、解挂任务);
✓熟练使用µC/OS-II任务管理的基本系统调用。
2实验原理及程序结构
2.1实验设计
为了展现任务的各种基本状态及其变迁过程,本实验设计了Task0、Task1两个任务:
任务Task0不断地挂起自己,再被任务Task1解挂,两个任务不断地切换执行。
通过本实验可以清晰地了解到任务在各个时刻的状态以及状态变迁的原因。
图1
注意:
图中的栅格并不代表严格的时间刻度,而仅仅表现各任务启动和执行的相对先后关系。
2.1.1运行流程
整个应用的运行流程如图1所示,其描述如下:
(1)main()函数调用OSInit()函数对µC/OS-II内核进行初始化,调用OSTaskCreate创建起始任务TaskStart;
(2)main()函数调用函数OSStart()启动µC/OS-II内核的运行,开始多任务的调度,执行当前优先级最高的就绪任务TaskStart;
(3)TaskStart完成如下工作:
a、安装时钟中断并初始化时钟,串口0初始化,创建2个应用任务;
b、挂起自己(不再被其它任务唤醒),系统切换到当前优先级最高的就绪任务Task0。
之后整个系统的运行流程如下:
●t1时刻,Task0开始执行,它运行到t2时刻挂起自己;
●t2时刻,系统调度处于就绪状态的优先级最高任务Task1执行,它在t3时刻唤醒Task0,后者由于优先级较高而抢占CPU;
●Task0执行到t4时刻又挂起自己,内核调度Task1执行;
●Task1运行至t5时刻再度唤醒Task0;
●……
2.1.2μC/OS-Ⅱ中的任务描述
一个任务通常是一个无限的循环,由于任务的执行是由操作系统内核调度的,因此任务是绝不会返回的,其返回参数必须定义成void。
在μC/OS-Ⅱ中,当一个运行着的任务使一个比它优先级高的任务进入了就绪态,当前任务的CPU使用权就会被抢占,高优先级任务会立刻得到CPU的控制权(在系统允许调度和任务切换的前提下)。
μC/OS-Ⅱ可以管理多达64个任务,但目前版本的μC/OS-Ⅱ有两个任务已经被系统占用了(即空闲任务和统计任务)。
必须给每个任务赋以不同的优先级,任务的优先级号就是任务编号(ID),优先级可以从0到OS_LOWEST_PR10-2。
优先级号越低,任务的优先级越高。
μC/OS-Ⅱ总是运行进入就绪态的优先级最高的任务。
2.2操作系统配置
操作系统配置的目的在于根据应用的需要,对操作系统的功能和规模进行设置,以便优化对系统存储空间的使用。
配置的方法为修改uC_OS-II源代码目录中的OS_CFG.h文件,配置文件配置如下:
#defineOS_MAX_EVENTS10/*最多可以有10个事件*/
#defineOS_MAX_FLAGS5/*最多可以有5个事件标志*/
#defineOS_MAX_MEM_PART5/*最多可以划分5个内存块*/
#defineOS_MAX_QS2/*最多可以使用2个队列*/
#defineOS_MAX_TASKS3/*最多可以创建3个任务*/
#defineOS_LOWEST_PRIO14/*任务优先级不可以大于14*/
#defineOS_TASK_IDLE_STK_SIZE1024/*空闲任务堆栈大小*/
#defineOS_TASK_STAT_EN1/*是否允许使用统计任务*/
#defineOS_TASK_STAT_STK_SIZE1024/*统计任务堆栈大小*/
#defineOS_FLAG_EN0/*是否允许使用事件标志功能*/
#defineOS_FLAG_WAIT_CLR_EN1/*是否允许等待清除事件标志*/
#defineOS_FLAG_ACCEPT_EN1/*是否允许使用OSFlagAccept()*/
#defineOS_FLAG_DEL_EN1/*是否允许使用OSFlagDel()*/
#defineOS_FLAG_QUERY_EN1/*是否允许使用OSFlagQuery()*/
#defineOS_MBOX_EN0/*是否允许使用邮箱功能*/
#defineOS_MBOX_ACCEPT_EN1/*是否允许使用OSMboxAccept()*/
#defineOS_MBOX_DEL_EN1/*是否允许使用OSMboxDel()*/
#defineOS_MBOX_POST_EN1/*是否允许使用OSMboxPost()*/
#defineOS_MBOX_POST_OPT_EN1/*是否允许使用OSMboxPostOpt()*/
#defineOS_MBOX_QUERY_EN1/*是否允许使用OSMboxQuery()*/
#defineOS_MEM_EN0/*是否允许使用内存管理的功能*/
#defineOS_MEM_QUERY_EN1/*是否允许使用OSMemQuery()*/
#defineOS_MUTEX_EN0/*是否允许使用互斥信号量的功能*/
#defineOS_MUTEX_ACCEPT_EN1/*是否允许使用OSMutexAccept()*/
#defineOS_MUTEX_DEL_EN1/*是否允许使用OSMutexDel()*/
#defineOS_MUTEX_QUERY_EN1/*是否允许使用OSMutexQuery()*/
#defineOS_Q_EN0/*是否允许使用队列功能*/
#defineOS_Q_ACCEPT_EN1/*是否允许使用OSQAccept()*/
#defineOS_Q_DEL_EN1/*是否允许使用OSQDel()*/
#defineOS_Q_FLUSH_EN1/*是否允许使用OSQFlush()*/
#defineOS_Q_POST_EN1/*是否允许使用OSQPost()*/
#defineOS_Q_POST_FRONT_EN1/*是否允许使用OSQPostFront()*/
#defineOS_Q_POST_OPT_EN1/*是否允许使用OSQPostOpt()*/
#defineOS_Q_QUERY_EN1/*是否允许使用OSQQuery()*/
#defineOS_SEM_EN0/*是否允许使用信号量功能*/
#defineOS_SEM_ACCEPT_EN1/*是否允许使用OSSemAccept()*/
#defineOS_SEM_DEL_EN1/*是否允许使用OSSemDel()*/
#defineOS_SEM_QUERY_EN1/*是否允许使用OSSemQuery()*/
#defineOS_TASK_CHANGE_PRIO_EN0/*是否允许使用OSTaskChangePrio()*/
#defineOS_TASK_CREATE_EN1/*是否允许使用OSTaskCreate()*/
#defineOS_TASK_CREATE_EXT_EN1/*是否允许使用OSTaskCreateExt()*/
#defineOS_TASK_DEL_EN1/*是否允许使用OSTaskDel()*/
#defineOS_TASK_SUSPEND_EN1/*是否允许使用OSTaskSuspend()andOSTaskResume()*/
#defineOS_TASK_QUERY_EN1/*是否允许使用OSTaskQuery()*/
#defineOS_TIME_DLY_HMSM_EN0/*是否允许使用OSTimeDlyHMSM()*/
#defineOS_TIME_DLY_RESUME_EN1/*是否允许使用OSTimeDlyResume()*/
#defineOS_TIME_GET_SET_EN1/*是否允许使用OSTimeGet()和OSTimeSet()*/
#defineOS_SCHED_LOCK_EN1/*是否允许使用OSSchedLock()和OSSchedUnlock()*/
#defineOS_TICKS_PER_SEC200/*设置每秒之内的时钟节拍数目*/
2.3源程序说明
系统启动后,经过ARM2200启动代码后,进入main()函数,这是我们编写实现应用程序的起点。
首先调用OSInit()对uC/OS-II进行了初始化,接着创建了起始任务TaskStart:
OSTaskCreate(TaskStart,(void*)0,&TaskStartStk[TASK_STK_SIZE-1],0);
TaskStart任务
TaskStart任务负责安装操作系统的时钟中断服务例程、初始化操作系统时钟,初始化串口0,并创建所有的应用任务:
voidTaskStart(void*pdata)
{
charstr[]="uC/OS-IIisStarted\n==============================\n";
TargetInit();/*目标板初始化*/
OSTaskCreate(Task0,(void*)0,&Task0Stk[TASK_STK_SIZE-1],5);/*创建任务Task0*/
OSTaskCreate(Task1,(void*)0,&Task1Stk[TASK_STK_SIZE-1],6);/*创建任务Task1*/
UART0_SendStr((uint8const*)str);/*向串口0发送字符串*/
for(;;)
{
OSTaskSuspend(0);/*挂起优先级为0的任务,即为TaskStart任务本身*/
}
}
TaskStart任务完成上述操作后将自己挂起,操作系统将调度当前优先级最高的应用任务Task0运行。
应用任务
应用任务Task0运行后将自己挂起,之后操作系统就会调度处于就绪状态的优先级最高的任务,具体代码如下:
voidTask0(void*pdata)
{
charstr[]="Task0isrunning\nTask1isSuspended\n==============================\n";
pdata=pdata;/*避免编译警告*/
for(;;)
{
UART0_SendStr((uint8const*)str);/*向串口0发送字符串*/
DelayTime(3000);/*延时*/
OSTaskSuspend(5);/*挂起优先级为5的任务,即Task0本身*/
}
}
应用任务Task1运行后将Task0唤醒,使其进入到就绪队列中:
voidTask1(void*pdata)
{
charstr[]="Task0isSuspended\nTask1isrunning\n==============================\n";
pdata=pdata;/*避免编译警告*/
for(;;)
{
UART0_SendStr((uint8const*)str);/*向串口0发送字符串*/
OSTimeDly(1000);/*延时*/
OSTaskResume(5);/*为优先级为5的任务即Task0解挂*/
}
}
3试验步骤
3.1硬件连接
将ARM开发板的JTAG口通过EasyJTAG-H或EasyJTAG连接到PC机上,ARM板的串口0连接到PC机的串口1,插上ARM开发板电源。
3.2利用周立功ARM2200工程模板建立工程
1)打开ADS1.2集成开发软件
点击开始->所有程序->ARMDeveloperSuitev1.2->CodeWarriorforARMDeveloperSuite,如下图所示:
图2打开ADS1.2集成开发软件
图3ADS1.2集成开发软件界面
2)用周立功LPC2200工程模板建立工程
在D盘下建立文件夹Experiment3,点击file->New,将弹出如下图的对话框。
工程名称
工程路径
选择工程模板类型lpc22xx
图4工程建立界面(a)
选择工程模板类型为“ARMExecutableImageforuCOSII(forlpc22xx)”,为工程命名如Experiment3,选择工程存储路径如“D:
/Experiment3”,设置完成后点击确定,工程建立完成。
下图为工程建立完成后的界面。
图5工程建立界面(b)
3)为工程添加用户程序文件
将文件夹UART0、ARM、SOURCE及文件main.C拷贝到Experiment3目录下。
在ADS1.2工程界面中点击右键,点击“AddFiles…”,将文件“D:
\Experiment3\main.c”和“D:
\Experiment3\UART0\SendStr.c”添加到工程中。
已经添加的C文件
图6添加用户程序到工程(c)
打开文件config.h,删除掉“#include“..\..\Arm_Pc\pc.h””语句,如下图所示:
将该语句删除掉
图7
4)编译程序代码
添加用户程序完成后,选择程序调试运行模式,选择在外部RAM中进行调试,即选择DebugInExram,如图21所示:
选择程序调试运行环境
程序在内部Flash中调试
程序在外部Flash中调试
程序在内部Flash中调试,并加密
程序在外部RAM中调试
图8设置程序运行环境
点击进入工程设置界面
点击编译工程
点击进入工程调试环境
图9编译程序界面(a)
点击
按钮开始编译程序,编译后界面如下,如果出现错误,要修改出错程序代码。
图10编译程序界面(b)
最后点击
下载调试,操作步骤与实验1、实验2相同。
在程序执行时,在PC机上打开串口调试助手,串口调试助手设置如下:
图11串口调试助手界面
4运行及观察应用输出信息
程序执行时,串口调试助手接收到信息如下:
图12实验输出结果
阅读程序源代码,并根据串口输出结果,分析任务的调度,任务的挂起及任务解挂过程。
5本实验中所用到的µC/OS-II相关函数
5.1OSTaskCreate()
建立一个新任务。
任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立。
中断处理程序中不能建立任务。
一个任务可以为无限循环的结构。
函数原型:
INT8UOSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT8Uprio);
参数说明:
task是指向任务代码首地址的指针。
Pdata指向一个数据结构,该结构用来在建立任务时向任务传递参数。
返回值:
OSTaskCreate()的返回值为下述之一:
●OS_NO_ERR:
函数调用成功。
●OS_PRIO_EXIST:
具有该优先级的任务已经存在。
●OS_PRIO_INVALID:
参数指定的优先级大于OS_LOWEST_PRIO。
●OS_NO_MORE_TCB:
系统中没有OS_TCB可以分配给任务了。
5.2OSTaskSuspend()
无条件挂起一个任务。
调用此函数的任务也可以传递参数OS_PRIO_SELF,挂起调用任务本身。
当前任务挂起后,只有其他任务才能唤醒被挂起的任务。
任务挂起后,系统会重新进行任务调度,运行下一个优先级最高的就绪任务。
唤醒挂起任务需要调用函数OSTaskResume()。
任务的挂起是可以叠加到其他操作上的。
例如,任务被挂起时正在进行延时操作,那么任务的唤醒就需要两个条件:
延时的结束以及其他任务的唤醒操作。
又如,任务被挂起时正在等待信号量,当任务从信号量的等待对列中清除后也不能立即运行,而必须等到被唤醒后。
函数原型:
INT8UOSTaskSuspend(INT8Uprio);
参数说明:
prio为指定要获取挂起的任务优先级,也可以指定参数OS_PRIO_SELF,挂起任务本身。
此时,下一个优先级最高的就绪任务将运行。
返回值:
OSTaskSuspend()的返回值为下述之一:
●OS_NO_ERR:
函数调用成功。
●OS_TASK_SUSPEND_IDLE:
试图挂起μC/OS-II中的空闲任务(Idletask)。
此为非法操作。
●OS_PRIO_INVALID:
参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF的值。
●OS_TASK_SUSPEND_PRIO:
要挂起的任务不存在。
5.3OSTaskResume()
唤醒一个用OSTaskSuspend()函数挂起的任务。
OSTaskResume()也是唯一能“解挂”挂起任务的函数。
函数原型:
NT8UOSTaskResume(INT8Uprio);
参数说明:
prio指定要唤醒任务的优先级。
返回值:
OSTaskResume()的返回值为下述之一:
●OS_NO_ERR:
函数调用成功。
●OS_TASK_RESUME_PRIO:
要唤醒的任务不存在。
●OS_TASK_NOT_SUSPENDED:
要唤醒的任务不在挂起状态。
●OS_PRIO_INVALID:
参数指定的优先级大于或等于OS_LOWEST_PRIO。
5.3OSTimeDly()
将调用该函数的任务延时一段特定的时间,延时的长短是由指定的时钟节拍数目来确定的,调用该函数后经进行一次任务调度,从而去执行一个优先级最高的就绪态任务。
任务在调用OSTimeDly()后,一旦规定的时间期满或者有其他任务通过调用OSTimeDlyResume()取消了延时,任务会立即进入就绪状态。
函数原型:
voidOSTimeDly(INT16Uticks)
参数说明:
ticks任务延时的时钟节拍数
返回值:
无