LoRaWan Mac Timer

LoRaWan Mac Timer

十二月 01, 2017

实际上在semtech公司官方提供的源码里面,定时器timer是用来实现的,此定时器的实现是通过链表的方式进行实现的。

  1. 在官方的源码中,定时器链表底层是通过RTC的Alarm机制(闹钟机制)来实现的,实际源码中是把日历时间的实现转换成了时间戳时间来进行显示而不是使用RTC定时器产生一个固定的时间(如1ms中断,RTC的秒中断),然后定时刷新整个链表。也就是说,RTC定时器并非产生一个嘀嗒定时器(systick)来定时检查定时器链表的,而是直接根据链表你的表头定时。

DEMO

假设程序刚刚开始运行,而且此时定时器链表为空,此时有4个定时事件需要放入链表之中,定时时间分别为事件A:10ms事件B:30ms事件C:20ms事件D:40ms

则此时关于RTC闹钟链表存储结果如下:

事件名称 定时时间(ms)
A 10
C 10
B 10
D 10

嘀嗒定时器(systick)的链表存储结果如下:

事件名称 定时时间(ms)
A 10
B 30
C 20
D 40

时间过了5ms之后,RTC闹钟链表中存储的数据是不会发生任何变化的,因为它是以RTC的闹钟来作为刷新的依据,而嘀嗒定时器的链表中的数据就全发生了改变

此时嘀嗒(systick)定时器的链表变化就变成如下:

事件名称 定时时间(ms)
A 5
B 25
C 15
D 35

而此时如果再过5秒,此时事件A的定时时间就到了,然后就会去执行,在RTC闹钟链表中表现是RTC Alarm中断触发,在嘀嗒(systick)定时链表中表现为定时时间逐渐减少至0而触发。当事件A被执行之后两种定时器链表的存储都会发生改变,都是由原来的链表的头指针指向原先的第二个节点,而原先的头节点就会被释放

  1. 在上面的例子中,假设定时器在执行了7ms之后,有个新事件需要插入,假设为事件E,定时24ms,此时,两种链表对于此事件的插入操作就会不同。

RTC闹钟插入后变成如下:

事件名称 定时时间
A 10
C 10
B 10
E 1
D 9

嘀嗒(systick)定时器在插入之后为:

事件名称 定时时间
A 3
B 13
C 23
D 33
E 24

两种对比之后不知道有没有发现,用RTC的方法相比较嘀嗒定时器定时的方法,工作效率会明显提升。

  1. 因为RTC闹钟定时链表中定时器数目的增加不会使得花费在刷新定时器上的时间增加,因为不需要遍历整个链表。
  2. 而嘀嗒定时器链表的实现,每当有新事件或者事件刷新,就会花费时间去刷新定时器,会遍历整个链表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
elapsedTime = TimerGetValue( );//获取距离上一次设置闹钟的时间
/*remainingTime表示剩余的头节点中的事件剩余的定时事件,因为此链表是按顺序存储的,所以头节点中的定时时间一定是最少的*/
remainingTime = TimerListHead->Timestamp - elapsedTime;

static void TimerInsertNewHeadTimer( TimerEvent_t *obj, uint32_t remainingTime )
{
TimerEvent_t* cur = TimerListHead;
/*表头不为空,将新的定时器插入之前,将原先表头的定时器时间减去新定时器的定时时间,确保原先的定时器任务定时正常*/
if( cur != NULL )
{
cur->Timestamp = remainingTime - obj->Timestamp;
cur->IsRunning = false;
}
obj->Next = cur;
obj->IsRunning = true;
TimerListHead = obj;
TimerSetTimeout( TimerListHead );//设置超时,等时间到的时候,会发生RTC报警
}