nesC语言特定:组件化 + 基于事件驱动 = 能很好地支持并发
1、组件(components)
{
uses interface Timer as Timer0;
uses interface Timer as Timer2;
uses interface Leds;
uses interface Boot;
}
注解:Timer[TMilli]当串连提供者和使用者的接口带有类型参数时,它们的类型必须相互匹配
3、BlinkC在调用这些接口所定义的命令(Command)的同时必须实现接口所定义的事件的处理函数(Event)
6. 程序编译
1、nesC的编译器会根据用户所指定的平台编译生成一个对应于特定平台的C源文件。
2、nesC依据不同的微控制器使用一个对应的本地GNU的C编译器将产生的C源文件编译成可执行文件并将其下载到对应硬件平台上
7. TinyOS应用程序中的并发模型(这个还不是很理解,到时要修改)
TinyOS程序的执行会涉及到两个线程:任务Task、硬件事件处理器(Event Handler)
1、任务:执行一些比较耗时的操作,可以被硬件事件中断抢占
2、事件中断:可以抢占任务的执行,具有实时性
3、命令和事件要作为事件中断来执行,则必须用关键字async来声明。
4、任务和事件中断是可以被其它异步代码抢占的,存在一定的数据竞争,可能导致数据的不一致或错误。为避免竞争而带来的错误产生,可以在任务内排外地访问数据,或者每次访问都采用原子 (atomic) 语句
8. 常用的make命令
1、make [platform]:此命令是将nesC
代码编译成可在特定平台运行的代码,在执行前要切换到代码所在的目录;
2、make [platform] reinstall:使用 make [platform]命令后,就可以将在某平台的可执行代码下载到对应的平台上了
3、make [platform] install :此命令的功能相当于先执行命令make [platform],再执行命令make [platform] reinstall。
4、make clean 此命令删除上述编译命令产生的文件及文件夹;
5、make [platform] docs :此命令生成程序使用的所有组件、接口的关系的
文件。生成的文件在tinyos-2.x\doc\nesdoc 目录下,其中索引文件为 “index.html”
/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;
}
1、 非顶层配置组件也可以使用和提供接口,顶层配置组件不需要provides和uses接口:
configuration BlinkAppC
{
}
2、components那行列出了此配件用到的一组组件。分别是MainC,BlinkC和LedsC和三个计时器,所以需要使用new关键字创建三个计时器的实例,然后分别用as被重命名为Timer0、Timer1和Timer2。
components MainC, BlinkC, LedsC;
components new TimerMilliC() as Timer0; components new TimerMilliC() as Timer1; components new TimerMilliC() as Timer2;
3、 再往下就是组件之间的接口的连接了。BlinkC使用了Boot接口,而MainC正好提供了BlinkC所需的Boot接口,所以我们将他们进行连接(即接口的使用者绑定到接口的提供者)。
BlinkC.Boot->Mainc.Boot
意为:Blink组件内使用的Boot接口由MainC组件提供
因为BlinkC内部就使用了一个Boot接口,所以BlinkC后面的
Boot可以被省略了。
3. Blink应用程序的模块组件:BlinkC.nc
BlinkC.nc代码:
include "Timer.h"
module BlinkC
{
uses interface Timer as Timer0;
uses interface Timer as Timer1;
uses interface Timer 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()
{
dbg("BlinkC", "Timer 0 fired @ %s.\n", sim_time_string());
call Leds.led0Toggle();
}
event void Timer1.fired()
{
dbg("BlinkC", "Timer 1 fired @ %s \n", sim_time_string());
call Leds.led1Toggle();
}
event void Timer2.fired()
{
dbg("BlinkC", "Timer 2 fired @ %s.\n", sim_time_string());
call Leds.led2Toggle();
}
}
1、在模块BlinkC的声明内(module BlinkC{})表明了该程序需要用到的全部接口;
2、在实现部分(implementation{})需要实现所有我们用到的接口的事件(接口内的命令,则由接口的提供者负责实现。)
3、在booted事件中,也就是程序启动以后,我们的主要任务就启动三个计时器(调用call使用的接口中实现了的命令方法)
event void Boot.booted()
{
//startPeriodic是一个启动计时器的命令
call Timer0.startPeriodic( 250 );
call Timer1.startPeriodic( 500 );
call Timer2.startPeriodic( 1000 );
}
4、另一个需要我们处理的事件就是计时器的触发,因为有三个计时器,所以需要书写三个触发事件:
event void Timer0(1、2).fired()
{
dbg("BlinkC", "Timer 0 fired @ %s.\n", sim_time_string());
call Leds.led0Toggle();
}