UCOS2笔记.docx

上传人:b****6 文档编号:6679042 上传时间:2023-01-08 格式:DOCX 页数:108 大小:2.60MB
下载 相关 举报
UCOS2笔记.docx_第1页
第1页 / 共108页
UCOS2笔记.docx_第2页
第2页 / 共108页
UCOS2笔记.docx_第3页
第3页 / 共108页
UCOS2笔记.docx_第4页
第4页 / 共108页
UCOS2笔记.docx_第5页
第5页 / 共108页
点击查看更多>>
下载资源
资源描述

UCOS2笔记.docx

《UCOS2笔记.docx》由会员分享,可在线阅读,更多相关《UCOS2笔记.docx(108页珍藏版)》请在冰豆网上搜索。

UCOS2笔记.docx

UCOS2笔记

目录

内核结构2

临界段(CriticalSections)2

任务2

任务控制块(TaskControlBlocks,OS_TCBs)5

就绪表(ReadyList)9

任务调度(TaskScheduling)11

给调度器上锁和开锁(LockingandUnLockingtheScheduler)12

空闲任务(IdleTask)14

统计任务14

μC/OS-Ⅱ中的中断处理18

时钟节拍23

μC/OS-Ⅱ初始化26

μC/OS-Ⅱ的启动26

获取当前μC/OS-Ⅱ的版本号30

OSEvent?

?

?

()函数30

任务管理30

建立任务,OSTaskCreate()31

建立任务,OSTaskCreateExt()35

任务堆栈38

堆栈检验,OSTaskStkChk()40

删除任务,OSTaskDel()43

请求删除任务,OSTaskDelReq()47

改变任务的优先级,OSTaskChangePrio()50

挂起任务,OSTaskSuspend()52

恢复任务,OSTaskResume()54

获得有关任务的信息,OSTaskQuery()55

时间管理57

任务延时函数,OSTimeDly()57

按时分秒延时函数OSTimeDlyHMSM()59

让处在延时期的任务结束延时,OSTimeDlyResume()61

系统时间,OSTimeGet()和OSTimeSet()62

内存管理63

内存控制块65

建立一个内存分区,OSMemCreate()65

释放一个内存块,OSMemPut()69

查询一个内存分区的状态,OSMemQuery()70

UsingMemoryPartitions71

等待一个内存块73

移植μC/OS-Ⅱ74

8.00开发工具76

8.01目录和文件76

8.02INCLUDES.H77

8.03OS_CPU.H77

8.04OS_CPU_A.ASM81

8.05OS_CPU_C.C85

内核结构

临界段(CriticalSections)

和其它内核一样,μC/OS-Ⅱ为了处理临界段代码需要关中断,处理完毕后再开中断。

这使得μC/OS-Ⅱ能够避免同时有其它任务或中断服务进入临界段代码。

关中断的时间是实时内核开发商应提供的最重要的指标之一,因为这个指标影响用户系统对实时事件的响应性。

μC/OS-Ⅱ努力使关中断时间降至最短,但就使用μC/OS-Ⅱ而言,关中断的时间很大程度上取决于微处理器的架构以及编译器所生成的代码质量。

微处理器一般都有关中断/开中断指令,用户使用的C语言编译器必须有某种机制能够在C中直接实现关中断/开中断地操作。

某些C编译器允许在用户的C源代码中插入汇编语言的语句。

这使得插入微处理器指令来关中断/开中断很容易实现。

而有的编译器把从C语言中关中断/开中断放在语言的扩展部分。

μC/OS-Ⅱ定义两个宏(macros)来关中断和开中断,以便避开不同C编译器厂商选择不同的方法来处理关中断和开中断。

μC/OS-Ⅱ中的这两个宏调用分别是:

OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。

因为这两个宏的定义取决于所用的微处理器,故在文件OS_CPU.H中可以找到相应宏定义。

每种微处理器都有自己的OS_CPU.H文件。

一个例子就是

#defineOS_ENTER_CRITICAL()EA=0;//移植到51,只使用中断方式1

#defineOS_EXIT_CRITICAL()EA=1

任务

一个任务通常是一个无限的循环[L3.1

(2)],如程序清单3.1所示。

一个任务看起来像其它C的函数一样,有函数返回类型,有形式参数变量,但是任务是绝不会返回的。

故返回参数必须定义成void[L3.1

(1)]。

程序清单L3.1任务是一个无限循环

voidYourTask(void*pdata)

(1)

{

for(;;){

(2)

/*用户代码*/

调用uC/OS-II的某种系统服务:

OSMboxPend();

OSQPend();

OSSemPend();

OSTaskDel(OS_PRIO_SELF);

OSTaskSuspend(OS_PRIO_SELF);

OSTimeDly();

OSTimeDlyHMSM();

/*用户代码*/

}

}

