第七章 TinyOS典型应用
第一节 传感
7.1 传感
本节主要介绍TinyOS系统中数据采集的工作方式,并将演示两个关于应用的例子:一个是简单的Sense实例,它周期性地读取传感数据,并显示在LED上;另一个实例Oscilloscope相对复杂些,节点周期性地读取传感器的数值并发送到基站节点,再由基站转发传感器数据到计算机串口,并在计算机上以图形界面显示出来。
7.1.1 传感简介
利用传感器进行感知是无线传感器网络的主要功能之一。在TinyOS 1.x中,如Oscilloscope或Sense之类的应用程序都使用ADCControl接口来获取传感器数据。当带有传感器的新平台出现,可以通过串行接口来读取传感器数据,为此需要引进诸如ADCError之类的额外接口,但是这并不一定适合于带有ADC的传感器。
通常,采集传感器数据可以分成两个步骤:配置并启动传感器和读取传感器数据。第1步的工作非常复杂,包括传感器的配置,以及与其链接的硬件模块的配置,例如当与处理器通过模数转换器(Analog to Digital Converter,ADC)或串行外设接口(Serial Peripheral Interface,SPI)相连接时,就需要配置相应的ADC模块和SPI模块。考虑到平台不同,传感器也不同,各自的配置要求(如ADC输入通道、参考电压等)也就完全不一样。第2步的工作是读取传感器的数据,其实现较为容易。
在TinyOS 2.x中,如Oscilloscope、Sense以及RadioSenseToLeds之类的应用都具有平台无关性,它们都没有使用如ADCControl之类的配置接口,而是使用了标准的数据获取接口,如Read接口、ReadStream接口和ReadNow接口。所有配置详情在应用程序里都被隐藏了,所以即使实际的传感器以及硬件连接情况都完全不一样,Sense应用也可以直接编译并下载到TelosB平台或MicaZ平台上。
7.1.2 Sense实例
Sense是一个简单的传感器数据采集程序示例。它周期性地采集传感器数据,并显示读取数值的低3位。Sense应用可以在/opt/tinyos-2.x/apps/Sense里找到,其配件SenseAppC的内容如下:
configuration SenseAppC
{
}
implementation {
components SenseC, MainC, LedsC, new TimerMilliC();
components new DemoSensorC() as Sensor;
SenseC.Boot -> MainC;
SenseC.Leds -> LedsC;
SenseC.Timer -> TimerMilliC;
SenseC.Read -> Sensor;
}
Sense应用的配件和Blink应用的BlinkAppC配件非常相似。为了更好地理解这些接口的绑定情况,查看SenseC模块中使用到的接口:
module SenseC
{
uses {
interface Boot;
interface Leds;
interface Timer<TMilli>;
interface Read<uint16_t>;
}
}
和BlinkC一样,SenseC模块使用了Boot、Leds和Timer<TMilli>接口。此外,它还使用了Read<unit16_t>接口。SenseC模块的具体操作步骤是:Boot接口在系统初始化后启动了一个周期性的定时器,每隔一定时间触发定时器事件,并在该事件的响应中通过Read<unit16_t>接口来读取数据。读取数据由Read.read命令的调用和Read.readDone事件的触发两部分构成。每次定时器到时都会调用Read.read命令,然后等待Read.readDone事件的触发。在Read.readDone事件中获取采样数据,并把数据的低3位显示在LED上。
Read接口一次只能读取一个数据,其定义位于“tinyos-2.x/tos/interfaces”目录:
interface Read<val_t> {
command error_t read();
event void readDone( error_t result, val_t val );
}
上述代码定义了一个通用Read接口。需要注意的是,该通用接口必须带有一个参数,当且仅当提供的接口和使用的接口具有一样的参数时,两个组件才可以连接起来。还须注意,readDone事件传递了一个<val_t>类型的参数,其实这只是代替实际参数的占位符。SenseC模块为Read接口使用了一个unit16_t的变量,它只能绑定到提供Read<unit16_t>接口的组件,这表明SenseC模块希望读取16位无符号整型数据。如果将该接口连接到提供Read<unit8_t>接口的组件,就会出现编译错误。