嵌入式实时操作系统课件_第1页
嵌入式实时操作系统课件_第2页
嵌入式实时操作系统课件_第3页
嵌入式实时操作系统课件_第4页
嵌入式实时操作系统课件_第5页
已阅读5页,还剩260页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1实时操作系统

µC/OS-Ⅱ分析和应用

12第一章:µC/OS-II概述µµC/OS-II概述任务管理中断和时间管理2Co存储管理任务之间的通信与同步SII3操作系统综述一、操作系统综述1、通用操作系统2、嵌入式操作系统二、为什么需要嵌入式操作系统三、µC/OS-II34一、操作系统综述:通用操作系统操作系统是计算机系统中的一个软件系统,它是这样一些程序模块的集合:它们能有效地组织和管理计算机中的硬件以及软件资源,合理地组织计算机工作流程,控制程序的执行,并向用户提供各种服务功能,使得用户能够灵活、方便和有效地使用计算机,使整个计算机系统能高效地运行。45非嵌入式操作系统-桌面操作系统:

MSDOS:基于Intelx86系列的PC机上的最早的操作系统,微软公司产品,只能管理运行一个程序,只提供字符显示界面。

WindowsXX:是现在基于Intelx86系列的PC机上的主要操作系统。提供GUI支持。可以运行多个程序,为面向桌面、面向个人用户的多任务操作系统。5一、操作系统综述:通用操作系统6操作系统综述-多任务操作系统WindowsX67非嵌入式操作系统-服务器操作系统:

UNIX:一个真正稳健、实用、强大的服务器操作系统,是一个多用户操作系统。广泛应用于科研、通讯、金融等关键领域。LINUX:是一套免费使用和自由传播的类Unix操作系统。

Windows2000Server:利用Windows的友好的用户界面的优势打进服务器操作系统市场。但其在整体性能、效率、稳定性上都与UNIX有一定差距,所以现在主要应用于中小企业市场。7一、操作系统综述:通用操作系统8操作系统综述-多用户操作系统UNIX8UNIX主机终端1终端2终端n网络TCP/IP网络终端服务器终端。。。主机m主机nRS2322RS2322RS2322RS2322RS2322RS232299一、操作系统综述:嵌入式操作系统在我们的现实生活和工作中,除了广泛使用计算机外,还有比计算机更多的IT产品应用于各个领域。1010

这些产品大都是“类计算机”产品,但是,在这些产品上,受资源限制和“个性”要求,不可能也没有必要运行完整的Windows、Linux等操作系统来管理系统的运行,因此,派生出了所谓的嵌入式实时操作系统(RTOS)和嵌入式应用系统:

嵌入式系统的一般定义:“以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计算机系统”。一、操作系统综述:嵌入式操作系统1111嵌入式(实时)操作系统:用于嵌入式设备的操作系统,具有通用操作系统的基本特点,又具有系统实时性、硬件的相关依赖性、软件固态化以及应用的专用性等特点,操作系统、应用软件等与硬件融为一体,不可分离;嵌入式(实时)操作系统通常包括与硬件相关的底层驱动软件、系统内核、设备驱动接口、通信协议、图形用户界面(GUI)等;嵌入式(实时)操作系统的重要指标:实时性(中断响应时间、任务切换时间等)、尺寸(可裁剪性)、可扩展性(内核、中间件);一、操作系统综述:嵌入式操作系统12常见的嵌入式操作系统

12嵌入式操作系统的种类繁多,大体上可分为两种,商用型和免费型。商用型的嵌入式操作系统功能稳定、可靠,有完善的技术支持和售后服务,但往往价格昂贵,如Vxworks、QNX、WinCE、PalmOS等。免费型的实时操作系统,如:

Linux,μC/OS-II等是一种源码开放的RTOS;

还有一个大家耳熟能详的系统....13常见的嵌入式操作系统13嵌入式系统的特点:专用性为特定应用定制的产品。裁减性软、硬件小而精,够用即可。实时性程序和数据都在存储器中,既满足逻

辑正确性,也要满足时间正确性。可靠性无人值守、自动化设备的使用要求。低功耗便携式应用的要求。高性价家用的应用要求。14其它组件

TCP/IP

设备I/ORTOS在嵌入式系统中的位置RTOS

KERNEL

调试工具

FS C/C++设备驱动BSP嵌入式硬件平台

应用系统RTOS在嵌入式系统中的位置1415二、为什么需要嵌入式操作系统在早期的一些嵌入式系统中没有操作系统的概念,程序员直接针对裸机及裸设备编写嵌入式产品的程序。在这种情况下,通常把嵌入式程序分成两部分:前台程序和后台程序。151616前后台系统运行流程二、为什么需要嵌入式操作系统17

