注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
dan158185的个人空间 https://home.eeworld.com.cn/space-uid-349284.html [收藏] [复制] [分享] [RSS]
日志

CC2538之TinyOS例程实验:3/4-timer nesC编程最难理解部分参数化接口讲解

已有 1397 次阅读2016-1-5 16:06 |个人分类:CC2538之TinyOS例程| 接口

前面两篇已经介绍了TinyOS的优点,nesC的事件代码分析,可以通过视频去学会自己编写基本应用

如果说interface,event你还觉得TinyOS的nesC的引入吸引不了你的话,那么现在咱们进入个人认为TinyOS编程最难的地方也是整个最吸引我的地方

参数化接口(parameterized interface),其中我们早就接触到了-blink例程


大家要注意的是对于TinyOS来说,components包含configuration和module,interface都是可以把他理解成一个数组元素,不要死板的理解成一个C文件,他们都是一个元素,当然也可以实例化n个;这就是参数化接口的意义!也是本人最喜欢使用TinyOS的最重要的原因;


至此咱们可以想一下,假设n路传感器,代码实现(驱动是一样的),就可以使用参数接口化来编写代码,有一点点对象的意思


回忆一下blink代码:

  1. configuration BlinkAppC  
  2. {  
  3. }  
  4. implementation  
  5. {  
  6.   components MainC, BlinkC, LedsC;  
  7.   components new TimerMilliC() as Timer0;  
  8.   components new TimerMilliC() as Timer1;  
  9.   components new TimerMilliC() as Timer2;  
  10.   
  11.   
  12.   BlinkC -> MainC.Boot;  
  13.   
  14.   BlinkC.Timer0 -> Timer0;  
  15.   BlinkC.Timer1 -> Timer1;  
  16.   BlinkC.Timer2 -> Timer2;  
  17.   BlinkC.Leds -> LedsC;  
  18. }  
TimerMilliC()的组件只有一份代码,为什么可以多个实例组件呢,这个也就是参数化接口的作用,相同的比较常常能看见的还有LedsC连接到底层发现IO口部分的参数化接口部分可以随意的设定led对应的IO口;

前面的blip和printf例程都使用到了timer,为什么没有讲解timer的用意也在此,这个参数化接口是nesC语言的杀手锏;

参数化接口有一点类似C语言的定义 uint_8 array[] = {0,0,0,0};的意思,只不过这个数组可以广域化一下,如components,interface,module等


带来的好处是显而易见的,一次编程,多次使用,如内存池pool,fragpool等,理解参数化编程最好的代码应该是fragpool



分析的是interface Timer<TMilli>,那么首先必须先看的是Timer.h,目录:tinyos-main-release_tinyos_2_1_2\tos\lib\timer
  1. // The TinyOS Timer structures are discussed in TEP 102.  
  2. #ifndef TIMER_H  
  3. #define TIMER_H  
  4.   
  5. // @note TSecond is an extension to be added in a successor to TEP 102  
  6. typedef struct { int notUsed; } TSecond;  
  7. typedef struct { int notUsed; } TMilli;  
  8. typedef struct { int notUsed; } T32khz;  
  9. typedef struct { int notUsed; } TMicro;  
  10.   
  11. #define UQ_TIMER_SECOND "HilTimerMicroC.Timer"  
  12. #define UQ_TIMER_MILLI "HilTimerMilliC.Timer"  
  13. #define UQ_TIMER_32KHZ "HilTimer32khzC.Timer"  
  14. #define UQ_TIMER_MICRO "HilTimerMicroC.Timer"  
  15.   
  16. #endif  

