ZigBee协议栈中定时器的几种使用方法(在Zigbee中使用定时器)

原文链接:http://www.kaleidscope.cn:1020/archives/1056

Zigbee协议栈中如果要实现一个定时事件或者延时的话,有很多种方法,定时事件呢其实就是我们熟悉的使用定时器来定时,产生定时事件,当然也可以用来延时。

1、协议栈定时器HalTimerConfig

ZigBee协议栈提供了定时器的使用接口,在hal层调用HalTimerConfig即可配置使用,而定时器2被协议栈占用了,所以只有使用1、3、4三个定时器。

在hal_timer.h中我们可以看到几个定时器的定义:

/* Timer ID definitions */

#define HAL_TIMER_0 0x00 // 8bit timer

#define HAL_TIMER_1 0x01 // 16bit Mac timer

#define HAL_TIMER_2 0x02 // 8bit timer

#define HAL_TIMER_3 0x03 // 16bit timer

#define HAL_TIMER_MAX 4 // Max number of timer

所以和硬件中的定时器是有区别的,经过了映射,这里需要注意一下。

* HAL_TIMER_0 –> HW Timer 3 8bit


* HAL_TIMER_2 –> HW Timer 4 8bit


* HAL_TIMER_3 –> HW Timer 1 16bit

如果我们要使用协议栈的定时器进行相关操作,只需进行定时器的配置即可:

extern uint8 extern uint8 HalTimerConfig ( uint8 timerId,uint8 opMode,uint8 channel,uint8 channelMode,bool intEnable,halTimerCBack_t cback );

opMode – Operation mode操作方式共3种


* channel – Channel where the counter operates on选择通道,对应IO口


* channelMode – Mode of that channel通道的模式


* intEnable –可中断


* cBack – Pointer to the callback function 中断函数

然后在回调函数中进行处理相关事件即可。

void timer_callback(uint8 timerId, uint8 channel, uint8 channelMode);

2、使用寄存器直接操作

直接使用寄存器就更简单了,就把CC2530当做一个单片机用就可以了,这里我拿了我以前写的代码给大家演示,注释有错的地方请忽略,大概就这样吧。

void InitT3(void)

{

T3CTL |= 0x08 ; //开溢出中断

T3IE = 1; //开总中断和T3中断

T3CTL|=0X12; //,128/16000000*N=0.5S,N=65200

T3CC0 = 0x01;

T3CTL &=
~0X03; //自动重装 00->0xff

T3CTL |=0X10; //启动

}

void timer1Init(void)

{/*设置定时器T1,128分频,模模式,从0计数到T1CC0*/

T1CTL |= 0x0E;

/*装入定时器初值(比较值)*/

T1CC0L = 0x01;

T1CC0H = 0x00;

/*设置捕获比较通道0为比较模式,用以触发中断*/

T1CCTL0 ^=BIT(2);

/*使能Timer1中断*/

T1IE = 1;

T1CTL |= 0x03; //开启定时器

/*开启总中断*/

}

#pragma vector=T1_VECTOR

__near_func __interrupt void t1_irq(void)

{

//做一点别的事情

}

#pragma vector=T3_VECTOR

__interrupt void T3_IRQ(void)

{

IRCON = 0x00; //清中断标志, 也可由硬件自动完成

}

3、使用OSAL_Timer延时或定时事件

假如我们现在需要20s翻转一次led灯,那么我们可以使用

uint8 osal_set_event( uint8 task_id, uint16 event_flag )这个函数设定一个事件,下一次协议栈轮询的时候就会执行相应的事件,在GenericApp_ProcessEvent中我们可以添加自己的事件:

if
( events & APP_LED_TOGGLE )


{

//执行LED灯的翻转


return
(events ^ APP_LED_TOGGLE);


}

如果你这个使用调用osal_set_event( your_task_id, APP_LED_TOGGLE )的话,就会执行一次LED灯的翻转,但是不会有第二次(注意,这里task_id需要填写你自己的task_id),如果我们需要每过20s就翻转一次,那我们还需要在事件处理的地方添加另一行代码即可:

osal_start_timerEx( your_task_id,,APP_LED_TOGGLE,20000 );

最后一个参数是定时时间,ms为单位,APP_LED_TOGGLE是你自己定义的任务,其中最高位(0x08000,SYS_EVENT_MSG)系统保留,用户可以使用的事件有15个。这个大家自己找个地方宏定义下就OK了。现在我们的代码就变成了这样:

if
( events & APP_LED_TOGGLE )


{

//执行LED灯的翻转

osal_start_timerEx( your_task_id,,APP_LED_TOGGLE,20000 );


return
(events ^ APP_LED_TOGGLE);


}

如此,20s后LED灯又会翻转一次,达到了定时事件的效果。同样,也可以用这个方法来延时。

总的来说,协议栈中使用定时器还是比较容易的,基本的用法就这三个,灵活的运用,一般的问题都可以解决。当然,在使用定时器的时候还需要注意,在PM3模式下定时器可能会不准的问题,我在之前的帖子中有提到过,是因为PM3模式下高频晶振已经不起振了,所以我们没法使用。



使用示例:

1,先在APP头文件中声明两个变量:一个表示事件,一个表示时间

#define SAMPLEAPP_SLEEP_MSG_EVT               0x000F
#define SAMPLEAPP_SLEEP_TIMEOUT_MSG_EVT       30000     //60s


2,在需要启动定时器的方法中开启定时器:

  osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SLEEP_MSG_EVT,
                       (SAMPLEAPP_SLEEP_TIMEOUT_MSG_EVT));

3,在事件处理函数中处理

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  
  if ( events & SAMPLEAPP_SLEEP_MSG_EVT )
  {
   
    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SLEEP_MSG_EVT,
                       (SAMPLEAPP_SLEEP_TIMEOUT_MSG_EVT));//继续定时
  
    printf("===>>>>>timer running..... \r\n");
    return (events ^ SAMPLEAPP_SLEEP_MSG_EVT);
  }
  
   return 0;
}











你可能感兴趣的:(zigbee)