Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread
学习笔记
软件定时器
RT-Thread 入门学习笔记 - 熟悉软件定时器的使用
发布于 2021-03-16 09:07:34 浏览:2422
订阅该版
[tocm] [RT-Thread 入门学习笔记 - 目录](https://club.rt-thread.org/ask/article/3420.html) ## 前言 - 通过RT-Thread内核定时器的熟悉,并根据自己的使用,发现,软件定时器的使用需要关心某些事项 - 软件定时器分为静态初始化与动态创建两种 - 软件定时器可以创建很多,分为一次性的,周期性的。 - 两个软件定时器,超时时间可以一样,同时超时,依次执行超时回调,注意超时回调中,不要过多的处理 - 一些动态申请内存的操作,可以放在`软件定时器线程`去处理,需要配置开启软件定时器线程 - 软件定时器分为系统定时器与软件定时器线程的定时器,分为两个独立的定时器链表管理,定时器超时回调函数执行的环境不一样。 - 可以让定时器在运行的中途停下来(rt_timer_stop),并修改参数,可以调用:rt_timer_control实现如修改超时时间等操作 ## 定时器操作 ### 静态初始化定时器 rt_timer_init - 主要需要首先定义一个定时器对象(非定时器指针),如struct rt_timer timer; - 静态定义的定时器,不需要判断是否为RT_NULL,因为全局静态的变量,内存是确定的。 - 静态的定时器,不需要了,可以调用:rt_timer_detach,detach后,静态的定时器对象,不会释放,可以再次初始化使用。 ### 动态创建定时器 rt_timer_create - 动态创建的定时器,返回为定时器对象的指针,需要判断是否为RT_NULL - 删除动态创建的定时器,使用:rt_timer_delete,定时器对象的内存释放 ## 使用经验 - 定时器对象,如:rt_timer_delete后,对象指针还存在(野指针),所以,可以在删除后,手动把定时器对象改为RT_NULL,确保不【重复删除】 - 定时器启动后,如再次启动,会返回失败。所以,最好管理一个是否启动的标志位,保证不【重复启动】。 - 如果没有开启软件定时器线程,初始化/创建定时器时,使用RT_TIMER_FLAG_SOFT_TIMER,无效果,依旧是定时器中断环境执行 ![2021-03-16_084432.png](https://oss-club.rt-thread.org/uploads/20210316/b7799ebc236f99d14f66e83ab212f5b2.png) - 每个线程创建后,都有一个线程定时器,这个线程定时器,挂在系统定时器链表上,是通过rt_timer_init初始化。 - 可以使用list_timer,查看系统的定时器。 ## 问题与分析 - 【问题】既然有两个定时器链表,但获取下一个定时器超时的函数,`rt_timer_next_timeout_tick`,获取的是 系统定时器链表的超时。如果开启了软件定时器线程,定义了`RT_TIMER_FLAG_SOFT_TIMER`,这个超时是否准确? 【答】:经过验证与内核源码的分析:准确。需要理解(1)每个线程都有一个静态的定时器,是挂在系统定时器链表上的。(2)软件定时器线程,并不是一直在跑,计算好下一个超时后,就会suspend(此时开启了一个定时器)。 - 【问题】动态申请的线程,定时器的内存空间是动态申请的,为何使用:rt_timer_init 【答】:因为整片内存虽然是动态申请的,但定时器对象是一个静态的对象。所以需要使用:rt_timer_init,线程删除时,使用:rt_timer_detach。因为整个动态申请的线程结构体一起free释放,所以,不用担心内存泄漏问题。 ## 静态timer初始化示例 ```c #include
#define DBG_TAG "demo.timer" #define DBG_LVL DBG_LOG #include
static struct rt_timer demo1_timer = { 0 }; static struct rt_timer demo2_timer = { 0 }; static rt_bool_t demo1_timer_init_flag = RT_FALSE; static rt_bool_t demo2_timer_init_flag = RT_FALSE; static rt_bool_t demo1_timer_run_flag = RT_FALSE; static rt_bool_t demo2_timer_run_flag = RT_FALSE; #define DEMO1_TIMEOUT_TIME 2000 #define DEMO2_TIMEOUT_TIME 5000 /* demo1 timer timeout entry */ static void demo1_timer_timeout(void *param) { LOG_I("%s : enter", __func__); } /* demo2 timer timeout entry */ static void demo2_timer_timeout(void *param) { LOG_I("%s : enter", __func__); } /* demo1 timer init */ rt_err_t demo1_timer_init(void) { if (demo1_timer_init_flag == RT_TRUE) return RT_EOK; rt_timer_init(&demo1_timer, "demo1_tm", demo1_timer_timeout, RT_NULL, DEMO1_TIMEOUT_TIME, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); demo1_timer_init_flag = RT_TRUE; return RT_EOK; } /* demo2 timer init */ rt_err_t demo2_timer_init(void) { if (demo2_timer_init_flag == RT_TRUE) return RT_EOK; rt_timer_init(&demo2_timer, "demo2_tm", demo2_timer_timeout, RT_NULL, DEMO2_TIMEOUT_TIME, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); demo2_timer_init_flag = RT_TRUE; return RT_EOK; } /* demo1 timer Start */ rt_err_t demo1_timer_start(void) { rt_err_t ret = RT_EOK; if (demo1_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo1_timer_run_flag == RT_FALSE) { ret = rt_timer_start(&demo1_timer); } if (ret == RT_EOK) { demo1_timer_run_flag = RT_TRUE; } return ret; } /* demo2 timer Start */ rt_err_t demo2_timer_start(void) { rt_err_t ret = RT_EOK; if (demo2_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo2_timer_run_flag == RT_FALSE) { ret = rt_timer_start(&demo2_timer); } if (ret == RT_EOK) { demo2_timer_run_flag = RT_TRUE; } return ret; } /* demo1 timer Stop*/ rt_err_t demo1_timer_stop(void) { rt_err_t ret = RT_EOK; if (demo1_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo1_timer_run_flag == RT_TRUE) { ret = rt_timer_stop(&demo1_timer); } if (ret == RT_EOK) { demo1_timer_run_flag = RT_FALSE; } return ret; } /* demo2 timer Stop*/ rt_err_t demo2_timer_stop(void) { rt_err_t ret = RT_EOK; if (demo2_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo2_timer_run_flag == RT_TRUE) { ret = rt_timer_stop(&demo2_timer); } if (ret == RT_EOK) { demo2_timer_run_flag = RT_FALSE; } return ret; } MSH_CMD_EXPORT(demo1_timer_init, demo1 timer init); MSH_CMD_EXPORT(demo2_timer_init, demo1 timer init); MSH_CMD_EXPORT(demo1_timer_start, demo1 timer start); MSH_CMD_EXPORT(demo2_timer_start, demo1 timer start); MSH_CMD_EXPORT(demo1_timer_stop, demo1 timer stop); MSH_CMD_EXPORT(demo2_timer_stop, demo1 timer stop); ``` ## 运行效果 - 执行 MSH CMD 命令 ```c msh />demo1_timer_init msh />demo2_timer_init msh />demo1_timer_start msh />demo2_timer_start ``` - 运行效果如下: ![2022-03-02_174955.png](https://oss-club.rt-thread.org/uploads/20220302/46de71ef4954efa41053f56f8ba9471b.png) ## 动态timer创建示例 ```c #include
#define DBG_TAG "demo.timer" #define DBG_LVL DBG_LOG #include
/* 这里 rt_timer_t 是个定时器 指针 */ static rt_timer_t demo3_timer = RT_NULL; static rt_timer_t demo4_timer = RT_NULL; static rt_bool_t demo3_timer_init_flag = RT_FALSE; static rt_bool_t demo4_timer_init_flag = RT_FALSE; static rt_bool_t demo3_timer_run_flag = RT_FALSE; static rt_bool_t demo4_timer_run_flag = RT_FALSE; #define DEMO1_TIMEOUT_TIME 2000 #define DEMO2_TIMEOUT_TIME 5000 /* demo3 timer timeout entry */ static void demo3_timer_timeout(void *param) { LOG_I("%s : enter", __func__); } /* demo4 timer timeout entry */ static void demo4_timer_timeout(void *param) { LOG_I("%s : enter", __func__); } /* demo3 timer init */ static rt_err_t demo3_timer_init(void) { if (demo3_timer_init_flag == RT_TRUE) return RT_EOK; demo3_timer = rt_timer_create("demo3_tm", demo3_timer_timeout, RT_NULL, DEMO1_TIMEOUT_TIME, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); if (demo3_timer == RT_NULL) { LOG_E("%s : create error!", __func__); return -RT_ERROR; } demo3_timer_init_flag = RT_TRUE; return RT_EOK; } /* demo4 timer init */ static rt_err_t demo4_timer_init(void) { if (demo4_timer_init_flag == RT_TRUE) return RT_EOK; demo4_timer = rt_timer_create("demo4_tm", demo4_timer_timeout, RT_NULL, DEMO2_TIMEOUT_TIME, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); if (demo4_timer == RT_NULL) { LOG_E("%s : create error!", __func__); return -RT_ERROR; } demo4_timer_init_flag = RT_TRUE; return RT_EOK; } /* demo3 timer Start */ rt_err_t demo3_timer_start(void) { rt_err_t ret = RT_EOK; if (demo3_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo3_timer_run_flag == RT_FALSE) { ret = rt_timer_start(demo3_timer); } if (ret == RT_EOK) { demo3_timer_run_flag = RT_TRUE; } return ret; } /* demo4 timer Start */ rt_err_t demo4_timer_start(void) { rt_err_t ret = RT_EOK; if (demo4_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo4_timer_run_flag == RT_FALSE) { ret = rt_timer_start(demo4_timer); } if (ret == RT_EOK) { demo4_timer_run_flag = RT_TRUE; } return ret; } /* demo3 timer Stop*/ rt_err_t demo3_timer_stop(void) { rt_err_t ret = RT_EOK; if (demo3_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo3_timer_run_flag == RT_TRUE) { ret = rt_timer_stop(demo3_timer); } if (ret == RT_EOK) { demo3_timer_run_flag = RT_FALSE; } return ret; } /* demo4 timer Stop*/ rt_err_t demo4_timer_stop(void) { rt_err_t ret = RT_EOK; if (demo4_timer_init_flag == RT_FALSE) { return -RT_ERROR; } if (demo4_timer_run_flag == RT_TRUE) { ret = rt_timer_stop(demo4_timer); } if (ret == RT_EOK) { demo4_timer_run_flag = RT_FALSE; } return ret; } MSH_CMD_EXPORT(demo3_timer_init, demo3 timer init); MSH_CMD_EXPORT(demo4_timer_init, demo4 timer init); MSH_CMD_EXPORT(demo3_timer_start, demo3 timer start); MSH_CMD_EXPORT(demo4_timer_start, demo4 timer start); MSH_CMD_EXPORT(demo3_timer_stop, demo3 timer stop); MSH_CMD_EXPORT(demo4_timer_stop, demo4 timer stop); ``` ## 运行效果 - 执行 MSH CMD 命令 ```c msh />demo3_timer_init msh />demo4_timer_init msh />demo3_timer_start msh />demo4_timer_start ``` - 运行效果如下: ![2022-03-02_180327.png](https://oss-club.rt-thread.org/uploads/20220302/9da1af0198ea3071fd401490e44519df.png) ## 总结 - 使用定时器,可以参考API或官方的定时器文档 - 使用过程中主要的事项,可以多总结,对照源码调试,思路会更清晰。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
804
被采纳
174
关注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
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
11
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
6
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部