再来看看接口Timer,为什么blink的使用uses interface Timer<TMilli>也就是跟了参数,这是咱们之前没有分析过的Timer.nc,接口文件,目录:tinyos-main-release_tinyos_2_1_2\tos\lib\timer
  1. interface Timer<precision_tag>  
  2. {  
  3.   // basic interface   
  4.   /**  
  5.    * Set a periodic timer to repeat every dt time units. Replaces any  
  6.    * current timer settings. Equivalent to startPeriodicAt(getNow(),  
  7.    * dt). The <code>fired</code> will be signaled every dt units (first  
  8.    * event in dt units).  
  9.    *  
  10.    * @param dt Time until the timer fires.  
  11.    */  
  12.   command void startPeriodic(uint32_t dt);  
  13.   
  14.   /**  
  15.    * Set a single-short timer to some time units in the future. Replaces  
  16.    * any current timer settings. Equivalent to startOneShotAt(getNow(),  
  17.    * dt). The <code>fired</code> will be signaled when the timer expires.  
  18.    *  
  19.    * @param dt Time until the timer fires.  
  20.    */  
  21.   command void startOneShot(uint32_t dt);  
  22.   
  23.   /**  
  24.    * Cancel a timer.  
  25.    */  
  26.   command void stop();  
  27.   
  28.   /**  
  29.    * Signaled when the timer expires (one-shot) or repeats (periodic).  
  30.    */  
  31.   event void fired();  
  32.   
  33.   // extended interface  
  34.   /**  
  35.    * Check if timer is running. Periodic timers run until stopped or  
  36.    * replaced, one-shot timers run until their deadline expires.  
  37.    *  
  38.    * @return TRUE if the timer is still running.  
  39.    */  
  40.   command bool isRunning();  
  41.   
  42.   /**  
  43.    * Check if this is a one-shot timer.  
  44.    * @return TRUE for one-shot timers, FALSE for periodic timers.  
  45.    */  
  46.   command bool isOneShot();  
  47.   
  48.   /**  
  49.    * Set a periodic timer to repeat every dt time units. Replaces any  
  50.    * current timer settings. The <code>fired</code> will be signaled every  
  51.    * dt units (first event at t0+dt units). Periodic timers set in the past  
  52.    * will get a bunch of events in succession, until the timer "catches up".  
  53.    *  
  54.    * <p>Because the current time may wrap around, it is possible to use  
  55.    * values of t0 greater than the <code>getNow</code>'s result. These  
  56.    * values represent times in the past, i.e., the time at which getNow()  
  57.    * would last of returned that value.  
  58.    *  
  59.    * @param t0 Base time for timer.  
  60.    * @param dt Time until the timer fires.  
  61.    */  
  62.   command void startPeriodicAt(uint32_t t0, uint32_t dt);  
  63.   
  64.   /**  
  65.    * Set a single-short timer to time t0+dt. Replaces any current timer  
  66.    * settings. The <code>fired</code> will be signaled when the timer  
  67.    * expires. Timers set in the past will fire "soon".  
  68.    *  
  69.    * <p>Because the current time may wrap around, it is possible to use  
  70.    * values of t0 greater than the <code>getNow</code>'s result. These  
  71.    * values represent times in the past, i.e., the time at which getNow()  
  72.    * would last of returned that value.  
  73.    *  
  74.    * @param t0 Base time for timer.  
  75.    * @param dt Time until the timer fires.  
  76.    */  
  77.   command void startOneShotAt(uint32_t t0, uint32_t dt);  
  78.   
  79.   
  80.   /**  
  81.    * Return the current time.  
  82.    * @return Current time.  
  83.    */  
  84.   command uint32_t getNow();  
  85.   
  86.   /**  
  87.    * Return the time anchor for the previously started timer or the time of  
  88.    * the previous event for periodic timers. The next fired event will occur  
  89.    * at gett0() + getdt().  
  90.    * @return Timer's base time.  
  91.    */  
  92.   command uint32_t gett0();  
  93.   
  94.   /**  
  95.    * Return the delay or period for the previously started timer. The next  
  96.    * fired event will occur at gett0() + getdt().  
  97.    * @return Timer's interval.  
  98.    */  
  99.   command uint32_t getdt();  
  100. }  
那么对于cc2538cb平台,谁提供了Timer<TMilli>接口呢;
需要看TimerMilliC.nc ,TimerMilliP.nc(tinyos-main-release_tinyos_2_1_2\tos\system)
TimerMilliC.nc 
  1. #include "Timer.h"  
  2.   
  3. generic configuration TimerMilliC() {  
  4.   provides interface Timer<TMilli>;  
  5. }  
  6. implementation {  
  7.   components TimerMilliP;  
  8.   
  9.   // The key to unique is based off of TimerMilliC because TimerMilliImplP  
  10.   // is just a pass-through to the underlying HIL component (TimerMilli).  
  11.   Timer = TimerMilliP.TimerMilli[unique(UQ_TIMER_MILLI)];  
  12. }  
TimerMilliP.nc省略

