LoRaWAN移植笔记(一)__RTC闹钟链表的实现
近日在阅读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闹钟链表的实现的更多相关文章
- LoRaWAN_stack移植笔记(四)__RTC
stm32相关的配置 由于例程使用的主控芯片为STM32L151C8T6,而在本设计中使用的主控芯片为STM32L051C8T6,内核不一样,并且Cube库相关的函数接口及配置也会有不同,所以芯片的驱 ...
- tslib移植笔记(1)【转】
本文转载自:https://blog.csdn.net/zijie_xiao/article/details/50740950 tslib移植笔记(1)2016-04-25 tslib背景[摘自百度] ...
- STemWin5.22移植笔记【转】
来自:http://www.openedv.com/posts/list/27697.htm STemWin5.22移植笔记 网上关于emwin的资料很少,我在移植的时候查了很多资料,对我一个感觉是好 ...
- LoRaWAN stack移植笔记(五)__调试1
先废话一小段 在将LoRaWAN的程序移植的过程中,调试发现了很多的问题. 做好记录工作,防止以后再踩坑 移植使用的是LoRaMac-node库,使用的是STM32L151CBT6 MCU,需要要移植 ...
- LoRaWAN stack移植笔记(六)_调试2
前言 调试的过程中碰到的问题基本都是以前没有遇到过的,而且需要对整个协议栈及射频方面的工作流程较熟悉才能找到问题的原因,需要多读SX1276的数据手册以及与射频芯片的物理层通信例程和MAC层通信例程进 ...
- LoRaWAN_stack移植笔记(三)__SPI
stm32相关的配置 由于例程使用的主控芯片为STM32L151C8T6,而在本设计中使用的主控芯片为STM32L051C8T6,内核不一样,并且Cube库相关的函数接口及配置也会有不同,所以芯片的驱 ...
- 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 ...
- java学习笔记(7)--链表
标签(空格分隔):笔记 java其实已经将很多底层的数据结构进行了封装,虽然工作用不到,但是笔试和面试问的还是比较频繁的,而且这种面试题还是直接手撕代码,故专门总结一下. 1. 概念 1.1 链表(L ...
- Redis设计与实现读书笔记(二) 链表
链表作为最基础的数据结构,在许多高级语言上已经有了很好的实现.由于redis采用C语言编写,需要自己实现链表,于是redis在adlist.h定义了链表类型.作者对于这部分没什么好说,源码比较简单,如 ...
随机推荐
- python一套完整的事务操作
#coding=utf-8 import sys import MySQLdb class TransferMoney(object): def __init__(self,conn): self.c ...
- android网络框架Retrofit 同步异步
http://blog.csdn.net/jiguangcanhen/article/details/39006197 同步的方式: 1)首先定义要接口.注解Get表示使用的Get请求方式,{user ...
- OpenBTS的安装(转)
OpenBTS source code可以在这里下载:http://sourceforge.net/projects/openbts/ OpenBTS入门的各种问题可以在这里找到答案:http://g ...
- MS SQL SERVER索引优化相关查询
查找缺失索引 -- ============================================= -- Description: 查询当前数据库中缺失的索引,知道你进行优化的 ...
- Oracle的 Pfile生成
SQL> create pfile from spfile; File created. SQL> [oracle@localhost dbs]$ ls -lrttotal 24-rw-r ...
- protocol buffer
下载与说明:https://github.com/google/protobuf Google Protocol Buffer 的使用和原理:http://www.ibm.com/developerw ...
- ECShop在任何页面调用最新文章并变成随机文章
一.让最新文章变成随机文章 在根目录 打开index.php文件 查找代码 ' ORDER BY a.article_type DESC, a.add_time DESC LIMIT ' . $GLO ...
- 判断big endian和little endian的方法
http://blog.sina.com.cn/s/blog_6ab0b9a80101awzr.html 不同体系的CPU在内存中的数据存储往往存在着差异.例如,Intel的x86系列处理器将低序 ...
- FindProcDLL::FindProc 和 KillProcDLL::KillProc,必须使用WPF x86编译出来的程序
如果是 WPF 编写的exe,想用NSIS打包. 脚本里面要注意了,如果使用了 FindProcDLL::FindProc 和 KillProcDLL::KillProc, 那么WPF 的编译选项必须 ...
- <img> to image_tag
<img src="clean_wave.jpg?" alt="Clean_wave"><%= image_tag("clean_w ...