TinyOS 2.x 入门教程 - 图文 下载本文

TinyOS Programming

其中接口Timer是一个带参数的接口,它使用类型作为参数,接口中的类型参数被放在一对尖括号中,当串连提供者和使用者的接口带有类型参数时,它们的类型必须相互匹配,有时类型参数只是用来做类型匹配检测的,而并没有用到命令和事件中去,本例中的Timer接口就是如此,虽然它带有一个类型参数,但它里面没有一个函数用到了这个类型参数。

Blink示例是一个LEDs的闪烁示例,其中LED0的开关频率为4HZ,LED1的开关频率为2HZ,LED2的开关频率为1HZ。模块BlinkC使用了三个Timer接口示例,同时也使用了LEDs和Boot接口,也就是说BlinkC在调用这些接口所定义的命令的同时必须实现接口所定义的事件的处理函数,如图2.3所示:

图2.3 Blink接口

其中各个组件和接口的作用为: Main.Boot:初始化并启动程序

LEDs.Leds:控制LED的动作(亮、灭、闪烁) Timer.Timer:计时器

之前提到过Timer是一个带类型参数的接口,它的3个标注的类型是TMilli, T32khz, 和 TMicro,分别表示毫秒级,32Khz和微妙级的计时器。这些类型都各自的定义为C的结构体。

2、 组成和编译

接口可以由组件提供或使用。被提供的接口表现它为使用者提供的功能,被使用者表现使用者完成它的作业所需要的功能。例如在Blink示例中,组件LEDs和Timer提供了使用的接口,实际上它们也需要再调用下层的组件,如MSP430GPIO和MSP430TimerB7等。

考虑到较好的代码重用性,nesC是基于由编译器生成完整程序代码的需求设计的。作为一个必要的组成部分,nesC的编译器会根据用户所指定的平台编译生成一个对应于特定平台的C源文件。对于其产生的C源文件,nesC依据不同的微控制器使用一个对应的本地GNU的C编译器将产生的C源文件编译成可执行文件并将其下载到对应硬件平台上。如图2.4所示,nesC就根据不同的环境使用不同的编译器:Atmel128 C 源文件对应的是AVRgcc 编译器,MPS430 C 源文件对应的是mspgcc 编译器,其他的C 源文件对应的是另外的编译组件,它们对应的下载到的硬件平台分别为MicaZ和Mica2、Telosb和Taroko、其他硬件平台。

Page 10 of 94

TinyOS Programming

图2.4 组成和编译方式

3、 开发环境

开发环境是一个命令行界面,下图是在Windows操作系统上Cygwin + TinyOS的一个开发环境界面。

图2.5 开发环境

2.1.2 并发模型

TinyOS一次只执行一个应用程序,而一个应用程序由一些必要的组件和一些可选的组件组合而成。TinyOS程序有两个执行线程:任务和硬件事件句柄。任务是一种被延迟执行的函数。一旦任务被执行,它们就一直运行直至结束,中间不会被其它任务中断。硬件事件句柄是对硬件中断的处理,同样会一直运行到结束,但是可能会抢占一个任务或其它硬件事件句柄的运行。命令和事件要作为硬件事件句柄来执行,则必须用关键字async来声明。

Page 11 of 94

TinyOS Programming

因为任务和硬件事件句柄是可以被其它异步代码抢占的,所以在一定竞争情况下,nesC程序是很容易受到影响,从而导致数据的不一致或错误。为避免竞争而带来的错误产生,可以在任务内排外地访问数据,或者每次访问都采用原子 (atomic) 语句。nesC编译器在编译期间给程序员报告潜在的数据竞争。编译器也可能会产生错误的报告(例如:该变量需要随时变化),这种情况下,变量可以用关键字norace声明。注意:关键字norace必须极其小心地使用。

要了解用 nesC 编程的更多信息,请参看:

http://www.tinyos.net/tinyos-2.x/doc/nesc/ref.pdf。

2.2 常用make命令简介

TinyOS编程中,有一些make命令是经常用到的,下面对其一一进行介绍。

1) make [platform]

此命令是将nesC代码编译成可在某平台运行的代码。在执行前要切换到代码所在的目录。例如:Blink程序的代码在C:\\UCB\\cygwin\\opt\\tinyos-2.x\\apps\\Blink 目录下。打开Cygwin shell后用cd命令转到该目录下,然后输入make telosb (make mica) 命令就可以让编译器将其编译成可以在telosb (mica) 平台运行的代码了,当然首先得保证没有任何语法错误。

