嵌入式实时操作系统uCOS-II(高清).pdf
《嵌入式实时操作系统uCOS-II(高清).pdf》由会员分享,可在线阅读,更多相关《嵌入式实时操作系统uCOS-II(高清).pdf(345页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第一章:范例第一章:范例在这一章里将提供三个范例来说明如何使用C/OS-II。笔者之所以在本书一开始就写这一章是为了让读者尽快开始使用C/OS-II。在开始讲述这些例子之前,笔者想先说明一些在这本书里的约定。这些例子曾经用 Borland C/C+ 编译器(V3.1)编译过,用选择项产生Intel/AMD80186处理器(大模式下编译)的代码。这些代码实际上是在 Intel Pentium II PC (300MHz)上运行和测试过,Intel Pentium II PC 可以看成是特别快的 80186。笔者选择 PC 做为目标系统是由于以下几个原因:首先也是最为重要的,以 PC 做为目标系统
2、比起以其他嵌入式环境,如评估板,仿真器等,更容易进行代码的测试,不用不断地烧写 EPROM,不断地向 EPROM 仿真器中下载程序等等。用户只需要简单地编译、链接和执行。其次,使用 Borland C/C+产生的 80186 的目标代码(实模式,在大模式下编译)与所有 Intel、AMD、Cyrix 公司的 80 x86CPU 兼容。1.00 安装1.00 安装C/OS-IIC/OS-II本书附带一张软盘包括了所有我们讨论的源代码。是假定读者在80 x86,Pentium,或者Pentium-II 处理器上运行 DOS 或 Windows95。至少需要 5Mb 硬盘空间来安装 uC/OS-II
3、。请按照以下步骤安装:1.进入到 DOS(或在 Windows 95 下打开 DOS 窗口)并且指定 C:为默认驱动器。2.将磁盘插入到 A:驱动器。3.键入 A:INSTALL 【drive】注意drive是读者想要将 C/OSII 安装的目标磁盘的盘符。INSTALL.BAT 是一个 DOS 的批处理文件,位于磁盘的根目录下。它会自动在读者指定的目标驱动器中建立SOFTWARE 目录并且将 uCOS-II.EXE 文件从 A: 驱动器复制到SOFTWARE 并且运行。 C/OSII 将在SOFTWARE 目录下添加所有的目录和文件。完成之后 INSTALL.BAT将删除 uCOS-II.E
4、XE 并且将目录改为SOFTWAREuCOS-IIEX1_x86L,第一个例子就存放在这里。在安装之前请一定阅读一下 READ.ME 文件。当 INSTALL.BAT 已经完成时,用户的目标目录下应该有一下子目录:zSOFTWARESOFTWARE这是根目录,是所有软件相关的文件都放在这个目录下。zSOFTWAREBLOCKSSOFTWAREBLOCKS子程序模块目录。笔者将例子中 C/OS-II 用到的与 PC 相关的函数模块编译以后放在这个目录下。zSOFTWAREHPLISTCSOFTWAREHPLISTC这个目录中存放的是与范例 HPLIST 相关的文件 (请看附录 D, HPLIST
5、C 和 TO) 。 HPLIST.C存放在SOFTWAREHPLISTCSOURCE 目录下。DOS下的可执行文件(HPLIST.EXE)存放在SOFTWARETOEXE 中。zSOFTWARETOSOFTWARETO这个目录中存放的是和范例 TO 相关的文件(请看附录 D,HPLISTC 和 TO) 。源文件 TO.C存放在SOFTWARETOSOURCE 中,DOS 下的可执行文件(TO.EXE)存放在SOFTWARETOEXE中。注意TO 需要一个 TO.TBL 文件,它必须放在根目录下。用户可以在SOFTWARETOEXE目录下找到 TO.TBL 文件。如果要运行 TO.EXE,必须将
6、 TO.TBL 复制到根目录下。zSOFTWAREuCOS-IISOFTWAREuCOS-II与 C/OS-II 相关的文件都放在这个目录下。zSOFTWAREuCOS-IIEX1_x86LSOFTWAREuCOS-IIEX1_x86L这个目录里包括例 1 的源代码(参见 1.07, 例 1),可以在 DOS(或 Windows 95 下的 DOS窗口)下运行。zSOFTWAREuCOS-IIEX2_x86LSOFTWAREuCOS-IIEX2_x86L这个目录里包括例 2 的源代码(参见 1.08, 例 2),可以在 DOS(或 Windows 95 下的 DOS窗口)下运行。zSOFTWA
7、REuCOS-IIEX3_x86LSOFTWAREuCOS-IIEX3_x86L这个目录里包括例 3 的源代码(参见 1.09, 例 3),可以在 DOS(或 Windows 95 下的 DOS窗口)下运行。zSOFTWAREuCOS-IIIx86LSOFTWAREuCOS-IIIx86L这个目录下包括依赖于处理器类型的代码。此时是为在 80 x86 处理器上运行 uC/OS-II而必须的一些代码,实模式,在大模式下编译。zSOFTWAREuCOS-IISOURCESOFTWAREuCOS-IISOURCE这个目录里包括与处理器类型无关的源代码。这些代码完全可移植到其它架构的处理器上。1.01
8、 INCLUDES.H1.01 INCLUDES.HINCLUDE.H 可以使用户不必在工程项目中每个*.C 文件中都考虑需要什么样的头文件。 换句话说,INCLUDE.H 是主头文件。这样做唯一的缺点是 INCLUDES.H 中许多头文件在一些*.C文件的编译中是不需要的。这意味着逐个编译这些文件要花费额外的时间。这虽有些不便,但代码的可移植性却增加了。本书中所有的例子使用一个共同的头文件 INCLUDES.H,3 个副本 分 别 存 放 在 SOFTWAREuCOS-IIEX1_x86L , SOFTWAREuCOS-IIEX2_x86L , 以 及SOFTWAREuCOS-IIEX3_x
9、86L 中。 当然可以重新编辑 INCLUDES.H 以添加用户自己的头文件。用户将注意到本书中所有的 *.C 文件都包括了以下定义:#include includes.h1.021.02不依赖于编译的数据类型不依赖于编译的数据类型因为不同的微处理器有不同的字长, C/OS-II 的移植文件包括很多类型定义以确保可移植性(参见SOFTWAREuCOS-IIIx86LOS_CPU.H,它是针对 80 x86 的实模式,在大模式下编译) 。 COS-II 不使用 C 语言中的 short,int,long 等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性。笔者代之以移植性强的整数数据类
10、型,这样,既直观又可移植,如表 L1.1 所示。为了方便起见,还定义了浮点数数据类型,虽然 C/OS-II 中没有使用浮点数。程序清单 L程序清单 L1.11.1 可移植型数据类型。可移植型数据类型。Typedef unsigned char BOOLEAN;Typedef unsigned char INT8U;Typedef signed char INT8S;Typedef unsigned int INT16U;Typedef signed int INT16S;Typedef unsigned long INT32U;Typedef signed long INT32S;Typede
11、f float FP32;Typedef double FP64;#define BYTE INT8S#define UBYTE INT8U#define WORD INT16S#define UWORD INT16U#define LONG INT32S#define ULONG INT32U以 INT16U 数据类型为例,它代表 16 位无符号整数数据类型。 C/OS-II 和用户的应用代码可以定义这种类型的数据,范围从 0 到 65,535。如果将 CO/S-II 移植到 32 位处理器中,那就意味着 INT16U 不再不是一个无符号整型数据, 而是一个无符号短整型数据。 然而将无论C/
12、OS-II 用到哪里, 都会当作 INT16U 处理。 表 1.1 是以 Borland C/C+编译器为例, 为 80 x86提供的定义语句。为了和 C/OS 兼容,还定义了BYTE,WORD,LONG 以及相应的无符号变量。这使得用户可以不作任何修改就能将 C/OS 的代码移植到 C/OS-II 中。之所以这样做是因为笔者觉得这种新的数据类型定义有更多的灵活性,也更加易读易懂。对一些人来说,WORD意味着 32 位数,而此处却意味着 16 位数。这些新的数据类型应该能够消除此类含混不请1.031.03 全局变量全局变量以下是如何定义全局变量。众所周知,全局变量应该是得到内存分配且可以被其他
13、模块通过 C 语言中 extern 关键字调用的变量。因此,必须在 .C 和 .H 文件中定义。这种重复的定义很容易导致错误。 以下讨论的方法只需用在头文件中定义一次。 虽然有点不易懂,但用户一旦掌握,使用起来却很灵活。表 1.2 中的定义出现在定义所有全局变量的.H 头文件中。程序清单 L程序清单 L 1.2 1.2定义全局宏。定义全局宏。#ifdef xxx_GLOBALS#define xxx_EXT#else#define xxx_EXT extern#endif.H 文件中每个全局变量都加上了 xxx_EXT 的前缀。 xxx 代表模块的名字。 该模块的.C 文件中有以下定义:#de
14、fine xxx_GLOBALS#include includes.h当编译器处理.C文件时, 它强制xxx_EXT (在相应.H文件中可以找到) 为空,(因为xxx_GLOBALS已经定义) 。所以编译器给每个全局变量分配内存空间,而当编译器处理其他.C文件时,xxx_GLOBAL 没有定义,xxx_EXT被定义为 extern,这样用户就可以调用外部全局变量。为了说明这个概念,可以参见 uC/OS_II.H,其中包括以下定义:#ifdef OS_GLOBALS#define OS_EXT#else#define OS_EXT extern#endifOS_EXT INT32U OSIdle
15、Ctr;OS_EXT INT32U OSIdleCtrRun;OS_EXT INT32U OSIdleCtrMax;同时,uCOS_II.H 有中以下定义:#define OS_GLOBALS#include “includes.h”当编译器处理 uCOS_II.C 时,它使得头文件变成如下所示,因为 OS_EXT 被设置为空。INT32U OSIdleCtr;INT32U OSIdleCtrRun;INT32U OSIdleCtrMax;这样编译器就会将这些全局变量分配在内存中。当编译器处理其他.C 文件时,头文件变成了如下的样子,因为 OS_GLOBAL 没有定义,所以 OS_EXT 被定
16、义为 extern。extern INT32U OSIdleCtr;extern INT32U OSIdleCtrRun;extern INT32U OSIdleCtrMax;在这种情况下,不产生内存分配,而任何 .C文件都可以使用这些变量。这样的就只需在 .H文件中定义一次就可以了。1.041.04OS_ENTER_CRITICAL() 和OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL()OS_EXIT_CRITICAL()用户会看到,调用 OS_ENTER_CRITICAL()和 OS_EXIT_CRITICAL()两个宏,贯穿本书的所有源代码。OS_ENTER
17、_CRITICAL() 关中断;而OS_EXIT_CRITICAL()开中断。关中断和开中断是为了保护临界段代码。 这些代码很显然与处理器有关。 关于宏的定义可以在 OS_CPU.H 中找到。9.03.02 节详细讨论定义这些宏的两种方法。程序清单 L程序清单 L 1.3 1.3进入正确部分的宏。进入正确部分的宏。#define OS_CRITICAL_METHOD 2#if OS_CRITICAL_METHOD = 1#define OS_ENTER_CRITICAL() asm CLI#define OS_EXIT_CRITICAL() asm STI#endif#if OS_CRITIC
18、AL_METHOD = 2#define OS_ENTER_CRITICAL() asm PUSHF; CLI#define OS_EXIT_CRITICAL() asm POPF#endif用户的应用代码可以使用这两个宏来开中断和关中断。 很明显, 关中断会影响中断延迟,所以要特别小心。用户还可以用信号量来保护林阶段代码。1.051.05基于基于PCPC的服务的服务PC.C 文件和 PC.H 文件(在SOFTWAREBLOCKSPCSOURCE 目录下)是笔者在范例中使用到的一些基于 PC 的服务程序。与C/OS-II 以前的版本(即C/OS)不同,笔者希望集中这些函数以避免在各个例子中都重
19、复定义,也更容易适应不同的编译器。PC.C 包括字符显示,时间度量和其他各种服务。所有的函数都以 PC_为前缀。1.05.011.05.01字符显示字符显示为了性能更好,显示函数直接向显示内存区中写数据。在VGA显示器中,显示内存从绝对地址 0 x000B8000 开始(或用段、偏移量表示则为B800:0000) 。在单色显示器中,用户可以把#define constant DISP_BASE从 0 xB800 改为 0 xB000。PC.C 中的显示函数用 x 和 y 坐标来直接向显示内存中写 ASCII 字符。 PC 的显示可以达到25 行 80 列一共 2,000 个字符。每个字符需要两
20、个字节来显示。第一个字节是用户想要显示的字符,第二个字节用来确定前景色和背景色。前景色用低四位来表示,背景色用第 4 位到6 位来表示。最高位表示这个字符是否闪烁, (1)表示闪烁, (0)表示不闪烁。 用 PC.H 中#defien constants 定义前景和背景色,PC.C 包括以下四个函数:PC_DispClrScr()Clear the screenPC_DispClrLine()Clear a single row (or line)PC_DispChar()Display a single ASCII character anywhere on the screenPC_Dis
21、pStr()Display an ASCII string anywhere on the screen1.05.021.05.02 花费时间的测量花费时间的测量时间测量函数主要用于测试一个函数的运行花了多少时间。测量时间是用 PC 的 82C54定时器 2。 被测的程序代码是放在函数 PC_ElapsedStart()和 PC_ElapsedStop()之间来测量的。在用这两个函数之前,应该调用PC_ElapsedInit()来初始化,它主要是计算运行这两个函数本身所附加的的时间。这样,PC_ElapsedStop()函数中返回的数值就是准确的测量结果了。注意,这两个函数都不具备可重入性,所
22、以,必须小心,不要有多个任务同时调用这两个函数。表 1.4 说明了如何测量 PC_DisplayChar()的执行时间。注意,时间是以 uS 为单位的。程序清单 L程序清单 L 1.4 1.4测量代码执行时间。测量代码执行时间。INT16U time;PC_ElapsedInit();.PC_ElapsedStart();PC_DispChar(40, 24, A, DISP_FGND_WHITE);time = PC_ElapsedStop();1.05.031.05.03 其他函数其他函数C/OS-II 的应用程序和其他 DOS 应用程序是一样的,换句话说,用户可以像在 DOS 下编译其他
23、单线程的程序一样编译和链接用户程序。 所生成的.EXE程序可以在DOS下装载和运行,当然应用程序应该从 main()函数开始。因为 C/OS-II 是多任务,而且为每个任务开辟一个堆栈,所以单线程的DOS 环境应该保存,在退出C/OS-II 程序时返回到DOS。调用PC_DOSSaveReturn()可以保存当前 DOS 环境, 而调用 PC_DOSReturn()可以返回到 DOS。 PC.C中使用 ANSI C 的 setjmp(),longjmp()函数来分别保存和恢复 DOS 环境。Borland C/C+编译库提供这些函数,多数其它的编译程序也应有这类函数。应该注意到无论是应用程序的
24、错误还是只调用 exit(0)而没有调用 PC_DOSReturn()函数都会使 DOS 环境被破坏,从而导致 DOS 或 WINDOWS95 下的 DOS 窗口崩溃。调用 PC_GetDateTime()函数可得到 PC 中的日期和时间, 并且以 SACII 字符串形式返回。格式是MM-DD-YY HH:MM:SS, 用户需要19个字符来存放这些数据。 该函数使用了Borland C/C+的 gettime()和 getdate()函数,其它 DOS 环境下的 C 编译应该也有类似函数。PC_GetKey() 函数检查是否有按键被按下。如果有按键被按下,函数返回其值。这个函数使用了 Borl
25、and C/C+的 kbhit()和 getch()函数,其它 DOS 环境下的 C 编译应该也有类似函数。函数 PC_SetTickRate()允许用户为C /OS-II 定义频率,以改变钟节拍的速率。在DOS下,每秒产生 18.20648 次时钟节拍,或每隔 54.925ms 一次。这是因为 82C54 定时器芯片没有初始化,而使用默认值 65,535 的结果。如果初始化为 58,659,那么时钟节拍的速率就会精确地为20.000Hz。笔者决定将时钟节拍设得更快一些,用的是200Hz(实际是上是199.9966Hz)。注意 OS_CPU_A.ASM 中的 OSTickISR()函数将会每
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式 实时 操作系统 uCOS II
限制150内