17二、为什么需要嵌入式操作系统18intmain(void){for(;;){while(Computer()) //计算机通讯数据ProcessHost();if(BarCode()) //条码枪处理 ProcessReader();if(BalanceWeight()) //电子秤处理 ProcessWeight();if(KeyInput()) //键盘处理 ProcessKey();}}18二、为什么需要嵌入式操作系统1919这样的系统我们称之为前后台系统:

应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台(background)。也可以叫做任务级。

时间相关性很强的关键操作(Criticaloperation)采用中断服务来完成,这部分可以看成前台(foreground)。前台也叫中断级。

因为中断服务提供的信息一直要等到后台程序走到该处理这个信息这一步时才能得到处理,这种系统在处理信息的及时性上,比实际可以做到的要差。这个指标称作任务级响应时间。最坏情况下的任务级响应时间取决于整个循环的执行时间。因为循环的执行时间不是常数,程序经过某一特定部分的准确时间也是不能确定的。进而,如果程序修改了,循环的时序也会受到影响。二、为什么需要嵌入式操作系统20前后台系统的实时性比预计的要差:

1.前后台系统中的所有任务依次序顺序处理,无优先级别,对那些实时性要求高的任务不可能立刻得到处理。

2.后台程序是一个无限循环的结构,一旦在这个循环体中正在处理的任务崩溃,将会导致整个任务序列中的其他任务得不到处理,从而造成整个系统的崩溃。

3.这类系统结构简单,每个任务几乎不需要额外的RAM/ROM开销,可以节约宝贵的存储资源,因而在简单的嵌入式应用被广泛使用.20二、为什么需要嵌入式操作系统21#include<stdio.h>intmain(void){FILE*in;if((in=fopen("TEST.DAT","rt"))==NULL) return1;while(!feof(in))

putch(fgetc(in));

fclose(in);return0;}使用编程平台编写应用程序读写文件数据在屏幕上显示内容与其它程序通信….磁盘显示器其它程序21由操作系统负责完成由硬件驱动负责二、为什么需要嵌入式操作系统22微处理器(MCU)

ROMSDRAMA/DI/OD/A实时操作系统(RTOS)图形用户接口(GUI)BSP板极支持包/HAL硬件抽象层/ 通用接口任务管理文件系统(FAT)应用程序硬件层软件层中间层功能层嵌入式计算机系统22二、为什么需要嵌入式操作系统23三、µC/OS简介1、µC/OS——MicroControllerOS,微控制器操作系统2、µC/OS简介lllll美国人JeanLabrosse1992年完成应用面覆盖了诸多领域,如照相机、医疗器械、音响设备、发动机控制、高速公路电话系统、自动提款机等1998年µC/OS-II,目前µC/OS-III版本也已经发布2000年,得到美国航空管理局(FAA)的认证,可以用于飞行器中网站www.ucos-II.com()2324uuuu公开源代码可移植性(Portable)绝大部分µ

C/OS-II的源码是用移植性很强的ANSIC写的。和微处理器硬件相关的那部分是用汇编语言写的。汇编语言写的部分已经压到最低限度,使得µ

C/OS-II便于移植到其他微处理器上。µ

C/OS-II可以在绝大多数8位、16位、32位以至64位微处理器、微控制器、数字信号处理器(DSP)上运行。可固化(ROMable)µ

C/OS-II是为嵌入式应用而设计的,这就意味着,只要读者有固化手段(C编译、连接、下载和固化),µ

C/OS-II可以嵌入到读者的产品中成为产品的一部分。可裁剪(Scalable)µC/OS的性能特点(一)

可以只使用µ

C/OS-II中应用程序需要的那些系统服务。也就是说某产 品可以只使用很少几个µ

C/OS-II调用,而另一个产品则使用了几乎所 有µ

C/OS-II的功能,这样可以减少产品中的µ

C/OS-II所需的存储器空 间(RAM和ROM)。这种可剪裁性是靠条件编译实现的。可扩展(Extendable)

可以增补uC/OS中未包含的其他功能2425uuuuuuu

占先式(Preemptive) 多任务

µC/OS-II可以管理64个任务,然而,目前这一版本保留8个给系统。

可确定性全部µ

C/OS-II的函数调用与服务的执行时间具有可确定性。

任务栈每个任务有自己单独的栈,µ

C/OS-II允许每个任务有不同的栈空间,以便压低应 用程序对RAM的需求。

系统服务

µC/OS-II提供很多系统服务,例如邮箱、消息队列、信号量、块大小固定的内存 的申请与释放、时间相关函数等。

中断管理中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被该中断唤醒,则 高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达255层。

稳定性与可靠性µC/OS的性能特点(二)2526µC/OS-II提供的系统服务ll信号量(OSSemPend(),使用共享资源,OSSemPost())带互斥机制的信号量n使用互斥信号量减少优先级倒置的问题llllll事件标志消息信箱消息队列内存管理时钟管理任务管理2627µC/GUI与µC/FSlµC/GUIlllll嵌入式的用户界面用ANSIC书写支持任何8,16,32-bitsCPU彩色,灰、度,等级或黑白显示代码尺寸小lµC/FSllll嵌入式的文件系统WritteninANSIC用ANSIC书写支持任何8,16,32-bitsCPU支持SMC,MMC,SD,CF,IDE,Flash,RAM其他介质2728可移植的数据类型typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;typedefsignedcharINT8S;typedefunsignedintINT16U;typedefsignedintINT16S;typedefunsignedlongINT32U;typedefsignedlongINT32S;typedeffloatFP32;typedefdoubleFP64;

2829µC/OS-II的组成文件结构

293030µµC/OS-II概述任务管理中断和时间管理Co存储管理任务之间的通信与同步SII第二章:µC/OS-II任务管理31RTOS在嵌入式系统中的位置µC/OS-II:任务管理 之前我们介绍过简单的收款机程序,其实也可以称之为一个任务,只是在这样简单的前后台编程方式下,MCU(MicroControlUnit)仅仅运行一个单一任务而已。但是,此任务是可以被中断服务程序所打断,当中断服务程序运行完毕后,MCU又会丝毫不差地返回到被中断位置继续执行处理收款机业务功能的“任务”程序。之所以能够做到这一点,是因为进入中断服务程序时,及时将断点位置的有关信息压入堆栈进行保存,这些信息包括:PC、程序状态字PSW等。这些工作由MCU的中断响应机制或者中断指令完成。3132RTOS在嵌入式系统中的位置µC/OS-II:任务管理以下示例为一个时钟中断服务汇编语言程序,当时钟计数器减到0时,会产生中断,并运行此中断服务程序:TIME_A4_ISR: pushmr0,r1,r2,r3,a0,a1 ;savegeneralregisters mov.b PRN_FISRSB,r0l ; mov.b r0l,a0 ; shl.w #1,a0 ......... popm r0,r1,r2,r3,a0,a1 ;restoreregisters reit ;returnfrominterrupt32进入TIME_A4_ISR前,中断处理机制会将PC和PSW自动存入堆栈中断服务程序再把自己要用到的寄存器压入堆栈,以免破坏被中断程序所使用到的寄存器中的内容中断服务程序运行完毕,从堆栈中恢复被保护的寄存器内容执行中断返回指令,完成两个操作:1。从堆栈中把PSW弹出并存入PSW寄存器;2。从堆栈中将断点地址弹出并存入到PC中,使MCU到回到断点处继续执行33一个从键盘输入字符串的小程序(任务).voidGetAString(intiLen,char*iBuf){inti;for(i=0;i<iLen;){if(kbhit())iBuf[i++]=getch();}}//------------------------------------------------------------//intmain(intargc,char*argv[]){charstr[100];while(1){

GetAString(90,str);}}33