不同的是,当任务完成以后,任务可以自我删除,如清单L3.2所示。

注意任务代码并非真的删除了,μC/OS-Ⅱ只是简单地不再理会这个任务了,这个任务的代码也不会再运行,如果任务调用了OSTaskDel(),这个任务绝不会返回什么。

 

程序清单L3.2.任务完成后自我删除

voidYourTask(void*pdata)

{

/*用户代码*/

OSTaskDel(OS_PRIO_SELF);

}

形式参数变量[L3.1

(1)]是由用户代码在第一次执行的时候带入的。

请注意,该变量的类型是一个指向void的指针。

这是为了允许用户应用程序传递任何类型的数据给任务。

这个指针好比一辆万能的车子,如果需要的话,可以运载一个变量的地址,或一个结构,甚至是一个函数的地址。

也可以建立许多相同的任务,所有任务都使用同一个函数(或者说是同一个任务代码程序),见第一章的例1。

例如,用户可以将四个串行口安排成每个串行口都是一个单独的任务,而每个任务的代码实际上是相同的。

并不需要将代码复制四次,用户可以建立一个任务,向这个任务传入一个指向某数据结构的指针变量,这个数据结构定义串行口的参数(波特率、I/O口地址、中断向量号等)。

μC/OS-Ⅱ可以管理多达64个任务,但目前版本的μC/OS-Ⅱ有两个任务已经被系统占用了。

作者保留了优先级为0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRI0-2,OS_LOWEST_PRI0-1以及OS_LOWEST_PRI0这8个任务以被将来使用。

OS_LOWEST_PRI0是作为定义的常数在OS_CFG.H文件中用定义常数语句#defineconstant定义的。

因此用户可以有多达56个应用任务。

必须给每个任务赋以不同的优先级,优先级可以从0到OS_LOWEST_PR10-2。

优先级号越低,任务的优先级越高。

μC/OS-Ⅱ总是运行进入就绪态的优先级最高的任务。

目前版本的μC/OS-Ⅱ中,任务的优先级号就是任务编号(ID)。

优先级号(或任务的ID号)也被一些内核服务函数调用,如改变优先级函数OSTaskChangePrio(),以及任务删除函数OSTaskDel()。

为了使μC/OS-Ⅱ能管理用户任务,用户必须在建立一个任务的时候,将任务的起始地址与其它参数一起传给下面两个函数中的一个:

OSTastCreat或OSTaskCreatExt()。

OSTaskCreateExt()是OSTaskCreate()的扩展,扩展了一些附加的功能。

,这两个函数的解释见第四章,任务管理

3.2任务状态

睡眠态(DORMANT)指任务驻留在程序空间之中,还没有交给μC/OS-Ⅱ管理,->把任务交给μC/OS-Ⅱ是通过调用下述两个函数之一:

OSTaskCreate()或OSTaskCreateExt()。

当任务一旦建立,这个任务就进入就绪态准备运行。

任务的建立可以是在多任务运行开始之前,也可以是动态地被一个运行着的任务建立。

如果一个任务是被另一个任务建立的,而这个任务的优先级高于建立它的那个任务,则这个刚刚建立的任务将立即得到CPU的控制权。

一个任务可以通过调用OSTaskDel()返回到睡眠态,或通过调用该函数让另一个任务进入睡眠态。

调用OSStart()可以启动多任务。

OSStart()函数运行进入就绪态的优先级最高的任务。

就绪的任务只有当所有优先级高于这个任务的任务转为等待状态,或者是被删除了,才能进入运行态。

正在运行的任务可以通过调用两个函数之一将自身延迟一段时间,这两个函数是OSTimeDly()或OSTimeDlyHMSM()。

这个任务于是进入等待状态,等待这段时间过去,下一个优先级最高的、并进入了就绪态的任务立刻被赋予了CPU的控制权。

等待的时间过去以后,系统服务函数OSTimeTick()使延迟了的任务进入就绪态(见3.10节,时钟节拍)。

正在运行的任务期待某一事件的发生时也要等待,手段是调用以下3个函数之一:

OSSemPend(),OSMboxPend(),或OSQPend()。

调用后任务进入了等待状态(WAITING)。

当任务因等待事件被挂起(Pend),下一个优先级最高的任务立即得到了CPU的控制权。

当事件发生了,被挂起的任务进入就绪态。

事件发生的报告可能来自另一个任务,也可能来自中断服务子程序。

