嵌入式系统实训
课程:嵌入式系统及应用
学号:
姓名:
班级:
教师:
计算机科学与技术学院
实训内容及安排
实训目的与要求:
嵌入式系统实训的目标是通过对嵌入式系统的体系结构和操作系统的开发培养学生嵌入式系统的能力。
实训方式:
自己设计方案,按照指导书的要求独立完成实训。
实训环境:PC机;ARM实际系统;UCOS—Ⅱ系统;ADS1.2环境
实训内容:
说明:实验总共分四个阶段,分别如下:
第一阶段 总体分析OS_TASK.C包含的函数
第二阶段 逐个分析OS_TASK.C中的函数
第三阶段 画流程图
第四阶段 实验总结
第一阶段 总体分析OS_TASK.C包含的函数
主要内容:
OS_TASK.C(是我们在机房使用的文件,下面的也是)
基本要求:
(1)、了解OS_TASK.C包含哪些函数
(2)、了解OS_TASK.C的作用
时间:第1天
OS_TASK.C包含的函数有:
OSTaskChangePrio()函数 允许生成OSTaskCreate()函数
OS_ENTER_CRITICAL();关闭中断函数 OS_EXIT_CRITICAL();打开中断函数
OSTaskStkInit()初始化函数 OSTaskDelHook();可在钩子程序中加入自定程序函数
第二阶段 逐个分析OS_TASK.C中的函数
主要内容:
OS_TASK.C
基本要求:
(1)、了解OS_TASK.C中各个函数的作用
(2)、分析OS_TASK.C中各个函数的代码
时间:第2—6天
/*
*************************************************************************************************
* uC/OS-II实时控制内核
* 主要的包含文件
* 任务管理
*
* 文 件: OS_TASK.C 任务管理代码
* 作 者: Jean J. Labrosse
* 中文注解: 钟常慰 zhongcw @ 126.com 译注版本:1.0 请尊重原版内容
*************************************************************************************************
*/
#ifndef OS_MASTER_FILE //是否已经定义OS_MASTER_FILE
#include "includes.h" //包含"includes.h"文件
#endif //结束定义
/*
*************************************************************************************************
* 改变一个任务的优先级(CHANGE PRIORITY OF A TASK)
* 描述: 改变一个任务的优先级。
*
* 参数: oldp 是任务原先的优先级。
* newp 是任务的新优先级。
* 返回: OS_NO_ERR 任务优先级成功改变。
* OS_PRIO_INVALID 参数中的任务原先优先级或新优先级大于或等于OS_LOWEST_PRIO。
(i.e. >= OS_LOWEST_PRIO)
* OS_PRIO_EXIST 优先级为PIP的任务已经存在;
* OS_PRIO_ERR 参数中的任务原先优先级不存在。
* 注意: 参数中的新优先级必须是没有使用过的,否则会返回错误码.在OSTaskChangePrio()中还会先
* 判断要改变优先级的任务是否存在。
*
*************************************************************************************************
#if OS_TASK_CHANGE_PRIO_EN > 0 //允许生成OSTaskChangePrio()函数
INT8U OSTaskChangePrio (INT8U oldprio, INT8U newprio)
{ //改变一个任务的优先级(任务旧的优先级、任务新的优先级)
#if OS_CRITICAL_METHOD == 3 //允许生成OSTaskCreate()函数
OS_CPU_SR cpu_sr;
#endif
#if OS_EVENT_EN > 0 //消息事件是否 > 0
OS_EVENT *pevent; //定义事件指针
#endif
OS_TCB *ptcb; //定义消息事件的任务控制块指针
INT8U x; //优先级低3位值
INT8U y; //优先级高3位值
INT8U bitx; //优先级低3位值计算对应值
INT8U bity; //优先级高3位值计算索引值
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
//当旧任务 >= 最低优先级 并且 旧任务不是本身 并且新任务>= 最低优先级
if ((oldprio >= OS_LOWEST_PRIO && oldprio != OS_PRIO_SELF) ||
newprio >= OS_LOWEST_PRIO) {
return (OS_PRIO_INVALID); //参数中的任务原先优先级或新优先级大于或等于OS_LOWEST_PRIO
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) { //确认新任务优先级未被使用,即就绪态为0
OS_EXIT_CRITICAL(); //打开中断
return (OS_PRIO_EXIST); //返回新任务(优先级为PIP的任务已经存在)
} else {
OSTCBPrioTbl[newprio] = (OS_TCB *)1; //新任务优先级未被使用,保留它(为1)
OS_EXIT_CRITICAL(); //打开中断
//预先计算新任务优先级任务控制块OS_TCB的某些值
y = newprio >> 3; //保留优先级高3位(3-5位)
bity = OSMapTbl[y]; //计算索引值
x = newprio & 0x07; //保存优先级低3位(0-2位)
bitx = OSMapTbl[x]; //计算对应值
2 H:\SOURCE中文源代码\OS_TASK.C
OS_ENTER_CRITICAL(); //关闭中断
if (oldprio == OS_PRIO_SELF) { //要改变的是否使旧任务本身
oldprio = OSTCBCur->OSTCBPrio; //如果是(正在运行的优先级(旧任务本身的优先级))
}
if ((ptcb = OSTCBPrioTbl[oldprio]) != (OS_TCB *)0) { //变更的旧任务必须存在(1即就绪)
OSTCBPrioTbl[oldprio] = (OS_TCB *)0; //旧任务就绪态去除它(为0)
if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) {
//如果该任务处于就绪态,那么必须在当前的优先级下,从就绪表中移除该任务,然后在新
//的优先级下,将该任务插入到就绪表中。
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
OSRdyGrp |= bity; //利用预先计算值将任务插入到就绪表中
OSRdyTbl[y] |= bitx;
#if OS_EVENT_EN > 0 //消息事件是否 > 0
} else { //(任务未就绪)否则,拾取任务事件指针
if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) { //任务事件表为1(有消息)
//如果任务正在等待某一事件的发生,该函数必须将任务从事件控制块的等待列表中删除
//并在新的优先级下将事件插入到等待队列中。任务也可能正在等待延时时间到,或是被
//挂起。
if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
}
pevent->OSEventGrp |= bity; //将任务插入到等待列表中
pevent->OSEventTbl[y] |= bitx;
}
#endif
}
OSTCBPrioTbl[newprio] = ptcb; //将任务的OS_TCB的指针存到新任务OSTCBPrioTbl[]
ptcb->OSTCBPrio = newprio; //设定新的任务优先级,并保存原有计算值
ptcb->OSTCBY = y; //高3位计算值
ptcb->OSTCBX = x; //低3位计算值
ptcb->OSTCBBitY = bity;
ptcb->OSTCBBitX = bitx;
OS_EXIT_CRITICAL(); //打开中断
OS_Sched(); //任务调度,最高任务优先级运行
return (OS_NO_ERR); //任务优先级成功改变
} else { //否则
OSTCBPrioTbl[newprio] = (OS_TCB *)0; //新任务就绪态去除它(为0不存在),
OS_EXIT_CRITICAL(); //打开中断
return (OS_PRIO_ERR); //返回(参数中的任务原先优先级不存在)
}
}
}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* 建立一个新任务(CREATE A TASK)
*
* 描述: 建立一个新任务。任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立.中断
* 处理程序中不能建立任务.一个任务必须为无限循环结构(如下所示),且不能有返回点。
* OSTaskCreate()是为与先前的μC/OS版本保持兼容,新增的特性在OSTaskCreateExt()函数中.
* 无论用户程序中是否产生中断,在初始化任务堆栈时,堆栈的结构必须与CPU中断后寄存器入栈的
* 顺序结构相同.详细说明请参考所用处理器的手册。
*
* 参数: task 是指向任务代码的指针。
*
* pdata 指向一个数据结构,该结构用来在建立任务时向任务传递参数。下例中说明uC/OS中的任
* 务结构以及如何传递参数pdata:
* void Task (void *pdata)
* {
* ... // 对参数'pdata'进行操作
* for (;;) { // 任务函数体.
* ...
* ...
* // 在任务体中必须调用如下函数之一:
* // OSMboxPend() 用于任务等待消息,消息通过中断或另外的任务发送给需要的任务
* // OSFlgPend() 用于任务等待事件标志中的事件标志
* // OSMutexPend() 任务需要独占资源
* // OSQPend() 用于任务等待消息
* // OSSemPend() 用于任务试图取得共享资源的使用权,任务需要与其它任务或中断
* 同步及任务需要等待特定事件的发生场合
* // OSTimeDly() 任务延时若干时钟节拍
* // OSTimeDlyHMSM() 任务延时若干时间
* // OSTaskSuspend() 挂起任务本身
3 H:\SOURCE中文源代码\OS_TASK.C
* // OSTaskDel() 删除任务本身
* ...
* ...
* }
* ptos 为指向任务堆栈栈顶的指针。任务堆栈用来保存局部变量,函数参数,返回地址以及任务被
* 中断时的CPU寄存器内容.任务堆栈的大小决定于任务的需要及预计的中断嵌套层数。计算
* 堆栈的大小,需要知道任务的局部变量所占的空间,可能产生嵌套调用的函数,及中断嵌套
* 所需空间。如果初始化常量OS_STK_GROWTH设为1,堆栈被设为从内存高地址向低地址增长,
* 此时ptos应该指向任务堆栈空间的最高地址。反之,如果OS_STK_GROWTH设为0,堆栈将从内
* 存的低地址向高地址增长。
*
* prio 为任务的优先级。每个任务必须有一个唯一的优先级作为标识。数字越小,优先级越高。
*
* 返回: OS_NO_ERR 函数调用成功;
* OS_PRIO_EXIT 具有该优先级的任务已经存在;
* OS_PRIO_INVALID 参数指定的优先级大于OS_LOWEST_PRIO; (i.e. >= OS_LOWEST_PRIO)
* OS_NO_MORE_TCB 系统中没有OS_TCB可以分配给任务了。
*
* 注意: 1、任务堆栈必须声明为OS_STK类型。
* 2、在任务中必须调用uC/OS提供的下述过程之一:延时等待、任务挂起、等待事件发生(等待信
* 号量,消息邮箱、消息队列),以使其他任务得到CPU。
* 3、用户程序中不能使用优先级0,1,2,3,以及OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2,
* OS_LOWEST_PRIO-1, OS_LOWEST_PRIO。这些优先级μC/OS系统保留,其余的56个优先级提供给
* 应用程序。
*************************************************************************************************
*/
#if OS_TASK_CREATE_EN > 0 //允许生成OSTaskCreate()函数
INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
{ //建立任务(任务代码指针、传递参数指针、分配任务堆栈栈顶指针、任务优先级)
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_STK *psp; //初始化任务堆栈指针变量,返回新的栈顶指针
INT8U err; //定义(获得并定义初始化任务控制块)是否成功
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0
OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留这个优先级,将就绪态设为0
OS_EXIT_CRITICAL(); //打开中断
psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); //初始化任务堆栈
err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); //获得并初始化任务控制块
if (err == OS_NO_ERR) { //任务控制初始化成功
OS_ENTER_CRITICAL(); //关闭中断
OSTaskCtr++; //任务计数器加1
OS_EXIT_CRITICAL(); //打开中断
if (OSRunning == TRUE) { //检查是否有(某个)任务在运行
OS_Sched(); //任务调度,最高任务优先级运行
}
} else { //否则,任务初始化失败
OS_ENTER_CRITICAL(); //关闭中断
OSTCBPrioTbl[prio] = (OS_TCB *)0; //放弃任务,设此任务就绪态为0
OS_EXIT_CRITICAL(); //打开中断
}
return (err); //返回(获得并定义初始化任务控制块是否成功)
}
OS_EXIT_CRITICAL(); //打开中断
return (OS_PRIO_EXIST); //返回(具有该优先级的任务已经存在)
}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* CREATE A TASK (Extended Version)
*
* 描述: 建立一个新任务。与OSTaskCreate()不同的是,OSTaskCreateExt()允许用户设置更多的细节
* 内容.任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立,但中断处理
* 程序中不能建立新任务。一个任务必须为无限循环结构(如下所示),且不能有返回点。
*
* 参数: task 是指向任务代码的指针。
4 H:\SOURCE中文源代码\OS_TASK.C
*
* pdata Pdata指针指向一个数据结构,该结构用来在建立任务时向任务传递参数。下例中说
* 明uC/OS中的任务代码结构以及如何传递参数pdata:(如果在程序中不使用参数pdata,
* 为了避免在编译中出现"参数未使用"的警告信息,可以写一句pdata= pdata;)
* void Task (void *pdata)
* {
* ... //对参数pdata进行操作,例如pdata= pdata
* for (;;) { // 任务函数体.总是为无限循环结构
* ...
* ...
* // 任务中必须调用如下的函数:
* // OSMboxPend() 用于任务等待消息,消息通过中断或另外的任务发送给需要的任务
* // OSFlgPend() 用于任务等待事件标志中的事件标志
* // OSMutexPend() 任务需要独占资源
* // OSQPend() 用于任务等待消息
* // OSSemPend() 用于任务试图取得共享资源的使用权,任务需要与其它任务或中断
* 同步及任务需要等待特定事件的发生场合
* // OSTimeDly() 任务延时若干时钟节拍
* // OSTimeDlyHMSM() 任务延时若干时间
* // OSTaskSuspend() 挂起任务本身
* // OSTaskDel() 删除任务本身
* ...
* ...
* }
* }
* ptos 为指向任务堆栈栈顶的指针.任务堆栈用来保存局部变量,函数参数,返回地址以及中
* 断时的CPU寄存器内容.任务堆栈的大小决定于任务的需要及预计的中断嵌套层数.计
* 算堆栈的大小,需要知道任务的局部变量所占的空间,可能产生嵌套调用的函数,及
* 中断嵌套所需空间.如果初始化常量OS_STK_GROWTH设为1,堆栈被设为向低端增长
* (从内存高地址向低地址增长).此时ptos应该指向任务堆栈空间的最高地址.反之,
* 如果OS_STK_GROWTH设为0,堆栈将从低地址向高地址增长.
*
* prio 任务的优先级。每个任务必须有一个唯一的优先级作为标识.数字越小,优先级越高。
*
* id 是任务的标识,目前这个参数没有实际的用途,但保留在OSTaskCreateExt()中供今后
* 扩展,应用程序中可设置id与优先级相同.(0..65535)
*
* pbos 为指向堆栈底端的指针。如果初始化常量OS_STK_GROWTH设为1,堆栈被设为从内存高
* 地址向低地址增长.此时pbos应该指向任务堆栈空间的最低地址.反之,如果
* OS_STK_GROWTH设为0,堆栈将从低地址向高地址增长。pbos应该指向堆栈空间的最高
* 地址.参数pbos用于堆栈检测函数OSTaskStkChk().
*
* stk_size 指定任务堆栈的大小。其单位由OS_STK定义:当OS_STK的类型定义为INT8U、INT16U、
* INT32U的时候, stk_size的单位为分别为字节(8位)、字(16位)和双字(32位)。
*
* pext 是一个用户定义数据结构的指针,可作为TCB的扩展。例如,当任务切换时,用户定义
* 的数据结构中可存放浮点寄存器的数值,任务运行时间,任务切入次数等等信息。
*
* opt 存放与任务相关的操作信息。opt的低8位由uC/OS保留,用户不能使用。用户可以使用
* opt的高8位。每一种操作由opt中的一位或几位指定,当相应的位被置位时,表示选择
* 某种操作。当前的μC/OS版本支持下列操作:
* OS_TASK_OPT_STK_CHK:决定是否进行任务堆栈检查;
* OS_TASK_OPT_STK_CLR:决定是否清空堆栈;
* OS_TASK_OPT_SAVE_FP:决定是否保存浮点寄存器的数值。此项操作仅当处理器有浮
* 点硬件时有效。保存操作由硬件相关的代码完成。
*
*
* 返回: OS_NO_ERR:函数调用成功;
* OS_PRIO_EXIST:具有该优先级的任务已经存在;
* OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO;
* OS_NO_MORE_TCB:系统中没有OS_TCB可以分配给任务了.
*
* 注意: 1、任务堆栈必须声明为OS_STK类型;
* 2、在任务中必须进行uC/OS提供的下述过程之一:延时等待、任务挂起、等待事件发生(等待
* 信号量,消息邮箱、消息队列),以使其他任务得到CPU;
* 3、用户程序中不能使用优先级0,1,2,3,以及OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2,
* OS_LOWEST_PRIO-1, OS_LOWEST_PRIO。这些优先级μC/OS系统保留,其余56个优先级提供给
* 应用程序.
*************************************************************************************************
*/
/*$PAGE*/
#if OS_TASK_CREATE_EXT_EN > 0 //允许生成OSTaskCreateExt()函数
INT8U OSTaskCreateExt (void (*task)(void *pd), //建立扩展任务(任务代码指针
void *pdata, //传递参数指针
OS_STK *ptos, //分配任务堆栈栈顶指针
INT8U prio, //分配任务优先级
5 H:\SOURCE中文源代码\OS_TASK.C
INT16U id, //(未来的)优先级标识(与优先级相同)
OS_STK *pbos, //分配任务堆栈栈底指针
INT32U stk_size, //指定堆栈的容量(检验用)
void *pext, //指向用户附加的数据域的指针
INT16U opt) //建立任务设定选项)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_STK *psp; //初始化任务堆栈指针变量,返回新的栈顶指针
INT8U err; //定义(获得并定义初始化任务控制块)是否成功
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0
OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留这个优先级,将就绪态设为0
OS_EXIT_CRITICAL(); //打开中断
//以下两为1堆栈才能清0
if (((opt & OS_TASK_OPT_STK_CHK) != 0x0000) || //检验任务堆栈,CHK=1
((opt & OS_TASK_OPT_STK_CLR) != 0x0000)) { //任务建立时是否清0,CLR=1
#if OS_STK_GROWTH == 1 //堆栈生长方向
(void)memset(pbos, 0, stk_size * sizeof(OS_STK)); //从下向上递增
#else
(void)memset(ptos, 0, stk_size * sizeof(OS_STK)); //从上向下递减
#endif
}
psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, opt); //初始化任务堆栈
err = OS_TCBInit(prio, psp, pbos, id, stk_size, pext, opt); //获得并初始化任务控制块
if (err == OS_NO_ERR) { //任务控制初始化成功
OS_ENTER_CRITICAL(); //关闭中断
OSTaskCtr++; //任务计数器加1
OS_EXIT_CRITICAL(); //打开中断
if (OSRunning == TRUE) { //检查是否有(某个)任务在运行
OS_Sched(); //任务调度,最高任务优先级运行
}
} else { //否则,任务初始化失败
OS_ENTER_CRITICAL(); //关闭中断
OSTCBPrioTbl[prio] = (OS_TCB *)0; //放弃任务,设此任务就绪态为0
OS_EXIT_CRITICAL(); //打开中断
}
return (err); //返回(获得并定义初始化任务控制块是否成功)
}
OS_EXIT_CRITICAL(); //打开中断
return (OS_PRIO_EXIST); //具有该优先级的任务已经存在
}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* 删除一个指定优先级的任务(DELETE A TASK)
*
* 描述: 删除一个指定优先级的任务。任务可以传递自己的优先级给OSTaskDel(),从而删除自身.如果任
* 务不知道自己的优先级,还可以传递参数OS_PRIO_SELF.被删除的任务将回到休眠状态.任务被删
* 除后可以用函数OSTaskCreate()或OSTaskCreateExt()重新建立.
*
* 参数: prio 为指定要删除任务的优先级,也可以用参数OS_PRIO_SELF代替,此时,下一个优先级最高
* 的就绪任务将开始运行。
*
* 返回: OS_NO_ERR:函数调用成功;
* OS_TASK_DEL_IDLE:错误操作,试图删除空闲任务(Idle task);
* OS_TASK_DEL_ ERR:错误操作,指定要删除的任务不存在;
* OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO;
* OS_TASK_DEL_ISR:错误操作,试图在中断处理程序中删除任务.
*
*
* 注意: 1、OSTaskDel()将判断用户是否试图删除uC/OS中的空闲任务(Idle task);
* 2、在删除占用系统资源的任务时要小心,此时,为安全起见可以用另一个函数OSTaskDelReq().
*************************************************************************************************
*/
6 H:\SOURCE中文源代码\OS_TASK.C
/*$PAGE*/
#if OS_TASK_DEL_EN > 0 //允许生成 OSTaskDel()函数
INT8U OSTaskDel (INT8U prio) //删除任务(任务的优先级)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
#if OS_EVENT_EN > 0 //消息事件是否 > 0
OS_EVENT *pevent; //定义事件指针
#endif
//版本是否 > 2.51 并且 允许产生事件标志相关代码 并且应用中最多事件标志组的数目 > 0
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
OS_FLAG_NODE *pnode; //定义标志节点
#endif
OS_TCB *ptcb; //定义消息事件的任务控制块指针
if (OSIntNesting > 0) { //当前中断嵌套 > 0时,表示还有中断程序运行
return (OS_TASK_DEL_ISR); //错误操作,试图在中断处理程序中删除任务
}
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio == OS_IDLE_PRIO) { //检查任务优先级是否是空闲任务
return (OS_TASK_DEL_IDLE); //错误操作,试图删除空闲任务(Idle task)
} //当任务 >= 最低优先级 并且 任务不是本身
if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (prio == OS_PRIO_SELF) { //检查的删除者是否是任务(优先级)本身
prio = OSTCBCur->OSTCBPrio; //正在运行的优先级(任务本身的优先级)
} //删除的任务必须存在
if ((ptcb = OSTCBPrioTbl[prio]) != (OS_TCB *)0) { //调用这个任务的优先级的就绪值
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) { //当就绪=1(即就绪状态)
OSRdyGrp &= ~ptcb->OSTCBBitY; //该任务处于就绪值,从就绪表中去除
}
#if OS_EVENT_EN > 0 //消息事件是否 > 0
pevent = ptcb->OSTCBEventPtr; //拾取该任务的事件控制指针
if (pevent != (OS_EVENT *)0) {
//指向事件控制块的指针是否为Null
if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
//事件(消息)在等待表中将自己所处的表中删除
pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
}
}
#endif
//版本是否 > 2.51 并且 允许产生事件标志相关代码 并且应用中最多事件标志组的数目 > 0
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
pnode = ptcb->OSTCBFlagNode; //标志节点 = 指向事件标志节点的指针
if (pnode != (OS_FLAG_NODE *)0) { //如果任务处于事件标志的等待表中
OS_FlagUnlink(pnode); //就从此表中删除
}
#endif
ptcb->OSTCBDly = 0; //将任务时钟节拍清0,确保重新开中断,中断程序不使该任务就绪
ptcb->OSTCBStat = OS_STAT_RDY; //将任务的状态字处于完毕状态
if (OSLockNesting < 255) { //如果锁定嵌套计数器 < 255,
OSLockNesting++; //锁定嵌套计数器加1,使这个任务处于休眠状态
}
OS_EXIT_CRITICAL(); //打开中断
OS_Dummy(); //增加一个空指令
OS_ENTER_CRITICAL(); //关闭中断
if (OSLockNesting > 0) { //(可以继续执行删除任务的操作了)
OSLockNesting--; //重新关闭中断后,可以通过锁定嵌套计数器减1,重新允许任务调度
}
OSTaskDelHook(ptcb); //可在钩子程序中加入自定程序
OSTaskCtr--; //任务计数器减1,ucos管理的任务减少一个
OSTCBPrioTbl[prio] = (OS_TCB *)0; //将被删除的任务控制块OS_TCB指针=Null,
//从任务优先级中把OS_TCB删除
if (ptcb->OSTCBPrev == (OS_TCB *)0) { //任务块双向链接表的前链接是否Null
ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0; //删除该任务的任务控制块OS_TCB
OSTCBList = ptcb->OSTCBNext; //链接表指向后一个链接
} else { //否则
ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext; // ?
ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev; // ?
7 H:\SOURCE中文源代码\OS_TASK.C
} //OSTCBPrev:用于任务块双向链接表的前链接
//OSTCBNext:用于任务块双向链接表的后链接
//OSTCBFreeList:空任务控制块指针
ptcb->OSTCBNext = OSTCBFreeList; //被删除的任务控制块OS_TCB被退回到空闲OS_TCB表中
OSTCBFreeList = ptcb; //以供建立其它任务使用
OS_EXIT_CRITICAL(); //打开中断
OS_Sched(); //任务调度,最高任务优先级运行
return (OS_NO_ERR); //函数调用成功
}
OS_EXIT_CRITICAL(); //打开中断
return (OS_TASK_DEL_ERR); //错误操作,指定要删除的任务不存在
}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* 请求一个任务删除其它任务或自身(REQUEST THAT A TASK DELETE ITSELF)
*
* 描述: 请求一个任务删除自身。通常OSTaskDelReq()用于删除一个占有系统资源的任务(例如任务建立
* 了信号量)对于此类任务,在删除任务之前应当先释放任务占用的系统资源。
* 具体的做法是:在需要被删除的任务中调用OSTaskDelReq()检测是否有其他任务的删除请求,如
* 果有,则释放自身占用的资源,然后调用OSTaskDel()删除自身。例如,假设任务5要删除任务10,
* 而任务10占有系统资源,此时任务5不能直接调用OSTaskDel(10)删除任务10,而应该调用
* OSTaskDelReq(10)向任务10发送删除请求.在任务10中调用OSTaskDelReq(OS_PRIO_SELF),并检测
* 返回值。如果返回OS_TASK_DEL_REQ,则表明有来自其他任务的删除请求,此时任务10应该先释放
* 资源,然后调用OSTaskDel(OS_PRIO_SELF)删除自己。任务5可以循环调用OSTaskDelReq(10)并检
* 测返回值,如果返回OS_TASK_NOT_EXIST,表明任务10已经成功删除。
* void Task(void *data)
* {
* ...
* ...
* while (1) {
* OSTimeDly(1);
* if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ)
* {
* 释放任务占用的系统资源;
* 释放动态分配的内存;
* OSTaskDel(OS_PRIO_SELF);
* }
* }
* }
* 参数: prio 为要求删除任务的优先级。如果参数为OS_PRIO_SELF,则表示调用函数的任务正在查询
* 是否有来自其他任务的删除请求。
*
* 返回: OS_NO_ERR:删除请求已经被任务记录;
* OS_TASK_NOT_EXIST:指定的任务不存在,发送删除请求的任务可以等待此返回值,看删除是否成功;
* OS_TASK_DEL_IDLE: 错误操作,试图删除空闲任务(Idle task);
* OS_PRIO_INVALID: 参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF的值;
* OS_TASK_DEL_REQ: 当前任务收到来自其他任务的删除请求;
* 注意:OSTaskDelReq()将判断用户是否试图删除uC/OS中的空闲任务(Idle task)。
*************************************************************************************************
*/
/*$PAGE*/
#if OS_TASK_DEL_EN > 0 //允许生成 OSTaskDel()函数
INT8U OSTaskDelReq (INT8U prio) //请求一个任务删除其它任务或自身?(任务的优先级)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN stat; //定义(布尔)任务标志返回值
INT8U err; //定义函数成功删除或其它任务正在申请删除
OS_TCB *ptcb; //定义消息事件的任务控制块指针
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio == OS_IDLE_PRIO) { //检查任务优先级是否是空闲任务
return (OS_TASK_DEL_IDLE); //错误操作,试图删除空闲任务(Idle task)
} //当任务 >= 最低优先级 并且 任务不是本身
if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
}
#endif
if (prio == OS_PRIO_SELF) { //如果删除者是任务本身
OS_ENTER_CRITICAL(); //关闭中断
stat = OSTCBCur->OSTCBDelReq; //stat:存储在任务控制块中的标志值
OS_EXIT_CRITICAL(); //打开中断
8 H:\SOURCE中文源代码\OS_TASK.C
return (stat); //返回任务标志值
}
OS_ENTER_CRITICAL(); //关闭中断
if ((ptcb = OSTCBPrioTbl[prio]) != (OS_TCB *)0) { //调用这个任务的优先级的就绪值
ptcb->OSTCBDelReq = OS_TASK_DEL_REQ; //当前任务收到来自其他任务的删除请求
err = OS_NO_ERR; //删除请求已经被任务记录
} else { //否则
err = OS_TASK_NOT_EXIST; //该任务可能已经删除了
}
//指定的任务不存在,发送删除请求的任务可以等待此返回值,看删除是否成功
OS_EXIT_CRITICAL(); //关闭中断
return (err); //返回删除情况标志
}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* 唤醒一个用OSTaskSuspend()函数挂起的任务(RESUME A SUSPENDED TASK)
*
* 描述: 唤醒一个用OSTaskSuspend()函数挂起的任务。OSTaskResume()也是唯一能"解挂"挂起任务的函数。
*
* 参数: prio 指定要唤醒任务的优先级。
*
* 返回: OS_NO_ERR: 函数调用成功;
* OS_TASK_RESUME_PRIO: 要唤醒的任务不存在;
* OS_TASK_NOT_SUSPENDED:要唤醒的任务不在挂起状态;
* OS_PRIO_INVALID: 参数指定的优先级大于或等于OS_LOWEST_PRIO。
*************************************************************************************************
*/
#if OS_TASK_SUSPEND_EN > 0 //允许生成 OSTaskDel()函数
INT8U OSTaskResume (INT8U prio) //唤醒一个用OSTaskSuspend()函数挂起的任务(任务的优先级)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_TCB *ptcb; //定义消息事件的任务控制块指针
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio >= OS_LOWEST_PRIO) { //当任务 >= 最低优先级
return (OS_PRIO_INVALID); //返回(要唤醒的任务不存在)
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { //调用这个任务的优先级的就绪值
OS_EXIT_CRITICAL(); //打开中断
return (OS_TASK_RESUME_PRIO); //返回(要唤醒的任务不存在)
} //任务控制块状态字相与OS_STAT_SUSPEND为1,任务存在
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) != 0x00) { //要恢复的任务必须是存在的
//通过清除OSTCBStat域中的OS_STAT_SUSPEND未而取消挂起
//要使任务处于就绪状态,OSTCBDly必须是0,这是因为在OSTCBStat中,没有任何标志表明任务正在
//等待延时事件到
if (((ptcb->OSTCBStat &= ~OS_STAT_SUSPEND) == OS_STAT_RDY) &&
(ptcb->OSTCBDly == 0)) {
//只有以上两个条件满足,任务才能处于就绪态
OSRdyGrp |= ptcb->OSTCBBitY; //保存任务就绪标准0-7到OSRdyGrp
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; //保存任务优先级别0-7到OSRdyTbl[]
OS_EXIT_CRITICAL(); //打开中断
OS_Sched(); //任务调度,最高任务优先级运行
} else { //否则
OS_EXIT_CRITICAL(); //打开中断
}
return (OS_NO_ERR); //返回(函数调用成功)
}
OS_EXIT_CRITICAL(); //打开中断
return (OS_TASK_NOT_SUSPENDED); //返回(要唤醒的任务不在挂起状态)
}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* 检查任务堆栈状态,计算指定任务堆栈中的未用空间和已用空间(STACK CHECKING)
*
* 描述: 检查任务堆栈状态,计算指定任务堆栈中的未用空间和已用空间。使用OSTaskStkChk()函数要求
9 H:\SOURCE中文源代码\OS_TASK.C
* 所检查的任务是被OSTaskCreateExt()函数建立的,且opt参数中OS_TASK_OPT_STK_CHK操作项打开。
* //计算堆栈未用空间的方法是从堆栈底端向顶端逐个字节比较,检查堆栈中0的个数,直到一个非0的
* 数值出现.这种方法的前提是堆栈建立时已经全部清零.要实现清零操作,需要在任务建立初始化
* 堆栈时设置OS_TASK_OPT_STK_CLR为1.如果应用程序在初始化时已经将全部RAM清零,且不进行任
* 务删除操作,也可以设置OS_TASK_OPT_STK_CLR为0,这将加快OSTaskCreateExt()函数的执行速度。
*
* 参数: prio 为指定要获取堆栈信息的任务优先级,也可以指定参数OS_PRIO_SELF,获取调用任务本身的
* 信息。
*
* pdata 指向一个类型为OS_STK_DATA的数据结构,其中包含如下信息:
* INT32U OSFree; // 堆栈中未使用的字节数
* INT32U OSUsed; // 堆栈中已使用的字节数
*
* 返回: OS_NO_ERR: 函数调用成功;
* OS_PRIO_INVALID: 参数指定的优先级大于OS_LOWEST_PRIO,或未指定OS_PRIO_SELF;
* OS_TASK_NOT_EXIST:指定的任务不存在;
* OS_TASK_OPT_ERR: 任务用OSTaskCreateExt()函数建立的时候没有指定OS_TASK_OPT_STK_CHK
* 操作,或者任务是用OSTaskCreate()函数建立的。
*
* 注意: 1、函数的执行时间是由任务堆栈的大小决定的,事先不可预料;
* 2、在应用程序中可以把OS_STK_DATA结构中的数据项OSFree和OSUsed相加,可得到堆栈的大小;
* 3、虽然原则上该函数可以在中断程序中调用,但由于该函数可能执行很长时间,所以实际中不提
* 倡这种做法。
*************************************************************************************************
*/
#if OS_TASK_CREATE_EXT_EN > 0 //允许生成 OSTaskStkChk()函数
INT8U OSTaskStkChk (INT8U prio, OS_STK_DATA *pdata)
{ //检查任务堆栈状态(任务优先级、检验堆栈数据结构)
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_TCB *ptcb; //定义消息事件的任务控制块指针
OS_STK *pchk; //定义指向当前任务堆栈栈底的指针
INT32U free; //定义任务堆栈实际空闲字节数
INT32U size; //定义存有栈中可容纳的指针数目
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
//当任务 >= 最低优先级 并且 任务不是本身
if (prio > OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO,或未指定OS_PRIO_SELF
}
#endif
pdata->OSFree = 0; //未使用的字节清0
pdata->OSUsed = 0; //已使用的字节清0
OS_ENTER_CRITICAL(); //关闭中断
if (prio == OS_PRIO_SELF) { //如果检查者是任务本身
prio = OSTCBCur->OSTCBPrio; //指向正在运行(优先级)任务控制块的指针
}
ptcb = OSTCBPrioTbl[prio]; //调用这个优先级别任务的就绪值
if (ptcb == (OS_TCB *)0) { //当检验OSTCBPrioTbl[]里是非0值,确定任务存在
OS_EXIT_CRITICAL(); //打开中断
return (OS_TASK_NOT_EXIST); //指定的任务不存在
}
//要执行堆栈检验,必须用OSTaskCreateExt()函数建立任务,并且已经传递了选项OS_TASK_OPT_STK_CHK,
//而对OSTaskCreate()函数建立的任务,那么会对OPT(传递给OS_TCBInit)为0,而使检验失败
if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0) { //如果检验OPT=0
OS_EXIT_CRITICAL(); //打开中断
return (OS_TASK_OPT_ERR); //返回检验失败
} //从堆栈栈底统计堆栈空闲空间,直到遇到一个存储非0值
free = 0; //堆栈中未使用的字节数free = 0
size = ptcb->OSTCBStkSize; //size = 存有栈中可容纳的指针数目
pchk = ptcb->OSTCBStkBottom; //pchk = 指向当前任务堆栈栈底的指针
OS_EXIT_CRITICAL(); //打开中断
#if OS_STK_GROWTH == 1 //查看堆栈增长方向,为1递增
while (*pchk++ == (OS_STK)0) { //当前任务堆栈栈顶的指针加1(内容)是否等于0
free++; //定义堆栈中未使用的字节数加1
}
#else //否则,向下递减
while (*pchk-- == (OS_STK)0) { //当前任务堆栈栈底的指针减1(内容)是否等于0
free++; //定义堆栈中未使用的字节数加1
}
#endif
pdata->OSFree = free * sizeof(OS_STK); //任务堆栈实际空闲字节数
pdata->OSUsed = (size - free) * sizeof(OS_STK); //任务堆栈已被占用的字节数
return (OS_NO_ERR); //函数调用成功
H:\SOURCE中文源代码\OS_TASK.C
}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* 无条件挂起一个任务(SUSPEND A TASK)
*
* 描述: 无条件挂起一个任务. 调用此函数的任务也可以传递参数OS_PRIO_SELF,挂起调用任务本身.
* 当前任务挂起后,只有其他任务才能唤醒.任务挂起后,系统会重新进行任务调度,运行下一个
* 优先级最高的就绪任务.唤醒挂起任务需要调用函数OSTaskResume().
* //任务的挂起是可以叠加到其他操作上的。例如,任务被挂起时正在进行延时操作,那么任务的
* 唤醒就需要两个条件:延时的结束以及其他任务的唤醒操作.又如,任务被挂起时正在等待信
* 号量,当任务从信号量的等待对列中清除后也不能立即运行,而必须等到唤醒操作后。
*
* 参数: prio 为指定要获取挂起的任务优先级,也可以指定参数OS_PRIO_SELF,挂起任务本身.此时,
* 下一个优先级最高的就绪任务将运行.
*
* 返回: OS_NO_ERR: 函数调用成功;
* OS_TASK_ SUSPEND_IDLE: 试图挂起uC/OS-II中的空闲任务(Idle task)。此为非法操作;
* OS_PRIO_INVALID: 参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF的值;
* OS_TASK_ SUSPEND _PRIO:要挂起的任务不存在。
*
* 注意: 1、在程序中OSTaskSuspend()和OSTaskResume()应该成对使用;
* 2、用OSTaskSuspend()挂起的任务只能用OSTaskResume()唤醒.
*************************************************************************************************
*/
#if OS_TASK_SUSPEND_EN > 0 //允许生成 OSTaskSuspend()函数
INT8U OSTaskSuspend (INT8U prio) //无条件挂起一个任务(任务优先级)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN self; //定义布尔(=1为任务本身)
OS_TCB *ptcb; //定义消息事件的任务控制块指针
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio == OS_IDLE_PRIO) { //检查任务的优先级是否是空闲任务
return (OS_TASK_SUSPEND_IDLE); //试图挂起uC/OS-II中的空闲任务(Idle task)。此为非法操作
} //当任务 >= 最低优先级 并且 任务不是本身
if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF的值}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (prio == OS_PRIO_SELF) { //如果删除者是任务本身
prio = OSTCBCur->OSTCBPrio; //从当前任务的任务控制块OS_TCB中获取当前任务的优先级
self = TRUE; //是任务本身(为1)
} else if (prio == OSTCBCur->OSTCBPrio) { //也可以通过指定优先级,挂起调用本函数的任务
self = TRUE; //是任务本身(为1)
} else { //否则
self = FALSE; //要删除的不是任务本身
}
if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { //检验要挂起的任务是否存在(为1任务存在)
OS_EXIT_CRITICAL(); //打开中断
return (OS_TASK_SUSPEND_PRIO); //返回(要挂起的任务不存在)
}
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) { //如果该任务存在
OSRdyGrp &= ~ptcb->OSTCBBitY; //从就绪表中清除它(等待事件的话也删除)
}
ptcb->OSTCBStat |= OS_STAT_SUSPEND; //在任务的状态字中标明'SUSPENDED',表示任务被挂起
OS_EXIT_CRITICAL(); //打开中断
if (self == TRUE) { //如果是任务本身(为1)
OS_Sched(); //任务调度,最高任务优先级运行
//说明:self == TRUE,删除本身,需要进入任务调度执行新的任务
//self = FALSE,删除的是其它任务,无需进入调度,可继续执行本任务
}
return (OS_NO_ERR); //返回(函数调用成功)}
#endif
/*$PAGE*/
/*
*************************************************************************************************
* 获取任务信息,函数返回任务TCB的一个完整的拷贝(QUERY A TASK)
11 H:\SOURCE中文源代码\OS_TASK.C
* 描述: 获取任务信息,函数返回任务TCB的一个完整的拷贝.应用程序必须建立一个OS_TCB类型的数据结
* 构容纳返回的数据.需要提醒用户的是,在对任务OS_TCB对象中的数据操作时要小心,尤其是数据
* 项OSTCBNext和OSTCBPrev.它们分别指向TCB链表中的后一项和前一项.
* 参数: prio 为指定要获取TCB内容的任务优先级,也可以指定参数OS_PRIO_SELF,获取调用任务的信息.
* pdata指向一个OS_TCB类型的数据结构,容纳返回的任务TCB的一个拷贝.
* 返回: OS_NO_ERR: 函数调用成功;
* OS_PRIO_ERR: 参数指定的任务非法;
* OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO.
* 注意: 任务控制块(TCB)中所包含的数据成员取决于下述开关量在初始化时的设定(参见OS_CFG.H)
* OS_TASK_CREATE_EN
* OS_Q_EN
* OS_MBOX_EN
* OS_SEM_EN
* OS_TASK_DEL_EN
*************************************************************************************************
*/
#if OS_TASK_QUERY_EN > 0 //允许(1)生成OSTaskQuery()代码
INT8U OSTaskQuery (INT8U prio, OS_TCB *pdata) //获取任务信息(任务指针、保存数据结构指针)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_TCB *ptcb; //定义消息事件的任务控制块指针
#if OS_ARG_CHK_EN > 0
//当任务 >= 最低优先级 并且 任务不是本身
if (prio > OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (prio == OS_PRIO_SELF) { //检查的删除者是否是任务(优先级)本身
prio = OSTCBCur->OSTCBPrio; //正在运行的优先级(任务本身的优先级)
} //获取(信息)任务必须存在
if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { //调用这个任务的优先级的就绪值
OS_EXIT_CRITICAL(); //打开中断
return (OS_PRIO_ERR); //返回(参数指定的任务非法)
}
memcpy(pdata, ptcb, sizeof(OS_TCB)); //所有的域(通过赋值语句)一次性复制
OS_EXIT_CRITICAL(); //打开中断
return (OS_NO_ERR); //返回获取信息成功(函数调用成功)
}
#endif
第三阶段 画流程图
主要内容:
OS_TASK.
基本要求:
(1)、了解OS_TASK.C中各个函数的执行过程
(2)、画出OS_TASK.C中各个函数的流程图
时间:第7—9天
流程图如下:
###下载文档查看####
第四阶段 实验总结
主要内容:
OS_TASK.C
基本要求和阶段目的:
总结实训的收获
时间:第10天
总结如下:
这次实训的代码非常多,不过注释都很清晰,理清楚这其中的关系函数的结构以后觉得非常有成就感,对以后面对工作后也有很大的帮助,应该在这门课程中找出自己的不足,并加以补充。希望可以取得最大的成绩