嵌入式技术论坛
直播中

ss

8年用户 8762经验值
擅长:电源/新能源 制造/封装 RF/无线
私信 关注
[经验]

教你一种移植RT-Thread定时器timer功能的方法

前言
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
验证效果初步符合预期

小结
基本实现的定时器的初始化、开启、停止等功能
占用资源不算太多,主要可以方便实现多个定时器应用。


更多回帖

发帖
×
20
完善资料,
赚取积分