contiki-rtimer

struct rtimer {
rtimer_clock_t time;
rtimer_callback_t func;
void *ptr;
}; typedef unsigned short rtimer_clock_t;
typedef void (* rtimer_callback_t)(struct rtimer *t, void *ptr);

三个参数:时钟类型,回调函数,回调函数的参数

参考博客:http://blog.csdn.net/jiangjunjie_2005/article/details/44947899 (简称博客1)

     http://blog.sina.com.cn/s/blog_686ee2910102vxce.html (简称博客2)

  这个timer不再是一个链表,只是一个timer,去提供实时性的要求。只能串行使用rtimer定时器的中断回调功能。

rtimer用途

  Contiki系统引入rtimer可以满足精准定时的需要,一些对时间极为敏感的模块(如MAC协议)依赖于rtimer。和etimer的粗粒度(常见为100Hz)不同,rtimer是细粒度(常见为10kHz,100us)定时器。根据经验(别人的经验),细粒度定时器如果中断频繁特别容易消耗CPU资源,为此,contiki设计rtimer时尽可能地减少中断,大部分应用场合为读取定时器计数值。

  contiki-rtimer

    上图发现,rtimer没有常见的next指针来挂接后续节点,确实,contiki为了减少rtimer中断的爆发,只能挂接一个rtimer结构。如果同时挂接2个或以上的rtimer结构,那么最新挂接的有效,其它的rtimer结构将丢失。

rtimer中断时序

  contiki-rtimer

  上图展示了rtimer的中断时序,当调用rtimer_arch_schedule()时,它设置rtimer定时器的中断间隔时长timeout,中断服务函数rtimer_irq_handler会调用rtimer->callback()回调函数。

  注意2点,中断只允许发生一次(不懂,搞明白再回头来解释原因)(终于明白了博客1中版主所说的这句话的意思,在使用rtimer的时候,只能rtimer_set一次,不能反复产生到时中断,搞明白rtimer_set函数的内涵),即rtimer_arch_schedule()使能中断,而rtimer_irq_handler()禁止中断;rtimer->callback()是在中断状态下运行,特别注意防止竟态错误,例如:调用process_poll()合法,调用process_post()非法。(暂时不懂原因)

rtimer的移植  

  即,基于MCU实现rtimer-arch.c和rtimer-arch.h

   大多数定时器(尤其是8位MCU)位宽为16位,即MAX=65535,而MAC协议往往需要1秒以上的定时周期,因此rtimer的频率必须小于30kHz。一个比较好的数值是10kHz,它既可以保证比较好的精度(间隔为100us),又具备6.5秒的满量程,这可以适应大多数的应用需要。

  另外,大多数应用需要随机撤销和重启动rtimer,它可以通过添加2个函数来实现:

  rtimer_arch_disable_irq()和rtimer_arch_enable_irq()。

  对于contiki系统而言,其已经在/core/sys/rtimer.h&c中对rtimer相关结构进行了定义,对于特定平台而言,主要需要实现以下几个函数:

  rtimer_arch_init(),针对特定平台的初始化操作,被rtimer_init()函数调用;

  rtimer_arch_now(),用于获取当前的rtimer时间;

  rtimer_arch_schedule(rtimer_clock_t t),传递一个唤醒时间​,在特定时刻进行调度操作,调用rtimer_run_next()。

  同时需要在rtimer_arch.h中定义RTIMER_ARCH_SECOND确定rtimer每秒的滴答数。

stm32移植准备

  1)移植过程中,首先确定rtimer每秒的滴答数是多少,在本系统中,达到100us的精度就OK了,因此选用了10kHz的频率。

  2)选定用于实现rtimer的定时器,stm32具备多个定时器,我所使用的是stm32f103,具备TIM1和TIM8等高级定时器,也有TIM2-TIM5等通用定时器,还有TIM6和TIM7等基本定时器。不知道用哪种定时器来实现rtimer更合适,知道的朋友可以来补充说明一下,这里暂时选用TIM2通用定时器。并用TIM2的TIM_IT_CC1中断来完成rtimer_run_next的调度。(因为常用的中断TIM_IT_Update,便搞不明白了定时器中断类型到底有什么区别,写个博客分析一下)

  以上也是整理参考博客的内容,下面说明一下我是如何实现的

实现rtimer-arch.h文件

