资源描述
TinyOS系统与nesC程序设计课内实验指导书
一、 课内实验项目一览表
序号
实验项目
学时
类型
每组
人数
基本教学要求
1
编程环境的建立
2
2
1
熟悉TinyOS安装过程,了解系统环境
2
Blink—TinyOS编程的“Hello World”
2
2
1
通过Blink程序,理解TinyOS编程结构
3
TinyOS任务及应用举例
2
2
1
通过实验了解任务的建立、调度及其作用
4
节点间的无线通信
2
2
1
通过实验了解和使用基本通信接口和组件
5
节点与PC的通信
2
2
1
了解数据包源和串口通信
6
传感
2
2
1
了解节点如何从环境中采集数据并显示在PC上
7
存储
2
2
1
了解TinyOS上永久数据存储方法及应用
8
多线程程序设计
2
2
1
了解线程工作原理和实现方法
二、详细实验指导书
实验一:编程环境建立
一 实验目的
1、 掌握Java基本开发环境(JDK)的安装和配置方法。
2、 掌握cygwin程序的安装,在建立windows下类似Unix环境。
3、 掌握Linux基本命令及cygwin下安装TinyOS的方法。
二 实验原理
无
三 实验环境
1、运行Windows的PC机,能够连接Internet
2、PC机配置要求:
CPU
最低CR 1GHz,建议P4 2.0以上
内存
最低256M,建议512M以上
硬盘容量
10G以上,cygwin安装盘符大于2 G
操作系统
Windows 2000 系列、Windows XP 系列
四 实验内容和步骤
1、 java jdk安装
首先,我们安装JAVA 开发工具JAVA JDK 1.6
官方下载地址:
安装过程只需下一步……下一步便可,默认安装路径是C:\Program Files\Java
上图是TinyOS 2.0.2 安装时截取的JAVA JDK1.5的图,只供参考。
然后,我们需要设置电脑的环境变量,需要新建两个环境变量,以便使用JDK
具体过程如下:右击我的电脑——〉属性——〉高级——〉环境变量
先新建或编辑系统变量:
变量名(N):JAVA_HOME
变量值(V):JDK安装的路径,其默认的路径为:
C:\Program Files\Java\jdk1.6.0_10
变量名(N):CLASSPATH
变量值(V):
.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
在系统变量(S)栏选中变量为Path的选项,点编辑
在变量值(V)的末尾添加:;%JAVA_HOME%\bin; ;%JAVA_HOME%\jre\bin;
然后新建或编辑用户变量:
同样再设置一个JAVA_HOME,变量值也一样。
在用户变量的PATH中添加:;%JAVA_HOME%\bin:$PATH;%JAVA_HOME%\jre\bin:$PATH;
这样,我们的环境变量已经设置完毕了。我们可以编个JAVA小程序简单地测试一下:打开记事本,输入下面这个小程序,另存为HelloWorld.java(注意扩展名是java,不是txt文本文件)。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
运行cmd,到HelloWorld.java所在目录,执行命令:
javac HelloWorld.java
java HelloWorld
如果能正确输出Hello, World! 说明环境变量设置成功。
2、 cygwin软件平台安装
我们需要安装Cygwin这个软件来虚拟Linux平台,运行TinyOS-2.X。
下载地址1:.
下载地址2:http://cone.informatik.uni-freiburg.de/people/aslam/cygwin-files.zip
安装时,最好先将安装包下载到本地,然后选择Install from Local Directory安装。
紧接着需要设置安装目录,默认是C:\cygwin
然后是选择下载的本地安装包源文件的文件路径
安装包策略选择:“Keep”、“Prev”、“Curr”、“Exp”等等选项
Keep, 意思就是说保持目前已经安装的版本不动,不替换你目前的版本。升级时比较方便。
Prev,意思是说安装上一个版本。
Curr,意思就是说把最新的版本下载下来安装,第一次安装时默认选项
"View"按钮是用来选择显示方式的
在选择安装包时候,一般默认,点下一步即可。
最后我们可以通过桌面上添加Cygwin的快捷方式或者运行安装目录下的cwgwin.bat文件,来运行该软件平台。第一次运行Cygwin会稍微慢点。
Cygwin启动界面如下图:
下面我们可以先来尝试一些简单的Linux命令:
help: 帮助命令。例如 ls --help 。显示ls命令使用说明。
pwd:显示所在路径。
rpm –qa :查看已经安装的程序,刚安装的Cygwin是没有安装任何系统的。
rpm –ivh 文件名:rpm文件安装。
rpm –ignoreos –force或者rpm -ivh --force --ignoreos:忽略错误,安装rpm文件
--ignoreos选项是用于忽略cygwin的版本号
rpm –uvh 文件名:rpm文件升级安装。
cd:切换目录 比如:cd /tmp 进入tmp文件。
cp:cp -R Blink BlinkSingle:复制文件或目录,复制Blink为BlinkSingle。
ls:显示当前目录下的文件。
whoami:显示登陆Windows帐号
uname –a: 显示版本信息
echo $PATH: 显示执行程式的搜索路径
ps ax: 显示process list ,显示目前有哪些process 执行
ctrl-D或exit 或logout:结束bash 视窗
motelist 查询当前设备
3、 本地编译器安装
当你给低功耗微控制器编译代码时,你需要可以产生适当的代码的编译器。如果你使用mica系列无线传感器节点,你需要的AVR工具;如果你使用的是telos系列节点,则需要的MSP430工具。
先以AVR为例,在根目录下创建文件夹avr,把下面所有rpm文件放在这个文件夹里。
l avr-binutils-2.17tinyos-3.cygwin.i386.rpm :
l avr-gcc-4.1.2-1.cygwin.i386.rpm :
l avr-libc-1.4.7-1.cygwin.i386.rpm :
l avarice-2.4-1.cygwin.i386.rpm :
l avr-insight-6.3-1.cygwin.i386.rpm :
l avrdude-tinyos-5.6cvs-1.cygwin.i386.rpm :
用cd命令进入该文件夹目录,输入:rpm -ivh --ignoreos rpmname.rpm 可以选择安装rpmname这个rpm包。
如果碰到missing /bin/sh的错误信息,则
rpm –ivh --ignoreos --force --nodeps rpmname.rpm
最简单的方法是,同时安装这个文件夹下所有的rpm包,输入命令:
$ cd /avr
$ rpm -ivh --ignoreos --force --nodeps *.rpm
MSP430工具包的安装方法也是一样的。其rpm包如下:
l msp430tools-base-0.1-20050607.cygwin.i386.rpm :
l msp430tools-python-tools-1.0-1.cygwin.noarch.rpm :
l msp430tools-binutils-2.16-20050607.cygwin.i386.rpm :
l msp430tools-gcc-3.2.3-20050607.cygwin.i386.rpm :
l msp430tools-libc-20080808-1.cygwin.i386.rpm :
在根目录下新建的MSP430文件夹,将所有rpm下载后全部放到这里,运行:
$ cd /msp430
$ rpm -ivh --ignoreos --force --nodeps *.rpm
安装成功。(若提示安装不了,可以先安装第四步的TinyOS工具包再回头安装这里)。
4、 TinyOS工具包安装
下载rpm包:
l Nesc :
l deputy :
l tinyos-tools :
安装方法同上面一样。
将rpm下载后全部放到一个根目录下新建的tinyos_tools文件夹,运行:
$ cd /tinyos_tools
$ rpm -ivh --ignoreos *.rpm
注:在win7或者是vista下安装nesC时可能会报错如下:unpacking of archive failed on file /usr: cpio: chmod failed - Permission denied
解决方法:运行cygwim的时候右键选择 “以管理员身份运行”
5、 TinyOS 2.x安装
下载rpm包:
安装方法同上面一样
$ cd /tinyos
rpm -ivh --ignoreos *.rpm
安装成功。
6、 设置TinyOS2.x环境变量
Environment Variable
Windows
Linux
TOSROOT
/opt/tinyos-2.x
same as in Cygwin
TOSDIR
$TOSROOT/tos
same as in Cygwin
CLASSPATH
C:\cygwin\opt\tinyos-2.x\support\sdk\java\tinyos.jar;.
$TOSROOT/support/sdk/java/tinyos.jar:.
MAKERULES
$TOSROOT/support/make/Makerules
same as in Cygwin
PATH†
/opt/msp430/bin:/opt/jflashmm:$PATH
same as in Cygwin
†注:只有在使用msp430平台时才有必要设置PATH变量
用UltraEdit创建C:\cygwin\etc\profile.d\tinyos.sh,输入以下内容:(使用UNIX换行符-LF保存,这一步很关键,字符是有区别的)(配置文件已经写好了)
# script for profile.d for bash shells, adjusted for each users
# installation by substituting /opt for the actual tinyos tree
# installation point.
export TOSROOT="/opt/tinyos-2.x"
export TOSDIR="$TOSROOT/tos"
export CLASSPATH="C:\cygwin\opt\tinyos-2.x\support\sdk\java\tinyos.jar"
export CLASSPATH="$CLASSPATH;."
export MAKERULES="$TOSROOT/support/make/Makerules"
export PATH="/opt/msp430/bin:$PATH"
export PATH="/cygdrive/c/Program Files/Java/jdk1.6.0_10/bin:$PATH"
执行命令: tos-install-jni
如果出现一下错误信息:
Installing 32-bit Java JNI code in /cygdrive/c/Program Files/Java/jdk1.6.0_10/jr
e/bin ...
install: cannot stat `/usr/lib/tinyos/*-32.dll': No such file or directory
我们需要将以下目录中的toscomm.dll,重命名为:toscomm-32.dll
C:\cygwin\lib\tinyos
C:\Program Files\Java\jdk1.6.0_10\jre\bin
toscomm.dll ——toscomm-32.dll
重新tos-install-jni命令。
7、 安装 Graphviz
下载地址:http://webs.cs.berkeley.edu/tos/dist-1.1.0/tools/windows/graphviz-1.10.exe,
默认安装到C:\Program Files\ATT目录下。一直点NEXT就可以完成安装。
8、 测试安装
1.环境测试:
运行cygwin,输入命令:
$ tos-check-env
如果上述安装成功,可能会出现WARNING:java 1.4 or java1.5,tos-check-env completed without error等,这是JAVA版本的问题,不必理会。
$ which java
正常情况出现:/cygdrive/c/Program Files/Java/jdk1.6.0_10/bin/java
如果出现/cygdrive/c/WINDOWS/system32/java
则尝试输入:export PATH="/cygdrive/c/Program Files/Java/jdk1.6.0_10/bin:$PATH"
2、检查己经让TinyOS build system环境可运行的.
输入如下命令:
$ printenv MAKERULES
如果看到:/opt/tinyos-2.x/support/make/Makerules 这是正确的
五 实验报告要求
①实验名称
②实验内容说明
③程序源代码
④实验步骤,实验中出现的问题,观察到的结果
⑤实验总结
实验二:Blink——TinyOS编程的“Hello World”
一 实验目的
1、 掌握Linux基本命令及其使用。
2、 掌握安装应用程序到节点(如telosb)的方法。
3、 掌握nesC语言语法风格、组织、命名和连接组件的机制。
4、 掌握组件中命令(command)和事件(event)接口的使用。
5、 掌握模块(module)和配件(configuration)的作用及使用方法。
二 实验原理
TinyOS操作系统、库和程序服务程序是用nesC写的。
◆ nesC是一种开发组件式结构程序的语言。
◆nesC是一种C语法风格的语言,但是支持TinyOS的并发模型,以及组织、命名和连接组件成为健壮的嵌入式网络系统的机制。
◇nesC应用程序是由有良好定义的双向接口的组件构建的。
◇nesC定义了一个基于任务和硬件事件处理的并发模型,并能在编译时检测数据流组件。
◆规范
◇nesC应用程序由一个或多个组件连接而成
◇一个组件可以提供或使用接口
●组件中command接口由组件本身实现
●组件中event接口由调用者实现
●接口是双向的,调用command接口必须实现其event接口
◆实现
◇modules
●包含应用程序代码,实现接口
◇configurations
●装配模块,连接模块使用的接口到其提供者
●每个nesC应用程序都有一个顶级configuration连接内部模块
●并发模型
◆TinyOS只能运行单个由所需的系统模块和自定义模块构成的应用程序
◆两个线程
◇任务
●一次运行完成,非抢占式
◇硬件事件处理
●处理硬件中断
●一次运行完成,抢占式
●用于硬件中断处理的command和event必须用async关键字声明
◆执行流程(race conditions)
◇nesC要避免任务排他性访问共享数据
◇nesC要避免所有共享数据访问都通过原子语句
◇nesC在编译过程中要检测数据流,但可能误报,可用norace关键字声明不检测,但对其使用 应格外小心
三 实验环境
1、JDK1.6 for windows
2、Cygwin with TinyOS 2.x
3、UltraEdit / EditPlus
四 实验内容和步骤
1、实验内容:
(1) 进入tmp文件夹并创建文件夹,取名Blink,进入这个文件夹。
cd /tmp
mkdir Blink
cd Blink
(2) 定义一个Blink配件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;
}
(3) 定义一个Blink配件BlinkC.nc。
#include "Timer.h"
module BlinkC
{
uses interface Timer<TMilli> as Timer0;
uses interface Timer<TMilli> as Timer1;
uses interface Timer<TMilli> as Timer2;
uses interface Leds;
uses interface Boot;
}
implementation
{
event void Boot.booted()
{
call Timer0.startPeriodic( 250 );
call Timer1.startPeriodic( 500 );
call Timer2.startPeriodic( 1000 );
}
event void Timer0.fired()
{
call Leds.led0Toggle();
}
event void Timer1.fired()
{
call Leds.led1Toggle();
}
event void Timer2.fired()
{
call Leds.led2Toggle();
}
}
(4) 新建一个Makefile文件。
COMPONENT=BlinkAppC
include $(MAKERULES)
(5)新建一个说明文档README(可选)
(6)编译程序
make telosb
(7)下载到telosb节点,观察实验结果
make telosb reinstall.ID bsl,serialport.
(8) 用nesdoc显示程序结构和配件组成,然后进入/tinyos-2.x/doc/nesdoc,打开index.html
make telosb docs
(9)编写实验报告
五 实验报告要求
①实验名称
②实验内容说明
③程序源代码
④实验步骤,实验中出现的问题,观察到的结果
⑤实验总结
实验三:TinyOS任务及应用举例
一 实验目的
1、 了解TinyOS两层调度策略:任务和硬件事件句柄。
2、 掌握任务(Task)的建立、提交及其作用。
3、 掌握nesC语法中的分相操作(split-phase operation)。
4、 理解BlinkTask应用程序。
二 实验原理
1、任务(Task)
TinyOS 提供任务和硬件事件句柄组成的两层调度策略。关键字 async 声明了可被硬件事件句柄执行的命令或事件。这意味着它可以在任何时候执行(可能会抢占其它代码的执行)。因此,用 async 声明的命令和事件所做的工作应该做尽量少,且要快速完成。此外,还得注意被异步命令或事件访问的数据可能存在的数据竞争。任务则被用来处理一些较长时间的操作,例如:后台数据处理,但任务可以被硬件事件句柄抢占。
一个任务可以用以下语法在你的实现模块中声明:
task void taskname() {
//……
}
其中,taskname 是程序员任意指定的任务的标识,也就是“函数名”。一个任务的返回值类型必须是void,并且不能有任何参数。而向操作系统提交任务则可以用以下语法:
post taskname();
一个任务可以在命令、事件或其它任务内部向操作系统提交。
post 操作把任务放置到一个以先进先出为处理方式的内部任务队列中去。当一个任务开
始执行的时候,只有它运行结束,下一个任务才能开始运行;因此,一个任务不应该占用或阻塞太长时间。任务之间不可以互相抢占,但是会被硬件事件句柄抢占。如果你的任务需要执行一系列长时间的操作,最好把任务分成几个而不是使用一个大的任务。
2、分相(split-phase)操作
在TinyOS中每一个长时间运行的操作都是分相的。在阻塞系统中,当一个调用长时间运行的操作时,只有操作完成时调用才会返回;而在分相系统中,调用会立即返回,当操作完成会发出callback。
分相操作相对于顺序代码有些复杂,但他可以使操作并行并且节省内存。Timer.StartOneShot就是一个分相调用的例子。
if (send() == SUCCESS) {
sendCount++;
}
// start phase
send();
//completion phase
void sendDone(error_t err) {
if (err == SUCCESS) {
sendCount++;
}
}
阻塞(Blocking)
分相(Split-Phase)
三 实验环境
1、JDK1.6 for windows
2、Cygwin with TinyOS 2.x
3、UltraEdit / EditPlus
四 实验内容和步骤
(1) 进入tmp文件夹并创建文件夹,取名BlinkTask,进入这个文件夹。
cd /tmp
mkdir BlinkTask
cd BlinkTask
(2) 把Blink文件夹里的所有文件复制到BlinkTask中。
cp –r /opt/tinyos-2.x/apps/Blink/* /tmp/
(3) 现给程序设置一个较长的计算任务。用UltraEdit打开模块文件BlinkC.nc,并修改如下:
#include "Timer.h"
module BlinkC
{
uses interface Timer<TMilli> as Timer0;
uses interface Timer<TMilli> as Timer1;
uses interface Timer<TMilli> as Timer2;
uses interface Leds;
uses interface Boot;
}
implementation
{
event void Boot.booted()
{
call Timer0.startPeriodic( 250 );
call Timer1.startPeriodic( 500 );
call Timer2.startPeriodic( 1000 );
}
event void Timer0.fired()
{
uint32_t i;
for (i = 0; i < 400001; i++) {
call Leds.led0Toggle();
}
}
event void Timer1.fired()
{
call Leds.led1Toggle();
}
event void Timer2.fired()
{
call Leds.led2Toggle();
}
}
(4) 编译程序并把它下载到节点观察三盏灯情况,记录结果。若第一盏灯没有闪烁,则将值改成20001,100001再观察结果。
(5)一个长的计算操作会一直占用CPU,从而阻塞其他操作的执行。所以,我们需要使用建立任务(Task)任务的方法来解决上述问题,重新修改程序。
implementation{
…
task void computeTask() {
uint32_t i;
for (i = 0; i < 400001; i++) {}
}
event void Timer0.fired() {
call Leds.led0Toggle();
post computeTask();
}
…
}
(6)编译、安装程序,观察记录结果。若第一盏灯仍然没有闪烁(想想为什么?),则将代码再次修改如下:
uint32_t i;
task void computeTask() {
uint32_t start = i;
for (;i < start + 10000 && i < 400001; i++) {}
if (i >= 400000) {
i = 0;
}
else {
post computeTask();
}
}
(7)再次编译并安装程序,观察记录结果。
(8)编写实验报告
五 实验报告要求
①实验名称
②实验内容说明
③程序源代码
④实验步骤,实验中出现的问题,观察到的结果
⑤实验总结
实验四:节点间的无线通信
一 实验目的
1、 了解TinyOS消息缓冲抽象—message_t。
2、 掌握用于抽象底层通信服务的基本通信接口名称及它们所实现的功能。
3、 掌握活动消息(AM)接口。
4、 掌握基本通信组件。
5、 理解BlinkToRadio程序代码,实现节点间的无线通信。
二 实验原理
1、message_t:TinyOS的消息缓冲
(1)TinyOS提供了许多接口去抽象底层通信服务,所有的这些接口以及许多提供这些接口的组件使用共同的消息缓冲抽象:message_t(底层通信数据的结构),用nesC结构体实现。
(2)message_t结构:
typedef nx_struct message_t {
nx_uint8_t header[sizeof(message_header_t)];
nx_uint8_t data[TOSH_DATA_LENGTH];
nx_uint8_t footer[sizeof(message_footer_t)];
nx_uint8_t metadata[sizeof(message_metadata_t)];
} message_t;
2、通信接口与组件
Ø 基本通信接口:
(1)Packet:提供对message_t的基本访问
a. 清除消息内容(命令)
b. 得到有效载荷的长度(命令)
c. 得到指向有效载荷地址的指针(命令)
(2)Send:提供与地址无关的发送接口
a. 发送消息内容(命令)
b. 取消挂起消息的发送(命令)
c. 消息是否发送成功(事件)
d. 得到有效载荷的长度(函数)
e. 得到指向有效载荷地址的指针(函数)
(3)Receive:提供基本消息的接收接口
a. 接收消息(事件)
b. 得到有效载荷的长度(命令)
c. 得到指向有效载荷地址的指针(命令)
(4)PacketAcknowledgements:为每个包的请求确认提供机制
(5)RadioTimeStaming:提供时间戳
Ø 活动消息接口
(1)AM层次实现了对radio的多路访问。“AM tpye”涉及到多路复用的领域。
(2)支持AM服务的接口:
a. AMPacket:提供基本的AM访问
b. AMSend:提供基本的AM发送接口
(3)一个节点的AM地址可以在初始化的时候设置:
make install.n or meke reinstall.n
Ø 通信组件:
许多组件实现了基本通信接口与AM接口
(1)AMReceiverC - Provides: Receive, Packet, and AMPacket.
(2)AMSenderC-Provides: AMSend, Packet, AMPacket, RacketAcknowledgements as Acks.
(3)AMSnooperC - Provides Receive, Packet, and AMPacket.
(4)AMSnoopingReceiverC - Provides Receive, Packet, and AMPacket.
(5)ActiveMessageAddressC – 提供用来得到或设置节点AM地址的命令(少用)
三 实验环境
1、JDK1.6 for windows
2、Cygwin with TinyOS 2.x
3、UltraEdit / EditPlus
四 实验内容和步骤
1、重新实现Blink
(1)进入tmp文件夹并创建文件夹,取名BlinkToRadio,进入这个文件夹。
cd /tmp
mkdir BlinkToRadio
cd BlinkToRadio
(2)新建模块文件BlinkToRadio.nc
#include <Timer.h>
#include "BlinkToRadio.h"
module BlinkToRadioC {
uses interface Boot;
uses interface Leds;
uses interface Timer<TMilli> as Timer0;
}
implementation {
uint16_t counter = 0;
event void Boot.booted() {
call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
}
展开阅读全文