2) make [platform] reinstall

使用 make [platform]命令后,就可以将在某平台的可执行代码下载到对应的平台上了。例如:make telosb reinstall (make mica reinstall) 就可以将编译好的可在telosb (mica) 平台上运行的代码下载到telosb (mica) 硬件平台。

3) make [platform] install

此命令的功能相当于先执行命令make [platform],再执行命令make [platform] reinstall。当然,如果执行make [platform] 命令时,发现程序有错误,则不会执行下载动作,即不会执行make [platform] reinstall命令。

4) make clean

此命令删除上述编译命令产生的文件及文件夹。

5) make [platform] docs

此命令生成程序使用的所有组件、接口的关系的文件。生成的文件在tinyos-2.x\\doc\\nesdoc 目录下,其中索引文件为 “index.html”。

2.3 应用举例:Blink ---TinyOS编程的“Hello World”程序

上面的nesC语言简介中,简略介绍了组件、接口、模块、连接、命令、事件等基本概念。对于初学者来说相当抽象,下面结合一个例子来看看各个概念在nesC/TinyOS编程中的用法。这个例子是TinyOS自带的程序,位于tinyos-2.x/apps/Blink,其功能是让一个LED以1Hz的频率闪烁。

Blink应用程序由两个组件组成:一个模块定义文件“BlinkC.nc”和一个配置文件“BlinkAppC.nc”,“BlinkAppC.nc”也就是顶层配置,它连接“BlinkC.nc”和其他必要组件。请记住,任何一个应用程序都有一个用应用程序名命名的顶层配件,在此处,配件BlinkAppC.nc就是Blink应用程序的顶层配件,nesC编译器根据该文件的内容产生可执行文件。另一方面,模块BlinkC.nc提供Blink应用程序的实现代码。正如你所想的,BlinkAppC配件是用来连接组件:BlinkC模块和Blink应用程序用到的其它组件的。

Page 12 of 94

TinyOS Programming

让配件和模块之间有所区别的理由是:配件允许系统设计人员快速建立程序。例如:设计者设计一个应用程序可以只提供一个配件,这个配件只是简单地将一个或多个模块连接起来,而此时设计者实际上并没有实现任何东西。同样地,另一个开发人员会提供可以在广泛范围应用程序中使用的“库”模块。

当然,有时您需要同时拥有配件和模块(在此处是 BlinkAppC 和 BlinkC)。TinyOS 中的其他命名规则请参看:http://www.tinyos.net/tinyos-2.x/doc/tutorial/naming.html,或本教程的附录二:《TinyOS命名约定》。

2.3.1 Blink配件

nesC 的编译器为ncc,它可以将包含顶层配件的文件编译成可执行的应用程序。一般而言,TinyOS 应用程序还拥有一个标准的Makefile 文件,允许进行平台选择以及在调用ncc时使用某些适当的选项。

Blink程序由两个组件构成。BlinkC.nc为模块,BlinkAppC.nc为配件。让我们先看看Blink程序的配件:BlinkAppC.nc。

//BlinkAppC.nc

configuration BlinkAppC { }

implementation {

components MainC, BlinkC, LedsC;

components new TimerMilliC() as Timer0; components new TimerMilliC() as Timer1; components new TimerMilliC() as Timer2;

BlinkC -> MainC.Boot;

BlinkC.Timer0 -> Timer0; BlinkC.Timer1 -> Timer1; BlinkC.Timer2 -> Timer2; BlinkC.Leds -> LedsC; }

TinyOS应用程序中,configuration可以提供和使用接口,但并不是所有的配置都是应用程序顶层的配置。Implementation是配置的内容,它将一系列的组件建立起引用关系。

首先,需要注意的是关键字 configuration ,此词声明这是一个配件文件。头两行: configuration BlinkAppC{ } 由于这个组件本身并不使用或者提供任何接口,所以在其声明部分为空。

首先简单地说明这个配件名为 BlinkAppC。跟模块一样,在声明后的这个花括号内可以指定 uses 语句和 provides 语句。有一点非常重要,必须记住:配件可以提供和使用接口。配件实际的实现代码是在紧接着的implementation后面的一对大括号里面。components那行列出了此配件用到的一组组件,分别是MainC,BlinkC和LedsC。剩下的语句是连接使用到的接口到该接

Page 13 of 94