2026/3/8 15:57:33
网站建设
项目流程
网站推广可采用的方法有哪些,wordpress+资源站模板,校园资源共享网站建设,国外企业网络会议的组织与优化本小节介绍定时器使用时的常见注意事项#xff0c;从而避免常见错误和不当用法#xff0c;实现学会在实际项目中更稳定、安全地使用定时器回调函数运行在中断/任务上下文对于HARD_TIMER模式的定时器#xff0c;由系统时钟节拍中断处理程序扫描定时器列表并执行回调函数…本小节介绍定时器使用时的常见注意事项从而避免常见错误和不当用法实现学会在实际项目中更稳定、安全地使用定时器回调函数运行在中断/任务上下文对于HARD_TIMER模式的定时器由系统时钟节拍中断处理程序扫描定时器列表并执行回调函数因此禁止使用 rt_thread_mdelay()等让当前中断暂停执行的API。RT-Thread可能无法处理这种问题进而导致整个系统运行出现混乱。同样地对于SOFT_TIMER模式的定时器由定时器任务扫描并执行回调函数不建议使用rt_thread_mdelay()等让当前任务暂停执行的API。这将造成定时器任务无法及时扫描并执行其它定时器的回调函数。因此在定时器回调处理函数中最好是快速完成相关的工作。如果有耗时的任务建议交由其它任务去完成。例如可以通过简单地设置标志位或者用信号量、消息队列等机制来实现这种操作。#include rtthread.h #include base.h // 全局定时器句柄 rt_timer_t led_timer; // 标志变量标志LED是否停止 volatile rt_bool_t led_stopped RT_FALSE; // 回调函数 static void led_timer_cb(void *parameter) { RT_UNUSED(parameter); led_toggle(LED0); // 切换 LED 状态 static int count 0; if (count 20) { rt_timer_stop(led_timer); // 停止定时器 led_stopped RT_TRUE; // 设置标志位 } } // 打印线程入口 static void print_task_entry(void *parameter) { RT_UNUSED(parameter); while (1) { if (led_stopped) { rt_kprintf(LED stopped flashing after 20 times.\n); // 为了不重复打印只执行一次后清标志 led_stopped RT_FALSE; } rt_thread_mdelay(200); // 每200ms检查一次 } } int main(void) { hardware_init(); // 创建LED定时器500ms周期周期性软定时器 led_timer rt_timer_create(led_t, led_timer_cb, RT_NULL, rt_tick_from_millisecond(500), RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); if (led_timer ! RT_NULL) { rt_timer_start(led_timer); // 启动定时器 } // 创建任务线程检测 LED 状态 rt_thread_t tid rt_thread_create(print_task, print_task_entry, RT_NULL, 1024, 20, 10); if (tid ! RT_NULL) rt_thread_startup(tid); return 0; }定时准确度虽然RT-Thread的定时器可用于实现毫秒级别的周期性事件但它并不一定能实现“精确定时”。也就是说假设设置了一个定时器每1000ms执行一次但它实际触发的时间可能是1002ms、998ms。因素说明系统时钟节拍周期RT-Thread 使用tick计时默认1 tick 1ms无法实现小于一个系统时钟节拍时期的时长定时。系统负载对于SOFT_TIMER定时器而言当系统任务过多或者高优先级任务长时间占用 CPU定时器线程无法及时执行回调函数从而产生延迟。定时器数量由于系统中定时器进行了排队当队列中定时器较多且超时的任务较多时会延后后面的定时器的任务执行。定时器类型对于HARD_TIMER定时器而言当程序中中断屏蔽时间太长时将影响到系统中定时器回调函数的执行时间。中断屏蔽时间如果代码中大量禁用了中断也可能延迟系统时钟节拍的响应从而影响定时器触发时机。使用不当比如在定时器回调中做了太复杂的操作影响下一次周期到达。下面通过一个简单的图示可以看出定时器回调函数不一定被准时调用。HARD/SOFT定时器该选哪种在 RT-Thread 中创建的定时器可以是“软定时器SOFT”或“硬定时器HARD”。这两者都会在设定的时间后回调一个函数但触发机制不同会影响程序的实时性和安全性。想实现“定时1秒闪灯”你会选择哪个我们已知这两种类型的定时器各有特点我们在实际使用时可以参考如下表格类型执行位置响应速度回调函数限制使用场景硬定时器中断上下文快速、精确严格不能阻塞、不允许长时间计算实时性强、快速响应任务如数据采集、电机控制等软定时器定时器任务稍慢灵活可调度任务、可打印日常逻辑定时处理如LED闪烁、状态轮询、自动保存等例如对于下述场景我们可以根据这两类定时器特点做出不同的选择应用场景推荐使用1s 闪烁 LED 指示灯软定时器数据采集每 1ms 精确触发硬定时器10 秒后保存参数到 Flash软定时器定时唤醒线程处理数据软定时器快速响应 GPIO 变化的处理硬定时器 或中断也就是说在选择使用定时器时我们可以如果需要在中断上下文中快速响应选择硬定时器如果需要安全灵活的定时处理逻辑比如打印、处理逻辑优先选软定时器实在不确定建议从软定时器入手再根据性能需求调整特别要注意当系统中HARD_TIMER定时器较多且执行时间较长时将大大影响时间片调度的执行。总结定时器功能强大但容易误用需了解其运行环境HARD、SOFT回调中避免耗时操作用信号量交由线程处理动态定时器和封装结构可实现更灵活设计精度与tick配置、系统负载密切相关补充说明在视频中我写了这样的代码。如果实际调试可能会发现main无法继续往下执行rt_timer_create()等函数CPU会一直执行threa_entry()中的while(1循环。之所以如此是因为rt_thread_startup(thread)执行时由于thread的优先级为0最高RT-Thread会转而执行该任务的代码。而由于 thread_entry()一直在死循环没有延时、挂起等操作所以一直占用CPU运行导致低优先级的main任务、定时器任务无法运行。#include rtthread.h #include base.h #include rtconfig.h static rt_timer_t led_timer; static void led_timer_cb (void * parameter) { led_toggle(LED0); static int count; if (count 20) { rt_timer_stop(led_timer); } } struct rt_timer oneshort_timer; static void oneshort_timer_cb (void * parameter) { led_toggle(LED1); rt_timer_start(oneshort_timer); } void thread_entry (void * param) { while (1) { } } int main (void) { hardware_init(); rt_thread_t thread rt_thread_create(thread, thread_entry, RT_NULL, 4096, 0, 200); rt_thread_startup(thread); led_timer rt_timer_create(led, led_timer_cb, RT_NULL, rt_tick_from_millisecond(10), // tick RT_TIMER_FLAG_PERIODIC ); rt_timer_start(led_timer); rt_timer_init(oneshort_timer, oneshort, oneshort_timer_cb, RT_NULL, 3*RT_TICK_PER_SECOND, // rt_tick_from_millisecond(3000), RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); rt_timer_start(oneshort_timer); return 0; }