正在运行的任务是可以被中断的,除非该任务将中断关了,或者μC/OS-Ⅱ将中断关了。

被中断了的任务就进入了中断服务态(ISR)。

响应中断时,正在执行的任务被挂起,中断服务子程序控制了CPU的使用权。

中断服务子程序可能会报告一个或多个事件的发生,而使一个或多个任务进入就绪态。

在这种情况下,从中断服务子程序返回之前,μC/OS-Ⅱ要判定,被中断的任务是否还是就绪态任务中优先级最高的。

如果中断服务子程序使一个优先级更高的任务进入了就绪态,则新进入就绪态的这个优先级更高的任务将得以运行,否则原来被中断了的任务才能继续运行。

当所有的任务都在等待事件发生或等待延迟时间结束,μC/OS-Ⅱ执行空闲任务(idletask),执行OSTaskIdle()函数。

任务控制块(TaskControlBlocks,OS_TCBs)

一旦任务建立了,任务控制块OS_TCBs将被赋值(程序清单3.3)。

任务控制块是一个数据结构,作用(当任务的CPU使用权被剥夺时,μC/OS-Ⅱ用它来保存该任务的状态)。

当任务重新得到CPU使用权时,任务控制块能确保任务从当时被中断的那一点丝毫不差地继续执行。

OS_TCBs全部驻留在RAM中。

读者将会注意到笔者在组织这个数据结构时,考虑到了各成员的逻辑分组。

任务建立的时候,OS_TCBs就被初始化了(见第四章任务管理)。

程序清单L3.3μC/OS-II任务控制块.

#ifOS_TASK_CREAT_EXT_EN>0

typedefstruct{

INT32UOSFree;//Numbersoffreebytesonthestack

INT32UOSUsed;//Numbersofbytesusedonthestack

}OS_STK_DATA;

#endif

typedefstructos_tcb{

OS_STK*OSTCBStkPtr;

#ifOS_TASK_CREATE_EXT_EN

void*OSTCBExtPtr;

OS_STK*OSTCBStkBottom;

INT32UOSTCBStkSize;

INT16UOSTCBOpt;

INT16UOSTCBId;

#endif

structos_tcb*OSTCBNext;

structos_tcb*OSTCBPrev;

#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN||OS_SEM_EN

OS_EVENT*OSTCBEventPtr;

#endif

#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN

void*OSTCBMsg;

#endif

INT16UOSTCBDly;

INT8UOSTCBStat;

INT8UOSTCBPrio;

INT8UOSTCBX;

INT8UOSTCBY;

INT8UOSTCBBitX;

INT8UOSTCBBitY;

#ifOS_TASK_DEL_EN

BOOLEANOSTCBDelReq;

#endif

}OS_TCB;

.OSTCBStkPtr是指向当前任务栈顶的指针。

μC/OS-Ⅱ允许每个任务有自己的栈,尤为重要的是,每个任务的栈的容量可以是任意的。

有些商业内核要求所有任务栈的容量都一样,除非用户写一个复杂的接口函数来改变之。

这种限制浪费了RAM,当各任务需要的栈空间不同时,也得按任务中预期栈容量需求最多的来分配栈空间。

OSTCBStkPtr是OS_TCB数据结构中唯一的一个能用汇编语言来处置的变量(在任务切换段的代码Context-switchingcode之中,)把OSTCBStkPtr放在数据结构的最前面,使得从汇编语言中处理这个变量时较为容易。

.OSTCBExtPtr指向用户定义的任务控制块扩展。

用户可以扩展任务控制块而不必修改μC/OS-Ⅱ的源代码。

.OSTCBExtPtr只在函数OstaskCreateExt()中使用,故使用时要将OS_TASK_CREAT_EN设为1,以允许建立任务函数的扩展。

例如用户可以建立一个数据结构,这个数据结构包含每个任务的名字,或跟踪某个任务的执行时间,或者跟踪切换到某个任务的次数(见例3)。

注意,笔者将这个扩展指针变量放在紧跟着堆栈指针的位置,为的是当用户需要在汇编语言中处理这个变量时,从数据结构的头上算偏移量比较方便。

.OSTCBStkBottom是指向任务栈底的指针。

如果微处理器的栈指针是递减的,即栈存储器从高地址向低地址方向分配,则OSTCBStkBottom指向任务使用的栈空间的最低地址。

类似地,如果微处理器的栈是从低地址向高地址递增型的,则OSTCBStkBottom指向任务可以使用的栈空间的最高地址。

函数OSTaskStkChk()要用到变量OSTCBStkBottom,在运行中检验栈空间的使用情况。

用户可以用它来确定任务实际需要的栈空间。

