UC-OS II多任务机制
- 格式:docx
- 大小:10.69 KB
- 文档页数:2
uCOS多任务演示实验一、实验目的(1)、理解任务,任务调度的概念(2)、理解任务通信的几种方式(管道、共享内存、消息、队列、邮箱、套接字等)(3)、理解任务同步的几种方式(信号量、互斥、忙等待、事件、临界区等)(4)、掌握LPC2200(for MagicARM2200)专用工程模板的使用;(5)、能够在MagicARM2200-S 上运行基于μC/OS-II 操作系统的程序;(6)、掌握基于μC/OS-II 操作系统的用户程序的编写格式。
二、实验内容及要求建立三个或三个以上的μC/OS-II 的任务,一个任务用于检测KEY1 按键输入,称之为按键检测任务,另一个任务用于控制蜂鸣器,就称之为蜂鸣器控制任务。
还有LED灯任务和电机任务。
要求各个任务之间不是独立的,而是有相互关联的,达到多任务间的数据通信和同步的实验要求。
三、实验设备及软件硬件:PC 机一台MagicARM2200-S 教学实验开发平台一套软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境μC/OS-II 操作系统(V2.52)四、设计方案(一)方案原理 1、信号量与邮箱(1)要完成两个任务之间的单向同步,需要通过邮箱或者信号量来实现。
用信号量进行单向同步,以一个事情触发两个以上任务时,按键任务划分原则可以将他们合并为一个任务。
如果这些任务因为其他原因不能合并(不同的功能部件),则可以采用有消息分发功能的通信机制——邮箱,以减少通信工具的个数。
(2)且用信号量进行行为同步时,只能提供同步的时刻信息,不能提供内容信息,当控制方在对被控制方进行控制,且还需要向被控制方提供内容信息(数据或字符串)时,消息邮箱是一种有效的方案。
(3)当两个任务是系统“信息链条”中的相邻两个环节时,前一个任务的输出信息就是后一个任务的输入信息,消息邮箱就是连接这两个任务的桥梁。
在消息邮箱看来,提供消息的任务(或ISR)是生产者,读取消息的任务是消费者,正常情况下,消息的消费时间比生产时间短,消费者总是在等待消息的到来,这时,生产者每向“消息邮箱”发送一次“消息”,就立即被消费者取走,两者达到理想的同步效果。
uCOS-II的任务切换机理及中断调度优化uC/OS-II的任务切换机理及中断调度优化摘要:μC/OS-II是一种适用于嵌入式系统的抢占式实时多任务操作系统,开放源代码,便于学习和使用。
介绍μC/OS-II在任务级和中断级的任务切换原理,以及这一操作系统基于嵌入式系统的对于中断的处理;相对于内存资源较少的单片机,着重讨论一种优化的实用堆栈格式和切换形式,以提高资源的利用率;结合MSP430单片机,做具体的分析。
关键词:实时多任务操作系统μC/OS MSP430 中断堆栈引言在嵌入式操作系统领域,由Jean J. Labrosse开发的μC/OS,由于开放源代码和强大而稳定的功能,曾经一度在嵌入式系统领域引起强烈反响。
而其本人也早已成为了嵌入式系统会议(美国)的顾问委员会的成员。
不管是对于初学者,还是有经验的工程师,μC/OS开放源代码的方式使其不但知其然,还知其所以然。
通过对于系统内部结构的深入了解,能更加方便地进行开发和调试;并且在这种条件下,完全可以按照设计要求进行合理的裁减、扩充、配置和移植。
通常,购买RTOS 往往需要一大笔资金,使得一般的学习者望而却步;而μC/OS对于学校研究完全免费,只有在应用于盈利项目时才需要支付少量的版权费,特别适合一般使用者的学习、研究和开发。
自1992第1版问世以来,已有成千上万的开发者把它成功地应用于各种系统,安全性和稳定性已经得到认证,现已经通过美国FAA认证。
1 μC/OS-II的几大组成部分μC/OS-II可以大致分成核心、任务处理、时间处理、任务同步与通信,CPU的移植等5个部分。
核心部分(OSCore.c) 是操作系统的处理核心,包括操作系统初始化、操作系统运行、中断进出的前导、时钟节拍、任务调度、事件处理等多部分。
能够维持系统基本工作的部分都在这里。
任务处理部分(OSTask.c) 任务处理部分中的内容都是与任务的操作密切相关的。
包括任务的建立、删除、挂起、恢复等等。
uCOS-II任务及其结构
正如前⾯所介绍,在uC/OS-II中,任务包括任务控制块、任务堆栈以及任务代码组成,
其中任务控制块包括程序控制块+链表(前⼀篇内容):指向前⼀个任务控制块的指针,后⼀⼽任务控制块的指针,指向任务指针,指向任务堆栈的指针以及任务的优先级等等,
任务堆栈是⽤来保存任务的环境,
任务代码即为需要执⾏的任务内容,
介绍下线程与进程的定义:
线程,不占有私有空间的任务
进程,占有私有任务的任务
在uC/OS-II中,任务可分为⽤户任务和系统任务,系统中,最多可以含有64个任务(包括系统任务和⽤户任务),其中⼀个具体的时刻只可以存在⼀个任务占⽤CPU(运⾏状态),⽽其他任务只可以出于其他状态,系统任务的状态主要有:
睡眠状态:没有配备任务控制块或被剥夺了任务控制块
就绪状态:配备了任务控制块且在任务就绪表中登记
运⾏状态:处于就绪状态且获得了CPU的使⽤权,
等待状态:正在运⾏的任务,需要等待⼀段时间或者需要等待⼀个事件的触发再运⾏,此时CPU的使⽤权将让给其他的任务:使该任务进⼊等待状态,
中断服务状态:⼀个正在运⾏的任务⼀旦响应中断申请就会中⽌运⾏,转⽽执⾏中断服务程序(需要保存断点)
任务代码是⼀个⽆限循环结构,并且在循环中可以响应中断,这种结构是超循环结构,⽤户任务是需要调度才会被执⾏的,操作系统在管理⽤户任务的同时会处理⼀些内部事务(系统任务),为了使CPU在没有⽤户任务可执⾏时,有事可做,uC/OS-II提供了⼀个空闲任务(OSTaskIdle())的系统任务(简单说就是任务运⾏次数计数器),还包含统计任务(CPU使⽤率),即每秒计算⼀次CPU在单位时间内被使⽤的时间,并把计算结果以百分⽐形式存放在OSCPUsage中。
uC/OS-II是一种基于优先级的可抢先的硬实时内核。
要实现多任务机制,那么目标CPU必须具备一种在运行期更改PC的途径,否则无法做到切换。
不幸的使,直接设置PC指针,目前还没有哪个CPU支持这样的指令。
但是一般CPU都允许通过类似JMP,CALL这样的指令来间接的修改PC。
我们的多任务机制的实现也正是基于这个出发点。
事实上,我们使用CALL指令或者软中断指令来修改PC,主要是软中断。
但在一些CPU上,并不存在软中断这样的概念,所以,我们在那些CPU上,使用几条PUSH指令加上一条CALL指令来模拟一次软中断的发生。
再uC/OS-II里,每个任务都有一个任务控制块(Task Control Block),这是一个比较复杂的数据结构。
在任务控制快的偏移为0的地方,存储着一个指针,它记录了所属任务的专用堆栈地址。
事实上,再uC/OS-II内,每个任务都有自己的专用堆栈,彼此之间不能侵犯。
这点要求程序员再他们的程序中保证。
一般的做法是把他们申明成静态数组。
而且要申明成OS_STK类型。
当任务有了自己的堆栈,那么就可以将每一个任务堆栈再那里记录到前面谈到的任务控制快偏移为0的地方。
以后每当发生任务切换,系统必然会先进入一个中断,这一般是通过软中断或者时钟中断实现。
然后系统会先把当前任务的堆栈地址保存起来,仅接着恢复要切换的任务的堆栈地址。
由于哪个任务的堆栈里一定也存的是地址(还记得我们前面说过的,每当发生任务切换,系统必然会先进入一个中断,而一旦中断CPU 就会把地址压入堆栈),这样,就达到了修改PC为下一个任务的地址的目的。
uC/OS-II内核工作原理uC/OS-II是一个源码公开应用于嵌入式的小型的RTOS(实时),由于其内核精简,可理解性和可移植性强,因此广泛应用于小型的嵌入式系统中.内核工作原理:实时嵌入式操作系统mC/OS-II内核的工作原理如图1所示。
首先,在主程序中对操作系统进行初始化,完成uC/OS-II所有变量和数据结构的初始化,包括任务控制块(TCB)初始化,TCB优先级表初始化,TCB链表初始化,事件控制块(ECB)链表初始化以及空闲任务的创建等。
1VC下时钟的获得《嵌入式实时操作系统uC/OS-II》这本书已经安排了大量篇幅来专门讲解uC/OS-II的移植:第13章移植uC/OS-II,第14章uC/OS-II在80x86上的移植,第15章uC/OS-II在带有硬件浮点运算单元的80x86上的移植。
所以本文只是重点讲解移植到VC下和其他处理器上的不同地方,更详细的介绍读者可以参考《嵌入式实时操作系统uC/OS-II》这本书。
和所有其他的移植一样,本文所做的移植也只需要修改uC/OS-II处理器相关代码,一共包括3个文件:OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C。
考虑到VC可以嵌入汇编代码,并不需要专门的汇编代码文件,所以OS_CPU_A.ASM是多余的,最终只有OS_CPU.H和OS_CPU_C.C两个文件。
所以这两个文件成了移植的关键,首先要解决的问题就是时钟“滴答”的获得。
移植到BC下的uC/OS-II是通过修改DOS下的硬件时钟中断来得到时钟滴答的,VC下时钟滴答从哪里来呢?这是移植uC/OS-II到VC下第一个要考虑的问题。
在windows的保护模式下不能像DOS下面那么容易,直接通过一个函数调用就能够修改中断。
windows下要修改中断涉及到驱动程序,这样就加大了移植的困难度与复杂度,但好处是只有真正硬件时钟的“滴答”才能够保证uC/OS-II的实时性。
另外一种解决方法是采用windows下的软件定时器,通过定时器来产生模拟时钟“滴答”。
考虑到本移植只是为了教学和学习,并没有应用到对实时性要求高的产品,所以最终决定采用软件定时器来模拟时钟中断。
Windows下软件定时器种类很多,下面分别简要介绍一下这些定时器:1.SetTimer()函数有windows下编程经验的最先想到的应该是SetTimer这个API函数,但本文采用的移植程序是基于控制台的,也就是说最开始建立VC工程的时候选择的是创建win32 console application,控制台下的程序是没有消息循环的,所以要使用SetTimer函数则必须再创建一个线程来专门处理消息循环,这样一来事情就复杂了,而且这个函数定时精度非常不高。
uC/OS-II的运行机制在嵌入式系统的应用中,实时性是一个重要的指标,而优先级翻转是影响系统实时性的重要问题。
本文着重分析优先级翻转问题的产生和影响,以及在uC/OS-II 中的解决方案。
uC/OS-II 采用基于固定优先级的占先式调度方式,是一个实时、多任务的操作系统。
系统中的每个任务具有一个任务控制快OS_TCB,任务控制块记录任务执行的环境,包括任务的优先级,任务的堆栈指针,任务的相关事件控制块指针等。
内核将系统中处于就绪态的任务在就绪表(ready list)进行标注,通过就绪表中的两个变量OSRdyGrp 和OSRdyTbl[]可快速查找系统中就绪的任务。
在uC/OS-II 中每个任务有唯一的优先级,因此任务的优先级也是任务的唯一编号(ID),可以作为任务的唯一标识。
内核可用控制块优先级表OSTCBPrioTbl[] 由任务的优先级查到任务控制块的地址。
uC/OS-II 主要就是利用任务控制快OS_TCB、就绪表(ready list)和控制块优先级表OSTCBPrioTbl[]来进行任务调度的。
任务调度程序OSSched()首先由就绪表(ready list)中找到当前系统中处于就绪态的优先级最高的任务,然后根据其优先级由控制块优先级表OSTCBPrioTbl[] 取得相应任务控制块的地址,由OS_TASK_SW()程序进行运行环境的切换。
将当前运行环境切换成该任务的运行环境,则该任务由就绪态转为运行态。
当这个任务运行完毕或因其它原因挂起时,任务调度程序OSSched()再次到就绪表(ready list)中寻找当前系统中处于就绪态中优先级最高的任务,转而执行该任务,如此完成任务调度。
若在任务运行时发生中断,则转向执行中断程序,执行完毕后不是简单的返回中断调用处,而是由OSIntExit()程序进行任务调度,执行当前系统中优先级最高的就绪态任务。
当系统中所有任务都执行完毕时,。
S.D.Lu的uC/OS II 入门学习笔记(2):多任务初学者的疑惑对于一个单片机学习者,如果从未接触过嵌入式操作系统,就会觉得它是非常复杂而神秘的。
从我个人的经历说起,之前写的所有程序都是在单片机上“裸奔”的。
开始学习OS之前,对OS存在几个疑惑:1.一个CPU如何同时执行多个任务?答:CPU不能同时执行多个任务,甚至不能同时执行两个任务。
每一个时刻,CPU 只能执行一个任务。
2.CPU如何运行多个任务呢?答:CPU是通过分时复用的方法运行多个任务的。
也就是把时间切分成一个一个的时间片段,一个时间片段运行一个任务,然后下一个时间片段运行另一个任务。
应注意的是,一个时间片段并不一定能完整的运行一个任务,一个任务可能需要若干个时间片段才能从头到尾将代码运行一遍。
3.这些任务是相互独立的吗?如果不是独立的,它们之间又有什么联系?答:这些任务可以是相互独立的,也可以是相互联系的。
举两个简单的例子。
(1):假设有两个任务,一个是用P1.0口控制LED闪烁,3次/秒;另一个是用P1.1口控制LED闪烁,2次/秒。
那么这两个任务就是相互独立的。
(2): 假设有两个任务,一个是测量外部输入的方波信号的频率;另一个是控制一个LCD显示模块,显示该方波信号的频率值。
那么这两个任务就是有联系的,它们有公共的资源,即(数据)频率值。
当然,这里的例子并不准确,因为这些任务太简单了,完全可以用一个任务来完成,根本不需要OS。
这里只是用于说明,两个任务之间存在联系的情况。
如果出现多个任务访问同一资源时,比如两个任务都可以对一个变量进行赋值,就会发生冲突。
如何解决这些冲突呢?这就是需要OS来进行管理。
这只是OS的工作之一,其最重要的工作是进行任务之间的切换。
本篇实验将在上一篇的基础上进行,将运行两个任务,每个任务控制一个LED的亮灭。
例2-1先修改程序,编译运行。
main文件不用修改。
增加一个任务Task_LED2()。
1.修改app_cfg.h文件增加新增任务Task_LED2的一些设置项定义。
UC/OS-II内核详解一.内核概述:多任务系统中,内核负责管理各个任务,或者说为每个任务分配CPU时间,并且负责任务之间的通讯。
内核提供的基本服务是任务切换。
之所以使用实时内核可以大大简化应用系统的设计,是因为实时内核允许将应用分成若干个任务,由实时内核来管理它们。
内核本身也增加了应用程序的额外负荷,代码空间增加ROM的用量,内核本身的数据结构增加了RAM的用量。
但更主要的是,每个任务要有自己的栈空间,这一块吃起内存来是相当厉害的。
内核本身对CPU的占用时间一般在2到5个百分点之间。
UC/OS-II有一个精巧的内核调度算法,实时内核精小,执行效率高,算法巧妙,代码空间很少。
UC/OS-II的内核还可以被裁剪,Hmax中RTOS的就是一个被高度裁剪过的UC/OS-II。
二.任务控制块 OS_TCB:uC/OS-II的TCB数据结构简单,内容容易理解,保存最基本的任务信息,同时还支持裁减来减小内存消耗,TCB是事先根据用户配置,静态分配内存的结构数组,通过优先级序号进行添加,查找,删除等功能。
减少动态内存分配和释放。
因为依靠优先级进行TCB分配,每个任务必须有自己的优先级,不能和其他任务具有相同的优先级。
typedef struct os_tcb{OS_STK *OSTCBStkPtr;#if OS_TASK_CREATE_EXT_ENvoid *OSTCBExtPtr;OS_STK *OSTCBStkBottom;INT32U OSTCBStkSize;INT16U OSTCBOpt;INT16U OSTCBId;#endifstruct os_tcb *OSTCBNext;struct os_tcb *OSTCBPrev;#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_ENOS_EVENT *OSTCBEventPtr;#endif#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_ENvoid *OSTCBMsg;#endifINT16U OSTCBDly;INT8U OSTCBStat;INT8U OSTCBPrio;INT8U OSTCBX;INT8U OSTCBY;INT8U OSTCBBitX;INT8U OSTCBBitY;#if OS_TASK_DEL_ENBOOLEAN OSTCBDelReq;#endif} OS_TCB;.OSTCBStkPtr是指向当前任务栈顶的指针。
UC/OS II 多任务机制
前面已经说过,uC/OS-II是一种基于优先级的可抢先的多任务内核。
那么,它的多任务机制到底如何实现的呢?了解这些原理,可以帮助我们写出更加健
壮的代码来。
首先我们来看看为什么多任务机制可以实现?其实在单一CPU的情况下,是不存在真正的多任务机制的,存在的只有不同的任务轮流使用CPU,所以本质上还是单任务的。
但由于CPU执行速度非常快,加上任务切换十分频繁并且
切换的很快,所以我们感觉好像有很多任务同时在运行一样。
这就是所谓的多
任务机制。
由上面的描述,不难发现,要实现多任务机制,那么目标CPU必须具备一
种在运行期更改PC的途径,否则无法做到切换。
不幸的使,直接设置PC指针,目前还没有哪个CPU支持这样的指令。
但是一般CPU都允许通过类似JMP,CALL这样的指令来间接的修改PC。
我们的多任务机制的实现也正是基于这个出发点。
事实上,我们使用CALL指令或者软中断指令来修改PC,主
要是软中断。
回想一下你在微机原理课程上学过的知识,当发生中断的时候,CPU保存当前的PC和状态寄存器的值到堆栈里,然后将PC设置为中断服务程序的入口
地址,再下来一个机器周期,就可以去执行中断服务程序了。
执行完毕之后,
一般都是执行一条RETI指令,这条指令会把当前堆栈里的值弹出恢复到状态
寄存器和PC里。
这样,系统就会回到中断以前的地方继续执行了。
那么设想
一下?如果再中断的时候,人为的更改了堆栈里的值,那会发生什么?或者通过更改当前堆栈指针的值,又会发生什么呢?如果更改是随意的,那么结果是无
法预料的错误。
因为我们无法确定机器下一条会执行些什么指令,但是如果更。