把学习笔记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使用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()
函数返回距离下次到期时间还剩余的时间。
和timer库几乎完全一样,只不过将clock_time
换成了clock_seconds
.
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)
函数主要工作是:
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结构如下:
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_BEGIN
和PROCESS_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没有使用clock模式,使用的是自己的定时器,这里指的是cc2530中的定时器T1.
RTIMER_NOW()
宏用来取得当前时间,RTIMER_SECOND
用来定义每秒的滴答数.
其他是移植时必须实现的函数接口,感谢前人的帮忙,这些接口都已经做好了。
就这样吧,写不动了。