近日在阅读semtech的Lora-net/LoRaMac-node。此代码是LoRaWAN MAC层的node段的代码。

此代码中构建了一个定时器链表,此链表构建得非常的巧妙,现在和大家分享。

此定时器链表底层使用的是RTC的闹钟(Alarm)机制(将日历时间转换成时间戳时间),而非使用一个定时器产生一个固定的定时(比如1ms),然后定时刷新整个链表。

也就是说此RTC定时器并非产生一个嘀嗒定时器来定时检查定时器链表,而是直接根据链表你的表头来直接定时,一步到位。

用RTC的方法相比较嘀嗒定时器定时的方法,工作效率会明显提升,并不会因为链表中定时器数目的增加使得花费在刷新定时器上的时间增加,因为不需要遍历整个链表。但代码的实现难度会较高

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

RTC闹钟链表:

其存储的结果会是这样:

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

而嘀嗒定时链表:

其存储的结果会是这样:

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

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

嘀嗒定时链表 变化得到情况如下:

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

再过5ms,此时A事件的定时时间就到了,需要被执行,在RTC闹钟链表中的表现是RTC Alarm中断触发,在嘀嗒定时链表中的表现是A事件的定时时间逐渐减少至0。当A事件被执行之后两种定时器链表中的存储都发生了变化,都是原先的链表的头指针指向原先的第二个节点,而原先的头节点被释放。

还是上述的例子,在定时器执行了7ms的时候,这时有个事件需要插入,为E 24ms,此时,两种链表对于此事件器的插入操作也会明显不同。

RTC闹钟插入之后

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

而嘀嗒定时器在插入之后为

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

以下是RTC闹钟的部分插入代码,其中可以看到他的定时器插入的逻辑


elapsedTime = TimerGetValue( );//获取距离上一次设置闹钟的时间
remainingTime = TimerListHead->Timestamp - elapsedTime;//remainingTime表示剩余的头节点中的事件剩余的定时事件,因为此链表是按顺序存储的,所以头节点中的定时时间一定是最少的 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报警
}

另外还有一点,此RTC中的1s并非物理时间的1s,在此具体的时间基准如下:

此项目中,使用的RTC的时钟源为32.768Khz的LSE,通过AsynchPrediv和SynchPrediv分频得到2.048KHz的RTCtick,计算公式为32.768/(3+1)/(3+1) = 2.048;

相关的配置代码如下:

	void RtcInit( void )
{
...
RtcHandle.Init.AsynchPrediv = 3;
RtcHandle.Init.SynchPrediv = 3;
...
} /*!
* RTC Time base in ms
*/
#define RTC_ALARM_TICK_DURATION 0.48828125 // 1 tick every 488us
#define RTC_ALARM_TICK_PER_MS 2.048 // 1/2.048 = tick duration in ms

由于原本每个tick相当于1s,而在这里,每个tick相当于0.48828125ms,小于1ms,所以在程序中能够实现ms级的定时任务。

RTC定时器的用法主要分为三步:

1. 初始化,注册回调函数
void TimerInit( TimerEvent_t *obj, void ( *callback )( void ) )//设置回调函数
2. 设置定时时间
void TimerSetValue( TimerEvent_t *obj, uint32_t value )
3. 开启定时时间
void TimerStart( TimerEvent_t *obj )

