IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32 裸机程序实现类似RT-Thread的timer功能 -> 正文阅读

[嵌入式]STM32 裸机程序实现类似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 <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
  • timer.c 的实现:
#include <timer.h>

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 <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());
    //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=%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;
}
  • 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-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>

/**
  * @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
  • 验证效果初步符合预期

小结

  • 基本实现的定时器的初始化、开启、停止等功能
  • 占用资源不算太多,主要可以方便实现多个定时器应用
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-01-16 13:13:51  更:2022-01-16 13:14:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 1:25:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码