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

TinyOS Programming

由DemoSensorC的配件可知,DemoSensorC提供的Read接口是实际上由VoltageC()提供的,即电压传感器。

VoltageC.nc

generic configuration VoltageC() { provides interface Read; }

implementation {

components new Msp430InternalVoltageC(); Read = Msp430InternalVoltageC.Read; }

在telosb平台,因此VoltageC()组件调用的是Msp430InternalVoltageC组件提供的Read接口。

下面我们向下更深层次的分析,这就直接和硬件相关了。 4.2 ADC

下图为MSP4301611芯片的内部结构,左侧为16路ADC输入通道,A0-A7为8个可以外接的输入通道,由具体的硬件平台决定。参考telosb节点的数据手册,外置的温湿度传感器和光电传感器分别对于A3和A4通道。

16路输入通道

Msp430Adc12.h

Page 30 of 94

TinyOS Programming

enum inch_enum {

// see device specific data sheet which pin Ax is mapped to INPUT_CHANNEL_A0 = 0, // input channel A0 INPUT_CHANNEL_A1 = 1, // input channel A1 INPUT_CHANNEL_A2 = 2, // input channel A2 INPUT_CHANNEL_A3 = 3, // input channel A3 INPUT_CHANNEL_A4 = 4, // input channel A4 INPUT_CHANNEL_A5 = 5, // input channel A5 INPUT_CHANNEL_A6 = 6, // input channel A6 INPUT_CHANNEL_A7 = 7, // input channel A7

EXTERNAL_REF_VOLTAGE_CHANNEL = 8, // VeREF+ (input channel 8) REF_VOLTAGE_NEG_TERMINAL_CHANNEL = 9, // VREF-/VeREF- (input channel 9)

TEMPERATURE_DIODE_CHANNEL = 10, // Temperature diode (input channel 10)

SUPPLY_VOLTAGE_HALF_CHANNEL = 11, // (AVcc-AVss)/2 (input channel 11-15)

INPUT_CHANNEL_NONE = 12 // illegal (identifies invalid settings) };

内部电压传感器Msp430InternalVoltage的实现如下所示: Msp430InternalVoltageP.nc

module Msp430InternalVoltageP {

provides interface AdcConfigure; }

implementation {

const msp430adc12_channel_config_t config = {

inch: SUPPLY_VOLTAGE_HALF_CHANNEL, //输入通道 sref: REFERENCE_VREFplus_AVss, //参考电压 ref2_5v: REFVOLT_LEVEL_1_5, adc12ssel: SHT_SOURCE_ACLK, adc12div: SHT_CLOCK_DIV_1, sht: SAMPLE_HOLD_4_CYCLES,

sampcon_ssel: SAMPCON_SOURCE_SMCLK, sampcon_id: SAMPCON_CLOCK_DIV_1 };

async command const msp430adc12_channel_config_t* AdcConfigure.getConfiguration() {

return &config; } }

内部电压的输入通道inch:SUPPLY_VOLTAGE_HALF_CHANNEL对于为ADC11,如果将输入通道设为INPUT_CHANNEL_A3(INPUT_CHANNEL_A4),即为温度传感器(光电传感器)。

Page 31 of 94

TinyOS Programming

第5章 TinyOS任务及应用举例

本章以实例的方式介绍TinyOS的一个重要概念:任务。所举例子:SenseTask,是Sense应用程序的另一个版本。

5.1 任务的创建和调度

TinyOS 提供任务和硬件事件句柄组成的两层调度策略。如前所述,过关键字 async 声明了可被硬件事件句柄执行的命令或事件。这意味着它可以在任何时候执行(可能会抢占其它代码的执行)。因此,用 async 声明的命令和事件所做的工作应该做尽量少,且要快速完成。此外,还得注意被异步命令或事件访问的数据可能存在的数据竞争。任务则被用来处理一些较长时间的操作,例如:后台数据处理,但任务可以被硬件事件句柄抢占。

一个任务可以用以下语法在你的实现模块中声明: task void taskname(){ //?? } 其中,taskname 是程序员任意指定的任务的标识,也就是“函数名”。一个任务的返回值类型必须是 void,并且不能有任何参数。而向操作系统提交任务则可以用以下语法: post taskname(); 一个任务可以在命令、事件或其它任务内部向操作系统提交。

post 操作把任务放置到一个以先进先出为处理方式的内部任务队列中去。当一个任务开始执行的时候,只有它运行结束,下一个任务才能开始运行;因此,一个任务不应该占用或阻塞太长时间。任务之间不可以互相抢占,但是会被硬件事件句柄抢占。如果你的任务需要执行一系列长时间的操作,最好把任务分成几个而不是使用一个大的任务。

Page 32 of 94

TinyOS Programming

5.2 举例:SenseTask应用程序

现在举例说明一下,大家可以在tinyos-2.x\\apps\\SenseTask目录下找到例子的源代码。组件SenseTaskM维护一个循环“队列”:rdata,该队列包含最近采集到的内部温度数据;putdata() 函数用来把新采样得到的数据插入队列。dataReady() 事件则简单地保存数据并提交一个名为processData() 任务。

// SenseTaskM.nc async event result_t ADC.dataReady(uint16_t data) { putdata(data); post processData(); return SUCCESS; } 异步事件执行完成后(这期间可能有其它任务被挂起),processData() 任务将得到运行的机会。该任务将ADC最近采样所得的值求和并在LED中显示其8 ~ 10位。

//SenseTaskM.nc task void processData() { int16_t i, sum=0; atomic for (i=0; i> 7); display(sum >> log2size); } 任务processData() 里使用了关键字atomic,在nesC里面称之为原子语句。这意味着紧接着atomic后面的一对大括号里的代码不可以被抢占。在此例中,访问共享缓冲区rdata是需要受保护的。

原子语句会使中断处理延迟从而导致系统响应缓慢,为了减少这种影响,原子语句应该避免调用命令或触发事件。

5.3 小结

任务是TinyOS中一个非常重要的概念,在编程中经常会用到。本章要注意的几点,如下: 1) 任务的声明,返回类型必须为void,且无任何参数; 2) 任务里执行的任务不应该占用太长时间; 3) 访问共享变量等尽量使用atomic语句;

4) 原子语句应该尽量避免调用命令或触发事件。

Page 33 of 94