LoRaWAN移植笔记(一)__RTC闹钟链表的实现的更多相关文章

  1. LoRaWAN_stack移植笔记(四)__RTC

    stm32相关的配置 由于例程使用的主控芯片为STM32L151C8T6,而在本设计中使用的主控芯片为STM32L051C8T6,内核不一样,并且Cube库相关的函数接口及配置也会有不同,所以芯片的驱 ...

  2. tslib移植笔记(1)【转】

    本文转载自:https://blog.csdn.net/zijie_xiao/article/details/50740950 tslib移植笔记(1)2016-04-25 tslib背景[摘自百度] ...

  3. STemWin5.22移植笔记【转】

    来自:http://www.openedv.com/posts/list/27697.htm STemWin5.22移植笔记 网上关于emwin的资料很少,我在移植的时候查了很多资料,对我一个感觉是好 ...

  4. LoRaWAN stack移植笔记(五)__调试1

    先废话一小段 在将LoRaWAN的程序移植的过程中,调试发现了很多的问题. 做好记录工作,防止以后再踩坑 移植使用的是LoRaMac-node库,使用的是STM32L151CBT6 MCU,需要要移植 ...

  5. LoRaWAN stack移植笔记(六)_调试2

    前言 调试的过程中碰到的问题基本都是以前没有遇到过的,而且需要对整个协议栈及射频方面的工作流程较熟悉才能找到问题的原因,需要多读SX1276的数据手册以及与射频芯片的物理层通信例程和MAC层通信例程进 ...

  6. LoRaWAN_stack移植笔记(三)__SPI

    stm32相关的配置 由于例程使用的主控芯片为STM32L151C8T6,而在本设计中使用的主控芯片为STM32L051C8T6,内核不一样,并且Cube库相关的函数接口及配置也会有不同,所以芯片的驱 ...

  7. JZ2440 u-boot-2016.11、linux-4.17和busybox-1.28.4移植笔记

    2018年5月份开始在JZ2440上陆续移植了u-boot-2016.11.u-boot-spl-2016.11.linux-4.17和busybox-1.28.4,其中linux-4.17和busy ...

  8. java学习笔记(7)--链表

    标签(空格分隔):笔记 java其实已经将很多底层的数据结构进行了封装,虽然工作用不到,但是笔试和面试问的还是比较频繁的,而且这种面试题还是直接手撕代码,故专门总结一下. 1. 概念 1.1 链表(L ...

  9. Redis设计与实现读书笔记(二) 链表

    链表作为最基础的数据结构,在许多高级语言上已经有了很好的实现.由于redis采用C语言编写,需要自己实现链表,于是redis在adlist.h定义了链表类型.作者对于这部分没什么好说,源码比较简单,如 ...

随机推荐

  1. SIFT 特征提取算法总结

    原文链接:http://www.cnblogs.com/cfantaisie/archive/2011/06/14/2080917.html   主要步骤 1).尺度空间的生成: 2).检测尺度空间极 ...

  2. iPhone开发视频教程 Objective-C部分 (51课时)

    第一.二章  OC基础语法 iPhone开发教程 第一章 OC基础语法  iPhone开发概述-必看(1.1)http://www.apkbus.com/android-102215-1-1.html ...

  3. Scala 基础入门【翻译】

    原文地址 本文只是带你进入 Scala 的世界,包括安装.不可变量 val.可变量 var.定义类.集合(包括列表(list).集(set).映射(map))以及集合遍历和集合库(能达到并行/并发效果 ...

  4. 原创:goldengate从11.2升级到12.1.2

    goldengate从11.2升级到12.1.2 1.停止抽取进程 GGSCI (001.oracle.drs.dc.com) 286> stop EXTSJ01 2. 停止投递和复制进程 等待 ...

  5. BW标准数据源初始化设置

    在安装了一干补丁和做好了BW与R3的链接之后(此处有BISIS操心,具体事宜不详),我们就可以登录到R3系统看个究竟了. 磨刀不误砍柴工,先检查一下两边系统的补丁: R3端如下, ,貌似我们是19,通 ...

  6. .net微信公众号开发——快速入门

    作者:王先荣 最近在学习微信公众号开发,将学习的成果做成了一个类库,方便重复使用. 现在微信公众号多如牛毛,开发微信的高手可以直接无视这个系列的文章了. 使用该类库的流程及寥寥数行代码得到的结果如下. ...

  7. TortoiseSVN and TortoiseGit 版本控制图标不见了

    突然有一天,代码文件夹上的版本控制图标不见了. 注册表中,将文件夹名重命名,让版本控制的靠前,Computer \ HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft ...

  8. C# 调用系统winmm.dll 播放音乐wav mp3

    using System.Runtime.InteropServices;//放wav public partial class frmMain : Form { 系统放 播放音乐 wav mp3 [ ...

  9. C# RSA PEM解密字符

    1.第一步先用openssl将pem的key转换为der的key //bin>openssl.exe rsa -in rsakeydec.pem -outform der -out pri.de ...

  10. 深圳测试研讨会圆满结束,PPT共享

    深圳测试研讨会圆满结束,PPT共享http://www.automationqa.com/forum.php?mod=viewthread&tid=3417&fromuid=29