OS或者编译器怎么识别是js 全局变量 局部变量还是局部变量

sponsored links
变量的属性全局变量、局部变量、动态变量、静态变量等
变量的属性&
1、变量的分类
l&&&&&&&&&根据作用域:可分为全局变量和局部变量。
l&&&&&&&&&& 根据生存周期:可分为静态存储方式和动态存储方式,具体地又分为自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)。
静态存储方式是指在程序运行期间分配固定的存储空间的方式,动态存储方式是在程序运行期间根据需要进行动态的分配存储空间的方式。
2、变量的作用域和存储类别的关系
每一个变量均有作用域和存储类别两个属性,这些属性共同用于描述一个变量,这些不同类型的变量与存储位置的关系如下:
l&&&&&&&&& 外部变量(全局变量)、静态外部变量、静态局部变量存储在静态存储区。
l&&&&&&&&& 自动局部变量(局部变量默认为自动局部变量)、函数形参存储在动态存储区(即栈区)。
l&&&&&&&&& 不论是静态存储区还是动态存储区均属于内存中的用户区。
l&&&&&&&&& 而寄存器变量是存储在CPU寄存器中的而不是内存中。
3、与作用域相关的几个属性:
l&&&&&&&&& 局部变量:在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的,这种类型的变量就称为“局部变量”。
l&&&&&&&&& 全局变量:在函数外定义的变量,可以为本源文件中其它函数所公用,有效范围为从定义变量的位置开始到本源文件结束,这种类型的变量就称为“全局变量”。
4、与存储类型相关的几个属性:
l&&&&&&&&& atuo:在声明局部变量时,若不指定 static,默认均是 auto,这类变量都是动态分配存储空间的,数据存储在动态存储区中。
l&&&&&&&& static:在声明局部变量时,使用关键字 static
将局部变量指定为“静态局部变量”,这样在函数调用结束后不消失而保留原值,即占用的存储单元不释放,在下一次函数调用时,该变量已有值就是上次函数调用结束时的值。
l&&&&&&&&& register:在声明动态局部变量或者函数形参时,可将变量声明为register,这样编译系统就会为变量分配一个寄存器而不是内存空间,通过这种方式可提升对某些局部变量频繁调用的程序的性能。(寄存器运算速度远高于内存)
l&&&&&&&&& extern:用于扩展全局变量的作用域。
1)&&&&&&&& 比如如果函数想引用一个外部变量,但该外部变量在该函数后定义,那么这个函数需要使用 extern
来声明变量,这样才能使用在该函数后面定义的全局变量。
2)&&&&&&&& 此外,extern
还可以在多文件的程序中声明外部变量。
c++内存到底分几个区? 一:
1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.
2.堆区(heap) - 一般由程序员分配释放, 若程序员不释放,程序结束时可能由os回收 .注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,.
3.全局区(静态区)(static)-,全局变量和 ...
比较全局变量.全局静态变量.局部变量.局部静态变量的区别,他们在编译完后存储位置在什么地方.初始化值在什么地方.内存什么时候分配.赋初值对这些变量有哪些影响等.要弄清楚这些问题,首先要弄清楚下面几个知识点.
C语言分下面几个存储区:
1.栈区(stack) 由编译器在需要的时候自动分配释放,在不需要的时候就自动清除的变量存储区.通常存放的变量 ...
c++内存到底分几个区? 一: 1.栈区(stack)由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap)一般由程序员分配释放(如new,delete), 若程序员没有释放,程序结束时可能由os自动回收 .注意它与数据结构中的堆是两回事,分配方式倒是类似于链表. 3.全局区(静态区.static)全 ...
C语言中变量可以简单的分为如下四种类型: 全局变量,局部变量,静态变量,寄存器变量 全局变量存储在静态数据区: 局部变量存储在动态数据区: 静态变量存储在静态数据区: 全局静态变量存储和局部静态变量都存储在静态数据区.
另: 静态函数和普通函数的区别: 静态函数在内存中维持一份,函数只能被当前文件中的函数调用: 而普通函数 ...
类体由2部分构成:一部分是变量的定义;一部分是方法的定义(一个类中可以有多个方法)在变量定义部分定义的变量叫做类的成员变量,成员变量在整个类中都有效.(全局变量应该是成员变量的俗称)在方法体中定义的变量叫做局部变量,局部变量只在定义它的方法中有效.成员变量又分为实例变量和类变量(static静态变量).class One{ //x为实例变量 ...
术语static有着不寻常的历史.起初,在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量.随后,static在C中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数.为了避免引入新的关键字,所以仍使用static关键字来表示这第二种含义.最后,C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任 ...他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)本帖子已过去太久远了,不再提供回复功能。当前位置:
一个面试题,OS或者编译器怎么识别是全局变量还是局部变量
一个面试题,OS或者编译器怎么识别是全局变量还是局部变量
来源:网络整理&&&&&时间: 10:33:56&&&&&关键词:
关于网友提出的“ 一个面试题,OS或者编译器怎么识别是全局变量还是局部变量”问题疑问,本网通过在网上对“ 一个面试题,OS或者编译器怎么识别是全局变量还是局部变量”有关的相关答案进行了整理,供用户进行参考,详细问题解答如下:
问题: 一个面试题,OS或者编译器怎么识别是全局变量还是局部变量
局部变量和全局变量有什么区别,
操作系统或编译器是如何识别的.解决方案1:
全局变量在&静态存储区中
局部变量在&栈中
解决方案2:引用&9&楼&bluesky&的回复:问:
局部变量和全局变量有什么区别,
============================
1.生存周期不同
2.作用域不同
3.编译器会保证全局变量的初始化,局部变量不作保证
操作系统或编译器是如何识别的.
============================
操作系统不识别。
编译器在语义检查的时候识别,具体怎识别,参考《编译原理》
解决方案3:
不是根据位置,编译器通常会建一个符号表,里面描述变量的各属性。语法检查与代码生成的时候访问并回填数据
解决方案4:
另外,操作系统只分静态变量和自动变量,变量作用域是编译器规定的
解决方案5:引用&15&楼&xzlcc&的回复:变量是语言层次上的东西&&方便人控制的
编译器根据变量定义位置确定是全局&&还是局部
全局变量的数据&&编译器会分配在堆(heap)上
局部变量的数据&&则是运行时在栈(stack)上创建
操作系统负责按照编译器事先分配的地址把程序加载到内存
全局变量怎么会分配在堆上??!!
全局变量与局部静态变量存放位置相同,都放在静态存储区。初始化过的变量存放在静态初始化区,编译时编译器会初始化这部分区域的值;未初始化或初始化为0的变量存放在静态非初始化区。
解决方案6:引用&13&楼&skyworth98&的回复:引用&6&楼&luciferisnotsatan&的回复:
操作系统也需要识别全局变量??
sp........
这个,关操作系统啥事儿?
操作系统加载可执行文件,为全局变量分配了一个特定的内存区域,全局变量程序运行期间内有效。而局部变量总是在每次函数调用期间从堆栈上分配,函数返回后失效。
解决方案7:
变量是语言层次上的东西&&方便人控制的
编译器根据变量定义位置确定是全局&&还是局部
全局变量的数据&&编译器会分配在堆(heap)上
局部变量的数据&&则是运行时在栈(stack)上创建
操作系统负责按照编译器事先分配的地址把程序加载到内存
解决方案8:
操作系统还不管你这些问题呢,人家管的是大事好不好
解决方案9:引用&6&楼&luciferisnotsatan&的回复:操作系统也需要识别全局变量??
sp........
这个,关操作系统啥事儿?
解决方案10:
同意引用&9&楼&bluesky&的回复:问:
局部变量和全局变量有什么区别,
============================
1.生存周期不同
2.作用域不同
3.编译器会保证全局变量的初始化,局部变量不作保证
操作系统或编译器是如何识别的.
============================
操作系统不识别。
编译器在语义检查的时候识别,具体怎识别,参考《编译原理》解决方案11:
操作系统也要识别???他知道区!
解决方案12:引用&5&楼&void_wuyu&的回复:操作系统内根本不关心你是什么变量,它只管代理运行程序,也就是进程,负责这些进程之间的调度,不过如果要说操作系统本身也是进程,那倒可以理解;
编译器最终会把程序编译成可执行文件,就是对应的一条一条汇编指令,在程序运行过程中按照定义,就可以有不同的寻址方式,这个就是汇编的内容了,其实不同类型的变量就是寻址方式的不同,说到底还是存储位置不同。
解决方案13:
操作系统内根本不关心你是什么变量,它只管代理运行程序,也就是进程,负责这些进程之间的调度,不过如果要说操作系统本身也是进程,那倒可以理解;
编译器最终会把程序编译成可执行文件,就是对应的一条一条汇编指令,在程序运行过程中按照定义,就可以有不同的寻址方式,这个就是汇编的内容了,其实不同类型的变量就是寻址方式的不同,说到底还是存储位置不同。
解决方案14:
生命周期不一样
就像LS说得,存储的地方不一样
解决方案15:识别是编译器的时,生成目标文件后,目标文件里有数据区,里面会记录类型的,
在链接生成可执行文件时会分配实际内存,根据变量的类型分为堆和栈。解决方案16:
OS根本就不知道变量是什么东东。
解决方案17:
局部变量和全局变量有什么区别,
============================
1.生存周期不同
2.作用域不同
3.编译器会保证全局变量的初始化,局部变量不作保证
操作系统或编译器是如何识别的.
============================
操作系统不识别。
编译器在语义检查的时候识别,具体怎识别,参考《编译原理》解决方案18:引用&4&楼&milkylove&的回复:变量定义的位置决定了它是全局变量还是局部变量。只要是定义在函数体内的变量,就是局部变量。函数体外定义的就是全局变量。
顶解决方案19:
操作系统也需要识别全局变量??
解决方案20:
变量定义的位置决定了它是全局变量还是局部变量。只要是定义在函数体内的变量,就是局部变量。函数体外定义的就是全局变量。
以上介绍了“ 一个面试题,OS或者编译器怎么识别是全局变量还是局部变量”的问题解答,希望对有需要的网友有所帮助。
本文网址链接:http://www.codes51.com/itwd/2768665.html
上一篇: 下一篇:uc-os中文版电子书(带源程序)
在这一章里将提供三个范例来说明如何使用 μC/OS-II。笔者之所以在本书一开始就写这一章是为了让读者尽快开始使用 μC/OS-II。在开始讲述这些例子之前,笔者想先说明一些在这本书里的约定。
在这一章里将提供三个范例来说明如何使用
μ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作为目标系统比起以其他嵌入式环境,如评估板,仿真器等,更容易进行代码的测试,不用不断地烧写EPROM,不断地向EPROM仿真器中下载程序等等。用户只需要简单地编译、链接和执行。其次,使用Borland C/C++产生的80186的目标代码(实模式,在大模式下编译)与所有Intel、AMD、Cyrix公司的80x86 CPU兼容。
<span style="font-size:14.0
color:#.00 安装 μC/OS-II
键入 INSTALL 【drive】
&&& 在安装之前请一定阅读一下READ.ME文件。当INSTALL.BAT已经完成时,用户的目标目录下应该有一下子目录:\SOFTWARE
&&& 这是根目录,是所有软件相关的文件都放在这个目录下。
l\SOFTWARE\BLOCKS
子程序模块目录。
l\SOFTWARE\HPLISTC
&&&&&&&&&&&&& 这个目录中存放的是与范例HPLIST相关的文件(请看附录D,HPLISTC和TO)。HPLIST.C存放在\SOFTWARE\HPLISTC\SOURCE目录下。DOS下的可执行文件(HPLIST.EXE)存放在\SOFTWARE\TO\EXE中。
l\SOFTWARE\TO
&&& 这个目录中存放的是和范例TO相关的文件(请看附录D,HPLISTC和TO)。源文件TO.C存放在\SOFTWARE\TO\SOURCE中,DOS下的可执行文件(TO.EXE)存放在\SOFTWARE\TO\EXE中。注意TO需要一个TO.TBL文件,它必须放在根目录下。用户可以在\SOFTWARE\TO\EXE目录下找到TO.TBL文件。如果要运行TO.EXE,必须将TO.TBL复制到根目录下。
l\SOFTWARE\uCOS-II
与μC/OS-II 相关的文件都放在这个目录下。
l\SOFTWARE\uCOS-II\EX1_x86L
&&& 这个目录里包括例1的源代码(参见 1.07, 例1),可以在DOS(或Windows 95下的DOS窗口)下运行。
l\SOFTWARE\uCOS-II\EX2_x86L
&&& 这个目录里包括例2的源代码(参见 1.08, 例2),可以在DOS(或Windows 95下的DOS窗口)下运行。
l\SOFTWARE\uCOS-II\EX3_x86L
&&& 这个目录里包括例3的源代码(参见 1.09, 例3),可以在DOS(或Windows 95下的DOS窗口)下运行。
l\SOFTWARE\uCOS-II\Ix86L
&&& 这个目录下包括依赖于处理器类型的代码。此时是为在80x86处理器上运行uC/OS-II而必须的一些代码,实模式,在大模式下编译。
l\SOFTWARE\uCOS-II\SOURCE
&&& 目录里包括与处理器类型无关的源代码。这些代码完全可移植到其它架构的处理器上。
<span style="font-size:14.0
color:#.01 INCLUDES.H
&&& 用户将注意到本书中所有的 *.C 文件都包括了以下定义:
#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以添加用户自己的头文件。
<span style="font-size:14.0
color:#.02不依赖于编译的数据类型
&&& 不同的微处理器有不同的字长,μC/OS-II的移植文件包括很多类型定义以确保可移植性(参见\SOFTWARE\uCOS-II\Ix86L\OS_CPU.H,它是针对80x86的实模式,在大模式下编译)。μCOS-II不使用C语言中的short,int,long等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性。笔者代之以移植性强的整数数据类型,这样,既直观又可移植,如表L1.1所示。为了方便起见,还定义了浮点数数据类型,虽然μC/OS-II中没有使用浮点数。
程序清单 L<span style="color:#.1 可移植型数据类型。
Typedef unsigned char&
Typedef unsigned char&
signed&&& char& INT8S;
Typedef unsigned
int&& INT16U;
signed&&& int&& INT16S;
Typedef unsigned long&
signed&&& long& INT32S;
float&&&&&&&&&&& FP32;
double&&&&&&&&&& FP64;
BYTE&&&&&&&&&& INT8S
UBYTE&&&&&&&&& INT8U
WORD&&&&&&&&&& INT16S
UWORD&&&&&&&&& INT16U
LONG&&&&&&&&&& INT32S
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位数。这些新的数据类型应该能够消除此类含混不请
<span style="font-size:14.0color:#.03全局变量
&&& 以下是如何定义全局变量。众所周知,全局变量应该是得到内存分配且可以被其他模块通过C语言中extern关键字调用的变量。因此,必须在 .C 和 .H 文件中定义。这种重复的定义很容易导致错误。以下讨论的方法只需用在头文件中定义一次。虽然有点不易懂,但用户一旦掌握,使用起来却很灵活。表1.2中的定义出现在定义所有全局变量的.H头文件中。
#ifdef&& xxx_GLOBALS
#define& xxx_EXT
#define& xxx_EXT extern
.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,其中包括以下定义:
OS_GLOBALS&&&&&&&&&&&&
//第<span style="color:#行
#define& OS_EXT
#define& OS_EXT extern
OS_EXT& INT32U&&&&&&
OS_EXT& INT32U&&&&&&
OSIdleCtrR
OS_EXT& INT32U&&&&&&
OSIdleCtrM
同时,uCOS_II.C有中以下定义:
#define& OS_GLOBALS
#include “includes.h”
当编译器处理uCOS_II.C时,它使得头文件变成如下所示,因为OS_EXT被设置为空。
INT32U&&&&&& OSIdleC
INT32U&&&&&& OSIdleCtrR
INT32U&&&&&&
OSIdleCtrM
这样编译器就会将这些全局变量分配在内存中。当编译器处理其他.C文件时,头文件变成了如下的样子,因为OS_GLOBAL没有定义,所以OS_EXT被定义为extern。
extern INT32U&&&&&&
extern INT32U&&&&&&
OSIdleCtrR
extern INT32U&&&&&&
OSIdleCtrM
在这种情况下,不产生内存分配,而任何 .C文件都可以使用这些变量。这样的就只需在 .H 文件中定义一次就可以了。
<span style="font-size:14.0
color:#.04 OS_ENTER_CRITICAL() 和 OS_EXIT_CRITICAL()
&&& 用户会看到,调用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()两个宏,贯穿本书的所有源代码。OS_ENTER_CRITICAL()
关中断;而OS_EXIT_CRITICAL()开中断。关中断和开中断是为了保护临界段代码。这些代码很显然与处理器有关。关于宏的定义可以在OS_CPU.H中找到。9.03.02节详细讨论定义这些宏的两种方法。
#define& OS_CRITICAL_METHOD&&& 2
#if&&&&& OS_CRITICAL_METHOD ==
#define& OS_ENTER_CRITICAL()& asm& CLI
#define& OS_EXIT_CRITICAL()&& asm&
#if&&&&& OS_CRITICAL_METHOD ==
#define& OS_ENTER_CRITICAL() &asm {PUSHF;
#define& OS_EXIT_CRITICAL()&& asm&
用户的应用代码可以使用这两个宏来开中断和关中断。很明显,关中断会影响中断延迟,所以要特别小心。用户还可以用信号量来保护林阶段代码。
<span style="font-size:14.0
color:#.05基于PC的服务
文件和 PC.H 文件(在\SOFTWARE\BLOCKS\PC\SOURCE目录下)是笔者在范例中使用到的一些基于PC的服务程序。与 μC/OS-II 以前的版本(即 μC/OS)不同,笔者希望集中这些函数以避免在各个例子中都重复定义,也更容易适应不同的编译器。PC.C包括字符显示,时间度量和其他各种服务。所有的函数都以PC_为前缀。
<span style="font-size:14.0color:#.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
<span style="font-size:14.0color:#.05.02花费时间的测量
&&& 时间测量函数主要用于测试一个函数的运行花了多少时间。测量时间是用PC的82C54定时器2。被测的程序代码是放在函数PC_ElapsedStart()和PC_ElapsedStop()之间来测量的。在用这两个函数之前,应该调用PC_ElapsedInit()来初始化,它主要是计算运行这两个函数本身所附加的的时间。这样,PC_ElapsedStop()函数中返回的数值就是准确的测量结果了。注意,这两个函数都不具备可重入性,所以,必须小心,不要有多个任务同时调用这两个函数。表1.4说明了如何测量PC_DisplayChar()的执行时间。注意,时间是以uS为单位的。
PC_ElapsedInit();
PC_ElapsedStart();
PC_DispChar(40, 24, ‘A’, DISP_FGND_WHITE);
time = PC_ElapsedStop();
<span style="font-size:14.0color:#.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()很容易改写,以适用于其它编译器。
<span style="font-size:14.0color:#.06
应用 μC/OS-II 的范例
本章中的例子都用Borland C/C++编译器编译通过,是在Windows95 的DOS窗口下编译的。可执行代码可以在每个范例的OBJ子目录下找到。实际上这些代码是在Borland IDE (Integrated Development Environment)下编译的,编译时的选项如表1.1所示:
笔者的Borland C/C++编译器安装在C:\CPP目录下,如果用户的编译器是在不同的目录下,可以在Options/Directories的提示下改变IDE的路径。
μC/OS-II是一个可裁剪的操作系统,这意味着用户可以去掉不需要的服务。代码的削减可以通过设置OS_CFG.H中的#defines OS_???_EN 为0来实现。用户不需要的服务代码就不生成。本章的范例就用这种功能,所以每个例子都定义了不同的OS_???_EN。
<span style="font-size:14.0color:#.07例1
第一个范例可以在\SOFTWARE\uCOS_II\EX1_x86L目录下找到,它有13个任务(包括 μC/OS-II 的空闲任务)。μC/OS-II 增加了两个内部任务:空闲任务和一个计算CPU利用率的任务。例1建立了11个其它任务。TaskStart()任务是在函数main()中建立的;它的功能是建立其它任务并且在屏幕上显示如下统计信息:
l每秒钟任务切换次数;
lCPU利用百分率;
l寄存器切换次数;
l目前日期和时间;
lμC/OS-II的版本号;
&TaskStart()还检查是否按下ESC键,以决定是否返回到DOS。
其余10个任务基于相同的代码――Task();每个任务在屏幕上随机的位置显示一个0到9的数字。
<span style="font-size:14.0color:#.07.01 main()
例1基本上和最初中的第一个例子做一样的事,但是笔者整理了其中的代码,并且在屏幕上加了彩色显示。同时笔者使用原来的数据类型(UBYTE, UWORD等)来说明μC/OS-II向下兼容。
main()程序从清整个屏幕开始,为的是保证屏幕上不留有以前的DOS下的显示[L1.5(1)]。注意,笔者定义了白色的字符和黑色的背景色。既然要请屏幕,所以可以只定义背景色而不定义前景色,但是这样在退回DOS之后,用户就什么也看不见了。这也是为什么总要定义一个可见的前景色。
μC/OS-II要用户在使用任何服务之前先调用OSInit() [L1.5(2)]。它会建立两个任务:空闲任务和统计任务,前者在没有其它任务处于就绪态时运行;后者计算CPU的利用率。
void main (void)
&&& PC_DispClrScr(DISP_FGND_WHITE +
DISP_BGND_BLACK);& //Clear the screen(1)
&&& OSInit(); &&&&&&&&
&&&&&&&&&&// Initialize
uC/OS-II&&&&&&&&&&&&&&&&&&&&&&&&
PC_DOSSaveReturn();&&&&&&&& // Save
environment to return to DOS&&&&& (3)
&&& PC_VectSet(uCOS, OSCtxSw);&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& RandomSem = OSSemCreate(1);&&&&&&&&&&&& &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&(5)
&&& OSTaskCreate(TaskStart,&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
(void *)0,
&&&&&&&&&&&&&&&
(void *)&TaskStartStk[TASK_STK_SIZE-1],
&&&&&&&&&&&&&&&
&&& OSStart();&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
当前DOS环境是通过调用PC_DOSSaveReturn()[L1.5(3)]来保存的。这使得用户可以返回到没有运行μC/OS-II以前的DOS环境。跟随清单L1.6中的程序可以看到PC_DOSSaveReturn()做了很多事情。PC_DOSSaveReturn()首先设置PC_ExitFlag为FALSE[L1.6(1)],说明用户不是要返回DOS,然后初始化OSTickDOSCtr为1[L1.6(2)],因为这个变量将在OSTickISR()中递减,而0将使得这个变量在OSTickISR()中减1后变为255。然后,PC_DOSSaveReturn()将DOS 的时钟节拍处理(tick handler)存入一个自由向量表入口中[L1.6(3)-(4)],以便为μC/OS-II的时钟节拍处理所调用。接着PC_DOSSaveReturn()调用jmp()[L1.6(5)],它将处理器状态(即所有寄存器的值)存入被称为PC_JumpBuf的结构之中。保存处理器的全部寄存器使得程序返回到PC_DOSSaveReturn()并且在调用setjmp()之后立即执行。因为PC_ExitFlag被初始化为FALSE[L1.6(1)]。PC_DOSSaveReturn()跳过if状态语句 [L1.6(6)C(9)] 回到main()函数。如果用户想要返回到DOS,可以调用 PC_DOSReturn()(程序清单 L 1.7),它设置PC_ExitFlag为TRUE,并且执行longjmp()语句[L1.7(2)],这时处理器将跳回 PC_DOSSaveReturn()[在调用 setjmp()之后] [L1.6(5)],此时PC_ExitFlag为TRUE,故if语句以后的代码将得以执行。 PC_DOSSaveReturn()将时钟节拍改为 18.2Hz[L1.6(6)],恢复PC 时钟节拍中断服务[L1.6(7)],清屏幕[L1.6(8)],通过exit(0)返回DOS [L1.6(9)]。
void PC_DOSSaveReturn (void)
&&& PC_ExitFlag& = FALSE;&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OSTickDOSCtr
=&&&& 1;&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& PC_TickISR&& =
PC_VectGet(VECT_TICK);&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&
&&& OS_ENTER_CRITICAL();
&&& PC_VectSet(VECT_DOS_CHAIN,
PC_TickISR);&&&&&&&&&& &&&&&&&&&&&&&&&&&&&
&&& OS_EXIT_CRITICAL();
&&& Setjmp(PC_JumpBuf);&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& if (PC_ExitFlag == TRUE) {
OS_ENTER_CRITICAL();
PC_SetTickRate(18);&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
PC_VectSet(VECT_TICK, PC_TickISR);&&&&&&&&&&& &&&&&&&&&&
&&&&&&&&&&(7)
OS_EXIT_CRITICAL();
PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);&&&&&&&&& &&&&&
&&&&&&& exit(0);&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
void PC_DOSReturn (void)
&&& PC_ExitFlag = TRUE;&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& longjmp(PC_JumpBuf, 1);&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
现在回到main()这个函数,在程序清单 L 1.5中,main()调用PC_VectSet()来设置μCOS-II中的 CPU寄存器切换。任务级的CPU寄存器切换由80x86 INT指令来分配向量地址。笔者使用向量0x80(即128),因为它未被DOS和BIOS使用。
这里用了一个信号量来保护Borland C/C++库中的产生随机数的函数[L1.5(5)],之所以使用信号量保护一下,是因为笔者不知道这个函数是否具备可重入性,笔者假设其不具备,初始化将信号量设置为1,意思是在某一时刻只有一个任务可以调用随机数产生函数。
在开始多任务之前,笔者建立了一个叫做TaskStart()的任务[L1.5(6)],在启动多任务OSStart()之前用户至少要先建立一个任务,这一点非常重要[L1.5(7)]。不这样做用户的应用程序将会崩溃。实际上,如果用户要计算CPU的利用率时,也需要先建立一个任务。μCOS-II的统计任务要求在整个一秒钟内没有任何其它任务运行。如果用户在启动多任务之前要建立其它任务,必须保证用户的任务代码监控全局变量OSStatRdy和延时程序 [即调用 OSTimeDly()]的执行,直到这个变量变成TRUE。这表明μC/OS-II的CPU利用率统计函数已经采集到了数据。
<span style="font-size:14.0color:#.07.02 TaskStart()
例1中的主要工作由TaskStart()来完成。TaskStart()函数的示意代码如程序清单 L 1.8所示。TaskStart()首先在屏幕顶端显示一个标识,说明这是例1 [L1.8(1)]。然后关中断,以改变中断向量,让其指向μC/OS-II的时钟节拍处理,而后,改变时钟节拍率,从DOS的 18.2Hz 变为 200Hz
[L1.8(3)]。在处理器改变中断向量时以及系统没有完全初始化前,当然不希望有中断打入!注意main()这个函数(见程序清单 L 1.5)在系统初始化的时候并没有将中断向量设置成μC/OS-II的时钟节拍处理程序,做嵌入式应用时,用户必须在第一个任务中打开时钟节拍中断。
void TaskStart (void *data)
&&& Prevent compiler warning by
assigning ‘data’
&&& Display banner identifying this as
EXAMPLE #1;&&&&&&&&& &&&&&&&&&&&&&
&&& OS_ENTER_CRITICAL();
&&& PC_VectSet(0x08, OSTickISR);&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&
&&& PC_SetTickRate(200);&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OS_EXIT_CRITICAL();
&&& Initialize the statistic task by
calling ‘OSStatInit()’;&&&&&&& &&&
&&& Create 10&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& for (;;) {
&&&&&&& Display the
&&&&&&& Display the
&&&&&&& Display the
number of task switches in 1
&&&&&&& Display
uC/OS-II’s version number
&&&&&&& If (key was
pressed) {
&&&&&&&&&&&
if (key pressed was the ESCAPE key) {
&&&&&&&&&&&&&&&
PC_DOSReturn();
&&&&&&&&&&&
&&&&&&& Delay for 1
在建立其他任务之前,必须调用OSStatInit()[L1.8(4)]来确定用户的PC有多快,如程序清单L1.9所示。在一开始,OSStatInit()就将自身延时了两个时钟节拍,这样它就可以与时钟节拍中断同步[L1.9(1)]。因此,OSStatInit()必须在时钟节拍启动之后调用;否则,用户的应用程序就会崩溃。当μC/OS-II调用OSStatInit()时,一个32位的计数器OSIdleCtr被清为0 [L1.9(2)],并产生另一个延时,这个延时使OSStatInit()挂起。此时,uCOS-II没有别的任务可以执行,它只能执行空闲任务(μC/OS-II的内部任务)。空闲任务是一个无线的循环,它不断的递增OSIdleCtr[L1.9(3)]。1秒以后,uCOS-II重新开始OSStatInit(),并且将OSIdleCtr保存在OSIdleMax中[L1.9(4)。所以OSIdleMax是OSIdleCtr所能达到的最大值。而当用户再增加其他应用代码时,空闲任务就不会占用那样多的CPU时间。OSIdleCtr不可能达到那样多的记数,(如果拥护程序每秒复位一次OSIdleCtr)CPU利用率的计算由μC/OS-II 中的OSStatTask()函数来完成,这个任务每秒执行一次。而当OSStatRdy置为TRUE[L1.9(5)],表示μC/OS-II将统计CPU的利用率。
void OSStatInit (void)
&&& OSTimeDly(2);&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OS_ENTER_CRITICAL();
&&& OSIdleCtr&&& = 0L;&&&&&&&&&&&&&&&&&& &&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(2)
&&& OS_EXIT_CRITICAL();
&&& OSTimeDly(OS_TICKS_PER_SEC);&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&
&&& OS_ENTER_CRITICAL();
&&& OSIdleCtrMax = OSIdleC&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OSStatRdy&&& = TRUE;&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&(5)
&&& OS_EXIT_CRITICAL();
<span style="font-size:14.0color:#.07.03 TaskN()
OSStatInit()将返回到TaskStart()。现在,用户可以建立10个同样的任务(所有任务共享同一段代码)。所有任务都由TaskStart()中建立,由于TaskStart()的优先级为0(最高),新任务建立后不进行任务调度。当所有任务都建立完成后,TaskStart()将进入无限循环之中,在屏幕上显示统计信息,并检测是否有ESC键按下,如果没有按键输入,则延时一秒开始下一次循环;如果在这期间用户按下了ESC键,TaskStart()将调用PC_DOSReturn()返回DOS系统。
程序清单L1.10给出了任务的代码。任务一开始,调用OSSemPend()获取信号量RandomSem [程序清单L1.10(1)](也就是禁止其他任务运行这段代码―译者注),然后调用Borland C/C++的库函数random()来获得一个随机数[程序清单L1.10(2)],此处设random()函数是不可重入的,所以10个任务将轮流获得信号量,并调用该函数。当计算出x和y坐标后[程序清单L1.10(3)],任务释放信号量。随后任务在计算的坐标处显示其任务号(0-9,任务建立时的标识)[程序清单L1.10(4)]。最后,任务延时一个时钟节拍[程序清单L1.10(5)],等待进入下一次循环。系统中每个任务每秒执行200次,10个任务每秒钟将切换2000次。
void Task (void *data)
&&& for (;;) {
OSSemPend(RandomSem, 0, &err);&&&&&&& &&&&&&&&&&&&&&&&
&&&&&&&&&&&&&(1)
&&&&&&& x =
random(80);&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&& y =
random(16);
OSSemPost(RandomSem);&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
PC_DispChar(x, y + 5, *(char *)data, DISP_FGND_LIGHT_GRAY);&&&& (4)
OSTimeDly(1);&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
<span style="font-size:14.0color:#.08 例2
例2使用了带扩展功能的任务建立函数OSTaskCreateExt()和uCOS-II的堆栈检查操作(要使用堆栈检查操作必须用OSTaskCreateExt()建立任务―译者注)。当用户不知道应该给任务分配多少堆栈空间时,堆栈检查功能是很有用的。在这个例子里,先分配足够的堆栈空间给任务,然后用堆栈检查操作看看任务到底需要多少堆栈空间。显然,任务要运行足够长时间,并要考虑各种情况才能得到正确数据。最后决定的堆栈大小还要考虑系统今后的扩展,一般多分配10%,25%或者更多。如果系统对稳定性要求高,则应该多一倍以上。
uCOS-II的堆栈检查功能要求任务建立时堆栈清零。OSTaskCreateExt()可以执行此项操作(设置选项OS_TASK_OPT_STK_CHK和OS_TASK_OPT_STK_CLR打开此项操作)。如果任务运行过程中要进行建立、删除任务的操作,应该设置好上述的选项,确保任务建立后堆栈是清空的。同时要意识到OSTaskCreateExt()进行堆栈清零操作是一项很费时的工作,而且取决于堆栈的大小。执行堆栈检查操作的时候,uCOS-II从栈底向栈顶搜索非0元素(参看图F 1.1),同时用一个计数器记录0元素的个数。
例2的磁盘文件为\SOFTWARE\uCOS-II\EX2_x86L,它包含9个任务。加上uCOS-II本身的两个任务:空闲任务(idle task)和统计任务。与例1一样TaskStart()由main()函数建立,其功能是建立其他任务并在屏幕上显示如下的统计数据:
l每秒种任务切换的次数;
lCPU利用率的百分比;
l当前日期和时间;
luCOS_II的版本号;
<span style="font-size:14.0color:#.08.01 main()
例2的main()函数和例1的看起来差不多(参看程序清单L1.11),但是有两处不同。第一,main()函数调用PC_ElapsedInit()[程序清单L1.11(1)]来初始化定时器记录OSTaskStkChk()的执行时间。第二,所有的任务都使用OSTaskCreateExt()函数来建立任务[程序清单L1.11(2)](替代老版本的OSTaskCreate()),这使得每一个任务都可进行堆栈检查。
void main (void)
&&& PC_DispClrScr(DISP_FGND_WHITE +
DISP_BGND_BLACK);
&&& OSInit();
&&& PC_DOSSaveReturn();
&&& PC_VectSet(uCOS, OSCtxSw);
&&& PC_ElapsedInit();&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OSTaskCreateExt(TaskStart,&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
(void *)0,
&&&&&&&&&&&&&&&&&&&
&TaskStartStk[TASK_STK_SIZE-1],
&&&&&&&&&&&&&&&&&&&
TASK_START_PRIO,
&&&&&&&&&&&&&&&&&&&
TASK_START_ID,
&&&&&&&&&&&&&&&&&&&
&TaskStartStk[0],
&&&&&&&&&&&&&&&&&&&
TASK_STK_SIZE,
&&&&&&&&&&&&&&&&&&&
(void *)0,
&&&&&&&&&&&&&&&&&&&
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
&&& OSStart();
除了OSTaskCreate()函数的四个参数外,OSTaskCreateExt()还需要五个参数(一共9个):任务的ID,一个指向任务堆栈栈底的指针,堆栈的大小(以堆栈单元为单位,80X86中为字),一个指向用户定义的TCB扩展数据结构的指针,和一个用于指定对任务操作的变量。该变量的一个选项就是用来设定uCOS-II堆栈检查是否允许。例2中并没有用到TCB扩展数据结构指针。
<span style="font-size:14.0color:#.08.02TaskStart()
程序清单L1.12列出了TaskStart()的伪码。前五项操作和例1中相同。TaskStart()建立了两个邮箱,分别提供给任务4和任务5[程序清单L1.12(1)]。除此之外,还建立了一个专门显示时间和日期的任务。
void TaskStart (void *data)
&&& Prevent compiler warning by
assigning ‘data’
&&& Display a banner and non-changing
&&& Install uC/OS-II’
&&& Change the tick rate to 200 Hz;
&&& Initialize
&&& Create 2 mailboxes which are used by
Task #4 and #5;&&&& &&&&&&&&&&&
&&& Create a task that will display the
date an&&& (2)
&&& Create 5
&&& for (;;) {
&&&&&&& Display
&&&&&&& Display CPU
usage in %;
&&&&&&& Display
&&&&&&& Clear the
&&&&&&& Display
uC/OS-II’
&&&&&&& If (Key was
pressed) {
&&&&&&&&&&&
if (Key pressed was the ESCAPE key) {
&&&&&&&&&&&&&&&
Return to DOS;
&&&&&&&&&&&
&&&&&&& Delay for 1
<span style="font-size:14.0color:#.08.03 TaskN()
任务1将检查其他七个任务堆栈的大小,同时记录OSTackStkChk()函数的执行时间[程序清单L1.13(1)C(2)],并与堆栈大小一起显示出来。注意所有堆栈的大小都是以字节为单位的。任务1每秒执行10次[程序清单L1.13(3)](间隔100ms)。
void& Task1 (void *pdata)
INT8U&&&&&&
&&& OS_STK_DATA
&&& INT16U&&&&&
INT8U&&&&&&
char&&&&&&& s[80];
&&& pdata =
&&& for (;;) {
&&&&&&& for (i = 0;
i & 7; i++) {
&&&&&&&&&&&
PC_ElapsedStart();&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
err& = OSTaskStkChk(TASK_START_PRIO+i, &data)
&&&&&&&&&&&
time = PC_ElapsedStop();&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
if (err == OS_NO_ERR) {
&&&&&&&&&&&&&&&
sprintf(s, "%3ld&&&&&
%3ld&&&&& %3ld&&&&&
&&&&&&&&&&&&&&&&&&&&&&&
data.OSFree + data.OSUsed,
&&&&&&&&&&&&&&&&&&&&&&&
data.OSFree,
&&&&&&&&&&&&&&&&&&&&&&&
data.OSUsed,
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
PC_DispStr(19, 12+i, s, DISP_FGND_YELLOW);
&&&&&&&&&&&
OSTimeDlyHMSM(0, 0, 0, 100);&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
程序清单L1.14所示的任务2在屏幕上显示一个顺时针旋转的指针(用横线,斜线等字符表示―译者注),每200ms旋转一格。
void& Task2 (void *data)
&& &data =
&&& for (;;) {
PC_DispChar(70, 15, '|',& DISP_FGND_WHITE + DISP_BGND_RED);
OSTimeDly(10);
PC_DispChar(70, 15, '/',& DISP_FGND_WHITE + DISP_BGND_RED);
OSTimeDly(10);
PC_DispChar(70, 15, '-',& DISP_FGND_WHITE + DISP_BGND_RED);
OSTimeDly(10);
PC_DispChar(70, 15, '\\', DISP_FGND_WHITE + DISP_BGND_RED);
OSTimeDly(10);
任务3(程序清单 L1.15)也显示了与任务2相同的一个旋转指针,但是旋转的方向不同。任务3在堆栈中分配了一个很大的数组,将堆栈填充掉,使得OSTaskStkChk()只需花费很少的时间来确定堆栈的利用率,尤其是当堆栈已经快满的时候。
void& Task3 (void *data)
&&& char&&& dummy[500];
&&& INT16U&
&&& data =
&&& for (I = 0; i & 499; i++) {
&&&&&&& dummy[i] =
&&& for (;;) {
PC_DispChar(70, 16, '|',& DISP_FGND_WHITE + DISP_BGND_BLUE);
OSTimeDly(20);
PC_DispChar(70, 16, '\\', DISP_FGND_WHITE + DISP_BGND_BLUE);
OSTimeDly(20);
&&&&&&& PC_DispChar(70,
16, '-',& DISP_FGND_WHITE + DISP_BGND_BLUE);
OSTimeDly(20);
PC_DispChar(70, 16, '/',& DISP_FGND_WHITE + DISP_BGND_BLUE);
OSTimeDly(20);
任务4(程序清单L1.16)向任务5发送消息并等待确认[程序清单L1.16(1)]。发送的消息是一个指向字符的指针。每当任务4从任务5收到确认[程序清单L1.16(2)],就将传递的ASCII码加1再发送[程序清单L1.16(3)],结果是不断的传送“ABCDEFG....”。
void& Task4 (void *data)
&&& char&&
&&& INT8U&
&&& data& =
&&& txmsg = 'A';
&&& for (;;) {
&&&&&&& while (txmsg
&&&&&&&&&&&
OSMboxPost(TxMbox, (void *)&txmsg);&&&&&&&&&&&&&& &&&&&&&&&&&&
&&&&&&&&&&&
OSMboxPend(AckMbox, 0, &err);&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
txmsg++;&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&& txmsg = 'A';
当任务5 [程序清单L1.17]接收消息后[程序清单L1.17(1)](发送的字符),就将消息显示到屏幕上[程序清单L1.17(2)],然后延时1秒[程序清单L1.17(3)],再向任务4发送确认信息。
void& Task5 (void *data)
&&& char& *
&&& INT8U&
&&& data =
&&& for (;;) {
&&&&&&& rxmsg =
(char *)OSMboxPend(TxMbox, 0, &err);&&&&& &&&&&&&&&&&&&&&&
PC_DispChar(70, 18, *rxmsg, DISP_FGND_YELLOW+DISP_BGND_RED);&&& (2)
OSTimeDlyHMSM(0, 0, 1, 0);&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OSMboxPost(AckMbox, (void *)1);&&&&&& &&&&&&&&&&&&&&&&&&&&
&&&&&&&&&(4)
TaskClk()函数[程序清单L1.18]显示当前日期和时间,每秒更新一次。
void& TaskClk (void *data)
char&&&&&&& s[40];
&&& data =
&&& for (;;) {
PC_GetDateTime(s);
PC_DispStr(0, 24, s, DISP_FGND_BLUE + DISP_BGND_CYAN);
OSTimeDly(OS_TICKS_PER_SEC);
<span style="font-size:14.0color:#.09例3
例<span style="color:#中使用了许多uCOS-II提供的附加功能。任务3使用了OSTaskCreateExt()中TCB的扩展数据结构,用户定义的任务切换对外接口函数(OSTaskSwHook()),用户定义的统计任务(statistic task )的对外接口函数(OSTaskStatHook())以及消息队列。例3的磁盘文件是\SOFTWARE\uCOS-II\EX3_x86L,它包括9个任务。除了空闲任务(idle task)和统计任务(statistic task ),还有7个任务。与例1,例2一样,TaskStart()由main()函数建立,其功能是建立其他任务,并显示统计信息。
<span style="font-size:14.0color:#.09.01 main()
main()函数[程序清单L1.19]和例2中的相不多,不同的是在用户定义的TCB扩展数据结构中可以保存每个任务的名称[程序清单L1.19(1)](扩展结构的声明在INCLUDES.H中定义,也可参看程序清单L<span style="color:#.20)。笔者定义了30个字节来存放任务名(包括空格)[程序清单L1.20(1)]。本例中没有用到堆栈检查操作,TaskStart()中禁止该操作[程序清单L1.19(2)]。
void main (void)
&&& PC_DispClrScr(DISP_FGND_WHITE +
DISP_BGND_BLACK);
&&& OSInit();
&&& PC_DOSSaveReturn();
&&& PC_VectSet(uCOS, OSCtxSw);
&&& PC_ElapsedInit();
Strcpy(TaskUserData[TASK_START_ID].TaskName, "StartTask");&&&&& &&&
&&& OSTaskCreateExt(TaskStart,
&&&&&&&&&&&&&&&&&&&
(void *)0,
&&&&&&&&&&&&&&&&&&&
&TaskStartStk[TASK_STK_SIZE-1],
&&&&&&&&&&&&&&&&&&&
TASK_START_PRIO,
&&&&&&&&&&&&&&&
&&&&TASK_START_ID,
&&&&&&&&&&&&&&&&&&&
&TaskStartStk[0],
&&&&&&&&&&&&&&&&&&&
TASK_STK_SIZE,
&&&&&&&&&&&&&&&&&&&
&TaskUserData[TASK_START_ID],
&&&&&&&&&&&&&&&&&&&
0);&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OSStart();
typedef struct {
&&& char&&& TaskName[30];&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& INT16U& TaskC
&&& INT16U& TaskExecT
&&& INT32U& TaskTotExecT
} TASK_USER_DATA;
<span style="font-size:14.0color:#.09.02任务
TaskStart()的伪码如程序清单L1.21所示,与例2有3处不同:
l为任务1,2,3建立了一个消息队列[程序清单L1.21(1)];
l每个任务都有一个名字,保存在任务的TCB扩展数据结构中[程序清单L1.21(2)];
l禁止堆栈检查。
void TaskStart (void *data)
&&& Prevent compiler warning by
assigning ‘data’
&&& Display a banner and non-changing
&&& Install uC/OS-II’
&&& Change the tick rate to 200 Hz;
&&& Initialize
&&& Cr&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& Create a task that will display the
&&& Create 5 application tasks with a
name stored in the TCB ext.;&& && (2)
&&& for (;;) {
&&&&&&& Display
&&&&&&& Display CPU
usage in %;
&&&&&&& Display
&&&&&&& Clear the
&&&&&& &Display
uC/OS-II’
&&&&&&& If (Key was
pressed) {
&&&&&&&&&&&
if (Key pressed was the ESCAPE key) {
&&&&&&&&&&&&&&&
Return to DOS;
&&&&&&&&&&&
&&&&&&& Delay for 1
任务1向消息队列发送一个消息[程序清单L1.22(1)],然后延时等待消息发送完成[程序清单L1.22(2)]。这段时间可以让接收消息的任务显示收到的消息。发送的消息有三种。
void& Task1 (void *data)
&&& char one&& = '1';
&&& char two&& = '2';
&&& char three = '3';
&&& data =
&&& for (;;) {
OSQPost(MsgQueue, (void *)&one);&&&&&&&&&&& &&&&&&&&&&&&&&
&&&&&&&&(1)
OSTimeDlyHMSM(0, 0, 1,&& 0);&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&
OSQPost(MsgQueue, (void *)&two);
OSTimeDlyHMSM(0, 0, 0, 500);
OSQPost(MsgQueue, (void *)&three);
OSTimeDlyHMSM(0, 0, 1,&& 0);
任务2处于等待消息的挂起状态,且不设定最大等待时间[程序清单L1.23(1)]。所以任务2将一直等待直到收到消息。当收到消息后,任务2显示消息并且延时500mS[程序清单L1.23(2)],延时的时间可以使任务3检查消息队列。
void& Task2 (void *data)
&&& INT8U *
&&& INT8U&
&&& data =
&&& for (;;) {
&&&&&&& msg = (INT8U
*)OSQPend(MsgQueue, 0, &err);&&&&& &&&&&&&&&&&&&&&&&&
PC_DispChar(70, 14, *msg, DISP_FGND_YELLOW+DISP_BGND_BLUE);&& &
OSTimeDlyHMSM(0, 0, 0, 500);&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
任务3同样处于等待消息的挂起状态,但是它设定了等待结束时间250mS[程序清单L1.24(1)]。如果有消息来到,任务3将显示消息号[程序清单L1.24(3)],如果超过了等待时间,任务3就显示“T”(意为timeout)[程序清单L1.24(2)]。
void& Task3 (void *data)
&&& INT8U *
&&& INT8U&
&&& data =
&&& for (;;) {
&&&&&&& msg = (INT8U
*)OSQPend(MsgQueue, OS_TICKS_PER_SEC/4, &err);&& & (1)
&&&&&&& If (err ==
OS_TIMEOUT) {
&&&&&&&&&&&
PC_DispChar(70,15,'T',DISP_FGND_YELLOW+DISP_BGND_RED);&&& &&
&&&&&&& } else {
&&&&&&&&&&&
PC_DispChar(70,15,*msg,DISP_FGND_YELLOW+DISP_BGND_BLUE);&&&& (3)
任务4的操作只是从邮箱发送[程序清单L1.25(1)]和接收[程序清单L1.25(2)],这使得用户可以测量任务在自己PC上执行的时间。任务4每10mS执行一次[程序清单L1.25(3)]。
void& Task4 (void *data)
&&& OS_EVENT *
&&& INT8U&&&&
&&& data =
&&& mbox = OSMboxCreate((void *)0);
&&& for (;;) {
&& &&&&&OSMboxPost(mbox,
(void *)1);&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OSMboxPend(mbox, 0, &err);&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OSTimeDlyHMSM(0, 0, 0, 10);&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
任务5除了延时一个时钟节拍以外什么也不做[程序清单L1.26(1)]。注意所有的任务都应该调用uCOS-II的函数,等待延时结束或者事件的发生而让出CPU。如果始终占用CPU,这将使低优先级的任务无法得到CPU。
void& Task5 (void *data)
&&& data =
&&& for (;;) {
OSTimeDly(1);&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
同样, TaskClk()函数[程序清单L1.18]显示当前日期和时间。
<span style="font-size:14.0color:#.09.03注意
有些程序的细节只有请您仔细读一读EX3L.C才能理解。EX3L.C中有OSTaskSwHook()函数的代码,该函数用来测量每个任务的执行时间,可以用来统计每一个任务的调度频率,也可以统计每个任务运行时间的总和。这些信息将存储在每个任务的TCB扩展数据结构中。每次任务切换的时候OSTaskSwHook()都将被调用。
每次任务切换发生的时候,OSTaskSwHook()先调用PC_ElapsedStop()函数[程序清单L1.27(1)] 来获取任务的运行时间[程序清单L1.27(1)],PC_ElapsedStop()要和PC_ElapsedStart()一起使用,上述两个函数用到了PC的定时器2(timer 2)。其中PC_ElapsedStart()功能为启动定时器开始记数;而PC_ElapsedStop()功能为获取定时器的值,然后清零,为下一次计数做准备。从定时器取得的计数将拷贝到time变量[程序清单L1.27(1)]。然后OSTaskSwHook()调用PC_ElapsedStart()重新启动定时器做下一次计数[程序清单L1.27(2)]。需要注意的是,系统启动后,第一次调用PC_ElapsedStart()是在初始化代码中,所以第一次任务切换调用PC_ElapsedStop()所得到的计数值没有实际意义,但这没有什么影响。如果任务分配了TCB扩展数据结构[程序清单L1.27(4)],其中的计数器TaskCtr进行累加[程序清单L1.27(5)]。TaskCtr可以统计任务被切换的频繁程度,也可以检查某个任务是否在运行。TaskExecTime [程序清单L1.27(6)]用来记录函数从切入到切出的运行时间,TaskTotExecTime[程序清单L1.27(7)]记录任务总的运行时间。统计每个任务的上述两个变量,可以计算出一段时间内各个任务占用CPU的百分比。OSTaskStatHook()函数会显示这些统计信息。
void OSTaskSwHook (void)
INT16U&&&&&&&&&
&&& TASK_USER_DATA *
&&& time& = PC_ElapsedStop();&&&&&&&&&& &&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&(1)
&&& PC_ElapsedStart();&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& puser = OSTCBCur-&OSTCBExtP&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& if (puser != (void *)0) {&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&& puser-&TaskCtr++;&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
puser-&TaskExecTime&&&& =&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&
puser-&TaskTotExecTime +=&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&
本例中的统计任务(statistic task)将调用对外接口函数OSTaskStatHook()(设置OS_CFG.H文件中的OS_TASK_STAT_EN为1允许对外接口函数)。统计任务每秒运行一次,本例中OSTaskStatHook()用来计算并显示各任务占用CPU的情况。
OSTaskStatHook()函数中首先计算所有任务的运行时间[程序清单L1.2<span style="color:#(1)],DispTaskStat()用来将数字显示为ASCII字符[程序清单L1.2<span style="color:#(2)]。然后是计算每个任务运行时间的百分比[程序清单L1.28(3)],显示在合适的位置上 [程序清单L1.28(4)]。
void OSTaskStatHook (void)
&&& char&& s[80];
&&& INT8U&
&&& INT32U
&&& INT8U&
&&& total = 0L;
&&& for (I = 0; i & 7; i++) {
&&&&&&& total +=
TaskUserData[i].TaskTotExecT&&&&&&&& &&&&&&&&&&&&&&&&
DispTaskStat(i);&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& if (total & 0) {
&&&&&&& for (i = 0;
i & 7; i++) {
&&&&&&&&&&&
pct = 100 * TaskUserData[i].TaskTotExecTime /&&&&&& &
&&&&&&&& &&&sprintf(s,
"%3d %%", pct);
&&&&&&&&&&&
PC_DispStr(62, i + 11, s, DISP_FGND_YELLOW);&&&&&&& &&&&&&&&&
&&& if (total & L) {
&&&&&&& for (i = 0;
i & 7; i++) {
&&&&&&&&&&&
TaskUserData[i].TaskTotExecTime = 0L;
第3章内核结构
临界段(Critical Sections)
YourTask (void *pdata)&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&
for (;;) {&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
/* 用户代码 */
调用uC/OS-II的某种系统服务:
OSMboxPend();
OSQPend();
OSSemPend();
OSTaskDel(OS_PRIO_SELF);
OSTaskSuspend(OS_PRIO_SELF);
OSTimeDly();
OSTimeDlyHMSM();
/* 用户代码 */
YourTask (void *pdata)
/* 用户代码 */
OSTaskDel(OS_PRIO_SELF);
任务控制块(Task Control Blocks, OS--_TCBs)
#if OS_TASK_CREAT_EXT_EN &
& typedef struct{
INT32U& OSF& //Numbers of free bytes on the stack
INT32U& OSU& //Numbers of bytes used on the stack
& }OS_STK_DATA;
typedef struct os_tcb {
OS_STK&&&&&&& *OSTCBStkP
#if OS_TASK_CREATE_EXT_EN
void&&&&&&&&& *OSTCBExtP
OS_STK&&&&&&& *OSTCBStkB
INT32U&&&&&&&& OSTCBStkS
INT16U&&&&&&&& OSTCBO
INT16U&&&&&&&& OSTCBId;
&&& struct
os_tcb *OSTCBN
&&& struct
os_tcb *OSTCBP
#if (OS_Q_EN &&
(OS_MAX_QS &= 2)) || OS_MBOX_EN || OS_SEM_EN
OS_EVENT&&&&& *OSTCBEventP
#if (OS_Q_EN &&
(OS_MAX_QS &= 2)) || OS_MBOX_EN
void&&&&&&&&& *OSTCBM
INT16U&&&&&&&& OSTCBD
INT8U&&&&&&&&& OSTCBS
INT8U&&&&&&&&& OSTCBP
INT8U&&&&&&&&& OSTCBX;
INT8U&&&&&&&&& OSTCBY;
INT8U&&&&&&&&& OSTCBBitX;
INT8U&&&&&&&&& OSTCBBitY;
#if OS_TASK_DEL_EN
BOOLEAN&&&&&&& OSTCBDelR
= priority && 3;
= OSMapTbl[priority &&
= priority & 0x07;
= OSMapTbl[priority &
就绪表(Ready List)
OSRdyGrp&&&&&
&&&&&&|= OSMapTbl[prio && 3];
OSRdyTbl[prio && 3] |=
OSMapTbl[prio & 0x07];
<span style="color:#000001
<span style="color:#000010
<span style="color:#000100
<span style="color:#001000
<span style="color:#010000
<span style="color:#100000
<span style="color:#000000
<span style="color:#000000
if ((OSRdyTbl[prio && 3] &= ~OSMapTbl[prio
& 0x07]) == 0)
&&& OSRdyGrp &= ~OSMapTbl[prio
y&&& = OSUnMapTbl[OSRdyGrp];
x&&& = OSUnMapTbl[OSRdyTbl[y]];
prio = (y && 3) +
任务调度(Task Scheduling)
OSSched (void)
OS_ENTER_CRITICAL();
&&& if ((OSLockNesting | OSIntNesting)
== 0)&&&&&&&&&&&&&&&&&&&&&&&&&&& (1)
&& y = OSUnMapTbl[OSRdyGrp];&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (2)
&OSPrioHighRdy = (INT8U)((y && 3)
+ OSUnMapTbl[OSRdyTbl[y]]);
&&& if (OSPrioHighRdy !=
OSPrioCur)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (3)
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];&&&&&&&&&&&&&&&&& (4)
OSCtxSwCtr++;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_TASK_SW();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_EXIT_CRITICAL();
给调度器上锁和开锁(Locking and UnLocking the Scheduler)
void OSSchedLock (void)
&&& if (OSRunning == TRUE) {
&&&&&&& OS_ENTER_CRITICAL();
OSLockNesting++;
OS_EXIT_CRITICAL();
void OSSchedUnlock (void)
&&& if (OSRunning == TRUE) {
OS_ENTER_CRITICAL();
&&&&&&& if
(OSLockNesting & 0) {
&&&&&&&&&&&
OSLockNesting--;
&&&&&&&&&&&
if ((OSLockNesting | OSIntNesting) == 0) {&&&&&&& &&&&&&&&&&&
&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
&&&&&&&&&&&&&&&
OSSched();&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
&&&&&&&&&&&
&&&&&&& } else {
&&&&&&&&&&&
OS_EXIT_CRITICAL();
空闲任务(Idle Task)
void OSTaskIdle (void *pdata)
&&& pdata =
&&& for (;;) {
OS_ENTER_CRITICAL();
&&&&&&& OSIdleCtr++;
OS_EXIT_CRITICAL();
Void main (void)
OSInit();&&&&&&&&&&&&&&&&
/* 初始化uC/OS-II&&&&&&&&&&&&&&&&&&&&&&&&& (1)*/
&&& /* 安装uC/OS-II的任务切换向量&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
& &&/* 创建用户起始任务(为了方便讨论,这里以TaskStart()作为起始任务)&&&&&&&& (2)*/
OSStart();&&&&&&&&&&&&&&&
/* 开始多任务调度&&&&&&&&&&&&&&&&&&&&&&&&&& (3)*/
Void TaskStart (void *pdata)
&&& /* 安装并启动uC/OS-II的时钟节拍&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (4)*/
OSStatInit();&&&&&&&&&&&&
/* 初始化统计任务&&&&&&&&&&&&&&&&&&&&&&&&&& (5)*/
&&& /* 创建用户应用程序任务&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
&&& for (;;) {
/* 这里是TaskStart()的代码!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
void OSStatInit (void)
&&& OSTimeDly(2);
&&& OS_ENTER_CRITICAL();
&&& OSIdleCtr&&& = 0L;
&&& OS_EXIT_CRITICAL();
&&& OSTimeDly(OS_TICKS_PER_SEC);
&&& OS_ENTER_CRITICAL();
&&& OSIdleCtrMax = OSIdleC
&&& OSStatRdy&&& = TRUE;
&&& OS_EXIT_CRITICAL();
void OSTaskStat (void *pdata)
&&& INT32U
&&& pdata =
&&& while (OSStatRdy == FALSE) {&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&& OSTimeDly(2
* OS_TICKS_PER_SEC);
&&& for (;;) {
OS_ENTER_CRITICAL();
&&&&&&& OSIdleCtrRun
run&&&&&&&&& = OSIdleC
OSIdleCtr&&& = 0L;
OS_EXIT_CRITICAL();
&&&&&&& if
(OSIdleCtrMax & 0L) {
&&&&&&&&&&&
usage = (INT8S)(100L - 100L * run / OSIdleCtrMax);&&&&&&& && (2)
&&&&&&&&&&&
if (usage & 100) {
&&&&&&&&&&&&&&&
OSCPUUsage = 100;
&&&&&&&&&&&
} else if (usage & 0) {
&&&&&&&&&&&&&&&
OSCPUUsage = 0;
&&&&&&&&&&&
&&&&&&&&&&&&&&&
OSCPUUsage =
&&&&&&&&&&&
&&&& &&&} else {
&&&&&&&&&&&
OSCPUUsage = 0;
OSTaskStatHook();&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OSTimeDly(OS_TICKS_PER_SEC);
μC/OS-Ⅱ中的中断处理
用户中断服务子程序:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& 保存全部CPU寄存器;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(1)&&&&&&&&&&&&&&&&&&&&&
调用OSIntEnter或OSIntNesting直接加<span style="font-family:'Courier New';color:#;&&&&&&
&&&&&&&&(2)
&&& 执行用户代码做中断服务;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(3)&&&&&&&&&&&&&&&&&
&&& 调用OSIntExit();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(4)&&&&&&&&&&&&&&&&&&&&
&&& 恢复所有CPU寄存器;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(5)&&&&&&&&&&&&&&&&&&&&&
&&& 执行中断返回指令;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(6)&&&&&&&&
void OSIntEnter (void)
& …………
}&&&& //参见OS_CORE.C
void OSIntExit (void)
&&& OS_ENTER_CRITICAL();&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& if ((--OSIntNesting | OSLockNesting)
== 0) {&&&&& &&&&&&&&&&&&&&&&&&&
OSIntExitY&&& = OSUnMapTbl[OSRdyGrp];&&&&&&& &&&&&&&&&&&&&&&&&&&&&&
OSPrioHighRdy = (INT8U)((OSIntExitY && 3) +
&&&&&&&&&&&&&&&&&&&&&&&
OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
&&&&&&& if
(OSPrioHighRdy != OSPrioCur) {
&&&&&&&&&&&
OSTCBHighRdy& = OSTCBPrioTbl[OSPrioHighRdy];
&&&&&&&&&&&
OSCtxSwCtr++;
&&&&&&&&&&&
OSIntCtxSw();&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OS_EXIT_CRITICAL();
M68HC11_ISR:&&&&&&&&&&&&&&&&&
/* 快中断服务程序,必须禁止中断*/
&&& 所有寄存器被CPU自动保存;
&&& 执行用户代码以响应中断;
&&& 执行中断返回指令;
void main(void)
&&& OSInit();&&&&&&&&&&&&&&&&
/* 初始化uC/OS-II&&&&&&&&&&&&&&& &&&&&&&&&&&&&&
&&& /* 应用程序初始化代码 ...&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&
&&& /* ... 通过调用OSTaskCreate()创建至少一个任务&&&&&&&&&&&&&&&&&&&& &&&&&&
&&& 允许时钟节拍(TICKER)中断; /* 千万不要在这里允许时钟节拍中断!!! &&&&&&&&&&&
OSStart();&&&&&&&&&&&&&&&
/* 开始多任务调度&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&
void OSTickISR(void)
&&& 保存处理器寄存器的值;
&&& 调用OSIntEnter()或是将OSIntNesting加<span style="font-family:'Courier New';color:#;
&&& 调用OSTimeTick();
&&& 调用OSIntExit();
&&& 恢复处理器寄存器的值;
&&& 执行中断返回指令;
void OSTimeTick (void)
&&& OS_TCB *
&&& OSTimeTickHook();&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& ptcb = OSTCBL&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& while (ptcb-&OSTCBPrio !=
OS_IDLE_PRIO) { &&&&&&&& &&&&&&&&&&&&&&&&&&&&(3)
OS_ENTER_CRITICAL();
&&&&&&& if
(ptcb-&OSTCBDly != 0) {
&&&&&&&&&&&
if (--ptcb-&OSTCBDly == 0) {
&&&&&&&&&&&&&&&
if (!(ptcb-&OSTCBStat & OS_STAT_SUSPEND)) {&&&&&&& &&&&&&
&&&&&&&&&&&&&&&&&&&
OSRdyGrp&&&&&&&&&&&&&&
|= ptcb-&OSTCBBitY;&&&&&&&&&& &&&
&&&&&&&&&&&&&&&&&&&
OSRdyTbl[ptcb-&OSTCBY] |= ptcb-&OSTCBBitX;
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
ptcb-&OSTCBDly = 1;
&&&&&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&& Ptcb =
ptcb-&OSTCBN
OS_EXIT_CRITICAL();
&&& OS_ENTER_CRITICAL();&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OSTime++;&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& OS_EXIT_CRITICAL();
void TickTask (void *pdata)
&&& pdata =
&&& for (;;) {
OSMboxPend(...);&&& /* 等待从时钟节拍中断服务程序发来的信号 */
OSTimeTick();
void OSTickISR(void)
&&& 保存处理器寄存器的值;
&&& 调用OSIntEnter()或是将OSIntNesting加<span style="font-family:'Courier New';color:#;
&&& 发送一个‘空’消息(例如, (void *)1)到时钟节拍的邮箱;
&&& 调用OSIntExit();
&&& 恢复处理器寄存器的值;
&&& 执行中断返回指令;
μC/OS-Ⅱ初始化
μC/OS-Ⅱ的启动
void main (void)
OSInit();&&&&&&&&&& /* 初始化uC/OS-II&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& 通过调用OSTaskCreate()或OSTaskCreateExt()创建至少一个任务;
OSStart();&&&&&&&&& /* 开始多任务调度!OSStart()永远不会返回 */
void OSStart (void)
&&& if (OSRunning == FALSE) {
y&&&&&&&&&&&& =
OSUnMapTbl[OSRdyGrp];
x&&&&&&&&&&&& =
OSUnMapTbl[OSRdyTbl[y]];
OSPrioHighRdy = (INT8U)((y && 3) + x);
OSPrioCur&&&& = OSPrioHighR
OSTCBHighRdy& = OSTCBPrioTbl[OSPrioHighRdy];&&&&&&&& &&&&&&
OSTCBCur&&&&& = OSTCBHighR
OSStartHighRdy();&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
获取当前μC/OS-Ⅱ的版本号
INT16U OSVersion (void)
&&& return (OS_VERSION);
OSEvent???()函数
第4章任务管理
void YourTask (void *pdata)
&&& for (;;) {
/* 用户代码 */
调用μC/OS-Ⅱ的服务例程之一:
&&&&&&&&&&&
OSMboxPend();
& &&&&&&&&&&OSQPend();
&&&&&&&&&&&
OSSemPend();
&&&&&&&&&&&
OSTaskDel(OS_PRIO_SELF);
&&&&&&&&&&&
OSTaskSuspend(OS_PRIO_SELF);
&&&&&&&&&&&
OSTimeDly();
&&&&&&&&&&&
OSTimeDlyHMSM();
/* 用户代码 */
void YourTask (void *pdata)
& &&/* 用户代码 */
OSTaskDel(OS_PRIO_SELF);
建立任务,OSTaskCreate()
INT8U OSTaskCreate (void
(*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
&&& if (prio
& OS_LOWEST_PRIO) {&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
return (OS_PRIO_INVALID);
OS_ENTER_CRITICAL();
(OSTCBPrioTbl[prio] == (OS_TCB *)0) {&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&
OSTCBPrioTbl[prio] = (OS_TCB *)1;&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
psp = (void *)OSTaskStkInit(task, pdata, ptos, 0);& &&& &&&&&&&&&&(5)
err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0); &&&&&
if (err == OS_NO_ERR) {&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_ENTER_CRITICAL();
&&&&&&&&&&&
OSTaskCtr++;&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&(8)
&&&&&&&&&&&
OSTaskCreateHook(OSTCBPrioTbl[prio]);&&& &&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_EXIT_CRITICAL();
&&&&&&&&&&&
if (OSRunning) {&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
OSSched();&&&&&&& &&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(11)
&&&&&&&&&&&
&&&&&&&&&&&
OS_ENTER_CRITICAL();
&&&&&&&&&&&
OSTCBPrioTbl[prio] = (OS_TCB *)0;&&& &&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_EXIT_CRITICAL();
return (err);
&&& } else {
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
INT8U OSTCBInit (INT8U&
prio,&&&& OS_STK *ptos,&& OS_STK *pbos, INT16U
&&&&&&&&INT16U stk_size,
void&& *pext,&& INT16U& opt)
&&& OS_TCB
OS_ENTER_CRITICAL();
&&& ptcb =
OSTCBFreeL&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& If (ptcb
!= (OS_TCB *)0) {&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&
OSTCBFreeList&&&&&&& = ptcb-&OSTCBN
OS_EXIT_CRITICAL();
ptcb-&OSTCBStkPtr&&& =&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&
ptcb-&OSTCBPrio&&&&& = (INT8U)
ptcb-&OSTCBStat&&&&& = OS_STAT_RDY;
ptcb-&OSTCBDly&&&&&& = 0;
#if OS_TASK_CREATE_EXT_EN
ptcb-&OSTCBExtPtr&&& =
ptcb-&OSTCBStkSize&& = stk_
ptcb-&OSTCBStkBottom =
ptcb-&OSTCBOpt&&&&&& =
ptcb-&OSTCBId&&&&&&& =
pext&&&&&&&&&&&&&&&&
&& &&&&&stk_size&&&&&&&&&&&&
pbos&&&&&&&&&&&&&&&&
opt&&&&&&&&&&&&&&&&&
id&&&&&&&&&&&&&&&&&&
#if OS_TASK_DEL_EN
ptcb-&OSTCBDelReq&&& = OS_NO_ERR;
ptcb-&OSTCBY&& &&&&&&= prio
ptcb-&OSTCBBitY&&&&& = OSMapTbl[ptcb-&OSTCBY];
ptcb-&OSTCBX&&&&&&&& = prio &
ptcb-&OSTCBBitX&&&&& = OSMapTbl[ptcb-&OSTCBX];
OS_MBOX_EN || (OS_Q_EN && (OS_MAX_QS &= 2)) || OS_SEM_EN
ptcb-&OSTCBEventPtr& = (OS_EVENT *)0;
OS_MBOX_EN || (OS_Q_EN && (OS_MAX_QS &= 2))
ptcb-&OSTCBMsg&&&&&& = (void *)0;
OS_ENTER_CRITICAL();&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OSTCBPrioTbl[prio]&& =&&&&&&&&&&&&&&&&& &&
&&&&&&&&&&&&&&&&&&&(5)
ptcb-&OSTCBNext&&&&& = OSTCBL
ptcb-&OSTCBPrev&&&&& = (OS_TCB *)0;
if (OSTCBList != (OS_TCB *)0) {
&&&&&&&&&&&
OSTCBList-&OSTCBPrev =
OSTCBList&&&&&&&&&&&&&&
OSRdyGrp&&&&&&&&&&&&&&
|= ptcb-&OSTCBBitY;&&&&&&&&&&&&&&&& &&&&&&&
OSRdyTbl[ptcb-&OSTCBY] |= ptcb-&OSTCBBitX;
OS_EXIT_CRITICAL();
return (OS_NO_ERR);&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& } else {
OS_EXIT_CRITICAL();
return (OS_NO_MORE_TCB);
建立任务,OSTaskCreateExt()
INT8U OSTaskCreateExt
(void&& (*task)(void *pd),
&&&&&&&&&&&&&&&&&&&&&&
void&&& *pdata,
&&&&&&&&&&&&&&&OS_STK&
&&&&&&&&&&&&&&&&&&&&&&
INT8U&&& prio,
&&&&&&&&&&&&&&&&&&&&&&
INT16U&& id,
&&&&&&&&&&&&&&&&&&&&&&
OS_STK& *pbos,
&&&&&&&&&&&&&&&&&&&&&&
INT32U&& stk_size,
&&&&&&&&&&&&&&&&&&&&&&
void&&& *pext,
&&&&&&&&&&&&&&&&&&&&&&
INT16U&& opt)
&&& if (prio
& OS_LOWEST_PRIO) {&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
return (OS_PRIO_INVALID);
OS_ENTER_CRITICAL();
(OSTCBPrioTbl[prio] == (OS_TCB *)0) {&&&& &&&&&&&&&&&&&&&&&&&&&&&&&
OSTCBPrioTbl[prio] = (OS_TCB *)1;&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
if (opt & OS_TASK_OPT_STK_CHK) {&&&&& &&&
&&&&&&&&&&&&&&&&&&&&&&&&&&(5)
&&&&&&&&&&&
if (opt & OS_TASK_OPT_STK_CLR) {
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
for (i = 0; i & stk_ i++) {
&&&&&&&&&&&&&&&&&&&
#if OS_STK_GROWTH == 1
&&&&&&&&&&&&&&&&&&&
*pfill++ = (OS_STK)0;
&&&&&&&&&&
&&&&&&&&&#else
&&&&&&&&&&&&&&&&&&&
*pfill-- = (OS_STK)0;
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&
psp = (void *)OSTaskStkInit(task, pdata, ptos, opt);&&& &&&&&&&&&
err = OSTCBInit(prio, psp, pbos, id, stk_size, pext, opt);&& &&&
if (err == OS_NO_ERR) {&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_ENTER_CRITICAL;
&&&&&&&&&&&
OSTaskCtr++;&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OSTaskCreateHook(OSTCBPrioTbl[prio]);&&&&& &&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_EXIT_CRITICAL();
&&&&&&&&&&&
if (OSRunning) {&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
OSSched();&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&OS_ENTER_CRITICAL();
&&&&&&&&&&&
OSTCBPrioTbl[prio] = (OS_TCB *)0;&&&&& &&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_EXIT_CRITICAL();
return (err);
&&& } else {
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
pstk = (OS_STK
*)malloc(stack_size);
If (pstk != (OS_STK *)0)
{&&&&&&&&&&& /* 确认malloc()能得到足够地内存空间 */
&&& Create the
TaskStack[TASK_STACK_SIZE];
OSTaskCreate(task, pdata,
&TaskStack[0], prio);
TaskStack[TASK_STACK_SIZE];
OSTaskCreate(task, pdata,
&TaskStack[TASK_STACK_SIZE-1], prio);
TaskStack[TASK_STACK_SIZE];
#if OS_STK_GROWTH == 0
OSTaskCreate(task, pdata, &TaskStack[0], prio);
OSTaskCreate(task, pdata, &TaskStack[TASK_STACK_SIZE-1], prio);
堆栈检验,OSTaskStkChk()
INT8U OSTaskStkChk (INT8U
prio, OS_STK_DATA *pdata)
&&& OS_TCB&
pdata-&OSFree = 0;
pdata-&OSUsed = 0;
&&& if (prio
& OS_LOWEST_PRIO && prio != OS_PRIO_SELF) {
return (OS_PRIO_INVALID);
OS_ENTER_CRITICAL();
& &&if (prio
== OS_PRIO_SELF) {&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
prio = OSTCBCur-&OSTCBP
&&& ptcb =
OSTCBPrioTbl[prio];
&&& if (ptcb
== (OS_TCB *)0) {&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
return (OS_TASK_NOT_EXIST);
((ptcb-&OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0) {&&&&&& &&&&&&&&&&&
OS_EXIT_CRITICAL();
return (OS_TASK_OPT_ERR);
&&& free = 0;&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& size =
ptcb-&OSTCBStkS
&&& pchk =
ptcb-&OSTCBStkB
OS_EXIT_CRITICAL();
#if OS_STK_GROWTH == 1
(*pchk++ == 0) {
(*pchk-- == 0) {
pdata-&OSFree = free * sizeof(OS_STK);&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&
pdata-&OSUsed = (size - free) * sizeof(OS_STK);
&&& return
(OS_NO_ERR);
删除任务,OSTaskDel()
INT8U OSTaskDel (INT8U prio)
OS_TCB&& *
&&& OS_EVENT
&&& if (prio
== OS_IDLE_PRIO) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (1)
return (OS_TASK_DEL_IDLE);
&&& if (prio
&= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) {&&&&&&&&&&&&&& (2)
return (OS_PRIO_INVALID);
OS_ENTER_CRITICAL();
(OSIntNesting & 0) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (3)
OS_EXIT_CRITICAL();
return (OS_TASK_DEL_ISR);
&&& if (prio
== OS_PRIO_SELF) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (4)
Prio = OSTCBCur-&OSTCBP
&&& if ((ptcb
= OSTCBPrioTbl[prio]) != (OS_TCB *)0) {&&&&&&&&&&&&&&&&&& (5)
if ((OSRdyTbl[ptcb-&OSTCBY] &= ~ptcb-&OSTCBBitX) == 0) {&&&&&&& (6)
&&&&&&&&&&&
OSRdyGrp &= ~ptcb-&OSTCBBitY;
if ((pevent = ptcb-&OSTCBEventPtr) != (OS_EVENT *)0) {&&&&&&&&& (7)
&&&&&&&&&&&
if ((pevent-&OSEventTbl[ptcb-&OSTCBY] &= ~ptcb-&OSTCBBitX) == 0)
&&&&&&&&&&&&&&&
pevent-&OSEventGrp &= ~ptcb-&OSTCBBitY;
&&&&&&&&&&&
Ptcb-&OSTCBDly& = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (8)
Ptcb-&OSTCBStat = OS_STAT_RDY;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (9)
&&OSLockNesting++;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (10)
OS_EXIT_CRITICAL();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (11)
OSDummy();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (12)
OS_ENTER_CRITICAL();
OSLockNesting--;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (13)
OSTaskDelHook(ptcb);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (14)
OSTaskCtr--;
OSTCBPrioTbl[prio] = (OS_TCB *)0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (15)
&&if (ptcb-&OSTCBPrev == (OS_TCB *)0) {&&&&&&&&&&&&&&&&&&&&&&&&& (16)
&&&&&&&&&&&
ptcb-&OSTCBNext-&OSTCBPrev = (OS_TCB *)0;
&&&&&&&&&&&
OSTCBList&&&&&&&&&&&&&&&&&
= ptcb-&OSTCBN
&&&&&&&&&&&
ptcb-&OSTCBPrev-&OSTCBNext = ptcb-&OSTCBN
&&&&&&&&&&&
ptcb-&OSTCBNext-&OSTCBPrev = ptcb-&OSTCBP
ptcb-&OSTCBNext = OSTCBFreeL&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (17)
OSTCBFreeList&& =
OS_EXIT_CRITICAL();
OSSched();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& (18)
return (OS_NO_ERR);
&&& } else {
OS_EXIT_CRITICAL();
return (OS_TASK_DEL_ERR);
请求删除任务,OSTaskDelReq()
void RequestorTask (void
&&& pdata =
&&& for (;;) {
/* 应用程序代码 */
if ('TaskToBeDeleted()' 需要被删除) {&&&&&&&&&&& &&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
while (OSTaskDelReq(TASK_TO_DEL_PRIO) != OS_TASK_NOT_EXIST) { (2)
&&&&&&&&&&&&&&&
OSTimeDly(1);&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
/*应用程序代码*/&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
void TaskToBeDeleted (void
&&& pdata =
&&& for (;;) {
/*应用程序代码*/
If (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) {&&&&&&&&&&& (1)
&&&&&&&&&&&
释放所有占用的资源;&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
释放所有动态内存;
&&&&&&&&&&&
OSTaskDel(OS_PRIO_SELF);& &&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&(3)
&&&&&&&&&&&
/*应用程序代码*/
INT8U OSTaskDelReq (INT8U
&&& if (prio
== OS_IDLE_PRIO) { &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
return (OS_TASK_DEL_IDLE);
&&& if (prio
&= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) {&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&
return (OS_PRIO_INVALID);
&&& if (prio
== OS_PRIO_SELF) { &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_ENTER_CRITICAL();
stat = OSTCBCur-&OSTCBDelR
OS_EXIT_CRITICAL();
return (stat);
&&& } else {
OS_ENTER_CRITICAL();
if ((ptcb = OSTCBPrioTbl[prio]) != (OS_TCB *)0) { &&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
ptcb-&OSTCBDelReq = OS_TASK_DEL_REQ; &&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
err&&&&&&&&&&&&&&
= OS_NO_ERR;
&&&&&&&&&&&
err&&&&&&&&&&&&&&
= OS_TASK_NOT_EXIST;& &&&&&&&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
return (err);
改变任务的优先级,OSTaskChangePrio()
INT8U OSTaskChangePrio (INT8U
oldprio, INT8U newprio)
OS_TCB&& *
&&& OS_EVENT
((oldprio &= OS_LOWEST_PRIO && oldprio != OS_PRIO_SELF)& || &&&&&&
newprio &= OS_LOWEST_PRIO) {
return (OS_PRIO_INVALID);
OS_ENTER_CRITICAL();
(OSTCBPrioTbl[newprio] != (OS_TCB *)0) { &&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
&&& } else {
OSTCBPrioTbl[newprio] = (OS_TCB *)1;& &&&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
y&&& = newprio && 3;&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
bity = OSMapTbl[y];
x&&& = newprio & 0x07;
bitx = OSMapTbl[x];
OS_ENTER_CRITICAL();
if (oldprio == OS_PRIO_SELF) {& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
oldprio = OSTCBCur-&OSTCBP
if ((ptcb = OSTCBPrioTbl[oldprio]) != (OS_TCB *)0) {& &&&&&&&&&&&
&&&&&&&&&&&
OSTCBPrioTbl[oldprio] = (OS_TCB *)0;& &&&&&&&&&&&
&&&&&&&&&&&&&&&(7)
&&&&&&&&&&&
if (OSRdyTbl[ptcb-&OSTCBY] & ptcb-&OSTCBBitX) {& &&&&&&&&&&&&&
&&&&&&&&&&&&&&&
if ((OSRdyTbl[ptcb-&OSTCBY] &= ~ptcb-&OSTCBBitX) == 0) {(9)
&&&&&&&&&&&&&&&&&&&
OSRdyGrp &= ~ptcb-&OSTCBBitY;
&&&&&&&&&&&&&&&
&&&&&&OSRdyGrp&&& |=&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
OSRdyTbl[y] |=
&&&&&&&&&&&
&&&&&&&&&&&&&&&
if ((pevent = ptcb-&OSTCBEventPtr) != (OS_EVENT *)0) {& (11)
&&&&&&&&&&&&&&&&&&&
if ((pevent-&OSEventTbl[ptcb-&OSTCBY]
&&&&&&&&&&&&&&&&&&&&&&&&
~ptcb-&OSTCBBitX) == 0) {
&&&&&&&&&&&&&&&&&&&&&&&
pevent-&OSEventGrp &= ~ptcb-&OSTCBBitY;
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
pevent-&OSEventGrp&&& |=&&&&&& &&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
pevent-&OSEventTbl[y] |=
&&&&&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&&&&&&
OSTCBPrioTbl[newprio] =& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
ptcb-&OSTCBPrio&&&&&& =&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
ptcb-&OSTCBY&&&& &&&&&=&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
ptcb-&OSTCBX&&&&&&&&& =
&&&&&&&&&&&
ptcb-&OSTCBBitY&&&&&& =
&&&&&&&&&&&
ptcb-&OSTCBBitX&&&&&& =
&&&&&&&&&&&
OS_EXIT_CRITICAL();
&&&&&&&&&&&
OSSched();&&&& &&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(16)
&&&&&&&&&&&
return (OS_NO_ERR);
&&&&&&&&&&&
OSTCBPrioTbl[newprio] = (OS_TCB *)0; &&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
OS_EXIT_CRITICAL();
&&&&&&&&&&&
return (OS_PRIO_ERR);
挂起任务,OSTaskSuspend()
INT8U OSTaskSuspend (INT8U
OS_TCB&& *
&&& if (prio
== OS_IDLE_PRIO) { &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
return (OS_TASK_SUSPEND_IDLE);
&&& if (prio
&= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) {&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&
return (OS_PRIO_INVALID);
OS_ENTER_CRITICAL();
&&& if (prio
== OS_PRIO_SELF) { &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
prio = OSTCBCur-&OSTCBP
self = TRUE;
&&& } else if
(prio == OSTCBCur-&OSTCBPrio) {&& &&&&&&&&&&&&&&&&&&&&&&&&&&&
self = TRUE;
&&& } else {
self = FALSE;
&&& if ((ptcb
= OSTCBPrioTbl[prio]) == (OS_TCB *)0)
{&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
return (OS_TASK_SUSPEND_PRIO);
&&& } else {
if ((OSRdyTbl[ptcb-&OSTCBY] &= ~ptcb-&OSTCBBitX) == 0) { &&&&&&&
&&&&&&&&&&&
OSRdyGrp &= ~ptcb-&OSTCBBitY;
ptcb-&OSTCBStat |= OS_STAT_SUSPEND; &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
OS_EXIT_CRITICAL();
if (self == TRUE) }

我要回帖

更多关于 js局部变量转全局变量 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信