这个功能只有当用户在任务建立时允许使用OSTaskCreateExt()函数时才能实现。

这就要求用户将OS_TASK_CREATE_EXT_EN设为1,以便允许该功能。

.OSTCBStkSize存有栈中可容纳的指针数目而不是用字节(Byte)表示的栈容量总数。

也就是说,如果栈中可以保存1,000个入口地址,每个地址宽度是32位的,则实际栈容量是4,000字节。

同样是1,000个入口地址,如果每个地址宽度是16位的,则总栈容量只有2,000字节。

在函数OSStakChk()中要调用OSTCBStkSize。

同理,若使用该函数的话,要将OS_TASK_CREAT_EXT_EN设为1。

.OSTCBOpt把“选择项”传给OSTaskCreateExt(),只有在用户将OS_TASK_CREATE_EXT_EN设为1时,这个变量才有效。

μC/OS-Ⅱ目前只支持3个选择项(见uCOS_II.H):

OS_TASK_OTP_STK_CHK,OS_TASK_OPT_STK_CLR和OS_TASK_OPT_SAVE_FP。

OS_TASK_OTP_STK_CHK用于告知TaskCreateExt(),在任务建立的时候任务栈检验功能得到了允许。

OS_TASK_OPT_STK_CLR表示任务建立的时候任务栈要清零。

只有在用户需要有栈检验功能时,才需要将栈清零。

如果不定义OS_TASK_OPT_STK_CLR,而后又建立、删除了任务,栈检验功能报告的栈使用情况将是错误的。

如果任务一旦建立就决不会被删除,而用户初始化时,已将RAM清过零,则OS_TASK_OPT_STK_CLR不需要再定义,这可以节约程序执行时间。

传递了OS_TASK_OPT_STK_CLR将增加TaskCreateExt()函数的执行时间,因为要将栈空间清零。

栈容量越大,清零花的时间越长。

最后一个选择项OS_TASK_OPT_SAVE_FP通知TaskCreateExt(),任务要做浮点运算。

如果微处理器有硬件的浮点协处理器,则所建立的任务在做任务调度切换时,浮点寄存器的内容要保存。

.OSTCBId用于存储任务的识别码。

这个变量现在没有使用,留给将来扩展用。

.OSTCBNext和.OSTCBPrev用于任务控制块OS_TCBs的双重链接,该链表在时钟节拍函数OSTimeTick()中使用,用于刷新各个任务的任务延迟变量.OSTCBDly,每个任务的任务控制块OS_TCB在任务建立的时候被链接到链表中,在任务删除的时候从链表中被删除。

双重连接的链表使得任一成员都能被快速插入或删除。

.OSTCBEventPtr是指向事件控制块的指针,后面的章节中会有所描述(见第6章)。

.OSTCBMsg是指向传给任务的消息的指针。

用法将在后面的章节中提到(见第6章)。

.OSTCBDly当需要把任务延时若干时钟节拍时要用到这个变量,或者需要把任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。

在这种情况下,这个变量保存的是任务允许等待事件发生的最多时钟节拍数。

如果这个变量为0,表示任务不延时,或者表示等待事件发生的时间没有限制。

.OSTCBStat是任务的状态字。

当.OSTCBStat为0,任务进入就绪态。

可以给.OSTCBStat赋其它的值,在文件uCOS_II.H中有关于这个值的描述。

.OSTCBPrio是任务优先级。

高优先级任务的.OSTCBPrio值小。

也就是说,这个值越小,任务的优先级越高。

.OSTCBX,.OSTCBY,.OSTCBBitX和.OSTCBBitY用于加速任务进入就绪态的过程或进入等待事件发生状态的过程(避免在运行中去计算这些值)。

这些值是在任务建立时算好的,或者是在改变任务优先级时算出的。

这些值的算法见程序清单L3.4。

程序清单L3.4任务控制块OS_TCB中几个成员的算法

OSTCBY

=priority>>3;

OSTCBBitY

=OSMapTbl[priority>>3];

OSTCBX

=priority&0x07;

OSTCBBitX

=OSMapTbl[priority&0x07];

.OSTCBDelReq是一个布尔量,用于表示该任务是否需要删除,用法将在后面的章节中描述(见第4章任务管理)

应用程序中可以有的最多任务数(OS_MAX_TASKS)是在文件OS_CFG.H中定义的。

这个最多任务数也是μC/OS-Ⅱ分配给用户程序的最多任务控制块OS_TCBs的数目。

将OS_MAX_TASKS的数目设置为用户应用程序实际需要的任务数可以减小RAM的需求量。

所有的任务控制块OS_TCBs都是放在任务控制块列表数组OSTCBTbl[]中的。

