uCOS-II学习笔记(一)

本文档详细介绍了uCOS-II操作系统的使用,包括安装、数据类型定义、全局变量处理、中断管理、基于PC的服务等多个方面。通过示例代码解析了如何在Borland C/C++环境下使用和移植uCOS-II,强调了代码的可移植性和任务管理。内容涵盖了任务建立、堆栈检查、中断处理、时间测量以及多任务的交互,旨在帮助读者快速理解和应用uCOS-II。
摘要由CSDN通过智能技术生成

                                                              第一章:范例

  在这一章里将提供三个范例来说明如何使用 µC/OS-II。这一章是为了让读者尽快开始使用 µC/OS-II。

1.00 安装µC/OS-II

1.01 INCLUDES.H

#include "includes.h"

     INCLUDE.H可以使用户不必在工程项目中每个*.C文件中都考虑需要什么样的头文件。换句话说,INCLUDE.H是主头文件。这样做唯一的缺点是INCLUDES.H中许多头文件在一些*.C文件的编译中是不需要的。这意味着逐个编译这些文件要花费额外的时间。这虽有些不便,但代码的可移植性却增加了。本书中所有的例子使用一个共同的头文件INCLUDES.H,3个副本分别存放在\SOFTWARE\uCOS-II\EX1_x86L,\SOFTWARE\uCOS-II\EX2_x86L,以及\SOFTWARE\uCOS-II\EX3_x86L 中。当然可以重新编辑INCLUDES.H以添加用户自己的头文件。

1.02不依赖于编译的数据类型

因为不同的微处理器有不同的字长,µC/OS-II的移植文件包括很多类型定义以确保可移植性(参见\SOFTWARE\uCOS-II\Ix86L\OS_CPU.H,它是针对80x86的实模式,在大模式下编译)。µCOS-II不使用C语言中的short,int,long等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性。笔者代之以移植性强的整数数据类型,这样,既直观又可移植,如表L1.1所示。为了方便起见,还定义了浮点数数据类型,虽然µC/OS-II中没有使用浮点数。

程序清单 L1.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;

Typedef 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/OS-II用到哪里,都会当作INT16U处理。 表1.1是以Borland C/C++编译器为例,为80x86提供的定义语句。为了和µC/OS兼容,还定义了BYTE,WORD,LONG以及相应的无符号变量。这使得用户可以不作任何修改就能将µC/OS的代码移植到µC/OS-II中。之所以这样做是因为笔者觉得这种新的数据类型定义有更多的灵活性,也更加易读易懂。对一些人来说,WORD意味着32位数,而此处却意味着16位数。这些新的数据类型应该能够消除此类含混不请

1.03全局变量

以下是如何定义全局变量。众所周知,全局变量应该是得到内存分配且可以被其他模块通过C语言中extern关键字调用的变量。因此,必须在 .C 和 .H 文件中定义。这种重复的定义很容易导致错误。以下讨论的方法只需用在头文件中定义一次。虽然有点不易懂,但用户一旦掌握,使用起来却很灵活。表1.2中的定义出现在定义所有全局变量的.H头文件中。

程序清单 L 1.2定义全局宏。

#ifdef xxx_GLOBALS

#define xxx_EXT

#else

#define xxx_EXT extern

#endif

.H 文件中每个全局变量都加上了xxx_EXT的前缀。xxx代表模块的名字。该模块的.C文件中有以下定义:

#define 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

#endif

OS_EXT INT32U OSIdleCtr;

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被定义为extern。

extern INT32U OSIdleCtr;

extern INT32U OSIdleCtrRun;

extern INT32U OSIdleCtrMax;

在这种情况下,不产生内存分配,而任何 .C文件都可以使用这些变量。这样的就只需在 .H 文件中定义一次就可以了。

1.04OS_ENTER_CRITICAL() 和

OS_EXIT_CRITICAL()

用户会看到,调用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()两个宏,贯穿本书的所有源代码。OS_ENTER_CRITICAL() 关中断;而OS_EXIT_CRITICAL()开中断。关中断和开中断是为了保护临界段代码。这些代码很显然与处理器有关。关于宏的定义可以在OS_CPU.H中找到。9.03.02节详细讨论定义这些宏的两种方法。

程序清单 L 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_CRITICAL_METHOD == 2

#define OS_ENTER_CRITICAL() asm {PUSHF; CLI}

