当前位置:首页 » 编程软件 » ostcb编译条件

ostcb编译条件

发布时间: 2024-10-05 11:28:24

⑴ 什么是UCOS操作系统

u C / O S 是一种免费公开源代码、结构小巧、具有可剥夺实时内核的实时操作系统。

μC/OS-II 的前身是μC/OS,最早出自于1992 年美国嵌入式系统专家Jean J.Labrosse 在《嵌入式系统编程》杂志的5 月和6 月刊上刊登的文章连载,并把μC/OS 的源码发布在该杂志的B B S 上。

μC/OS 和μC/OS-II 是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。CPU 硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU 上。用户只要有标准的ANSI 的C交叉编译器,有汇编器、连接器等软件工具,就可以将μC/OS-II嵌人到开发的产品中。μC/OS-II 具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点, 最小内核可编译至 2KB 。μC/OS-II 已经移植到了几乎所有知名的CPU 上。

严格地说uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。没有提供输入输出管理,文件系统,网络等额外的服务。但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。

uC/OS-II目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等。

任务管理

uC/OS-II 中最多可以支持64 个任务,分别对应优先级0~63,其中0 为最高优先级。63为最低级,系统保留了4个最高优先级的任务和4个最低优先级的任务,所有用户可以使用的任务数有56个。

uC/OS-II提供了任务管理的各种函数调用,包括创建任务,删除任务,改变任务的优先级,任务挂起和恢复等。

系统初始化时会自动产生两个任务:一个是空闲任务,它的优先级最低,改任务仅给一个整形变量做累加运算;另一个是系统任务,它的优先级为次低,改任务负责统计当前cpu的利用率。

时间管理

uC/OS-II的时间管理是通过定时中断来实现的,该定时中断一般为10毫秒或100毫秒发生一次,时间频率取决于用户对硬件系统的定时器编程来实现。中断发生的时间间隔是固定不变的,该中断也成为一个时钟节拍。

uC/OS-II要求用户在定时中断的服务程序中,调用系统提供的与时钟节拍相关的系统函数,例如中断级的任务切换函数,系统时间函数。

内存管理

在ANSI C中是使用malloc和free两个函数来动态分配和释放内存。但在嵌入式实时系统中,多次这样的错作会导致内存碎片,且由于内存管理算法的原因,malloc和free的执行时间也是不确定。

uC/OS-II中把连续的大快内存按分区管理。每个分区中包含整数个大小相同的内存块,但不同分区之间的内存快大小可以不同。用户需要动态分配内存时,系统选择一个适当的分区,按块来分配内存。释放内存时将该块放回它以前所属的分区,这样能有效解决碎片问题,同时执行时间也是固定的。

任务间通信与同步

对一个多任务的操作系统来说,任务间的通信和同步是必不可少的。uC/OS-II中提供了4中同步对象,分别是信号量,邮箱,消息队列和事件。所有这些同步对象都有创建,等待,发送,查询的接口用于实现进程间的通信和同步。

任务调度

uC/OS-II 采用的是可剥夺型实时多任务内核。可剥夺型的实时内核在任何时候都运行就绪了的最高优先级的任务。

uC/os-II的任务调度是完全基于任务优先级的抢占式调度,也就是最高优先级的任务一旦处于就绪状态,则立即抢占正在运行的低优先级任务的处理器资源。为了简化系统设计,uC/OS-II规定所有任务的优先级不同,因为任务的优先级也同时唯一标志了该任务本身。

任务调度将在以下情况下发生:

1) 高优先级的任务因为需要某种临界资源,主动请求挂起,让出处理器,此时将调度就绪状态的低优先级任务获得执行,这种调度也称为任务级的上下文切换。

2) 高优先级的任务因为时钟节拍到来,在时钟中断的处理程序中,内核发现高优先级任务获得了执行条件(如休眠的时钟到时),则在中断态直接切换到高优先级任务执行。这种调度也称为中断级的上下文切换。

这两种调度方式在uC/OS-II的执行过程中非常普遍,一般来说前者发生在系统服务中,后者发生在时钟中断的服务程序中。

调度工作的内容可以分为两部分:最高优先级任务的寻找和任务切换。其最高优先级任务的寻找是通过建立就绪任务表来实现的。u C / O S 中的每一个任务都有独立的堆栈空间,并有一个称为任务控制块TCB(Task Control Block)的数据结构,其中第一个成员变量就是保存的任务堆栈指针。任务调度模块首先用变量OSTCBHighRdy 记录当前最高级就绪任务的TCB 地址,然后调用OS_TASK_SW()函数来进行任务切换。

