Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread
定时器
RT-Thread的定时器timer功能移植到裸机程序上
发布于 2022-01-15 22:24:48 浏览:1049
订阅该版
[tocm] [RT-Thread 入门学习笔记 - 目录](https://club.rt-thread.org/ask/article/3420.html) ## 前言 - RTOS使用多了,是不是认为一切皆RTOS,其实小的设备,反而使用裸机程序也是可以完成的 - 本篇把RT-Thread中的timer,通过【魔改】的方式,改成裸机程序 - 裸机程序,虽然没有OS,也需要设计一些软件架构,让开发更高效 ## 移植方法 - 移除操作系统的依赖 - 修复编译 - API重命名 ## 验证平台 - STM32L476平台,理论上稍微调整,可以用于多个平台 - timer部分尽量保证平台无关 - 由于没有充分的测试验证,不清楚是否有BUG - 由于基于systick,默认1ms的硬件定时器,所以定时器回调中,执行时间不能过长 ## 实现代码 - timer.h : 定义timer使用的数据类型与结构,timer的API ```c #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_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 的实现: ```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 ```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=%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 ```c #ifndef __TIMER_TEST_H__ #define __TIMER_TEST_H__ #include "timer.h" int os_timer_run_test(void); #endif ``` - main 函数: ```c /* * 裸机工程:用于功能验证 * 硬件平台: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计数 ```c #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 ```c 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 ``` - 验证效果初步符合预期 ## 小结 - 基本实现的定时器的初始化、开启、停止等功能 - 占用资源不算太多,主要可以方便实现多个定时器应用
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
813
被采纳
177
关注TA
发私信
相关文章
1
RT-THREAD在STM32H747平台上移植lwip
2
正点原子miniSTM32开发板读写sdcard
3
反馈rtt串口驱动对低功耗串口lpuart1不兼容的问题
4
Keil MDK 移植 RT-Thread Nano
5
RT1061/1052 带 RTT + LWIP和LPSPI,有什么坑要注意吗?
6
RT thread HID 如何收发数据
7
求一份基于RTT系统封装好的STM32F1系列的FLASH操作程序
8
RT-Thread修改项目名称之后不能下载
9
rt-studio编译c++
10
有木有移植rt-thread(nano)到riscv 32位MCU上
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
10
个答案
3
次被采纳
xiaorui
3
个答案
2
次被采纳
winfeng
2
个答案
2
次被采纳
三世执戟
8
个答案
1
次被采纳
KunYi
8
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
lizimu
2
篇文章
9
次点赞
swet123
1
篇文章
4
次点赞
Days
1
篇文章
4
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部