RTthread学习笔记————第5章 时钟管理

  • 系统节拍

RT-Thread 的时钟管理以时钟节拍为基础,时钟节拍指的是周期性硬件定时器两次中断间的间隔时间长度,这个周期性硬件定时器称之为系统时钟。时钟节拍(OS Tick)是 RT-Thread 操作系统中最小的时钟单位,系统节拍一般定义为无符号 32 位整数,提供给应用程序所有和时间有关的服务,如线程的延时、线程的时间片轮转调度以及定时器超时等,从系统启动开始计数的时钟节拍数称为系统时间。

  • 系统节拍的实现方式

系统节拍由配置为中断触发模式的硬件定时器产生,当中断到来时,将调用一次:void rt_tick_increase(void),通知操作系统已经过去一个系统时钟;不同硬件定时器中断实现都不同,下面的中断函数以 STM32 定时器作为示例。

void SysTick_Handler(void)
{
    /* 进入中断 */
    rt_interrupt_enter();
    ……
    rt_tick_increase();
    /* 退出中断 */
    rt_interrupt_leave();
}

/*在中断函数中调用 rt_tick_increase()对全局变量 rt_tick 进行自加,代码如下所示:*/
void rt_tick_increase(void)
{
    struct rt_thread *thread;
    /* 全局变量 rt_tick 自加 */
    ++ rt_tick;
    /* 检查时间片 */
    thread = rt_thread_self();
    -- thread->remaining_tick;
    if (thread->remaining_tick == 0)
    {
        /* 重新赋初值 */
        thread->remaining_tick = thread->init_tick;
        /* 线程挂起 */
        rt_thread_yield();
    }
    /* 检查定时器 */
    rt_timer_check();
}

/*中断中的 rt_timer_check()用于检查系统硬件定时器链表,如果有定时器超时,将调用相应的超
时函数。且所有定时器在定时超时后都会从定时器链表中被移除,而周期性定时器会在它再次启动
时被加入定时器链表。*/

获取系统节拍

rt_tick_t rt_tick_get(void);

  • 定时器管理

     定时器的分类

1) 硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。
2) 软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。

    什么是定时器的上下文环境

RTthread学习笔记————第5章 时钟管理_第1张图片

HARD_TIMER 模式 :HARD_TIMER 模式的定时器超时函数在中断上下文环境中执行,可以在初始化/创建定时器时
                                 使用参数 RT_TIMER_FLAG_HARD_TIMER 来指定。

SOFT_TIMER 模式 :SOFT_TIMER 模式可配置,通过宏定义 RT_USING_TIMER_SOFT 来决定是否启用该模式。
                                 该模式被启用后,系统会在初始化时创建一个 timer 线程,然后 SOFT_TIMER 模式的定时器超时
                                 函数在都会在 timer 线程的上下文环境中执行。

  •      定时器相关函操作

在系统启动时需要初始化定时器管理系统。可以通过下面的函数接口完成:void rt_system_timer_init(void);

如果需要使用 SOFT_TIMER ,则系统初始化时,应该调用下面这个函数接口:void rt_system_timer_thread_init(void);

RTthread学习笔记————第5章 时钟管理_第2张图片

    创建定时器(动态)

/*当动态创建一个定时器时,可使用下面的函数接口:*/
rt_timer_t rt_timer_create(const char* name,
                            void (*timeout)(void* parameter),
                            void* parameter,
                            rt_tick_t time,
                            rt_uint8_t flag);

/*flag:*/
#define RT_TIMER_FLAG_ONE_SHOT 0x0 /* 单次定时 */
#define RT_TIMER_FLAG_PERIODIC 0x2 /* 周期定时 */
#define RT_TIMER_FLAG_HARD_TIMER 0x0 /* 硬件定时器 */
#define RT_TIMER_FLAG_SOFT_TIMER 0x4 /* 软件定时器 */

RTthread学习笔记————第5章 时钟管理_第3张图片

   删除定时器(动态)

/*系统不再使用动态定时器时,可使用下面的函数接口:*/
rt_err_t rt_timer_delete(rt_timer_t timer);

RTthread学习笔记————第5章 时钟管理_第4张图片

    初始化定时器(静态)

当选择静态创建定时器时,可利用 rt_timer_init 接口来初始化该定时器,函数接口如下:
void rt_timer_init(rt_timer_t timer,
                    const char* name,
                    void (*timeout)(void* parameter),
                    void* parameter,
                    rt_tick_t time, rt_uint8_t flag);

RTthread学习笔记————第5章 时钟管理_第5张图片

    脱离定时器(静态)

/*当一个静态定时器不需要再使用时,可以使用下面的函数接口:*/
rt_err_t rt_timer_detach(rt_timer_t timer);

RTthread学习笔记————第5章 时钟管理_第6张图片

启动和停止定时器

rt_err_t rt_timer_start(rt_timer_t timer);

RTthread学习笔记————第5章 时钟管理_第7张图片

rt_err_t rt_timer_stop(rt_timer_t timer);

RTthread学习笔记————第5章 时钟管理_第8张图片

    控制定时器

/*控制定时器函数接口可根据命令类型参数,来查看或改变定时器的设置*/
rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);

/*arg*/
#define RT_TIMER_CTRL_SET_TIME 0x0 /* 设置定时器超时时间 */
#define RT_TIMER_CTRL_GET_TIME 0x1 /* 获得定时器超时时间 */
#define RT_TIMER_CTRL_SET_ONESHOT 0x2 /* 设置定时器为单一超时型 */
#define RT_TIMER_CTRL_SET_PERIODIC 0x3 /* 设置定时器为周期型定时器 */

RTthread学习笔记————第5章 时钟管理_第9张图片RTthread学习笔记————第5章 时钟管理_第10张图片

  • TRthread小结

(1)HARD_TIMER 定时器的超时函数在(系统时钟)中断上下文环境中执行,可以在定时器控制块中使用参数 RT_TIMER_FLAG_HARD_TIMER 来指定。HARD_TIMER 定时器的超时函数的要求与中断服务例程的要求相同:执行时间应该尽量短,执行时不应导致当前上下文挂起、等待。
(2)SOFT_TIMER 定时器的超时函数在线程的上下文环境中执行,可以在定时器控制块中使用参数 RT_TIMER_FLAG_SOFT_TIMER 来指定。

(3)动态定时器的创建与删除调用接口 rt_timer_create 与 rt_timer_delete;静态定时器的初始化与脱离调用接口 rt_timer_init 与 rt_timer_detach。
(4)当需要实现更短时间长度的系统定时时,例如 OS Tick 是 10ms,而程序需要实现 1ms的定时或延时,这种时候操作系统定时器将不能够满足要求,只能通过读取系统某个硬件定时器的计数器或直接使用硬件定时器的方式来实现。

 

注:文章参考培训教

你可能感兴趣的:(嵌入式,STM32,RTthread)