μC/OS-II的组成部分

μC/OS-II可以大致分成核心、任务处理、时间处理、任务同步与通信,CPU的移植等5个部分。

1) 核心部分(OSCore.c)

是操作系统的处理核心,包括操作系统初始化、操作系统运行、中断进出的前导、时钟节拍、任务调度、事件处理等多部分。能够维持系统基本工作的部分都在这里。

2) 任务处理部分(OSTask.c)

任务处理部分中的内容都是与任务的操作密切相关的。包括任务的建立、删除、挂起、恢复等等。因为μC/OS-II是以任务为基本单位调度的,所以这部分内容也相当重要。

3) 时钟部分(OSTime.c)

μC/OS-II中的最小时钟单位是timetick(时钟节拍)。任务延时等操作是在这里完成的。

4) 任务同步和通信部分

为事件处理部分,包括信号量、邮箱、邮箱队列、事件标志等部分;主要用于任务间的互相联系和对临界资源的访问

5) 与CPU的接口部分

是指μC/OS-II针对所使用的CPU的移植部分。由于μC/OS-II是一个通用性的操作系统,所以对于关键问题上的实现,还是需要根据具体CPU的具体内容和要求作相应的移植。这部分内容由于牵涉到SP等系统指针,所以通常用汇编语言编写。主要包括中断级任务切换的底层实现、任务级任务切换的底层实现、时钟节拍的产生和处理、中断的相关处理部分等内容。

⑵ 嵌入式实时操作系统uc/uo-II在ARM上的移植 这个设计有做过吗,给点线索 非常感谢

所谓移植,就是使一个实时内核能在某个微处理器或微控制器上运行。为了方便移植,大部分的µC/OS-Ⅱ代码是用C语言写的;但仍需要用C和汇编语言写一些与处理器相关的代码,这是因为µC/OS-Ⅱ在读写处理器寄存器时只能通过汇编语言来实现。由于µC/OS-Ⅱ在设计时就已经充分考虑了可移植性,所以µC/OS-Ⅱ的移植相对来说是比较容易的。[5,6]
要使µC/OS-Ⅱ正常运行,处理器必须满足以下要求:
(1) 处理器的C编译器能产生可重入代码。
(2) 用C语言就可以打开和关闭中断。
(3) 处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)。
(4) 处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。
(5) 处理器有将堆栈指针和其它CPU寄存器读出和存储的指令
图2-1说明了µC/OS-Ⅱ的结构以及它与硬件的关系。从图中可以看到整个系统的架构。最底层是硬件层,该层主要涉及到CPU处理器的架设,以及它与外部各功能模块的连接,对于CPU处理器的初始化也是构架嵌入式系统的重要内容,特别是对定时器的设置,将是构建操作系统的基础,它决定整个系统的性能。对于软件部分,最底层是与处理器相关的程序代码,该段代码直接对CPU处理器进行初始化,这部分代码就是移植操作系统的主要内容,也是最难以理解的部分。这段代码绝大部分程序是用汇编语言编写的,因为在程序运行的时候,这部分代码的调用次数最频繁。在向上的代码就与处理器没有任何的关系,其中一部分包括操作系统的配置文件,像OS_CORE.c,OS_FLAG.c等文件。这部分代码是用来编写一些基本的底层函数,这些函数将作为以后应用部分的基本函数库进行调用,这部分函数构成了操作系统的基本构架,不同的操作系统所对应的系统的设计思想不同,主要体现在这些函数的设计中。除了系统的基本函数外,还有应用部分的基本配置文件。该文件声明的是与具体的应用配置有关的一些设置文件。比如,各任务的一些基本参数,所使用的信号量的声明,以及液晶的参数配置等。不同的应用程序对应的该文件参数配置也不同。有了底层的基本配置文件,就可以编写具体的应用程序了,最上层就是应用程序,针对不同的应用需求,编写不同的应用程序。
μCOS-II不使用C语言中的short、int、long等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性。代之以移植性强的整数数据类型,这样,既直观又可移植,不过这就成了必须移植的代码。根据ADS编译器的特性,这些代码如程序清单图2-2所示。
与所有的实时内核一样,µC/OS-Ⅱ需要先禁止中断再访问代码的临界段,并且在访问完毕后重新允许中断。这就使得µC/OS-Ⅱ能够保护临界段代码免受多任务或中断服务例程(ISRs)的破坏。为了隐藏编译器厂商提供的具体实现方法,µC/OS-Ⅱ定义了两个宏来禁止和允许中断:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。
μCOS-II使用结构常量OS_STK_GROWTH中指定堆栈的生长方式:置OS_STK_GROWTH为0表示堆栈从下往上长。置OS_STK_GROWTH为1表示堆栈从上往下长。虽然ARM处理器核对于两种方式均支持,但ADS的C语言编译器仅支持一种方式,即从上往下长,并且必须是满递减堆栈,所以OS_STK_GROWTH的值为1。
µC/OS-Ⅱ的移植实例要求用户编写四个简单的汇编语言函数: OSStartHighRdy();OSCtxSw();OSIntCtxSw();OSTickISR()。如果用户的编译器支持插入汇编语言代码的话,用户就可以将所有与处理器相关的代码放到OS_CPU_C.C文件中,而不必再拥有一些分散的汇编语言文件。
使就绪状态的任务开始运行的函数叫做OSStart(),如下示意函数所示。在用户调用OSStart()之前,用户必须至少已经建立了一个任务。OSStartHighRdy()假设OSTCBHighRdy指向的是优先级最高的任务的任务控制块。为了简单一点,堆栈指针总是储存在任务控制块(即它的OS_TCB)的开头。换句话说,也就是要想恢复的任务堆栈指针总是储存在OS_TCB的0偏址内存单元中。
如果当前任务调用µC/OS-Ⅱ提供的系统服务,并使得更高优先级任务处于就绪状态,µC/OS-Ⅱ就会借助上面提到的向量地址找到OSCtxSw()。在系统服务调用的最后,µC/OS-Ⅱ会调用OSSched(),并由此来推断当前任务不再是要运行的最重要的任务了。软中断 (或陷阱) 指令会强制一些处理器寄存器(比如返回地址和处理器状态字)到当前任务的堆栈中,并使处理器执行OSCtxSw()。这些代码必须写在汇编语言中,因为用户不能直接从C中访问CPU寄存器。注意在OSCtxSw()和用户定义的函数OSTaskSwHook()的执行过程中,中断是禁止的。

