TinyOS学习笔记作者幽暗天琴.docx
《TinyOS学习笔记作者幽暗天琴.docx》由会员分享,可在线阅读,更多相关《TinyOS学习笔记作者幽暗天琴.docx(23页珍藏版)》请在冰豆网上搜索。
![TinyOS学习笔记作者幽暗天琴.docx](https://file1.bdocx.com/fileroot1/2023-2/1/650a7214-30c4-455c-bdbc-d71b41347447/650a7214-30c4-455c-bdbc-d71b413474471.gif)
TinyOS学习笔记作者幽暗天琴
TinyOS学习笔记1---入门
当我们uses某接口时,那么该接口下的所有command和event都可以调用。
在一些情况下,组件也可以provides和uses
Command。
同样的provides的组件要实现command的函数内容。
配置文件
现在,我们已经知道某些组件提供的接口,但,仅仅通过这还不足以访问这个组件。
如果a,b同时都提供了一个接口c,那么,当组件d访问c接口时访问的到底是a还是b呢?
所以配置文件就产生了,它的目的就是声明你要访问的组件名称,并且将它所提供的接口与你想要使用的接口相连接。
配置文件的构成
配置文件configuration首先声明了其应用程序下的组件,关键字:
components.
声明了组件之后,通过->可以将两个组件的接口连接起来。
Main.StdControl->BlinkM.StdControl;
这段代码就是把组件main和blinkm的stdcontrol连接起来,这样,就建立了两个组件之间的联系。
当调用main.stdcontrol的时候就相当于调用了blinkm.stdcontrol。
关键字->永远是将一个使用(uses)的接口(左边)于一个提供(provides)的接口(右边)相连接。
也就是说只有左边的组件能够调用右边的组件的接口。
反之则不可以。
并且该关键是一个多对多的关系,即一个组件可以连接到很多接口,反之一样
配置文件还可以通过=关键字来进行接口之间的连接,=号表示两个接口之间的关系是等同的,类似于c语言中的指针。
=号两边可以是uses=pro
也可以是u=u,p=p.
注:
配置文件中也可以使用或提供接口。
(后面有例子)
配置文件和顶级配置文件
一个程序中可以有多个配置文件,但一定要有一个顶级配置文件。
在tinyos中组件也是分层次的。
最底层的组件贴近硬件部分,是经过一层一层封装才有了上层的组件,封装的过程中就使用了配置文件。
而一个应用程序需要一个顶级配置文件,在所有其他的配置文件的更高一层,编译时会首先参照该文件进行编译。
程序组成
程序实例:
blink
现在我们要编写一个程序,是传感器上的灯每一秒闪烁一次。
首先,我们要根据实际情况去筛选我们所需要的组件。
控制亮灯的组件:
ledc.
控制时间的组件:
singletime.
控制程序开始的组件:
main.程序开始从这里运行所以要通过这个组件带动blinkm.再通过blinkm中的函数控制ledc和singletime.
控制程序逻辑上下文:
blinkm.在该文件中表达逻辑思路。
因此该组件需要连接到时间和亮灯的组件接口上。
编写配置文件
Blink.nc
configurationBlink{}implementation{componentsMain,BlinkM,SingleTimer,LedsC;Main.StdControl->BlinkM.StdControl;Main.StdControl->SingleTimer.StdControl;BlinkM.Timer->SingleTimer.Timer;BlinkM.Leds->LedsC;}
StdControl接口
interfaceStdControl{commandresult_tinit();commandresult_tstart();commandresult_tstop();}
Result_t是一个数据类型,表示uint8_t
该接口用来初始化和启动TinyOS组件。
我们需要知道,tinyos中,任何组件使用之前都需要进行初始化,有些组件会提供如stdcontrol的接口比如singletime我们就可以用它实现该组件的初始化。
编写blinkm.nc
通过我们知道要使用一个组件或者模块必须先要启动它,而main又usesstdcontrol来实现blinkm和singletime的启动,因此我们blinkm一定要提供stdcontrol的接口,并且实现它。
同时,blink需要控制ledc和singletime因此它还需要使用他们所提供的接口leds,timer。
Blinkm.nc
moduleBlinkM{
provides{
interfaceStdControl;
}
uses{
interfaceTimer;
interfaceLeds;
}
Stdcontrol的实现
implementation{
commandresult_tStdControl.init(){
returnSUCCESS;
}
commandresult_tStdControl.start(){
}
commandresult_tStdControl.stop(){
}
在前面我们说过,没一个组件使用之前都需要初始化,现在我们还剩下led没有进行初始化,观看该接口的函数,我们通过添加callLeds.init();进行此接口的初始化。
再让我们看看timer接口。
Timer接口
Timer.nc
interfaceTimer{
commandresult_tstart(chartype,uint32_tinterval);
commandresult_tstop();
eventresult_tfired();
}
Start()命令被用于指定timer的类型和那些即将过期的时间间隔。
我们使用毫秒来计算时间间
隔。
有TIMER_REPEAT和TIMER_ONE_SHOT两种可用的类型。
在指定的时间间隔过后,timer将会结束,
下一个重复的timer将会继续执行,直到被stop()命令所终止。
当一个间隔到来时,事件fired()被触发。
因此我们的设计思路如下:
在blinkm初始化时我们需要对所有组件进行启动,然后开始设置时间间隔,当一个时间间隔过后,事件函数被触发,callLeds.redToggle();使红灯亮起。
经修改,blinkm.nc如下:
Blinkm.nc
implementation{
commandresult_tStdControl.init(){
callLeds.init();
returnSUCCESS;
}
commandresult_tStdControl.start(){
returncallTimer.start(TIMER_REPEAT,1000);
}
commandresult_tStdControl.stop(){
returncallTimer.stop();
}
eventresult_tTimer.fired()
{
callLeds.redToggle();
returnSUCCESS;
}
}
关系图
命令是一层一层向下传递
事件是一层一层向上传递
当timer到期时。
首先发生硬件中断然后将此时间向上传递到timer.fired()中,我们再callleds.red()
编译
Vi,写字板可以进行.nc的创建编译
通过gywin我们到apps/blink目录,输入makemicazncc编译起会产生一个main.exe文件,而这就是我们需要灌到板子上的程序。
但通过软件将程序下载到传感器时无法识别程序的型号,所以采用在blink目录下输入makemicazinstalleprb,ip的方法也可以将程序下载到传感器当中,经过实验第二种方法可以成功实现blink程序。
之所以输入makeplatform就可以进行编译是因为该目录先有一个makefile的脚本。
在以后的实验中,一个新程序的编译脚本将由我们自己来编写。
如果没有该文件那么要进行编译就要输入
ncc-omain.exe-target=micaBlink.nc
小结
我们所操作的仅仅是上层部分。
我们所使用的模块和组件都是经过一层一层封装。
程序真正的入口是在raelmain.nc底下
当然,因为这涉及到底层的调用,我们可以不关心这一点。
但我们要知道的是,就像是c++,c#一样,系统组件和将来我们编写自己的组件一样都需要进行封装。
模块内部声明的变量都是局部私有的变量。
如果需要声明全局函数或者变量要用到_attribute_.
关于blink程序的补充
关于blink的代码只有configuration和module两个.nc文件,但是,如果只用这两个文件的是编译不出来main.exe的。
这是因为singletime并不是一个系统组件,他是一个非系统的配置文件。
我们来看下他的代码
singletimer.nc
configurationSingleTimer{
providesinterfaceTimer;
providesinterfaceStdControl;
}
implementation{
componentsTimerC;
Timer=TimerC.Timer[unique("Timer")];
StdControl=TimerC;
}
Singletime.nc
Timerc是一个时间集。
Singletime是对timerc的一个封装。
从其中抽象出来了一个时间timer。
启示:
使用配置文件可以对原有系统组件进行封装。
编译时类似文件需要添加在一个文件夹内一起编译。
Tinyos调度机制
TinyOS中的调度机制比较简单,它仅设置一个任务队列。
关键字post将一个任务添加到任务队列中。
TinyOS的调度遵循FIFS(先来先服务)规则
当事件发生时发生抢占。
总结
Tinyos事件驱动。
程序调度使用任务列表,当事件发生时产生中断处理,没有事件发生时任务列表按着fifs进行处理,因为我们是在post一个个的任务,同时当事件发生时编写时间处理函数。
Nesc语言组件之间通过接口和配置文件进行联系。
每个模块要声明自己使用和提供的接口,当提供一接口,就要实现其command函数,当使用一个接口就要实现其event函数。
调用command函数时使用call关键字,发送event事件时使用signal关键字。
认识到tinyos程序是层次化的。
命令由顶层向底层传递,而事件有底层向顶层传递。
函数和接口通过一步步的封装成为模块,模块又可以通过配置文件的封装成为新的组件。
编译的过程中,自定义的组件都要一起编译。
系统中所有的应用程序都放在opt/tinyos-1.x/apps中
系统中所有的系统组件都方在opt/tinyos-1.x/tos/system下
系统中所有的接口都放在opt/tinyos-1.x/tos/interface
通过命令makeplatformdocs可以在opt/tinyos-1.x/doc/nesc/生成sourcetree和组件关系图。
TinyOS学习笔记2---连接
永远箭头左边是use
关于通信的时候
顶级配置文件要使用箭头
configurationRfmToLeds{
}
implementation{
componentsMain,RfmToInt,IntToLeds;
Main.StdControl->IntToLeds.StdControl;
Main.StdControl->RfmToInt.StdControl;
RfmToInt.IntOutput->IntToLeds.IntOutput;
}
configurationRfmToInt{
providesinterfaceStdControl;
usesinterfaceIntOutput;在这里此地使用的是use接口是因为rfmtoint要调用intoutput接口顶级配置文件
可以把他方在左边是他调用别人同时有些数据结构使用时要加上头文件才可以用
}
implementation{
componentsRfmToIntM,GenericComm;
IntOutput=RfmToIntM;
StdControl=RfmToIntM;
RfmToIntM.ReceiveIntMsg->GenericComm.ReceiveMsg[AM_INTMSG];
RfmToIntM.CommControl->GenericComm;
}
sense程序中
configurationSense{
//thismoduledoesnotprovideanyinterface
}
implementation
{
componentsMain,SenseM,LedsC,TimerC,Photo;
Main.StdControl->SenseM;
Main.StdControl->TimerC;
SenseM.ADC->Photo;
SenseM.ADCControl->Photo;
SenseM.Leds->LedsC;
SenseM.Timer->TimerC.Timer[unique("Timer")];
}
和
configurationSense{
//thismoduledoesnotprovideanyinterface
}
implementation
{
componentsMain,SenseM,LedsC,TimerC,DemoSensorCasSensor;
Main.StdControl->Sensor;
Main.StdControl->TimerC;
Main.StdControl->SenseM;
SenseM.ADC->Sensor;
SenseM.ADCControl->Sensor;
SenseM.Leds->LedsC;
SenseM.Timer->TimerC.Timer[unique("Timer")];
}
两者相同一个是使用了main.stdcontrol接口来初始化sensor但在模块内部没有实现其中的adccontrol接口
另一个是没有使用main进行初始化而是使用了adccontrol接口在模块中初始化语句如下:
commandresult_tStdControl.init(){
returnrcombine(callADCControl.init(),callLeds.init());
}
/**
*
从这里我们可以知道使用了一个接口但并不一定要在实现中出现其中的函数。
今日完成:
编译blink程序并且改名之后再次编译都成功将blink中的red改为green也成功最后绿灯每秒亮一次
编译了sense程序得知该程序是在传感器中取得数据,并且将数据通过led显示出来
得到的硬件依赖于光线或者温度传感器。
看了关于传感器之间的通信,阅读其中的源代码发现use的另类使用方法。
在下载程序到传感器的时候扳子和传感器的接口一定要连接紧密同时也许要reset编程主板。
有些程序要使用头文件发现一些程序在lib以下以前没有注意到过photo
D:
\学习\tinyos-1.x\tos\sensorboards\basicsb下面。
TinyOS学习笔记3
弄明白了cnttoledandrfm和rfmtoled两个程序
知道了组件和组件之间如何进行工作
同时只有前者的程序时也可以接收到数据但接收到的数据没有编写事件处理函数所以不显示。
初次使用模拟器进行模拟节点的之间的数据通信
configurationRfmToLeds{
}
implementation{
componentsMain,RfmToInt,IntToLeds;
Main.StdControl->IntToLeds.StdControl;
Main.StdControl->RfmToInt.StdControl;
RfmToInt.IntOutput->IntToLeds.IntOutput;
}
includesIntMsg;
configurationRfmToInt{
providesinterfaceStdControl;
usesinterfaceIntOutput;
}
implementation{
componentsRfmToIntM,GenericComm;
IntOutput=RfmToIntM;
StdControl=RfmToIntM;
RfmToIntM.ReceiveIntMsg->GenericComm.ReceiveMsg[AM_INTMSG];
RfmToIntM.CommControl->GenericComm;
}
includesIntMsg;
moduleRfmToIntM{
providesinterfaceStdControl;
uses{
interfaceReceiveMsgasReceiveIntMsg;
interfaceIntOutput;
interfaceStdControlasCommControl;
}
}
implementation{
commandresult_tStdControl.init(){
returncallCommControl.init();
}
commandresult_tStdControl.start(){
returncallCommControl.start();
}
commandresult_tStdControl.stop(){
returncallCommControl.stop();
}
eventTOS_MsgPtrReceiveIntMsg.receive(TOS_MsgPtrm){
IntMsg*message=(IntMsg*)m->data;
callIntOutput.output(message->val);
returnm;
}
eventresult_tIntOutput.outputComplete(result_tsuccess){
returnSUCCESS;
}
}
进行了通信结点的试验结果和预期想符合当两者都同cnttoledandrfm时都是以广播形式
向外发送数据只有当另一者为rfmtoled时才进行了接收事件的处理使leds组件工作。
分配ip时如果找不到设备可以手动添加输入ip
数据显示文档的阅读。
TinyOS学习笔记4
uartcomm组件是什么发送和接受数据的一个组件封装于底层类似于genericcomm
该程序是通过adc先接受来自传感器上的数据然后通过通信组件将数据发送到本地然后接受再读取数据并且把他显示在pc上面。
configurationOscilloscope{}
implementation
{
componentsMain,OscilloscopeM
TimerC
LedsC
DemoSensorCasSensor
UARTCommasComm;
Main.StdControl->OscilloscopeM;
Main.StdControl->TimerC;
OscilloscopeM.Timer->TimerC.Timer[unique("Timer")];
OscilloscopeM.Leds->LedsC;
OscilloscopeM.SensorControl->Sensor;
OscilloscopeM.ADC->Sensor;
OscilloscopeM.CommControl->Comm;
OscilloscopeM.ResetCounterMsg->Comm.ReceiveMsg[AM_OSCOPERESETMSG];
OscilloscopeM.DataMsg->Comm.SendMsg[AM_OSCOPEMSG];
}
moduleOscilloscopeM
{
providesinterfaceStdControl;
uses{
interfaceTimer;
interfaceLeds;
interfaceStdControlasSensorControl;
interfaceADC;
interfaceStdControlasCommControl;
interfaceSendMsgasDataMsg;
interfaceReceiveMsgasResetCounterMsg;
}
}
implementation
{
uint8_tpacketReadingNumber;
uint16_treadingNumber;
TOS_Msgmsg[2];
uint8_tcurrentMsg;
commandresult_tStdControl.init(){
callLeds.init();
callLeds.yellowOff();callLeds.redOff();callLeds.greenOff();
//turnonthesensorssothattheycanberead.
callSensorControl.init();
callCommControl.init();
atomic{
currentMsg=0;
packetReadingNumber=0;
readingNumber=0;
}
dbg(DBG_BOOT,"OSCOPEinitialized\n");
returnSUCCESS;
}
commandresult_tStdControl.start(){
callSensorControl.start();
callTimer.start(TIMER_REPEAT,125);
callCommControl.start();
returnSUCCESS;
}
commandresult_tStdControl.stop(){
callSensorControl.stop();
callTimer.stop();
callCommControl.stop();
returnSUCCESS;
}
taskvoiddataTask(){
structOscopeMsg*pack;
atomic{
pack=(structOscop