Contiki学习笔记3:定时器

把学习笔记2暂时删掉了。我的论文查重居然和自己的重复了,等确实不再查重了再恢复吧。论文里面分析了protothread机制,完成了contiki内核的移植,然后在内核移植的基础上完成了uIP协议栈的移植,实现了UDP通信^_^,以后在把这些移植过程详细描述。
上次翻译完process篇后,感觉不错。写论文时自己分析了阅读了一些源码,感觉其实contiki的学习一定要自己去阅读源代码,去展开宏,不要害怕。
今天参照wiki上的 contiki-timers 来说一下定时器部分。

定时器模式

众所周知,Contiki有五种定时器模式:timer,stimer,etimer,rtimer,ctimer.
timer定时us级别的时间,stimer定时s级别的时间。
etimer就是事件定时器,用来调度Contiki中的进程。在contiki进程中使用etimer可以使进程等待,从而系统可以调度其他进程。
ctiemr是回调定时器,定时一段时间后去再次调度函数,Rime协议栈里面会经常用来处理通信超时。感觉ctimer比较复杂。
rtimer就是实时定时器,他可以抢占任何进程,这样子使得实时任务可以准确调度。

时钟模式

该部分内容向我们展示了clock接口函数的作用,这部分函数在中定义。以下结合cc2530的

clock_init() 函数就是初始化系统时钟,这里面cc2530使用的是sleep定时器来定时,中断时间也即定时时间是7.8ms。每次中断都会使全局变量count+1。

clock_time() 函数就是计时函数,直接返回count的值,这样就知道当前时间了,因为每次count+1都表示时间经过了7.8ms。

CLOCK_SECOND宏就是一秒的宏,该宏值乘以7.8ms应该是1s,所以程序里面设置该宏值为128,这样,128 * 7.8 = 998.4≈1S。

clock_seconds() 函数返回以秒为单位的数值seconds.该全局变量在时钟中断函数中,每当count值为128时,都会加1,相当于每增加1都经过了1秒。

剩下两个API是用来阻塞CPU的,但不会放弃控制权,就是平常的延时函数,有的底层驱动可能会需要。分别是clock_delay()clock_wait()函数。

以上就是中的API,基于这些知识,我们自己就可以编写clock文件。

Timer库

Timer使用clock模式中的clock_time() 函数来获取当前系统时间。应用程序必须自行检查timer是否到期。

struct timer {
  clock_time_t start;
  clock_time_t interval;
};

timer_set() 函数结构如下:

void
timer_set(struct timer *t, clock_time_t interval)
{
  t->interval = interval;
  t->start = clock_time();
}

strar获取当前时间,interval存储间隔时间,这样就设置好了timer定时器。
timer_restart() 函数就是t->start = clock_time(); 重设start时间,而间隔不变,这样子必然导致时间轴发生变化,轴上的每一个时间节点都会移动位置。
区别函数是timer_reset() 函数,该函数就是t->start += t->interval; 相当于将当前时间移到下一个时间节点,并不会改变时间轴。
timer_expired() 函数定义如下:

int
timer_expired(struct timer *t)
{
  clock_time_t diff = (clock_time() - t->start) + 1;
  return t->interval < diff;
}

该函数通过判断间隔时间和diff这个时间差的大小,从而确定timer是否到期。比如,start为5,internal为8,那么可知下一个时间节点是13,那么当clock_time返回12时,diff为8,所以函数返回0;当clock_time返回13时,diff为9,所以函数返回1,表示时间到期,至于为什么要给diff额外+1,从而return变为不是返回diff >= t->interval ,注释里面说明,这样做是为了避免mspgcc报错。
timer_remaining() 函数返回距离下次到期时间还剩余的时间。

Stimer库

和timer库几乎完全一样,只不过将clock_time 换成了clock_seconds .

Etimer库

etimer结构体先放在前面:

struct etimer {
  struct timer timer;
  struct etimer *next;
  struct process *p;
};

etimer_set() 函数和timer中的作用差不多。函数定义如下:

void
etimer_set(struct etimer *et, clock_time_t interval)
{
  timer_set(&et->timer, interval);
  add_timer(et);
}

其中timer_set() 函数已经讲过,设置到期时间。
add_timer(et) 函数主要工作是:

  • 将etimer_process进程优先级变高。
  • 遍历etimer链表,如果需要添加的etimer不在链表中,那么将其加入到链表,并且使其process结构指针指向当前的进程,这是将etimer和进程绑定到一起了。
  • 然后调用更新时间函数update_time() ,该函数的作用就是通过遍历etimer链表,来统计下一个etimer发生还需要多长时间。

etimer_reset()etimer_restart() 函数和timer中的功能差不多,不再赘述。
etimer_stop() 函数就是将目标事件定时器移出链表。
etimer_expired() 来判断etimer是否到期,到期的话会在etimer_process进程中将etimer中的进程指针p设置为PROCESS_NONE。
看一个1s调用一次的例程:

 #include "sys/etimer.h"

 PROCESS_THREAD(example_process, ev, data)
 {
   static struct etimer et;
   PROCESS_BEGIN();

   /* Delay 1 second */
   etimer_set(&et, CLOCK_SECOND);

   while(1) {
     PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
     /* Reset the etimer to trig again in 1 second */
     etimer_reset(&et);
     /* ... */
   }
   PROCESS_END();
 }

Ctimer库

ctimer结构如下:

struct ctimer {
  struct ctimer *next;
  struct etimer etimer;
  struct process *p;
  void (*f)(void *);
  void *ptr;
};

可以看出,这几个定时器都是继承的关系,ctimer->etimer->timer。结构体中f为一个指向函数的指针,就是用来调用回调函数的。
ctimer函数库和etimer基本一样,除了ctimer_set() 函数。
该函数声明如下:

void
ctimer_set(struct ctimer *c, clock_time_t t,
       void (*f)(void *), void *ptr)

介绍两个宏,PROCESS_CONTEXT_BEGINPROCESS_CONTEXT_END 。这两个宏搭配使用,就是用来保存当前process_current指针的,用完后再将其恢复。
一个例子:

 #include "sys/ctimer.h"
 static struct ctimer timer;

 static void
 callback(void *ptr)
 {
   ctimer_reset(&timer);
   /* ... */
 }

 void
 init(void)
 {
   ctimer_set(&timer, CLOCK_SECOND, callback, NULL);
 }

每秒调用一次callback函数。上述实例展示了使用方法。

Rtimer库

Rtimer没有使用clock模式,使用的是自己的定时器,这里指的是cc2530中的定时器T1.
RTIMER_NOW() 宏用来取得当前时间,RTIMER_SECOND用来定义每秒的滴答数.
其他是移植时必须实现的函数接口,感谢前人的帮忙,这些接口都已经做好了。
就这样吧,写不动了。

你可能感兴趣的:(contiki)