#define OS_EXIT_CRITICAL() asm POPF

#endif

用户的应用代码可以使用这两个宏来开中断和关中断。很明显,关中断会影响中断延迟,所以要特别小心。用户还可以用信号量来保护林阶段代码。

1.05基于PC的服务

PC.C 文件和 PC.H 文件(在\SOFTWARE\BLOCKS\PC\SOURCE目录下)是笔者在范例中使用到的一些基于PC的服务程序。与µC/OS-II 以前的版本(即µC/OS)不同,笔者希望集中这些函数以避免在各个例子中都重复定义,也更容易适应不同的编译器。PC.C包括字符显示,时间度量和其他各种服务。所有的函数都以PC_为前缀。

1.05.01字符显示

为了性能更好,显示函数直接向显示内存区中写数据。在VGA显示器中,显示内存从绝对地址0x000B8000开始(或用段、偏移量表示则为B800:0000)。在单色显示器中,用户可以把#define constant DISP_BASE从0xB800改为0xB000。

PC.C中的显示函数用x和y坐标来直接向显示内存中写ASCII字符。PC的显示可以达到25行80列一共2,000个字符。每个字符需要两个字节来显示。第一个字节是用户想要显示的字符,第二个字节用来确定前景色和背景色。前景色用低四位来表示,背景色用第4位到6位来表示。最高位表示这个字符是否闪烁,(1)表示闪烁,(0)表示不闪烁。用PC.H中 #defien constants定义前景和背景色,PC.C包括以下四个函数:

PC_DispClrScr() Clear the screen

PC_DispClrLine() Clear a single row (or line)

PC_DispChar() Display a single ASCII character anywhere on the screen

PC_DispStr() Display an ASCII string anywhere on the screen

1.05.02花费时间的测量

时间测量函数主要用于测试一个函数的运行花了多少时间。测量时间是用PC的82C54定时器2。被测的程序代码是放在函数PC_ElapsedStart()和PC_ElapsedStop()之间来测量的。在用这两个函数之前,应该调用PC_ElapsedInit()来初始化,它主要是计算运行这两个函数本身所附加的的时间。这样,PC_ElapsedStop()函数中返回的数值就是准确的测量结果了。注意,这两个函数都不具备可重入性,所以,必须小心,不要有多个任务同时调用这两个函数。表1.4说明了如何测量PC_DisplayChar()的执行时间。注意,时间是以uS为单位的。

程序清单 L 1.4测量代码执行时间。

INT16U time;

PC_ElapsedInit();

.

.

PC_ElapsedStart();

PC_DispChar(40, 24, ‘A’, DISP_FGND_WHITE);

time = PC_ElapsedStop();

1.05.03其他函数

µC/OS-II的应用程序和其他DOS应用程序是一样的,换句话说,用户可以像在DOS下编译其他单线程的程序一样编译和链接用户程序。所生成的.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++编译库提供这些函数,多数其它的编译程序也应有这类函数。

应该注意到无论是应用程序的错误还是只调用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() 函数检查是否有按键被按下。如果有按键被按下,函数返回其值。这个函数使用了Borland 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()函数将会每11个时钟节拍调用一次DOS中的时钟节拍处理,这是为了保证在DOS下时钟的准确性。如果用户希望将时钟节拍的速度设置为20HZ,就必须这样做。在返回DOS以前,要调用PC_SetTickRate(),并设置18为目标频率,PC_SetTickRate()就会知道用户要设置为18.2Hz,并且会正确设置82C54。

PC.C中最后两个函数是得到和设置中断向量,笔者是用Borland C/C++中的库函数来完成的,但是PC_VectGet()和PC_VectSet()很容易改写,以适用于其它编译器。

1.06 应用µC/OS-II 的范例

本章中的例子都用Borland C/C++编译器编译通过,是在Windows95 的DOS窗口下编译的。可执行代码可以在每个范例的OBJ子目录下找到。实际上这些代码是在Borland IDE (Integrated Development Environment)下编译的,编译时的选项如表1.1所示:

T1.1 IDE中编译选项。

Code generation

Model

: Large

Options

: Treatenums asints

AssumeSSEqualsDS

: Default for memory model

Advanced code generation

Floating point

: Emulation

Instruction set

: 80186

Options

: Generate underbars

Debug info in OBJs

F

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值