OSIntExit()通过调用OSIntCtxSw()来从ISR中执行切换功能。因为OSIntCtxSw()是在ISR中被调用的,所以可以断定所有的处理器寄存器都被正确地保存到了被中断的任务的堆栈之中。实际上除了需要的东西外,堆栈结构中还有其它的一些东西。OSIntCtxSw()必须要清理堆栈,这样被中断的任务的堆栈结构内容才能满足人们的需要。
要想了解OSIntCtxSw(),大家可以看看µC/OS-Ⅱ调用该函数的过程。假定中断不能嵌套(即ISR不会被中断),中断是允许的,并且处理器正在执行任务级的代码。当中断来临的时候,处理器会结束当前的指令,识别中断并且初始化中断处理过程,包括将处理器的状态寄存器和返回被中断的任务的地址保存到堆栈中。至于究竟哪些寄存器保存到了堆栈上,以及保存的顺序是怎样的,并不重要。
接着,CPU会调用正确的ISR。µC/OS-Ⅱ要求ISR在开始时要保存剩下的处理器寄存器。一旦寄存器保存好了,µC/OS-Ⅱ就要求或者调用OSIntEnter(),或者将变量OSIntNesting加1。在这个时候,被中断任务的堆栈中只包含了被中断任务的寄存器内容。现在,ISR可以执行中断服务了。并且如果ISR发消息给任务(通过调用OSMboxPost()或OSQPost()),恢复任务(通过调用OSTaskResume()),或者调用OSTimeTick()或OSTimeDlyResume()的话,有可能使更高优先级的任务处于就绪状态。
假设有一个更高优先级的任务处于就绪状态。µC/OS-Ⅱ要求用户的ISR在完成中断服务的时候调用OSIntExit()。OSIntExit()会告诉µC/OS-Ⅱ到了返回任务级代码的时间了。调用OSIntExit()会导致调用者的返回地址被保存到被中断的任务的堆栈中。
OSIntExit()刚开始时会禁止中断,因为它需要执行临界段的代码。根据OS_ENTER_CRITICAL()的不同执行过程,处理器的状态寄存器会被保存到被中断的任务的堆栈中。OSIntExit()注意到由于有更高优先级的任务处于就绪状态,被中断的任务已经不再是要继续执行的任务了。在这种情况下,指针OSTCBHighRdy会被指向新任务的OS_TCB,并且OSIntExit()会调用OSIntCtxSw()来执行任务切换。调用OSIntCtxSw()也同样使返回地址被保存到被中断的任务的堆栈中。
用户切换任务的时候,用户只想将某些项保留在堆栈中,并忽略其它项。这是通过调整堆栈指针(加一个数在堆栈指针上)来完成的。加在堆栈指针上的数必须是明确的,而这个数主要依赖于移植的目标处理器(地址空间可能是16,32或64位),所用的编译器,编译器选项,内存模式等等。另外,处理器状态字可能是8,16,32甚至64位宽,并且OSIntExit()可能会分配局部变量。有些处理器允许用户直接增加常量到堆栈指针中,而有些则不允许。在后一种情况下,可以通过简单的执行一定数量的pop(出栈)指令来实现相同的功能。一旦堆栈指针完成调整,新的堆栈指针会被保存到被切换出去的任务的OS_TCB中。
这些代码必须写在汇编语言中,因为用户不能直接从C语言中访问CPU寄存器。如果用户的编译器支持插入汇编语言代码的话,用户就可以将OSIntCtxSw()代码放到OS_CPU_C.C文件中,而不放到OS_CPU_A.ASM文件中。正如用户所看到的那样,除了第一行以外,OSIntCtxSw()的代码与OSCtxSw()是一样的。这样在移植实例中,用户可以通过“跳转”到OSCtxSw()中来减少OSIntCtxSw()代码量。
µC/OS-Ⅱ要求用户提供一个时钟资源来实现时间的延时和期满功能。时钟节拍应该每秒钟发生10-100次。为了完成该任务,可以使用硬件时钟,也可以从交流电中获得50/60Hz的时钟频率。
这些代码必须写在汇编语言中,因为用户不能直接从C语言中访问CPU寄存器。如果用户的处理器可以通过单条指令来增加OSIntNesting,那么用户就没必要调用OSIntEnter()了。增加OSIntNesting要比通过函数调用和返回快得多。OSIntEnter()只增加OSIntNesting,并且作为临界段代码中受到保护。
µC/OS-Ⅱ的移植实例要求用户编写六个简单的C函数:OSTaskStkInit(); OSTaskCreateHook();OSTaskDelHook();OSTaskSwHook();OSTaskStatHook(); OSTimeTickHook()。唯一必要的函数是OSTaskStkInit(),其它五个函数必须得声明但没必要包含代码。
OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInt()来初始化任务的堆栈结构,因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。显示了OSTaskStkInt()放到正被建立的任务堆栈中的东西。注意,在这里我假定了堆栈是从上往下长的。下面的讨论同样适用于从下往上长的堆栈。
在用户建立任务的时候,用户会传递任务的地址,pdata指针,任务的堆栈栈顶和任务的优先级给OSTaskCreate()和OSTaskCreateExt()。虽然OSTaskCreateExt()还要求有其它的参数,但这些参数在讨论OSTaskStkInt()的时候是无关紧要的。为了正确初始化堆栈结构,OSTaskStkInt()只要求刚才提到的前三个参数和一个附加的选项,这个选项只能在OSTaskCreateExt()中得到。
该函数主要是对相关的几个寄存器进行初始化工作,初始化的寄存器对应于

