09 在ZStack里的定时器应用

ZStack里的任务是基于事件来调度的, 里面的定时器其实就是在约定的时间到后,设置指定任务的事件,从而让设置定时的任务处理定时事件.

定时器封装在工程目录OSAL里的OSAL_Timers.h头文件里:

  extern uint8 osal_start_timerEx( uint8 task_id, uint16 event_id, uint16 timeout_value ); //设置timeout_value毫秒后,系统会设置task_id任务号的任务发生event_id事件. 此函数创建的定时器是一次性的.

  extern uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint16 timeout_value ); //此定时器与上面的定时器相似,但可重复使用。

  extern uint8 osal_stop_timerEx( uint8 task_id, uint16 event_id ); //停止定时器

  extern uint32 osal_GetSystemClock( void ); //返回系统的时钟,毫秒级别

//
此定时器功能是依赖SOC上的Timer2(MAC Timer)来实现的.
大概过程:

void osal_run_system( void ) //在系统任务的死循环检查事件函数里
{
  uint8 idx = 0;

  osalTimeUpdate(); //根据Timer2的计时来更新系统时间
  Hal_ProcessPoll();
    ...
}
///

void osalTimeUpdate( void )
{
    ...
    if ( elapsedMSec )
    {
      osalClockUpdate( elapsedMSec );
      osalTimerUpdate( elapsedMSec ); //更新系统里定时器时间
    }
}
///
//当调用osal_start_timerEx函数创建对象时:
uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
    ...
  newTimer = osalAddTimer( taskID, event_id, timeout_value );
    ...
}


typedef struct
{
  void   *next;
  uint16 timeout; //此值为0时表示定时器已超时
  uint16 event_flag; //记录定时器超时后给task_id任务设置什么事件
  uint8  task_id;
  uint16 reloadTimeout; //重复性定时器用的初始计时值
} osalTimerRec_t;

osalTimerRec_t *timerHead; //timerHead是全局指针变量,也就是定时器的链表头节点

osalTimerRec_t * osalAddTimer( uint8 task_id, uint16 event_flag, uint16 timeout )
{
  osalTimerRec_t *newTimer;
  osalTimerRec_t *srchTimer;

    // New Timer
    newTimer = osal_mem_alloc( sizeof( osalTimerRec_t ) ); //动态创建一个定时器对象

    if ( newTimer )
    {
      // 初始化定时器对象
      newTimer->task_id = task_id;
      newTimer->event_flag = event_flag;
      newTimer->timeout = timeout;
      newTimer->next = (void *)NULL;
      newTimer->reloadTimeout = 0;

      if ( timerHead == NULL ) //如果还没有头节点,则创建出来的定时器对象就成为头节点
        timerHead = newTimer;
      else
      {
        srchTimer = timerHead;
        while ( srchTimer->next ) //如果已经有头节点了,则在链表的尾部加入新的定时器对象
          srchTimer = srchTimer->next;
        srchTimer->next = newTimer;
      }
    ...
  }
/

//再回到定时器的计时更新函数里:
void osalTimerUpdate( uint16 updateTime )
{
  halIntState_t intState;
  osalTimerRec_t *srchTimer;
  osalTimerRec_t *prevTimer;

    ...
  osal_systemClock += updateTime; //更新系统的计时时间
    ...

  if ( timerHead != NULL ) //判断定时器链表是否为空
  {
    srchTimer = timerHead;
    prevTimer = (void *)NULL;

    while ( srchTimer ) //遍历定时器链表里的每个定时器对象,检查是否已超时
    {
      osalTimerRec_t *freeTimer = NULL;

      if (srchTimer->timeout <= updateTime)
     srchTimer->timeout = 0;
      else
        srchTimer->timeout = srchTimer->timeout - updateTime;

      if ( (srchTimer->timeout == 0) && (srchTimer->reloadTimeout) && (srchTimer->event_flag) ) //重复性的定时器发生超时的操作
      {
        //下面这语句其实就是"tasksEvents[task_id] |= event_flag"
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );
        srchTimer->timeout = srchTimer->reloadTimeout;//重新设置要计时的初始值
      }

      if ( srchTimer->timeout == 0 || srchTimer->event_flag == 0 ) //定时器超时,但没有事件需要设置的操作
      {
        if ( prevTimer == NULL )
          timerHead = srchTimer->next;
        else
          prevTimer->next = srchTimer->next;

        freeTimer = srchTimer;
        srchTimer = srchTimer->next;
      }
      else
      {
        prevTimer = srchTimer;
        srchTimer = srchTimer->next; //移动到链表的下一个节点
      }
    ...
  }
}

//
定时2秒控制led灯的实现:

MyApp.c

#include "OnBoard.h"
#include "MyApp.h"
#include "hal_led.h"

#define TIME_OUT_EVENT 0x4
#define TIME_LEN       2000

uint8  mytask_id; //用于存放本身的任务号


void MyApp_Init(uint8 task_id )
{
   mytask_id = task_id; 


   osal_start_reload_timer(task_id, TIME_OUT_EVENT, TIME_LEN);  
}



uint16 MyApp_ProcessEvent(uint8 task_id, uint16 events )
{
  if (events & TIME_OUT_EVENT)
  {
     HalLedSet(HAL_LED_ALL, HAL_LED_MODE_TOGGLE);
  }

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值