rt_thread 的定时器管理源码分析.doc_第1页
rt_thread 的定时器管理源码分析.doc_第2页
rt_thread 的定时器管理源码分析.doc_第3页
rt_thread 的定时器管理源码分析.doc_第4页
rt_thread 的定时器管理源码分析.doc_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 前言rt-thread可以采用软件定时器或硬件定时器来实现定时器管理的,所谓软件定时器是指由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。而硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。软件定时器的精度取决于它使用的硬件定时器精度。而rt-thread操作系统在默认情况下是采用的硬件定时器的方式,用户可以通过修改宏定义#ifdef RT_USING_TIMER_SOFT来修改采用哪种。2 rt-thread的定时器的基本工作原理在RT-Thread定时器模块维护两个重要的全局变量,一个是当前系统的时间rt_tick(当硬件定时器中断来临时,它将加1),另一个是定时器链表rt_timer_list,系统中新创建的定时期都会被以排序的方式插入到rt_timer_list(硬件定时器模式下使用)链表中,rt_timer_list的每个节点保留了一个定时器的信息,并且在这个节点加入链表时就计算好了产生时间到达时的时间点,即tick,在rt-thread系统中如果采用软件定时器模式,则存在一定时器线程rt_thread_timer_entry,不断获取当前TICK值并与定时器链表rt_timer_list上的定时器对比判断是否时间已到,一旦发现就调用对应的回调函数,即事件处理函数进行处理,而如果采用硬件定时器管理模式的话,则该检查过程放到系统时钟中断例程中进行处理,此时,是不存在定时器线程的。如下图:注:如果采用软件定时器软件定时器,则该定时器链表为rt_soft_timer_list。3 源码分析3.1 数据定义cpp view plaincopyprint?1. /*2. *timerstructure3. */4. structrt_timer5. 6. structrt_objectparent;/内核对象 7. 8. rt_list_tlist;/链表节点 9. 10. void(*timeout_func)(void*parameter);/定时器超时例程 11. void*parameter;/定时器例程的传入参数 12. 13. rt_tick_tinit_tick;/定时器的超时时间,即总共多长时间将产生超时事件 14. rt_tick_ttimeout_tick;/定时器超时的时间点,即产生超时事件时那一该的时间点 15. ;16. typedefstructrt_timer*rt_timer_t;/* * timer structure */struct rt_timer struct rt_object parent; /内核对象 rt_list_t list; /链表节点 void (*timeout_func)(void *parameter); /定时器超时例程 void *parameter; /定时器例程的传入参数 rt_tick_t init_tick; /定时器的超时时间,即总共多长时间将产生超时事件 rt_tick_t timeout_tick; /定时器超时的时间点,即产生超时事件时那一该的时间点;typedef struct rt_timer *rt_timer_t;3.2 rt-thread的软件定时器模式软件定时器线程初始化及启动:cpp view plaincopyprint?1. /*2. *ingroupSystemInit3. *4. *Thisfunctionwillinitializesystemtimerthread5. */6. voidrt_system_timer_thread_init(void)7. 8. #ifdefRT_USING_TIMER_SOFT/如果采用软件定时器管理模式,则启动定时器线程 9. rt_list_init(&rt_soft_timer_list);/初始化软件定时器链表 10. 11. /*startsoftwaretimerthread*/12. rt_thread_init(&timer_thread,/初始化软件定时器线程,并启动 13. timer,14. rt_thread_timer_entry,15. RT_NULL,16. &timer_thread_stack0,17. sizeof(timer_thread_stack),18. RT_TIMER_THREAD_PRIO,19. 10);20. 21. /*startup*/22. rt_thread_startup(&timer_thread);23. #endif 24. /* * ingroup SystemInit * * This function will initialize system timer thread */void rt_system_timer_thread_init(void)#ifdef RT_USING_TIMER_SOFT/如果采用软件定时器管理模式,则启动定时器线程 rt_list_init(&rt_soft_timer_list);/初始化软件定时器链表 /* start software timer thread */ rt_thread_init(&timer_thread,/初始化软件定时器线程,并启动 timer, rt_thread_timer_entry, RT_NULL, &timer_thread_stack0, sizeof(timer_thread_stack), RT_TIMER_THREAD_PRIO, 10); /* startup */ rt_thread_startup(&timer_thread);#endif软件定时器线程如下: cpp view plaincopyprint?1. /*systemtimerthreadentry*/2. staticvoidrt_thread_timer_entry(void*parameter)3. 4. rt_tick_tnext_timeout;5. 6. while(1)7. 8. /*getthenexttimeouttick*/9. next_timeout=rt_timer_list_next_timeout(&rt_soft_timer_list);/得到软件定时器链表上的下一个定时器的超时时间点 10. if(next_timeout=RT_TICK_MAX)/如果超过范围,则挂起当前线程,继续线程调度 11. 12. /*nosoftwaretimerexist,suspendself.*/13. rt_thread_suspend(rt_thread_self();14. rt_schedule();15. 16. else17. 18. rt_tick_tcurrent_tick;19. 20. /*getcurrenttick*/21. current_tick=rt_tick_get();/获取当前时间点 22. 23. if(next_timeout-current_tick)RT_TICK_MAX/2)/离下个中断时间点还差些时候 24. 25. /*getthedeltatimeouttick*/26. next_timeout=next_timeout-current_tick;/计算还差多长时间 27. rt_thread_delay(next_timeout);/休眠一段时间 28. 29. 30. 31. /*lockscheduler*/32. rt_enter_critical();/时间到,进入临界区 33. /*checksoftwaretimer*/34. rt_soft_timer_check();/检查是否该产生超时事件 35. /*unlockscheduler*/36. rt_exit_critical();/退出临界区 37. 38. /* system timer thread entry */static void rt_thread_timer_entry(void *parameter) rt_tick_t next_timeout; while (1) /* get the next timeout tick */ next_timeout = rt_timer_list_next_timeout(&rt_soft_timer_list);/得到软件定时器链表上的下一个定时器的超时时间点 if (next_timeout = RT_TICK_MAX)/如果超过范围,则挂起当前线程,继续线程调度 /* no software timer exist, suspend self. */ rt_thread_suspend(rt_thread_self(); rt_schedule(); else rt_tick_t current_tick; /* get current tick */ current_tick = rt_tick_get();/获取当前时间点 if (next_timeout - current_tick) timeout_tick)next;/指向下一定时器 29. 30. /*removetimerfromtimerlistfirstly*/31. rt_list_remove(&(t-list);/移除当前定时器 32. 33. /*calltimeoutfunction*/34. t-timeout_func(t-parameter);/产生定时器超时事件,调用对应处理函数 35. 36. /*re-gettick*/37. current_tick=rt_tick_get();/再次获取当前时间点 38. 39. RT_DEBUG_LOG(RT_DEBUG_TIMER,(currenttick:%dn,current_tick);40. 41. if(t-parent.flag&RT_TIMER_FLAG_PERIODIC)&/如果当前定时器是周期性定时器,则将其再次按序放入软件定时器链表 42. (t-parent.flag&RT_TIMER_FLAG_ACTIVATED)43. 44. /*startit*/45. t-parent.flag&=RT_TIMER_FLAG_ACTIVATED;/置标志为非激活状态 46. rt_timer_start(t);/再次将定时器t放入软件定时器链表末尾 47. 48. else49. 50. /*stoptimer*/51. t-parent.flag&=RT_TIMER_FLAG_ACTIVATED;/置标志为非激活状态 52. 53. 54. elsebreak;/*notcheckanymore*/55. 56. 57. RT_DEBUG_LOG(RT_DEBUG_TIMER,(softwaretimercheckleaven);58. /* * This function will check timer list, if a timeout event happens, the * corresponding timeout function will be invoked. */void rt_soft_timer_check(void) rt_tick_t current_tick; rt_list_t *n; struct rt_timer *t; RT_DEBUG_LOG(RT_DEBUG_TIMER, (software timer check entern); current_tick = rt_tick_get();/得到当前时间点 for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list);)/得到下一定时器节点 t = rt_list_entry(n, struct rt_timer, list);/t指向rt_timer定时器 /* * It supposes that the new tick shall less than the half duration of * tick max. */ if (current_tick - t-timeout_tick) next;/指向下一定时器 /* remove timer from timer list firstly */ rt_list_remove(&(t-list);/移除当前定时器 /* call timeout function */ t-timeout_func(t-parameter);/产生定时器超时事件,调用对应处理函数 /* re-get tick */ current_tick = rt_tick_get();/再次获取当前时间点 RT_DEBUG_LOG(RT_DEBUG_TIMER, (current tick: %dn, current_tick); if (t-parent.flag & RT_TIMER_FLAG_PERIODIC) &/如果当前定时器是周期性定时器,则将其再次按序放入软件定时器链表 (t-parent.flag & RT_TIMER_FLAG_ACTIVATED) /* start it */ t-parent.flag &= RT_TIMER_FLAG_ACTIVATED;/置标志为非激活状态 rt_timer_start(t);/再次将定时器t放入软件定时器链表末尾 else /* stop timer */ t-parent.flag &= RT_TIMER_FLAG_ACTIVATED;/置标志为非激活状态 else break; /* not check anymore */ RT_DEBUG_LOG(RT_DEBUG_TIMER, (software timer check leaven);上面代码中,为什么定时器里判断超时的条件是(current_tick - ttimeout_tick) parent.flag&RT_TIMER_FLAG_ACTIVATED)/如果传入的定时器已经激活,则直接返回错误 17. return-RT_ERROR;18. 19. RT_OBJECT_HOOK_CALL(rt_object_take_hook,(&(timer-parent);/使用钩子函数 20. 21. /*22. *gettimeouttick,23. *themaxtimeouttickshallnotgreatthanRT_TICK_MAX/224. */25. RT_ASSERT(timer-init_ticktimeout_tick=rt_tick_get()+timer-init_tick;/得到定时器超时的时间点 27. 28. /*disableinterrupt*/29. level=rt_hw_interrupt_disable();/关中断 30. 31. #ifdefRT_USING_TIMER_SOFT/如果采用的是软件定时器管理模式,则将定时器加入到rt_soft_timer_list中 32. if(timer-parent.flag&RT_TIMER_FLAG_SOFT_TIMER)33. 34. /*inserttimertosofttimerlist*/35. timer_list=&rt_soft_timer_list;36. 37. else38. #endif 39. 40. /*inserttimertosystemtimerlist*/41. timer_list=&rt_timer_list;42. 43. 44. for(n=timer_list-next;n!=timer_list;n=n-next)/将定时器按序加入到定时器链表中 45. 46. t=rt_list_entry(n,structrt_timer,list);47. 48. /*49. *Itsupposesthatthenewtickshalllessthanthehalfdurationof50. *tickmax.51. */52. if(t-timeout_tick-timer-timeout_tick)list);/将定时器timer插入到t之前 55. break;56. 57. 58. /*nofoundsuitablepositionintimerlist*/59. if(n=timer_list)/没有找到合适的位置,则放到链表头 60. 61. rt_list_insert_before(n,&(timer-list);62. 63. 64. timer-parent.flag|=RT_TIMER_FLAG_ACTIVATED;/置定时器为激活状态 65. 66. /*enableinterrupt*/67. rt_hw_interrupt_enable(level);68. 69. #ifdefRT_USING_TIMER_SOFT 70. if(timer-parent.flag&RT_TIMER_FLAG_SOFT_TIMER)/如果系统采用的是软件定时器管理模式,且软件定时器线程处理ready状态,则恢复此线程 71. 72. /*checkwhethertimerthreadisready*/73. if(timer_thread.stat!=RT_THREAD_READY)74. 75. /*resumetimerthreadtochecksofttimer*/76. rt_thread_resume(&timer_thread);/恢复定时器线程 77. rt_schedule();/开始线程调度 78. 79. 80. #endif 81. 82. return-RT_EOK;83. /* * This function will start the timer * * param timer the timer to be started * * return the operation status, RT_EOK on OK, -RT_ERROR on error */rt_err_t rt_timer_start(rt_timer_t timer) struct rt_timer *t; register rt_base_t level; rt_list_t *n, *timer_list; /* timer check */ RT_ASSERT(timer != RT_NULL); if (timer-parent.flag & RT_TIMER_FLAG_ACTIVATED)/如果传入的定时器已经激活,则直接返回错误 return -RT_ERROR; RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer-parent);/使用钩子函数 /* * get timeout tick, * the max timeout tick shall not great than RT_TICK_MAX/2 */ RT_ASSERT(timer-init_tick timeout_tick = rt_tick_get() + timer-init_tick;/得到定时器超时的时间点 /* disable interrupt */ level = rt_hw_interrupt_disable();/关中断#ifdef RT_USING_TIMER_SOFT/如果采用的是软件定时器管理模式,则将定时器加入到rt_soft_timer_list中 if (timer-parent.flag & RT_TIMER_FLAG_SOFT_TIMER) /* insert timer to soft timer list */ timer_list = &rt_soft_timer_list; else#endif /* insert timer to system timer list */ timer_list = &rt_timer_list; for (n = timer_list-next; n != timer_list; n = n-next)/将定时器按序加入到定时器链表中 t = rt_list_entry(n, struct rt_timer, list); /* * It supposes that the new tick shall less than the half duration of * tick max. */ if (t-timeout_tick - timer-timeout_tick) list);/将定时器timer插入到t之前 break; /* no found suitable position in timer list */ if (n = timer_list)/没有找到合适的位置,则放到链表头 rt_list_insert_before(n, &(timer-list); timer-parent.flag |= RT_TIMER_FLAG_ACTIVATED;/置定时器为激活状态 /* enable interrupt */ rt_hw_interrupt_enable(level);#ifdef RT_USING_TIMER_SOFT if (timer-parent.flag & RT_TIMER_FLAG_SOFT_TIMER)/如果系统采用的是软件定时器管理模式,且软件定时器线程处理ready状态,则恢复此线程 /* check whether timer thread is ready */ if (timer_thread.stat != RT_THREAD_READY) /* resume timer thread to check soft timer */ rt_thread_resume(&timer_thread);/恢复定时器线程 rt_schedule();/开始线程调度 #endif return -RT_EOK;软件定时器管理模式的源码分析完了,接下来介绍RTT的硬件定时器管理模式。 3.3 RTT的硬件定时器管理模式硬件定时器管理模式顾名思义,就是说与硬件相关,因此,不用的MCU,其部分源码是不一样的,因为其要采用MCU的系统时钟中断例程来实现。以STM32F2XX为例,先找到其启动汇编,位置在:RTT/bsp/stm32f2xx/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F2xx/startup/arm/startup_stm32f2xx.s找到中断向量:plain view plaincopyprint?1. DCDSysTick_Handler;SysTickHandlerDCD SysTick_Handler ; SysTick Handler这是系统时钟中断向量,再找到其中断例程实现: 在bsp/stm32f2xx/drivers/board.c文件中:cpp view plaincopyprint?1. /*2. *Thisisthetimerinterruptserviceroutine.3. *4. */5. voidSysTick_Handler(void)/系统时钟中断例程 6. 7. /*enterinterrupt*/8. rt_interrupt_enter();9. 10. rt_tick_increase();11. 12. /*leaveinterrupt*/13. rt_interrupt_leave();14. /* * This is the timer interrupt service routine. * */void SysTick_Handler(void)/系统时钟中断例程/* enter interrupt */rt_interrupt_enter();rt_tick_increase();/* leave interrupt */rt_interrupt_leave();其中rt_tick_increase函数在RTT/src/clock.c文件中的实现如下: cpp view plaincopyprint?1. /*2. *Thisfunctionwillnotifykernelthereisonetickpassed.Normally,3. *thisfunctionisinvokedbyclockISR.4. */5. voidrt_tick_increase(void)6. 7. structrt_thread*thread;8. 9. /*increasetheglobaltick*/10. +rt_tick;/全局rt_tick加1 11. 12. /*checktimeslice*/13. thread=rt_thread_self();/得到当前正在运行的线程 14. 15. -thread-remaining_tick;/纯种剩下时间减1 16. if(thread-remaining_tick=0)/如果线程剩余时间为0,即调度时间已到 17. 18. /*changetoinitializedtick*/19. thread-remaining_tick=thread-init_tick;/将线程剩余时间重新设置初始化值 20. 21. /*yield*/22. rt_thread_yield();/调度时间到,切换到其它线程 23. 24. 25. /*checktimer*/26. rt_timer_check();/检查硬件定时器链表是否有定时器产生超时事件 27. /* * This function will notify kernel there is one tick passed. Normally, * this function is invoked by clock ISR. */void rt_tick_increase(void) struct rt_thread *thread; /* increase the global tick */ + rt_tick;/全局rt_tick加1 /* check time slice */ th

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论