⑶ uC/OS-II的解决方法

对于这样的设计方式,CPU必须能够:
◆ 有相应的CPU寄存器能够模仿SP的一些功能,能使用相应的指令来完成类似SP的一些操作;
◆ 作为SP使用的寄存器在编译过程中最好不被编译器默认使用。在IAR的编译器中,有一个选项可以避免在编译过程中使用到R4、R5。
这两点MSP430都可以做到。
下面对一个正在运行的优先级为6的任务中断后,会发生的几种情况进行分析。
1)在中断的处理过程中没有更高优先级的中断产生,即不会产生中断嵌套。
图3所示为中断发生后对于任务优先级为6的任务堆栈所进行的操作。中断发生后,PC和SR被系统压栈②,对于IAR C编译器来说,会按照复杂度不同的中断服务程序的要求,默认地进行一些寄存器的压栈操作③。因为我们要求的堆栈格式是如图2所示的,我们要把SP调整到SR后面④,然后进行R4~R15的压栈操作,形成我们所要求的堆栈格式⑤。
进行任务堆栈的压栈工作以后,就可以调整SP的指针到系统堆栈了,如图4所示。压栈后的SP指向最后一个压栈内容①。我们把SP的值赋值给优先级6任务的TCB->OSTCBStkPtr,以便进行任务调度的时候出栈使用②。接着,就把SP调整到系统堆栈处③。在中断处理过程中,可能会出现压栈的操作,那么这种情况下SP的指针会随之移动。由于是中断堆栈中,所以不会破坏任务堆栈的格式。
由于没有中断嵌套,在中断处理中没有别的中断发生,那么返回的步骤和上述的进栈操作正好相反。在中断处理完了以后,SP会自动回到图4中③的SP位置。接着,系统会查询到优先级最高的任务,然后把SP的指针移到优先级最高的任务的任务堆栈,进行R15~R4的出栈工作,最后用RETI中断返回指令返回到新的任务。因为我们把所有的任务堆栈都规定成相同的格式,所以它们之间不会产生问题。这里需要注意的是,因为系统在C编译器的中断处理中会对中断进入时默认压栈的寄存器出栈,所以在设计出栈的程序时,要先把这些内容压栈,这样才能正确出栈。
2)在中断的处理过程中,有别的中断产生,产生中断嵌套。
如图5所示,由于在处理中断的时候,SP已经被移到系统堆栈去了,只有当中断退出的时候才可能把SP移到别的任务的任务堆栈中。所以在中断的时候进行中断嵌套,那么对于中断的处理和第一次是一样的,所不同的是,这次保存在堆栈中的不是任务运行中的寄存器,而是中断处理中的寄存器,而且是保存在系统堆栈中而不是任务堆栈中。从这里就可以看出优化内存的效果。所有的中断嵌套中的寄存器压栈都压在系统堆栈中,这样对于任务堆栈内存大小的要求大大降低。
因为μC/OS-II在进入中断中,会把全局变量OSIntNesting++;在退出中断的时候,又会把OSIntNesting--。在退出中断进行任务切换之前,μC/OS-II会先判断OSIntNesting是否为0,是0才会进行任务调度。当第二中断运行结束以后,退出中断嵌套的时候,OSIntNesting不为0,也就不会进行任务调度。因此,仍旧在系统堆栈出栈,那么系统会继续前面没有完成的中断服务程序。
接着退出中断的顺序和非中断嵌套的顺序是一样的。在中断处理完以后,SP会自动回到图4中③的SP位置。接着,系统会查询到优先级最高的任务,然后把SP的指针移到优先级最高的任务的任务堆栈。进行R15~R4的出栈工作,最后用RETI中断返回指令返回到新的任务。
中断的情况基本上就是上述两种。对于有些文献中提到的在中断中会调度到更高优先级的任务的情况,笔者觉得是不应该发生的。因为从上面的分析可以看出,默认的(μC/OS-II的设计思路)中断处理会同时对全局变量OSIntNesting进行增减处理,以给出是否需要任务调度的条件。那么即使在中断服务程序中把更高优先级的任务就绪,也会等到中断退出以后再进行调度,除非是在中断中直接调用更高优先级的任务函数。但这种方法应该是和μC/OS-II的原则相违背的,沿用的是以前前后台设计的思路。
对于这样的设计方式,时钟节拍的处理方式必须和一般的中断处理方式是一样的。一般来说,MSP430使用WATCHDOG时钟中断作为时钟节拍的产生源。从本质上来说,时钟节拍本身也是中断处理过程,所以对于时钟节拍的处理应该和其它的中断处理过程相同。实际上,在时钟节拍的处理过程中也可能会存在中断嵌套的问题。
中断堆栈和任务堆栈分离设计的程序流程如图6所示。

