(原创)RTOS-RTX分析系列之定时器

2017/07/21 RTX

简介

这里定时器使用方式和rt_timer大同小异。

关键结构

// ==== Timer Management ====

// Timer definitions
#define osTimerInvalid  0
#define osTimerStopped  1
#define osTimerRunning  2

// Timer structures 

typedef struct os_timer_cb_ {                   // Timer Control Block
  struct os_timer_cb_ *next;                    // Pointer to next active Timer
  uint8_t             state;                    // Timer State
  uint8_t              type;                    // Timer Type (Periodic/One-shot)
  uint16_t         reserved;                    // Reserved
  uint32_t             tcnt;                    // Timer Delay Count
  uint32_t             icnt;                    // Timer Initial Count 
  void                 *arg;                    // Timer Function Argument
  const osTimerDef_t *timer;                    // Pointer to Timer definition
} os_timer_cb;

关键变量

// Timer variables
os_timer_cb *os_timer_head;                     // Pointer to first active Timer

关键实现

定时器这块非常简单,仅仅是一个链表,然后在系统滴答中断里调用就好,不做过多解释,看注释把。

rt_timer_insert

// Insert Timer into the list sorted by time
static void rt_timer_insert (os_timer_cb *pt, uint32_t tcnt) {
  os_timer_cb *p, *prev;

  prev = NULL;
  p = os_timer_head;
  while (p != NULL) {
    if (tcnt < p->tcnt) break; //找到插入位置
    tcnt -= p->tcnt;
    prev = p;
    p = p->next;
  }
  pt->next = p;
  pt->tcnt = tcnt;
  if (p != NULL) {
    p->tcnt -= pt->tcnt;//保证后面的定时器延时时间不变
  }
  if (prev != NULL) {
    prev->next = pt;
  } else {
    os_timer_head = pt;
  }
}

rt_timer_remove

// Remove Timer from the list
static int rt_timer_remove (os_timer_cb *pt) {
  os_timer_cb *p, *prev;

  prev = NULL;
  p = os_timer_head;
  while (p != NULL) {
    if (p == pt) break;
    prev = p;
    p = p->next;
  }
  if (p == NULL) return -1;
  if (prev != NULL) {
    prev->next = pt->next;
  } else {
    os_timer_head = pt->next;
  }
  if (pt->next != NULL) {
    pt->next->tcnt += pt->tcnt;//保证后面的定时器延时时间不变
  }

  return 0;
}

回调

/// Timer Tick (called each SysTick)
void sysTimerTick (void) {
  os_timer_cb *pt, *p;
  osStatus     status;

  p = os_timer_head;
  if (p == NULL) return;

  p->tcnt--;//每次减1,然后查看下一个链接节点的定时器是否触发。
  while ((p != NULL) && (p->tcnt == 0)) {
    pt = p;
    p = p->next;
    os_timer_head = p;
    status = isrMessagePut(osMessageQId_osTimerMessageQ, (uint32_t)pt, 0);//由于是在中断里,因此只能使用带isr头的邮箱投递。
    if (status != osOK) {
      os_error(OS_ERR_TIMER_OVF);
    }
    if (pt->type == osTimerPeriodic) {
      rt_timer_insert(pt, pt->icnt);//如果是周期性定时器,再次插入链表。
    } else {
      pt->state = osTimerStopped;
    }
  }
}

运行机制

上面的代码仅仅是在中断里投递定时触发邮箱,并不是立马就执行定时器回调函数,真正的执行在下面线程里:

// Timer Thread
__NO_RETURN void osTimerThread (void const *argument) {
  osCallback cb;
  osEvent    evt;

  for (;;) {
    evt = osMessageGet(osMessageQId_osTimerMessageQ, osWaitForever);//一旦检测有一个定时器完成触发就开始执行
    if (evt.status == osEventMessage) {
      cb = osTimerCall(evt.value.p);
      if (cb.fp != NULL) {
	(*(os_ptimer)cb.fp)(cb.arg);//执行回调函数
      }
    }
  }
}

那么这线程是在哪里开启的呢?看看下面就知道了:

/// Initialize the RTOS Kernel for creating objects
osStatus svcKernelInitialize (void) {
  int ret;

  if (!os_initialized) {

    // Init Thread Stack Memory (must be 8-byte aligned)
    if ((uint32_t)os_stack_mem & 7) return osErrorNoMemory;
    ret = rt_init_mem(os_stack_mem, os_stack_sz);
    if (ret != 0) return osErrorNoMemory;

    rt_sys_init();                              // RTX System Initialization
  }

  os_tsk.run->prio = 255;                       // Highest priority

  if (!os_initialized) {//第一次初始化时,开启定时器线程。
    // Create OS Timers resources (Message Queue & Thread)
    osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
    osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL);
  }

  sysThreadError(osOK);

  os_initialized = 1;
  os_running = 0;

  return osOK;
}

知识共享许可协议
本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

站内搜索

    撩我备注-博客

    joinee

    目录结构