前言
- RTOS使用多了,是不是认为一切皆RTOS,其实小的设备,反而使用裸机程序也是可以完成的
- 本篇把RT-Thread中的timer,通过【魔改】的方式,改成裸机程序
- 裸机程序,虽然没有OS,也需要设计一些软件架构,让开发更高效
移植方法
验证平台
- STM32L476平台,理论上稍微调整,可以用于多个平台
- timer部分尽量保证平台无关
- 由于没有充分的测试验证,不清楚是否有BUG
- 由于基于systick,默认1ms的硬件定时器,所以定时器回调中,执行时间不能过长
实现代码
- timer.h : 定义timer使用的数据类型与结构,timer的API
#ifndef __TIMER_H__
#define __TIMER_H__
#include <stdint.h>
#define TIMER_FLAG_DEACTIVATED 0x00
#define TIMER_FLAG_ACTIVATED 0x01
#define TIMER_FLAG_ONE_SHOT 0x00
#define TIMER_FLAG_PERIODIC 0x02
#define TIMER_CTRL_GET_TIME 0x01
#define TIMER_CTRL_SET_TIME 0x02
#define TIMER_CTRL_SET_ONESHOT 0x04
#define TIMER_CTRL_SET_PERIODIC 0x08
#define TIMER_CTRL_GET_STATE 0x10
#define TIM_NULL 0
#define TIM_EOK 0
#define TIM_ERROR 1
#define TIM_TICK_MAX 0xffffffff
#define TIM_ASSERT(ex) \
if (!(ex)) \
{ \
while (1); \
}
struct list_head
{
struct list_head *next;
struct list_head *prev;
};
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
#define container_of(ptr, type, member) \
((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
typedef struct list_head dl_list_t;
struct sys_timer
{
uint32_t flag;
dl_list_t list;
void (*timeout_func)(void *arg);
void *arg;
uint32_t init_tick;
uint32_t timeout_tick;
};
typedef struct sys_timer sys_timer_t;
uint32_t isr_enable(void);
void isr_disable(uint32_t level);
uint32_t tick_get(void);
void tick_set(uint32_t tick);
void tick_increase(void);
void timer_init(sys_timer_t *timer,
void (*timeout_func)(void *param),
void *param,
uint32_t ticks,
uint32_t flag);
int32_t timer_detach(sys_timer_t *timer);
int32_t timer_start(sys_timer_t *timer);
int32_t timer_stop(sys_timer_t *timer);
void system_timer_init(void);
int32_t timer_control(sys_timer_t *timer, int cmd, void *arg);
void timer_check(void);
#endif
#include <timer.h>
static uint32_t tim_tick = 0;
static struct list_head system_timer_list;
uint32_t isr_enable(void)
{
return 1;
}
void isr_disable(uint32_t level)
{
}
uint32_t tick_get(void)
{
return tim_tick;
}
void tick_set(uint32_t tick)
{
uint32_t level;
level = isr_enable();
tim_tick = tick;
isr_disable(level);
}
void tick_increase(void)
{
uint32_t irq_lock;
irq_lock = isr_enable();
tim_tick++;
isr_disable(irq_lock);
timer_check();
}
dl_list_t * get_system_timer_list(void)
{
return &system_timer_list;
}
static void _timer_init(sys_timer_t *timer,
void (*timeout_func)(void *arg),
void *arg,
uint32_t ticks,
uint32_t flag)
{
timer->flag = flag;
timer->flag &= ~TIMER_FLAG_ACTIVATED;
timer->timeout_func = timeout_func;
timer->arg = arg;
timer->timeout_tick = 0;
timer->init_tick = ticks;
INIT_LIST_HEAD(&(timer->list));
}
void timer_init(sys_timer_t *timer,
void (*timeout_func)(void *arg),
void *arg,
uint32_t ticks,
uint32_t flag)
{
TIM_ASSERT(timer != TIM_NULL);
_timer_init(timer, timeout_func, arg, ticks, flag);
}
int32_t timer_detach(sys_timer_t *timer)
{
uint32_t irq_lock;
TIM_ASSERT(timer != TIM_NULL);
irq_lock = isr_enable();
list_del_init(&timer->list);
timer->flag &= ~TIMER_FLAG_ACTIVATED;
isr_disable(irq_lock);
return TIM_EOK;
}
int32_t timer_start(sys_timer_t *timer)
{
uint32_t irq_lock;
dl_list_t *timer_list = TIM_NULL;
dl_list_t *list = TIM_NULL;
sys_timer_t *tm = TIM_NULL;
TIM_ASSERT(timer != TIM_NULL);
TIM_ASSERT(timer->init_tick < TIM_TICK_MAX / 2);
irq_lock = isr_enable();
list_del_init(&timer->list);
timer->flag &= ~TIMER_FLAG_ACTIVATED;
timer->timeout_tick = tick_get() + timer->init_tick;
timer_list = &system_timer_list;
for (list = timer_list; list != timer_list->prev; list = list->next)
{
tm = list_entry(list->next, sys_timer_t, list);
if (tm->timeout_tick - timer->timeout_tick == 0)
{
continue;
}
else if ((tm->timeout_tick - timer->timeout_tick) < TIM_TICK_MAX / 2)
{
break;
}
}
list_add(&timer->list, list);
timer->flag |= TIMER_FLAG_ACTIVATED;
isr_disable(irq_lock);
return TIM_EOK;
}
int32_t timer_stop(sys_timer_t *timer)
{
uint32_t irq_lock;
TIM_ASSERT(timer != TIM_NULL);
if (!(timer->flag & TIMER_FLAG_ACTIVATED))
{
return TIM_ERROR;
}
irq_lock = isr_enable();
list_del_init(&timer->list);
timer->flag &= ~TIMER_FLAG_ACTIVATED;
isr_disable(irq_lock);
return TIM_EOK;
}
void system_timer_init(void)
{
INIT_LIST_HEAD(&system_timer_list);
}
int32_t timer_control(sys_timer_t *timer, int cmd, void *arg)
{
uint32_t irq_lock;
TIM_ASSERT(timer != TIM_NULL);
irq_lock = isr_enable();
switch (cmd)
{
case TIMER_CTRL_GET_TIME:
*(uint32_t *)arg = timer->init_tick;
break;
case TIMER_CTRL_SET_TIME:
timer->init_tick = *(uint32_t *)arg;
break;
case TIMER_CTRL_SET_ONESHOT:
timer->flag &= ~TIMER_FLAG_PERIODIC;
break;
case TIMER_CTRL_SET_PERIODIC:
timer->flag |= TIMER_FLAG_PERIODIC;
break;
case TIMER_CTRL_GET_STATE:
if (timer->flag & TIMER_FLAG_ACTIVATED)
{
*(uint32_t *)arg = TIMER_FLAG_ACTIVATED;
}
else
{
*(uint32_t *)arg = TIMER_FLAG_DEACTIVATED;
}
break;
default:
break;
}
isr_disable(irq_lock);
return TIM_EOK;
}
void timer_check(void)
{
uint32_t irq_lock;
sys_timer_t *tm;
uint32_t cur_tick;
dl_list_t temp_list;
INIT_LIST_HEAD(&temp_list);
cur_tick = tick_get();
irq_lock = isr_enable();
while (!list_empty(&system_timer_list))
{
tm = list_entry(system_timer_list.next, sys_timer_t, list);
if ((cur_tick - tm->timeout_tick) < TIM_TICK_MAX / 2)
{
list_del_init(&tm->list);
if (!(tm->flag & TIMER_FLAG_PERIODIC))
{
tm->flag &= ~TIMER_FLAG_ACTIVATED;
}
list_add(&(tm->list), &temp_list);
tm->timeout_func(tm->arg);
cur_tick = tick_get();
if (list_empty(&temp_list))
{
continue;
}
list_del_init(&tm->list);
if ((tm->flag & TIMER_FLAG_PERIODIC) &&
(tm->flag & TIMER_FLAG_ACTIVATED))
{
tm->flag &= ~TIMER_FLAG_ACTIVATED;
timer_start(tm);
}
}
else
{
break;
}
}
isr_disable(irq_lock);
}
#include <timer_test.h>
#include <board.h>
static sys_timer_t timer_test1;
static sys_timer_t timer_test2;
static sys_timer_t timer_test3;
void timer_test1_timeout_func(void *param)
{
printk("tim1 func, tick=%d\r\n", tick_get());
}
void timer_test1_init(void)
{
timer_init(&timer_test1,
timer_test1_timeout_func,
TIM_NULL,
1000,
TIMER_FLAG_ONE_SHOT);
}
void timer_test1_start(void)
{
timer_start(&timer_test1);
}
void timer_test1_stop(void)
{
timer_stop(&timer_test1);
}
void timer_test2_timeout_func(void *param)
{
printk("tim2 func, tick=%d\r\n", tick_get());
}
void timer_test2_init(void)
{
timer_init(&timer_test2,
timer_test2_timeout_func,
TIM_NULL,
2000,
TIMER_FLAG_PERIODIC);
}
void timer_test2_start(void)
{
timer_start(&timer_test2);
}
void timer_test2_stop(void)
{
timer_stop(&timer_test2);
}
void timer_test3_timeout_func(void *param)
{
printk("tim3 func, tick=%d\r\n", tick_get());
}
void timer_test3_init(void)
{
timer_init(&timer_test3,
timer_test3_timeout_func,
TIM_NULL,
5000,
TIMER_FLAG_PERIODIC);
}
void timer_test3_start(void)
{
timer_start(&timer_test3);
}
void timer_test3_stop(void)
{
timer_stop(&timer_test3);
}
int timer_test_handler(void)
{
system_timer_init();
timer_test1_init();
timer_test2_init();
timer_test3_init();
timer_test1_start();
timer_test2_start();
timer_test3_start();
return 0;
}
#ifndef __TIMER_TEST_H__
#define __TIMER_TEST_H__
#include "timer.h"
int os_timer_run_test(void);
#endif
#include "board.h"
#include "timer_test.h"
#define USART2_BAUDRATE 115200
int main(void)
{
HAL_Init();
SystemClock_Config();
bsp_systick_init();
MX_GPIO_Init();
usart2_init(USART2_BAUDRATE);
LEDG_GPIO_Init();
printk("hello, NUCLEO-L476RG\r\n");
os_timer_run_test();
while (1)
{
LEDG_power_ctrl(1);
HAL_Delay(1000);
LEDG_power_ctrl(0);
HAL_Delay(1000);
}
}
- systick.c : 这里使用systick实现1ms计数
#include <board.h>
void SysTick_Handler(void)
{
HAL_IncTick();
tick_increase();
}
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
return HAL_OK;
}
void bsp_systick_init(void)
{
HAL_SYSTICK_Config(SystemCoreClock / 1000);
NVIC_SetPriority(SysTick_IRQn, 0xFF);
}
验证效果
hello, NUCLEO-L476RG
tim1 func, tick=1002
tim2 func, tick=2002
tim2 func, tick=4002
tim3 func, tick=5002
tim2 func, tick=6002
tim2 func, tick=8002
tim3 func, tick=10002
tim2 func, tick=10002
tim2 func, tick=12002
tim2 func, tick=14002
tim3 func, tick=15002
tim2 func, tick=16002
tim2 func, tick=18002
tim3 func, tick=20002
tim2 func, tick=20002
小结
- 基本实现的定时器的初始化、开启、停止等功能
- 占用资源不算太多,主要可以方便实现多个定时器应用
|