⑷ UC/OS与linux操作系统的区别

uc/os比较简单一点,开始学的uc/os,感觉没意思了就开始学linux,感觉ucos只是在单片机上跑跑,像arm9的一般是跑linux。其实先学哪个都差不多,因为学习方法大不相同,差别太大了,ucos太简单,就一些信号量,邮箱什么的,懂了也就会了,linux有点难,涉及知识太多,光是涉及内核以外的编程就需要大把大把的经典书籍去看。兴趣很重要,都靠兴趣过来的。

热点内容
cf游戏里最低配置怎么调 发布:2024-11-24 09:02:51 浏览:81
java排序算法效率 发布:2024-11-24 08:59:06 浏览:145
安卓vivo蓝牙耳机掉了一只怎么找 发布:2024-11-24 08:45:28 浏览:846
加油站脚本 发布:2024-11-24 08:44:02 浏览:434
绝地求生和cod哪个更吃配置 发布:2024-11-24 08:42:36 浏览:945
在哪里可以下载小游戏安卓版 发布:2024-11-24 08:42:30 浏览:691
移动硬盘怎么解除加密 发布:2024-11-24 08:42:30 浏览:492
数据库可以存储图片吗 发布:2024-11-24 08:33:55 浏览:593
linux私房菜基础篇 发布:2024-11-24 08:32:36 浏览:328
高创脚本 发布:2024-11-24 08:32:22 浏览:78