简介
这里定时器使用方式和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;
}