#include "contiki-conf.h"
#include "rtimer.h" //确定rtimer每秒的滴答数
#define RTIMER_ARCH_SECOND 10000 /* 10kHz(100us)*/
//这里使用stm32的通用定时器2来实现
#define RTIMER_TIM TIM2 /*在TIM2的中断服务函数TIM2_IRQHandler中调用*/
void rtimer_irq_handler(void);
/*针对特定平台的初始化操作,被rtimer_init()函数调用*/
void rtimer_arch_init(void);
/*用于获取当前的rtimer时间*/
rtimer_clock_t rtimer_arch_now(void);
/*传递一个唤醒时间,在特定时刻进行中断调度操作,中断中调用rtimer_run_next()*/
/*还不太理解这个唤醒时间是怎么个调度法,关键不理解函数中的TIM_SetCompare1()的意义*/
void rtimer_arch_schedule(rtimer_clock_t t);
/*失能和使能超时中断*/
void rtimer_arch_disable_irq(void);
void rtimer_arch_enable_irq(void);

实现rtimer-arch.c文件

 #include "sys/rtimer.h"
#include "rtimer-arch.h"
#include "timer2.h" #define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif void
rtimer_irq_handler(void)
{ /* Clear interrupt pending bit */
TIM_ClearITPendingBit(RTIMER_TIM,TIM_IT_CC1); /* Do interrupt only once! */
/*中断到来后需要将中断禁止,避免多次产生中断*/
rtimer_arch_disable_irq(); //ENERGEST_ON(ENERGEST_TYPE_IRQ);//开启了节能中断
rtimer_run_next();
//ENERGEST_OFF(ENERGEST_TYPE_IRQ); return;
} void
rtimer_irq_handler(void)
{ /* Clear interrupt pending bit */
TIM_ClearITPendingBit(RTIMER_TIM,TIM_IT_CC1); /* Do interrupt only once! */
/*中断到来后需要将中断禁止,避免多次产生中断*/
rtimer_arch_disable_irq(); //ENERGEST_ON(ENERGEST_TYPE_IRQ);//开启了节能中断
rtimer_run_next();
//ENERGEST_OFF(ENERGEST_TYPE_IRQ); return;
} void
rtimer_arch_init(void)
{
TIM2_Int_Init(); return;
} rtimer_clock_t
rtimer_arch_now(void)
{
rtimer_clock_t tT1, tT2; do
{
/* Avoid race condition on reading counter of TIM1 */
tT1 = TIM_GetCounter(RTIMER_TIM);
tT2 = TIM_GetCounter(RTIMER_TIM);
} while (tT1 != tT2); return tT1;
} void
rtimer_arch_schedule(rtimer_clock_t t)
{
/* Sets the TIM2 Capture Compare1 Register value */
TIM_SetCompare1(RTIMER_TIM,t);
PRINTF("进入rtimer_arch_schedule\r\n");
PRINTF("%d\r\n",rtimer_arch_now()); /* MUST clear the remained flag of TIM2 compare */
TIM_ClearFlag(RTIMER_TIM,TIM_FLAG_CC1); /* Enable interrupt of Capture compare 1 */
TIM_ITConfig(RTIMER_TIM,TIM_IT_CC1, ENABLE); return;
} void
rtimer_arch_disable_irq(void)
{
TIM_ITConfig(RTIMER_TIM,TIM_IT_CC1, DISABLE); return;
} void
rtimer_arch_enable_irq(void)
{
/* MUST clear the remained flag of TIM2 compare */
TIM_ClearFlag(RTIMER_TIM,TIM_FLAG_CC1); /* Enable interrupt of Capture compare 1 */
TIM_ITConfig(RTIMER_TIM,TIM_IT_CC1, ENABLE); return;
}

最后附上timer2.c的代码,来显示和rtimer的衔接

 void TIM2_Int_Init(void)
{
u16 arr=;
u16 psc=(uint16_t)(SystemCoreClock / RTIMER_ARCH_SECOND) -;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//①定时器时钟使能 TIM_TimeBaseInitStruct.TIM_Period=arr;//设置自动重装载寄存器周期的值
TIM_TimeBaseInitStruct.TIM_Prescaler=psc;//设置时钟频率的预分频值
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//定时器向上计数
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置时钟分割
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//②初始化、配置定时器 TIM_ITConfig(TIM2,TIM_IT_CC1,ENABLE);//开启更新中断 TIM_Cmd(TIM2,ENABLE);//使能定时器 NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=;
NVIC_Init(&NVIC_InitStruct);//配置中断 }
//编写中断服务函数
void TIM2_IRQHandler(void)
{ if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==SET)
{
TickCounter2++;//6.5535s产生一次中断
rtimer_irq_handler();//调用rtimer中的中断处理函数 }
/* leave interrupt */ }

  正确使用rtimer还不是很理解,还需要继续实验。

  

  

  

上一篇:python核心编程第六章练习6-9


下一篇:Linux下printf格式符%d、%lld、%llx、%u等【转自CSDN博客】