请注意,μC/OS-Ⅱ分配给OS_N_SYS_TASKS特别的OS_TCB用于内部使用。

目前,一个分配于空闲任务,另一个分配于统计任务(如果OS_TASK_STAT_EN是设为1的)。

在μC/OS-Ⅱ初始化的时候,如图3.2所示,所有任务控制块OS_TCBs被链接成单向空任务链表。

当任务一旦建立,空任务控制块指针OSTCBFreeList指向的任务控制块便赋给了该任务,(即每当建立一个任务时,就从该链表中取出一个空闲事件控制块,并对它进行初始化。

)然后OSTCBFreeList的值调整为指向下链表中下一个空的任务控制块。

一旦任务被删除,它的

OS_TCB就还给空任务链表。

与信号量、邮箱和消息队列不同的是:

信号量、邮箱和消息队列一旦建立就不能删除,所以事件控制块也不能放回到空闲事件控制块链表中

就绪表(ReadyList)

每个任务被赋予不同的优先级等级,从0级到最低优先级OS_LOWEST_PRIO,包括0和OS_LOWEST_PRIO在内(见文件OS_CFG.H)。

当μC/OS-Ⅱ初始化的时候,最低优先级OS_LOWEST_PRIO总是被赋给空闲任务idletask。

注意,最多任务数目OS_MAX_TASKS和最低优先级数是没有关系的。

用户应用程序可以只有10个任务,而仍然可以有32个优先级的级别(如果用户将最低优先级数设为31的话)。

每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRdyGrp和OSRdyTbl[]。

在OSRdyGrp中,任务按优先级分组,8个任务为一组。

OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。

任务进入就绪态时,就绪表OSRdyTbl[]中的相应元素的相应位也置位。

就绪表OSRdyTbl[]数组的大小取决于OS_LOWEST_PRIO(见文件OS_CFG.H)。

当用户的应用程序中任务数目比较少时,减少OS_LOWEST_PRIO的值可以降低μC/OS-Ⅱ对RAM(数据空间)的需求量。

为确定下次该哪个优先级的任务运行了,内核调度器总是将OS_LOWEST_PRIO在就绪表中相应字节的相应位置1。

OSRdyGrp和OSRdyTbl[]的关系见图3.3,是按以下规则给出的:

当OSRdyTbl[i]中的任何一位是1时,OSRdyGrp的第i位置1。

i从0到7。

程序清单3.5中的代码用于将任务放入就绪表。

Prio是任务的优先级。

程序清单L3.5使任务进入就绪态

OSRdyGrp|=OSMapTbl[prio>>3];

OSRdyTbl[prio>>3]|=OSMapTbl[prio&0x07];

(有问题:

读者可以看出,任务优先级的低三位用于确定任务在总就绪表OSRdyTbl[]中的所在位。

接下去的三位用于确定是在OSRdyTbl[]数组的第几个元素)应该是低三位为用于确定是在OSRdyTbl[]数组的第几个元素,接下三位为SRdyTbl[]中的那一行共八行(也是OSRdyGrp的值),。

OSMapTbl[]是在ROM中的(见文件OS_CORE.C)屏蔽字,用于限制OSRdyTbl[]数组的元素下标在0到7之间,见表3.1

表T3.1OSMapTbl[Index]的值

Index

BitMask(Binary)

0

00000001

1

00000010

2

00000100

3

00001000

4

00010000

5

00100000

6

01000000

7

10000000

如果一个任务被删除了,则用程序清单3.6中的代码做求反处理。

程序清单L3.6从就绪表中删除一个任务

if((OSRdyTbl[prio>>3]&=~OSMapTbl[prio&0x07])==0)

OSRdyGrp&=~OSMapTbl[prio>>3];

以上代码将就绪任务表数组OSRdyTbl[]中相应元素的相应位清零,而对于OSRdyGrp,只有当被删除任务所在任务组中全组任务一个都没有进入就绪态时,才将相应位清零。

也就是说OSRdyTbl[prio>>3]所有的位都是零时,OSRdyGrp的相应位才清零。

为了找到那个进入就绪态的优先级最高的任务,并不需要从OSRdyTbl[0]开始扫描整个就绪任务表,只需要查另外一张表,即优先级判定表OSUnMapTbl([256])(见文件OS_CORE.C)。

OSRdyTbl[]中每个字节的8位代表这一组的8个任务哪些进入就绪态了,低位的优先级高于高位。

利用这个字节为下标来查OSUnMapTbl这张表,返回的字节就是该组任务中就绪态任务中优先级最高的那个任务所在的位置。

这个返回值在0到7之

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1