TinyOS 2.x 入门教程 - 图文(7)

2019-04-13 19:15

TinyOS Programming

4.1 模块实现

SenseC.nc

#include \

module SenseC {

uses {

interface Boot; interface Leds;

interface Timer; interface Read; } }

implementation {

// 采样周期100ms

#define SAMPLING_FREQUENCY 100

event void Boot.booted() {

call Timer.startPeriodic(SAMPLING_FREQUENCY);//启动计数器 }

event void Timer.fired() {

call Read.read(); //计时器到,开始读取数据 }

//读取数据完毕,处理数据,即将数据用LED显示

event void Read.readDone(error_t result, uint16_t data) {

if (result == SUCCESS){ if (data & 0x0004) call Leds.led2On(); else

call Leds.led2Off(); if (data & 0x0002) call Leds.led1On(); else

call Leds.led1Off(); if (data & 0x0001) call Leds.led0On(); else

call Leds.led0Off(); } } }

event result_t Timer.fired() { return call ADC.getData(); }

async event result_t ADC.dataReady(uint16_t data) { display(7-((data>>7) &0x7));

Page 28 of 94

TinyOS Programming

return SUCCESS; } }

像BlinkC模块一样,SenseC组件使用Boot,Timer和Leds接口。此外,SenseC组件还使用了Read接口。SenseC周期性的读取采集到的数据并根据数据决定LED的亮灯情况。具体实现过程如下:

1. 首先系统初始化,调用Timer.startPeriodic(SAMPLING_FREQUENCY)启动周期性计数器 2. 计数器到,触发事件Timer.fired(),调用Read接口Read.read()命令读取数

据 3. 当读取数据完成,触发事件Read.readone(),然后将数据通过LED显示出来

可以看出,SenseC应用程序是事件驱动的,即每隔一段时间触发一次定时器事件,然后在事件中执行采集数据的任务。这种编程的模式是tinyos编程普遍的做法,几乎每个TinyOS都是采用事件驱动模式的,在这里是采样事件,在另外一些应用程序可能是串口事件和无线电收发事件。

现在你可能有这样的疑问:Sense程序中ADC访问的究竟Telosb中的哪个传感器,是温度传感器,电压传感器还是光电传感器呢?我们通过查看Sense配件可以得到答案。 Sense.nc

configuration SenseAppC {

//该模块不提供接口 }

implementation {

components SenseC, MainC, LedsC, new TimerMilliC(), new DemoSensorC() as Sensor;

SenseC.Boot -> MainC; SenseC.Leds -> LedsC;

SenseC.Timer -> TimerMilliC; SenseC.Read -> Sensor; }

SenseAppC.nc组件和BlinkAppC组件类似。其中Read接口是由DemoSensorC提供的。

DemoSensorC.nc

generic configuration DemoSensorC() {

provides interface Read; }

implementation {

components new VoltageC() as DemoSensor; Read = DemoSensor; }

Page 29 of 94

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 2.x 入门教程 - 图文(7).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:口语交际四(导学案)

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: