【无线传感网】Blink组件的学习_blink_protocol

通过调用这些命令函数和实现这些事件函数,我们可以实现各种LED灯的控制和闪烁效果。例如,我们可以通过调用set命令函数设置LED灯的亮度,通过调用timer.fired事件函数控制LED灯的闪烁频率和模式,从而实现各种闪烁效果。

总之,Blink组件的功能主要是控制LED灯的闪烁,通过调用命令函数和实现事件函数来实现LED灯的控制和闪烁效果。

二、Blink组件相关关系

TinyOS的编程方式采用nesc语言,这是一种类C语言,nesc语言有几个最重要概念:组件,接口,模块。如下图BlinkC程序组件图:

在这里插入图片描述

图1.1:Blink程序组件图

  1. 每一个程序都是由若干组件(component)组成;
  2. 组件有两种类型,一种是模块(module),另一种是配置(configuration);
  3. 配置文件的作用是表明组件之间的关系。模块文件的作用是将程序的具体实现放在其中;
  4. 每个程序都需要一个顶层的配置文件,它的名字是用程序名字命名。

从上图可以发现,BlinkC这个组件是由MainC,TimeMilliC,LedsC组件组成。

  1. 每个component都提供以及使用 interface;
  2. Component提供的interface说明了该组件为使用者提供的功能;
  3. Component使用的interface说明了该组件需要用到的由其他组件提供的功能。
  4. 接口常使用的关键词是command和event。

主要组件及接口的功能介绍:

MainC是blink组件的主要控制器,负责协调各个组件之间的通信和数据传输。

BlinkMilliC是一个定时器组件,用于控制数据采集和传输的时间间隔。

Leds组件用于控制传感器和无线模块的LED指示灯。

boot是一个启动组件,用于初始化blink组件和相关硬件设备。

Timer接口用于控制数据采集和传输的

从图1.1中,箭头的名字表示组件与组件之间访问使用的接口。下面我们结合程序来看下组件、接口、模块的概念。时间间隔。这些接口可以帮助用户构建高效、安全的无线传感网系统。

三、blink目录下三个文件及其源码

Blink目录下面包含Makefile、BlinkAppC.nc、BlinkC.nc三个文件。

BlinkAppC.nc

源码:

configurationBlinkAppC//表示这是一个名为BlinkAppC的配置

{

}

implementation

{//组件申明

componentsMainC,BlinkC,LedsC;

componentsnewTimerMilliC()asTimer0;

componentsnewTimerMilliC()asTimer1;

componentsnewTimerMilliC()asTimer2;

//组件间使用关系定义

BlinkC->MainC.Boot;

BlinkC.Timer0->Timer0;

BlinkC.Timer1->Timer1;

BlinkC.Timer2->Timer2;

BlinkC.Leds->LedsC;

}

在implementation关键字后面的括号内是配置的具体实现。components关键字后面表明了这个配置文件所引用的组件,在这里分别是Main、BlinkC、LedsC以及三个TimerMilliC组件。最后五行表明了各组件间的provider和user的关系。A->B表示了一种关系,其中A为使用方(user),而B为提供方(provider)。命令(command)就是接口提供方已经实现的函数。事件(event)就是需要接口使用方实现的函数。

BlinkC.nc

源码

module BlinkC @safe() //声明了使用到的接口名称,具体语法可以详细查看Nesc语法。

{

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 ); //每250ms触发一次event void Timer0.fired()

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(); //使Led状态反转

}

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();

}

}

注意这里面定义的接口我们可以从BlinkC组件图里面看到,箭头上的接口名称就是在这个区域定义的。

第一行内容表明这是一个名为BlinkC的module,而后括号的内容表明了该module使用的接口(interface)。[注意这个module没有提供接口(provide)]

由于使用方必须实现接口中的event函数。因此我们可以看到该文件中的implement中包含了初始化Boot.booted,以及三个timer计时的event函数的具体实现。在每个timer的触发event函数内容中写明了其需要触发的内容。详见示例程序。

在模块文件的具体实现里面涉及到了TinyOS执行模型,该模块使用了MainC组件的boot接口,以事件的响应的方式作为节点上电后的响应事件。在这里涉及到了接口中常见的用法:命令(command)和事件(event)。在BlinkC模块具体实现中,从节点上电开发,触发Boot接口事件,在该事件中,调用了TimerMilliC组件的Timer接口。

四、用户模块组件BlinkTimerM

4.1 BlinkTimerM的功能

BlinkTimerM是TinyOS中的一个用户模块组件,其主要功能是实现定时器定时事件的产生和处理,在应用程序中常用于实现周期性的数据采集、任务调度等功能。

BlinkTimerM组件主要提供了定时器的功能,通过它可以实现定时事件的产生和处理。在TinyOS中,定时器是一种非常常见的功能,它可以用于周期性任务调度、数据采集、实时控制等各种场景。因此,BlinkTimerM组件在很多应用中都有着广泛的应用。

程序中进行实例化并使用。具体来说,应用程序需要在使用BlinkTimerM组件之前,先定义一个回调函数来处理定时器触发的事件;然后在应用程序初始化中实例化一个BlinkTimerM组件;最后,在需要使用定时器的地方调用BlinkTimerM组件的start()函数即可开始定时器的运行。

此外,BlinkTimerM组件还提供了其他一些API函数,如setTimerPeriod()函数用于设置定时器的重复周期,getTimerPeriod()函数用于获取定时器的重复周期,isRunning()函数用于确定定时器是否正在运行,等等。

总之,BlinkTimerM组件是TinyOS中的一个非常重要的用户模块组件,通过它可以实现周期性的数据采集、任务调度等功能、可以方便地实现定时器功能,并且可以根据实际需求进行灵活的设置和控制、通过它还可以实现周期性任务的调度、实时数据采集和控制等功能,同时还提供了丰富的API函数来满足不同应用的需求。

4.2 BlinkTimerM中主要函数功能流程图及文字说明

4.2.1 流程图

Strt()函数流程图:
在这里插入图片描述

图4.1 start()

fired()函数:

在这里插入图片描述

图4.2 fired()流程图

4.2.2函数文字说明

BlinkTimerM组件中的核心函数之一是start()函数,其功能是启动一个定时器,并设置定时器的触发时间和重复周期。该函数的代码流程如下:

  1. 首先检查定时器是否已经启动,如果已经启动则不执行任何操作,直接返回。
  2. 如果定时器未启动,则初始化定时器,并设置定时器的触发时间和重复周期。
  3. 启动定时器并返回。

另一个核心函数是fired()函数,其功能是在定时器触发时调用应用程序中的回调函数来处理定时事件。该函数的代码流程如下:

  1. 首先检查定时器是否已经运行,如果未运行则不执行任何操作,直接返回。
  2. 如果定时器已经运行,则根据定时器设置的触发时间和重复周期计算下一个定时时间。
  3. 如果当前时间大于等于下一个定时时间,则调用应用程序中注册的回调函数来处理定时事件。
  4. 如果定时器设置为只运行一次,则停止定时器并返回。
  5. 如果定时器设置为重复运行,则更新定时器的触发时间并重新启动定时器,然后返回。

在BlinkTimerM组件中,还有一些其他的函数,如stop()函数用于停止定时器的运行,setTimerPeriod()函数用于设置定时器的重复周期,等等。这些函数也都是实现定时器的关键部分,但与start()和fired()函数相比,它们的实现逻辑较为简单,主要是对已有定时器进行设置和控制。

五、用户代码的启动过程、执行过程

假设现在我们需要在TinyOS应用程序中使用BlinkTimerM组件来实现每隔1秒钟闪烁一下LED灯的功能,具体实现启动和执行过程如下:

在应用程序目录下的AppC.nc文件中引入BlinkTimerM组件,并将LEDC.nc作为组件的一个子模块引入。

#include “BlinkTimerM.h”

#include “LEDC.h”

在AppC.nc文件中定义回调函数,用于处理定期事件,在定期事件发生时把LED灯翻转一下。

// 定义回调函数,用于处理定时事件

event void BlinkTimerM.fired() {

LEDC.toggle();

}

在AppC.nc文件中实例化BlinkTimerM组件,并设置定时器的触发时间和重复周期。

// 实例化BlinkTimerM组件

BlinkTimerMC.TimerInterface timer = TimerM.Timer0;

BlinkTimerM.Timer<TimerM.Timer0> blinkTimer;

// 设置定时器的触发时间和重复周期

blinkTimer.setTimerPeriod(1000);

在硬件初始化之后,启动定时器。

// 在硬件初始化之后,启动定时器

call blinkTimer.start();

等待事件发生。

在硬件初始化之后,BlinkTimerM组件启动了一个定时器,每隔1秒钟就会产生一个定时事件,并调用之前定义的回调函数进行处理。在应用程序中等待该事件的发生即可。

综上所述,使用BlinkTimerM组件实现定时器功能的过程主要包括:在应用程序中引入BlinkTimerM组件并定义回调函数、实例化BlinkTimerM组件并设置定时器的触发时间和重复周期、启动定时器,最后等待事件发生并处理。这些步骤将在用户代码启动时依次执行,以达到实现定时器功能的目的。

六、mainC及RealMainP模块组件

6.1 mainC及RealMainP的功能

在TinyOS应用程序中,mainC配置组件及RealMainP模块组件是十分重要的部分,它们实现了整个应用程序的初始化工作和数据处理流程。

mainC配置组件:

mainC配置组件是TinyOS中的应用配置组件之一,它使用配置语言(全称是NesC Configuration Language)来定义应用程序所需的组件和模块。mainC配置组件功能通常包含如下几个部分:

  • 引入库文件:通过引入TinyOS库文件,如Ctp、Sense、Storage等,来使用TinyOS中的一些常用功能。
  • 引入用户组件和模块:通过引入用户自定义的组件和模块,实现特定的功能和处理流程。
  • 配置组件参数:配置某些组件的参数,如系统时钟频率、网络层协议等。
  • 实例化组件:将组件具体定义为某个硬件接口的实例。

mainC配置组件是整个TinyOS应用程序的入口,它会在用户程序启动时进行初始化,对所有的组件进行实例化,并将其关联到对应的硬件接口上,以便在后续的执行过程中使用。

RealMainP模块组件:

RealMainP模块组件是小型控制器的主函数实现组件,在TinyOS的应用程序中负责定义启动时的执行过程,并启动组件之间的消息传递和数据处理流程。在RealMainP模块组件中,用户可以编写自己的主程序代码,并实例化所需的组件并将其连接起来。

RealMainP模块组件功能通常包含如下几个部分:

  • 引入需要使用的组件和模块:用户可以引入需要使用的硬件驱动、协议栈、传感器等组件和模块。
  • 定义启动时的执行过程:用户可以定义应用程序启动时需要进行的各种操作,如硬件接口的初始化、网络协议栈的启动等。
  • 实例化组件:用户可以根据需要实例化需要使用的组件,并将其绑定到合适的消息通道上。
  • 消息处理流程:用户可以根据具体需求,编写消息处理函数,对从消息通道中接收到的数据进行处理。

总之,RealMainP模块组件是整个TinyOS应用程序的核心之一。在用户程序的执行过程中,RealMainP模块主要负责:定义启动时的执行过程,实例化所需的组件并将其连接起来,启动组件之间的消息传递和数据处理流程,以及对特定事件的响应等

6.2 RealMainP中main函数功能流程及说明

在RealMainP组件中,main函数通常作为整个TinyOS应用程序的入口,它定义了应用程序的启动过程和执行流程,主要包括如下几个部分:

  1. 引入需要使用的组件和模块:在main函数中,用户需要引入需要使用的硬件驱动、协议栈、传感器等组件和模块。
  2. 定义启动时的执行过程:在main函数中,用户需要定义启动时需要进行的各种操作,如硬件接口的初始化、网络协议栈的启动等。这些操作可以通过TinyOS提供的接口函数来完成。例如,以下代码将硬件接口初始化为标准参数:

call Hardware.init();

  1. 实例化需要使用的组件:在main函数中,用户可以根据需要实例化需要使用的组件,并进行必要的参数设置。例如,对于一个使用Blink组件驱动LED灯的应用程序,可以使用以下代码对Blink组件进行实例化并设置闪烁的时间为500MS:

BlinkC.HardwareInit = true;

BlinkC.TimerCycle = 500;

component BlinkC Blink;

  1. 连接组件之间的消息通道:在main函数中,用户需要连接组件之间的消息通道,以便实现数据传输和处理。这可以通过使用TinyOS提供的接口函数来完成。例如,以下代码将Blink组件与LEDNC组件绑定到一起:

Blink.Timer -> Timer0;

Blink.LED -> LEDC;

  1. 启动组件之间的消息传递和数据处理流程:在main函数中,用户需要对组件之间的消息传递和数据处理流程进行启动和管理。这可以通过使用TinyOS提供的接口函数来完成。例如,以下代码启动了Blink组件中的定时器,并等待LED组件进行处理:

call Blink.start();

// 等待LED组件处理完毕

event result_t LEDC.waitForActive();

综上所述,RealMainP组件中的main函数主要负责定义应用程序的启动过程和执行流程,包括引入需要使用的组件和模块、定义启动时的执行过程、实例化需要使用的组件、连接组件之间的消息通道以及启动组件之间的消息传递和数据处理流程。这些操作都是在用户程序启动时被依次执行的。
在这里插入图片描述

图6.1 RealMainP中main函数功能流程图

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

sB4-1715628049013)]

[外链图片转存中…(img-amHHdyaI-1715628049014)]

[外链图片转存中…(img-rp0D2TdO-1715628049014)]

[外链图片转存中…(img-l0QjLOuV-1715628049015)]

[外链图片转存中…(img-XwhJ9x99-1715628049016)]

[外链图片转存中…(img-S7umzsrw-1715628049016)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值