Main在调用GetAString时要做的几件事情:1.

将执行完GetAString后的返回地址压入堆栈;2.

将GetAString的两个参数iLen和iBuf压入堆栈;3.

GetAString在堆栈中为自己的内部变量i分配空间.34程序代码程序堆栈内存处理器PCSP寄存器组程序运行时与处理器之间的关系处理器通过两个指针寄存器(PC和SP)来与任务代码和任务堆栈建立联系并运行它处理器通过两个指针寄存器(PC和SP)来与任务代码和任务堆栈建立联系并运行它运行环境包括了两部分:处理器中的运行环境和内存中的运行环境运行环境包括了两部分:处理器中的运行环境和内存中的运行环境35一个从键盘输入字符串的小程序(任务)voidGetAString(intiLen,char*iBuf){inti;for(i=0;i<iLen;){if(kbhit())iBuf[i++]=getch();}}//------------------------------------------------------------//intmain(intargc,char*argv[]){charstr[100];while(1){

GetAString(90,str);}}实际应用要求:运行此程序的设备突然断电了,重新开机后,需要从断电时的程序断点位置继续运行,怎么办?3536一个从键盘输入字符串的小程序(任务)掉电时进行如下处理:掉电时,产生系统中断,进入掉电中断服务程序;将程序断点(PC)存入非易失存储器将所有寄存器的值存入非易失存储器将堆栈中的数据存入非易失存储器开机时进行如下处理:判断是否有被保护的现场数据;恢复堆栈数据恢复寄存器数据恢复PC中的数据3637任务代码任务堆栈内存处理器PCSP任务代码任务堆栈内存任务代码任务堆栈内存?当有多个任务时,处理器中的运行环境应该怎么办?寄存器组程序运行环境多任务运行时与处理器之间的关系38程序

虚拟处理器PCSP

虚拟处理器PCSP

虚拟处理器PCSP

