前言
RTOS使用多了,是不是认为一切皆RTOS,其实小的设备,反而使用裸机程序也是可以完成的
本篇把RT-Thread中的 timer,通过【魔改】的方式,改成裸机程序
裸机程序,虽然没有OS,也需要设计一些软件架构,让开发更高效
移植方法
移除操作系统的依赖
修复编译
API重命名
验证平台
STM32L476平台,理论上稍微调整,可以用于多个平台
timer部分尽量保证平台无关
由于没有充分的测试验证,不清楚是否有BUG
由于基于systick,默认1ms的硬件定时器,所以定时器回调中,执行时间不能过长
实现代码
timer.h : 定义timer使用的数据类型与结构,timer的API
#ifndef __TIMER_H__
#define __TIMER_H__
#include
#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_time
{
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
timer.c 的实现:
#include
static uint32_t tim_tick = 0;
/* systick : system timer list */
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();
/* step1 : stop timer */
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); /* add to tail */
timer->flag |= TIMER_FLAG_ACTIVATED; /* set activated flag */
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); /* insert temp list */
tm->timeout_func(tm->arg);
cur_tick = tick_get();
/* check timer object is detached or started again */
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);
}
测试 timer_test.c
#include
#include
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=%drn", 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=%drn", tick_get());
//os_timer_start(&timer_test2);
}
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=%drn", 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;
}
test_timer.h
#ifndef __TIMER_TEST_H__
#define __TIMER_TEST_H__
#include "timer.h"
int os_timer_run_test(void);
#endif
main 函数:
/*
* 裸机工程:用于功能验证
* 硬件平台:STM32L476RG : NUCLEO-L476RG
* 2022-01-15
*/
#include "board.h"
#include "timer_test.h"
#define USART2_BAUDRATE 115200
/**
* @Brief The application entry point.
* @retval int
*/
int main(void)
{
HAL_Init();
SystemClock_Config();
bsp_systick_init();
MX_GPIO_Init();
usart2_init(USART2_BAUDRATE);
LEDG_GPIO_Init();
printk("hello, NUCLEO-L476RGrn");
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
/**
* @brief This function handles System tick timer.
*/
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);
}
验证效果
这里使用uart串口打印,类似于printf
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
验证效果初步符合预期
小结
基本实现的定时器的初始化、开启、停止等功能
占用资源不算太多,主要可以方便实现多个定时器应用。
|