通过查看cc2538cb平台的chips源码 目录tinyos-main-release_tinyos_2_1_2\tos\chips\cc2538\timer
找见HilTimerMilliC.nc 下面是部分代码,发现他提供了interface
  1. configuration HilTimerMilliC{  
  2.   provides interface Init;  
  3.   provides interface Timer<TMilli> as TimerMilli[ uint8_t num ];  
  4.   ...  
  5. }  
  6. implementation{  
  7.       ...  
  8. }  


nesC福利:
unique(..)------------提供唯一的id,每调用一次id+1,如果把interface看成是数组的话,类似于数组的下标
uniqueCount(..)---计算使用unique总次数
new-------------------用于参数化接口的components的创建,实例化

Timer的库的写法是最复杂也是最全的nesC的参数化接口写法,最好是大家通过yeti2去查看图形连接关系,然后在eclipse下查看分析源码;

参数化接口格式
  1. interface xx<...>  
  2. {  
  3.   command;  
  1. event;  

实际应用我常常使用下面的的方法一样可以达到参数化接口的目的,可以参考fragpool写法或者cc2538底层的io口的写法,interface可以简化写成简单的interface结构,改为configuration和module提供接口的时候改为
configuration/module name(xx){
 provides interface_name[xx];
}
使用他采用components new name(unique(xx));

见仁见智吧,哪一种方法都行,喜欢第二种是代码阅读稍微直观一点。

在此大家可以看到components和interface的编程可以使用参数,使用new创建并完成实例化,实例个数限制和参数有关,更多的需要自己去阅读代码,这玩意只能自己去阅读清楚



例程目录tinyos-main-release_tinyos_2_1_2\apps\cc2538_Test\timerTest

包含文件:

Makefile

TimerAppC.nc---configuration

TimerC.nc


timertest例程为ms单位的定时器使用实验

Makefile

  1. COMPONENT=TimerAppC  
  2. CFLAGS += -DUSE_TIMER_HANDLER  
  3. #CFLAGS += -DUSE_UART_HANDLER  
  4. #CFLAGS += -DUSE_RF_HANDLER  
  5. CFLAGS += -DNOT_USE_PRINTFC_BUT_USE_PRINT  
  6. include $(MAKERULES)  

不做介绍,不清楚可以去看blink和printf讲解

TimerAppC.nc

  1. configuration TimerAppC  
  2. {  
  3. }  
  4. implementation  
  5. {  
  6.   components MainC, TimerC;   
  7.   components new TimerMilliC() as Timer1;  
  8.     
  9.   TimerC -> MainC.Boot;  
  10.   TimerC.Timer1 -> Timer1;  
  11. }  

阅读省略

TimerC.nc

  1.  /*******************************************************************  
  2.  *实验4----毫秒定时器实验  
  3.  *节点需求数1  
  4.  *编译命令make cc2538cb  
  5.  ********************************************************************/  
  6.   
  7. #include "Timer.h"  
  8. #include "printf.h"  
  9.   
  10. module TimerC  
  11. {  
  12.    uses interface Timer<TMilli> as Timer1;  
  13.    uses interface Boot;  
  14. }  
  15. implementation  
  16. {  
  17.   task void time1_Task();  
  18.   uint16_t Timer_counter=0;  
  19.     
  20.   /***************************************************  
  21.   *启动事件  
  22.   ****************************************************/  
  23.   event void Boot.booted()  
  24.   {  
  25.     /**开启一秒的周期性定时器(单位毫秒)  Timer1**/  
  26.     call Timer1.startPeriodic( 1000 );   
  27.   
  28.   }  
  29.   
  30.   /***************************************************  
  31.   *任务time1_Task  
  32.   ****************************************************/  
  33.   task void time1_Task()  
  34.   {    
  35.       printf("Timer1 fired: %u\n", Timer_counter++);  
  36.   }  
  37.     
  38.   /***************************************************  
  39.   *Timer1定时时间到事件  
  40.   ****************************************************/  
  41.   event void Timer1.fired()  
  42.   {  
  43.     /****提交time1_Task任务***/  
  44.     post time1_Task();  
  45.   }  
  46.     
  47. }  
阅读省略


例程目录tinyos-main-release_tinyos_2_1_2\apps\cc2538_Test\TimerMicro

TimerMicro例程为us单位的定时器使用实验,代码省略
评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章