虚拟处理器PCSP调度器程序处理器PCSP在内存中为每个任务创建一个虚拟的处理器(处理器部分的运行环境由操作系统的调度器按某种规则来进行这两个复制工作复制当需要运行某个任务时就把该任务的虚拟处理器复制到实际处理器中复制当需要中止当前任务时,则把任务对应的虚拟处理器复制到内存复制再把另一个需要运行的任务的虚拟处理器复制到实际处理器中寄存器组寄存器组也就是说,任务的切换实际上是任务运行环境的切换多任务运行时与处理器之间的关系39虚拟处理器应该存储的主要信息:1。程序的断点地址(PC)2。任务堆栈指针(SP)3。程序状态字寄存器(PSW)4。通用寄存器内容5。函数调用信息(已存在于堆栈)另外再用一个数据结构保存任务堆栈指针(SP),这个数据结构叫做任务控制块,它除了保存任务堆栈指针之外还要负责保存任务其他信息。这些内容通常保存在任务堆栈中,这些内容也常叫做任务的上下文。任务控制块是由操作系统另行构造的一个数据结构,每个任务都有一个。任务代码任务堆栈内存任务控制块多任务运行时虚拟处理器40程序切换的关键是把程序的私有堆栈指针赋予处理器的堆栈指针SP,实质上系统是通过SP的切换来实现任务的切换的。要建立一个概念:具有控制块的程序才是一个可以被系统所运行的任务。程序代码、私有堆栈、任务控制块是任务的三大要素。任务控制块提供了运行环境的存储位置。多任务运行时虚拟处理器41

在多任务环境下,把一个大型软件分解成多个小任务,然后在计算机中通过运行这些小任务,最终达到完成软件所要实现的功能的目的。

在μC/OS-II中,与上述那些小任务对应的程序实体就叫做“任务”(实质上是一个线程),μC/OS-II就是一个能对这些小任务的运行进行管理和调度的多任务操作系统。

任务的概念421.

一个任务,也称作一个线程,是完成某一特定功能的程序,该程序认为CPU完全属于自己;2.

应用程序的设计过程,就是如何把复杂的功能分割成多个任务来实现,每个任务被赋予一定的优先级,有它自己的一套CPU寄存器和自己的栈空间;3.

典型地、每个任务都是一个无限的循环。每个任务都处在5种状态之一的状态下:休眠态,就绪态、运行态、挂起态(等待某一事件发生)和被中断态;42任务的概念4343任务的概念44从应用程序设计的角度来看,μ/OS-II的任务就是一个用户编写的C函数和与之相关联的一些数据结构而构成的一个实体。

任务代码任务堆栈内存在内存中应该存有任务的代码和与该任务配套的堆栈任务的概念任务控制块在内存中还必须保存任务控制块45µC/OS-II所管理的任务一般结构:voidMyTask(void*pdata) { for(;;) { {可以被中断的任务代码;}

OS_ENTER_CRITICAL();//进入临界段(关中断)

{不可以被中断的任务代码;}

OS_EXIT_CRITICAL(); //退出临界段(开中断) {可以被中断的任务代码;}

OSTimeDly(10); //引起任务调度 }}pdata参数为任务所需要的参数,在创建任务时指定为了有效的对中断进行控制,在任务的代码里可使用UC/OS-II定义的宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来控制何时响应中断,何时屏蔽中断。在运行这两个宏之间的代码时是不会响应中断的,这种受保护的代码段叫临界段。µC/OS-II的任务45根据嵌入式系统任务的工作特点,任务的执行代码通常是一个无限循环结构,并且在这个循环中可以响应中断,这种结构也叫超循环结构。并非每个任务都要pdata,当多个任务完成相同的功能,仅仅是其使用的数据不同时,可以通过提供不同的pdata参数来用同一个函数创建多个任务,如:可以将四个串口安排成每个串口都是一个单独的任务,而每个任务的代码实际上是相同的。不同的仅仅是串口的参数(波特率、I/O口地址、中断向量号、数据收发区等)。46µC/OS-II的任务voidTask1(void*pdata) //定义用户任务1{ for(;;){ …… }}voidTask2(void*pdata) //定义用户任务2{ for(;;){ …… }}voidmain(){ ……OSInit(); //初始化uC/OS-IIOSTaskCreate(Task1,……); //创建用户任务1 OSTaskCreate(Task2,……); //创建用户任务2OSStart(); //启动任务} Task1是一个任务。因此它不是被主函数或其它函数调用的,主函数main()只负责创建和启动它们,而由操作系统负责来调度运行它们。OSInit()在main()函数中首先被调用,是uC/OS运行的第一个函数。它完成uC/OS的初始化,建立任务空闲键表OSTCBFreeList,建立事件空闲键表OSEventFreeList.创建空闲任务OS_TaskIdle等。

使用函数OSStart()启动任务之后,任务就交由操作系统管理和调度了。46创建任务。建立此任务的TCB,为任务分配堆栈,,设定任务的优先级,将任务置为就绪状态47µC/OS-II的任务OSInit函数原型:voidOSInit(void){OS_InitMisc();//完成一般变量初始化OS_InitRdyList();//就绪列表初始化OS_InitTCBList();//空闲任务键表OSTCBFreeList建立OS_InitEventList();//事件空闲键表OSEventFreeList建立。OS_FlagInit();//其它相关功能参数初始化。OS_MemInit();//内存管理初始化函数OS_QInit();//消息队列初始化函数OS_InitTaskIdle();//创建空闲任务OS_TaskIdle.OS_InitTaskStat();OSInitHookEnd();}

4748voidMyTask(void*pdata){ /*对参数pdata进行操作,例如pdata=pdata*/for(;;){/*任务函数体.为无限循环结构*/ . .

/*任务中必须调用如下的函数之一:*/ /*OSMboxPend()*/ /*OSQPend()*/ /*OSSemPend()*/ /*OSTimeDly()*/ /*OSTimeDlyHMSM()*/ /*OSTaskSuspend()(挂起任务自身)*/ /*OSTaskDel()(删除任务自身)*/ .}}

µC/OS-II的任务48任务中必须调用如下的函数之一,其目的是能够引起任务调度49lμC/OS-Ⅱ可以管理多达64个任务;lll每个任务被赋以不同的优先级,取值从0到OS_LOWEST_PRIO-2,数值越小,优先级越高;系统保留了优先级为0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRI0-2,OS_LOWEST_PRI0-1以及OS_LOWEST_PRI0这8个任务以被将来使用,用户可以有56个应用任务;任务的优先级同样也是它的标识号ID。µC/OS-II的任务4950uC/OS-II的任务有两种,用户任务和系统任务:由应用程序设计者编写的任务叫做用户任务,由系统提供的任务叫做系统任务。用户任务是为解决应用问题而编写的,系统任务是为应用程序来提供某种服务的。µC/OS-II的任务5051系统任务之:空闲任务(IdleTask)

μC/OS-Ⅱ总要建立一个空闲任务,这个任务在没有其它任务进入就绪态时投入运行。这个空闲任务OSTaskIdle()永远设为最低优先级,即OS_LOWEST_PRI0。空闲任务OSTaskIdle()什么也不做,只是在不停地给一个32位的名叫OSIdleCtr的计数器加1,统计任务使用这个计数器以确定现行应用软件实际消耗的CPU时间。空闲任务不能被应用软件删除。5152系统任务之:

统计任务OSTaskStat()任务OSTaskStat()是负责统计运行时间的任务,如果用户将系统定义常数OS_TASK_STAT_EN(见文件OS_CFG.H)设为1,这个任务就会建立。一旦得到允许,统计任务每秒运行一次(OS_CORE.C)以计算当前的CPU利用率。也即计算应用程序使用了多少CPU时间,用百分比表示,这个值放在一个有符号8位整数OSCPUsage中,精确度是1个百分点。5253任务的实现µC/OS-II任务创建功能函数之一:53INT8UOSTaskCreate( void(*task)(void*pd),//是指向任务代码的指针 void*pdata,

//指向任务传递参数的一个数据结构 OS_STK*ptos,

//指向任务堆栈栈顶的指针 INT8Uprio

//为任务的优先级);54任务的实现lOSTaskCreateExt()µC/OS-II中的任务是进程还是线程?µC/OS-II任务创建功能函数之二:INT8UOSTaskCreateExt( void(*task)(void*pd),//是指向任务代码的指针 void*pdata,//指针指向向任务传递参数的一个数据结构 OS_STK*ptos,//指向任务堆栈栈顶的指针 INT8Uprio,//为任务的优先级 INT16Uid,//是任务的标识(保留) OS_STK*pbos,//指向堆栈底端的指针 INT32Ustk_size,//指定任务堆栈的大小 void*pext,//个用户定义数据结构的指针,可作为TCB的扩展 INT16Uopt//存放与任务相关的操作信息);54当前的μC/OS版本的Opt支持下列操作:OS_TASK_OPT_STK_CHK:决定是否进行任务堆栈检查。OS_TASK_OPT_STK_CLR:决定是否清空堆栈。OS_TASK_OPT_SAVE_FP:决定是否保存浮点寄存器的数值。此项操作仅当处理器有浮点硬件时有效。保存操作由硬件相关的代码完成。55任务也可以自我删除(并非真的删除,只是内核不再知道该任务)voidMyTask(void*pdata){....../*任务代码*/OSTaskDel(OS_PRIO_SELF);}

55任务的实现56

µC/OS-II多任务的启动是用户通过调用OSStart()实现的。然而,启动μC/OS-Ⅱ之前,用户至少要建立一个应用任务。OSStart函数直接调用OSStartHighRdy去执行最高优先级的任务,OSStart不返回.OSInit();/*初始化uC/OS-II*/

...通过调用OSTaskCreate()或OSTaskCreateExt()创建至少一个任务;

...OSStart();/*开始多任务调度!永不返回*/}56

voidmain(void) {任务的实现任务创建示例#defineTASK_STK_SIZE512//定义堆栈大小#defineTaskStart_ID5//定义任务的ID,优先级voidTaskStart(void*data)

//定义任务{

WORDkey;data=data;/*避免编译警告*/

PC_DispStr(16,0,"uC/OS-II,TheReal-TimeKernel",DISP_BGND_RED);

PC_DispStr(17,1,"JeanJ.Labrosse",DISP_FGND_WHITE);

PC_DispStr(18,3,"EXAMPLE#1",DISP_FGND_WHITE);

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

for(;;){

if(PC_GetKey(&key)==TRUE){

/*是否有按键*/

if(key==0x1B)/*有按键,且为ESC*/

PC_DOSReturn();/*退出系统*/

}

OSTimeDlyHMSM(0,0,1,0);/*延迟等待1秒*/

}//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}OS_STKTaskStartStk[TASK_STK_SIZE];

//定义堆栈任务创建示例voidmain(void){

PC_DispClrScr(DISP_FGND_WHITE+DISP_BGND_BLACK);/*清除屏幕*/

OSInit();/*初始化uC/OS-II*/

PC_DOSSaveReturn();/*保护用于返回DOS的系统环境*/

PC_VectSet(uCOS,OSCtxSw);/*初始化uC/OS-II的中断向量*/

OSTaskCreate(TaskStart,//要创建的任务名称(void*)0,//传递给任务的参数&TaskStartStk[TASK_STK_SIZE-1],//任务要用到的堆栈

TaskStart_ID//任务优先级

);/*创建任务*/

OSStart();/*启动任务*/}59µC/OS-II系统的初始化与启动lll在调用µC/OS-II的任何其它服务之前,用户必须首先调用系统初始化函数OSInit()来初始化µC/OS的所有变量和数据结构;OSInit()建立空闲任务OSTaskIdle(),该任务总是处于就绪状态,其优先级一般被设成最低,即OS_LOWEST_PRIO;如果需要,OSInit()还建立统计任务OSTaskStat(),并让其进入就绪状态;OSInit()还初始化了4个空数据结构缓冲区:空闲

TCB链表OSTCBFreeList、空闲事件链表

OSEventFreeList、空闲队列链表OSQFreeList和 空闲存储链表OSMemFreeList。

5960µC/OS-II系统初始化后的状态

60调用OSInit()之后的数据结构61

OSStart()voidOSStart(void){ INT8UY; INT8UX; if(OSRunning==FALSE){yx=OSUnMapTbl[OSRdyGrp];=OSUnMapTbl[OSRdyTbl[y]];OSPrioHighRdy=(INT8U)((Y<<3)+X);OSPrioCurOSTCBHighRdy=OSPrioHighRdy;=OSTCBPrioTbl[OSPrioHighRdy];OSTCBCur=OSTCBHighRdy;

OSStartHighRdy();//启动最高优先级任务 } }6162系统启动后的状态

62调用OSStart()以后的变量与数据结构假设用户创建的任务优先级为663任务控制块TCBll任务控制块OS_TCB是描述一个任务的核心数据结构,存放了它的各种管理信息,包括任务堆栈指针,任务的状态、优先级,任务链表指针等;一旦任务建立了,任务控制块OS_TCB将被赋值。记住:μC/OS-Ⅱ管理任务的核心是任务控制块TCB!6364任务堆栈voidmytask(){…..for(;;){…..}}任务代码任务控制块指向前一个任务控制块的指针指向后一个任务控制块的指针指向任务的指针指向任务堆栈的指针任务的优先级别……任务任务控制块TCB

:任务的存储结构从任务的存储结构看,任务由三个部分组成:任务控制块、任务代码与任务堆栈6465任务控制块TCB

:任务的存储结构任务控制块任务代码任务堆栈任务1任务控制块任务代码任务堆栈任务2任务控制块任务代码任务堆栈任务n……任务控制块链表系统在调用函数OSInit()对uC/OS-II系统进行初始化时,先在RAM中建立一个OS_TCB结构类型的数组OSTCBTbl[],每个数组元素就是一个任务控制块,然后把这些控制块链接成一个如图所示的链表。由于链表中的这些控制块还没有与具体任务相关联,因此这个链表叫做空任务块链表。每当应用程序调用系统函数OSTaskCreate()创建一个任务时,系统就会将任务控制块链表头指针OSTCBFreeList指向的任务控制块分配给该任务。在给任务控制块中的各成员赋值后,就按任务控制块链表的头指针OSTCBList将其加入到任务控制块链表中。6566任务控制块TCB

:任务的存储结构一旦任务建立,uCOS就会为此任务创建一个任务控制块OS_TCB。任务控制块是一个数据结构,保存该任务的相关参数,包括任务堆栈指针,任务的当前状态,任务的优先级等。任务CPU使用权被剥夺时,OS_TCB保存该时刻任务状态;任务重新得到CPU控制权时,OS_TCB可确保任务从此前被中断的那一点丝毫不差地继续执行。OS_TCB全部驻留在RAM中。任务控制块就相当于一个任务的身份证,没有任务控制块的任务是不能被系统承认和管理的。

6667任务控制块TCBtypedef

struct

os_tcb

{OS_STK*OSTCBStkPtr;//指向任务堆栈栈顶的指针

INT16UOSTCBOpt; //任务选择项

INT16UOSTCBId;

//任务的ID

……

structos_tcb*OSTCBNext;//指向后一个任务控制块的指针

structos_tcb*OSTCBPrev;//指向前一个任务控制块的指针OS_EVENT*OSTCBEventPtr;//事件指针void*OSTCBMsg;//消息指针

……INT16U OSTCBDly;//任务等待的时限(节拍数)

INT8U OSTCBStat;//任务的当前状态标志

INT8U OSTCBPrio;//任务的优先级别

……}OS_TCB;6768任务控制块TCB:栈指针

OSTCBStkPtr:指向当前任务栈顶的指针,每个任务可以有自己的栈,栈的容量可以是任意的;

OSTCBStkBottom:执行任务栈底的指针;。如果微处理器的栈指针是递减的,即栈存储器从高地址向低地址方向分配,则OSTCBStkBottom指向任务使用的栈空间的最低地址。类似地,如果微处理器的栈是从低地址向高地址递增型的,则OSTCBStkBottom指向任务可以使用的栈空间的最高地址。函数OSTaskStkChk()要用到变量OSTCBStkBottom,在运行中检验栈空间的使用情况。用户可以用它来确定任务实际需要的栈空间

OSTCBStkSize:栈的容量,用可容纳的指针数目而不是字节数(Byte)来表示。在函数OSStakChk()中要使用OSTCBStkSize。6869任务控制块TCB:栈指针

任务所需的堆栈的容量是在创建任务时指定的。在指定堆栈大小的时候必须考虑此任务所调用的所有函数的嵌套情况,任务所调用的所有函数会分配的局部变量的数目,以及所有可能的中断服务例程嵌套的堆栈需求。另外,为任务分配的堆栈必须能储存所有的CPU寄存器。由于嵌入式硬件平台的RAM资源很宝贵,因此我们应该给每个任务分配够用的堆栈!用户如何确定一个任务所需要的堆栈大小呢?6970任务控制块TCB:栈检测

OSTCBOpt:为使用OSTaskCreateExt()创建任务时的选择项。

OS_TASK_OTP_STK_CHK用于告知TaskCreateExt(),在任务建立的时候可以进行任务栈检验功能;OS_TASK_OPT_STK_CLR表示任务建立的时候任务栈要清零。如果要进行栈检测,创建任务时必须将栈清0;OS_TASK_OPT_SAVE_FP通知TaskCreateExt(),任务要做浮点运算。如果微处理器有硬件的浮点协处理器,则所建立的任务在做任务调度切换时,浮点寄存器的内容要保存7071任务控制块TCB:栈检测7172任务控制块TCB:栈检测μC/OS-Ⅱ提供的OSTaskStkChk()函数可以为用户确定任务做需要的堆栈大小,要使用此功能,用户必须要做以下几件事情:在OS_CFG.H文件中设OS_TASK_CREATE_EXT为1。用OSTaskCreateExt()建立任务,并给予任务比实际需要更多的内存空间。在OSTaskCreateExt()中,将参数opt设置为OS_TASK_OPT_STK_CHK+OS_TASK_OPT_STK_CLR。注意如果用户的程序启动代码清除了所有的RAM,并且从未删除过已建立了的任务,那么用户就不必设置选项OS_TASK_OPT_STK_CLR了。这样就会减少OSTaskCreateExt()的执行时间。将用户想检验的任务的优先级作为OSTaskStkChk()的参数并调用之。

72用户应该使自己的应用程序运行足够长的时间,并且经历最坏的堆栈使用情况,这样才能得到正确的数。一旦OSTaskStkChk()提供给用户最坏情况下堆栈的需求,用户就可以重新设置堆栈的最后容量了。为了适应系统以后的升级和扩展,用户应该多分配10%-100%的堆栈空间。在堆栈检验中,用户所得到的只是一个大致的堆栈使用情况,并不能说明堆栈使用的全部实际情况。73任务控制块TCB:链表指针

OSTCBNext、OSTCBPrev:用于任务控制块OS_TCBs的双重链接,该链表在时钟节拍函数OSTimeTick()中使用,用于刷新各个任务的任务延迟变量.OSTCBDly,每个任务的任务控制块OS_TCB在任务建立的时候被链接到链表中,在任务删除的时候从链表中被删除。双重连接的链表使得任一成员都能被快速插入或删除。所有的任务控制块分属于两条不同的链表,单向的空闲链表(头指针为OSTCBFreeList)和双向的使用链表(头指针为OSTCBList);7374任务控制块TCB:空闲TCB链表l所有的任务控制块都被放置在任务控制块列表数组

OSTCBTbl[]中,系统初始化时,所有TCB被链接成空闲的 单向链表,头指针为OSTCBFreeList。当创建一个任务后, 就把OSTCBFreeList所指向的TCB赋给了该任务,并将它加 入到使用链表中,然后把OSTCBFreeList指向空闲链表中的 下一个结点。7475任务控制块TCB:延迟/状态/优先级

OSTCBDly:保存的是任务允许等待事件发生的最多时钟节拍数。如果这个变量为0,表示任务不延时,或者表示等待事件发生的时间没有限制。当需要把任务延时若干时钟节拍时要用到这个变量,或者需要把任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。OSTCBStat:任务的状态字。为0时,任务进入就绪态。在uCOS_II.H中有这个值的其它状态定义:等待信号量、等待邮箱、挂起等。OSTCBPrio:是任务优先级。任务优先级越高,.OSTCBPrio的值越小。7576任务控制块TCB:系统初始化后…指针数组,指向相应TCB76总结:任务控制块是一个数据结构,当任务的CPU使用权被剥夺时,μC/OS-Ⅱ用它来保存该任务的状态。当任务重新得到CPU使用权时,任务控制块能确保任务从当时被中断的指令位置丝毫不差地继续执行。77任务的状态-就绪lll就绪状态(Ready):万事具备,只欠CPU;在所有的就绪任务当中,具有最高优先级的任务被选中去运行;如果任务在运行的时候被抢占了CPU,则

又回到就绪状态。7778任务的状态-运行lll运行状态(Running):任务在CPU上运行;当一个任务在运行时,如果没有关闭中断,则有可能被中断所打断;当一个任务在运行时,可能因为各种原因进入阻塞状态。–OSMBoxPend(),OSQPend(),OSSemPend()

OSTaskSuspend(),OSTimeDly()7879任务的状态-休眠ll休眠状态(Dormant):任务存在于内存空间中,但内核不可见;可以通过以下函数通知内核,使之变为就绪状态:–OSTaskCreate()或OSTaskCreateExt()l可以通过以下函数返回到休眠状态:–OSTaskDel()7980任务的状态-ISRll中断服务状态(ISR):该任务原来在CPU上运行,后来被中断所打断,由中断服务程序ISR接管了CPU;当中断服务程序运行完毕后,内核要判断是

否有新的、更高优先级的任务就绪,如果有 ,则原有的任务被抢占;如果没有,则原有 的任务重新运行。8081任务的状态-阻塞ll阻塞/等待状态(Waiting):任务由于正在等待某个事件(信号量、邮箱或队列)而被挂起;当任务等待的事件发生时,回到就绪状态。–OSMBoxpost(),OSQPost(),

OSSemPost(),OSTaskResume(), OSTimeDlyResume()或OSTimeTick()8182状态的转换正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把CPU的使用权让给别的任务而使任务进入等待状态。任务在没有被配备任务控制块或被剥夺了任务控制块时的状态叫做任务的睡眠状态

系统为任务配备了任务控制块且在任务就绪表中进行了就绪登记,这时任务的状态叫做就绪状态。

处于就绪状态的任务如果经调度器判断获得了CPU的使用权,则任务就进入运行状态

一个正在运行的任务一旦响应中断申请就会中止运行而去执行中断服务程序,这时任务的状态叫做中断服务状态

83状态的转换83删除任务创建任务挂起时间到收到等待的消息等待消息挂起中断结束任务调度删除任务自我删除84状态的转换84OSTaskDel()OSTaskCreate()OSTaskCreateExt()OSIntExitOSStart()OSIntExit()OSTASKSW()OSTaskDel()OSTaskDel()OSMBoxPost()OSQPost()OSQPostFront()OSSemPost()OSTaskResume()OSTaskDlyResume()OSTimeTick()OSMBoxPend()OSQPend()OSSemPend()OSTaskSuspend()OSTaskDly()OSTimeDlyHMSM()中断85任务就绪表ll每个任务的就绪态标志存放在就绪表中,就绪表中有两个变量OSRdyGrp和OSRdyTbl[]。在OSRdyGrp中,任务按优先级分组,8个任

务为一组。OSRdyGrp中的每一位表示8组任 务中每一组中是否有进入就绪态的任务。 任务进入就绪态时,就绪表OSRdyTbl[]中 的相应元素的相应位也置位。8586任务就绪表

OSRdyGrp7

6

5

4

3

2

1

000YYYXXX任务优先级

21018

0 816

1 917

71523

61422

51321

41220

3111926344250582432404856253341495731394755633038465462293745536128364452602735435159[0][1][2][3][4][5][6][7]OSRdyTbl[8]

XY优先级最低任务(空闲任务)优先级最高任务任务优先级号

对于整数OSRdyTbl[i],若它的某一位为1,则OSRdyGrp的第i位为1。 任务的优先级由X和Y确定

86为加快访问任务就绪表的速度,系统定义了一个变量OSRdyGrp来表明就绪表每行中是否存在就绪任务。87根据优先级确定就绪表(1)n假设优先级为12的任务进入就绪状态,12=1100b,则OSRdyTbl[1]的第4位置1,且OSRdyGrp的第1位置1,相应的数学表达式为:OSRdyGrp

|=0x02;OSRdyTbl[1]|=0x10;87881

OSRdyTbl[]1OSRdyGrp

D7D6D5D4D3D2D1D0

任务就绪表的示意图01234567xy0123456789根据优先级确定就绪表(2)n由以上计算可知:若要将OSRdyGrp及OSRdyBbl[]

的第n位置1,则应该把OSRdyGrp及OSRdyBbl[]

的值与2n相或。uC/OS中,把2n的n=0-7的8个 值先计算好存在数组OSMapTbl[7]中,也就是:

OSMapTbl[0]=20=0x01(00000001)

OSMapTbl[1]=21=0x02(00000010)

……

OSMapTbl[7]=27=0x80(10000000)8990使任务进入就绪态n如果prio是任务的优先级,即任务的标识号,则将任务放入就绪表,即使任务进入就绪态的方法是:OSRdyGrp|=OSMapTbl[prio>>3];OSRdyTbl[prio>>3]|=OSMapTbl[prio&0x07];n假设优先级为29——11101bOSRdyGrpOSRdyTbl[3]|=OSMapTbl[29>>3](0x04);|=0x20;9091OSRdyGrp

D7D6D5D4D3D2D1D0

11110000prio=29D7D6D5D4D3D2D1D0

1D7D6D5D4D3D2D1D0

1OSRdyTbl[3]把prio为29的任务置为就绪状态YXOSRdyGrp|=OSMapTbl[prio>>3];OSRdyTbl[prio>>3]|=OSMapTbl[prio&0x07];使任务进入就绪态92使任务脱离就绪态n将任务就绪表OSRdyTbl[prio>>3]相应元素的相应

位清零,而且当OSRdyTbl[prio>>3]中的所有位都 为零时,即该任务所在组的所有任务中没有一个 进入就绪态时,OSRdyGrp的相应位才为零。

if((OSRdyTbl[prio>>3]&=

∼OSMapTbl[prio&0x07])==0) OSRdyGrp&=∼OSMapTbl[prio>>3];9293

OSRdyTbl[8]

OSRdyGrp

D7D6D5D4D3D2D1D0

01234567xy01234567当要把任务优先级为34的任务加入到任务就绪表中时,要进行以下操作:1.将任务优先级号34>>8,确定任务在就续表中的行42.将任务优先级号34%8,确定任务在就续表中的列2,将此位置1113.再将任务组管理单元位置194任务的调度lllµC/OS是可抢占实时多任务内核,它总是运行就绪任务中优先级最高的那一个。µC/OS中不支持时间片轮转法,每个任务的优先级要求不一样且是唯一的,所以任务调度的工作就是:查找准备就绪的最高优先级的任务并进行任务调度。µC/OS任务调度所花的时间为常数,与应用程

序中建立的任务数无关。

9495l确定哪个任务的优先级最高,应该选择哪个任务去运行,这部分的工作是由调度器(Scheduler)来完成的。ww任务级的调度是由函数OSSched()完成的;中断级的调度是由另一个函数OSIntExt()完成的。95任务的调度96根据就绪表确定最高优先级9697根据就绪表确定最高优先级97intRdyTask(){ inti,j,k=0; for(i=0;i<8;i++) { for(j=0;j<8;j++) { if(ODRdyTbl[i]&(1<<j))//判断是否就绪

returnk;//返回就绪任务优先级(任务ID) k++;} } return-1;//无就绪任务}此程序的缺陷?98

根据就绪表确定最高优先级两个关键:ll将优先级数分解为高三位和低三位分别确定;高优先级对应的优先级编号值小;9899根据就绪表确定最高优先级ll通过OSRdyGrp值确定高3位,假设OSRdyGrp=0x08=0x00001000,第3位为1,因此优先级的高3位为011([3]);通过OSRdyTbl[3]的值来确定低3位,假设OSRdyTbl[3]

=0x3a,第2位为1,因此优先级的低3位为010,3*8+2=2699如何确定一个字节中第一个为1的位序号?此位在OSRdyTbl[3]中的位编号为1,而在整个OSRdyTbl表中的总编号为26.任务优先级=26

00011

010100根据就绪表确定最高优先级100为了加快处理速度,uC/OS-II采用查表法,来获得计算优先级的数据,为此定义了优先级参数表:INT8UconstOSUnMapTbl[]={0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};OSUnMapTbl中存放了一个字节中第一个位为1的位序号(0~7).如:值10010100B(十进制为148)中的第二位为1,在OSUnMapTbl中找到148位置的值,为2.101源代码中使用了查表法n查表法具有确定的时间,增加了系统的可预测性,uC/OS中所有的系统调用时间都是确定的参见OS_CORE.C

Y=OSUnMapTbl[OSRdyGrp]; X=OSUnMapTbl[OSRdyTbl[Y]]; Prio=(Y<<3)+X;

101102INT8UconstOSUnMapTbl[]={0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};举例:如OSRdyGrp的值为00101000B,即0X28,则查得OSUnMapTbl[OSRdyGrp]的值是3,它相应于OSRdyGrp中的第3位置1;如OSRdyTbl[3]的值是11100100B,即0XE4,则查OSUnMapTbl[OSRdyTbl[3]]的值是2,则进入就绪态的最高任务优先级

Prio=3*8+2=26

优先级判定表OSUnMapTbl[256]103

任务调度器voidOSSched(void){INT8

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论