时钟节拍
任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件,如线程的延时、时间片的轮转调度以及定时器超时等。
RTT中,时钟节拍的长度可以根据RT_TICK_PER_SECOND的定义来调整。rtconfig.h配置文件中定义:
/**
* This is the timer interrupt service routine.
*
*/
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
HAL_IncTick();
rt_tick_increase();
/* leave interrupt */
rt_interrupt_leave();
}
获取系统节拍
rt_tick_get();
定时器
定时器,是指从指定的时刻开始,经过一定的指定时间后触发一个事件,定时器有硬件定时器和软件定时器之分:
- 硬件定时器:芯片本身提供的定时功能,一般由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。
硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。 - 软件定时器:由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。
RTT操作系统提供软件实现的定时器,以时钟节拍(OS Tick)的时间长度为单位,即定时数值必须是OS Tick的整数倍。
RTT提供的两类定时器机制
- 单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动停止。
- 周期触发定时器,这类定时器会周期性地触发定时器事件,直到用户手动的停止,否则将永远持续执行下去。
根据定时器超时函数执行时所处的上下文环境,RT-Thread的定时器可以分为HARD_TIMER模式和SOFT_TIMER模式。
HARD_TIMER模式:中断上下文
定时器超时函数的要求:执行时间应该尽量短,执行时不应导致当前上下文挂起、等待。例如在中断上下文中执行超时函数不应该试图去申请动态内存、释放动态内存等。
SOFT_TIMER模式:线程上下文
该模式被弃用后,系统会在初始化时创建一个timer线程,然后SOFT_TIMER模式的定时器超时函数都会在timer线程的上下文环境中执行。
定时器工作机制
在RTT定时器模块中维护着两个重要的全局变量:
- 当前系统经过的tick时间rt_tick(当硬件定时器中断来临时,它将加1)。
- 定时器链表rt_timer_list。系统新创建并激活的定时器都会按照以超时时间排序的方式插入到rt_timer_list链表中。
系统当前tick值为20,在当前系统中以及创建并启动了三个定时器。
分别是定时时间为50个tick的Timer1、100个tick的Timer2和500个tick的Timer3.
这三个定时器分别加上系统当前时间rt_tick=20,从小到大排序链接在rt_timer_list链表中。
rt_tick随着硬件定时器的触发一直在增加(每一次硬件定时器中断来临,rt_tick变量会加1),50个tick以后,rt_tick从20增长到70,与Timer1的timeout值相等,这时会触发与Timer1定时器相关联的超时函数,同时将Timer1从rt_timer_list链表上删除。同理,100个tick和500个tick过去后,与Timer2和Timer3定时器相关联的超时函数会被触发,接着将Timer2和Timer3定时器从rt_timer_list链表删除。
如果系统当前定时器状态在10个tick以后(rt_tick=30)有一个任务新创建了一个tick值为300的Timer4定时器,由于Timer4定时器的timeout=rt_tick+300=330,因此它被插入到Timer2和Timer3定时器中间,形成如下图所示链表结构:
高精度延时
此函数只支持低于1个OS Tick的延时,否则SysTick会出现溢出而不能够获取指定的延时时间。
void rt_hw_us_delay(rt_uint32_t us);//只支持小于1ms的延时