目前在做一个项目使用到了 RT-Thread 操作系统,这里就记录一下在使用过程中的一些学习记录。
任何操作系统中,都需要提供一个时钟节拍(OS Tick),它是操作系统中最小的时间单位,供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等。
以 RT-Thread 为例,在创建任务时,需要配置一个时间片:
/** * @brief This function will create a thread object and allocate thread object memory. * and stack. * * @param tick is the time slice if there are same priority thread. */ rt_thread_t rt_thread_create(const char *name, void (*entry)(void *parameter), void *parameter, rt_uint32_t stack_size, rt_uint8_t priority, rt_uint32_t tick)
线程延时函数的实现,也需要依赖系统节拍:
/** * @brief This function will let current thread delay for some milliseconds. * * @param ms is the delay ms time. * * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed. * If the return value is any other values, it means this operation failed. */ rt_err_t rt_thread_mdelay(rt_int32_t ms) { rt_tick_t tick; tick = rt_tick_from_millisecond(ms); return rt_thread_sleep(tick); } RTM_EXPORT(rt_thread_mdelay);
时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳,中断时间间隔取决于不同的应用,一般是 1ms–100ms,时钟节拍率越快,系统的额外开销就越大,从系统启动开始计数的时钟节拍数称为系统时间。
在 RT-Thread 中,时钟节拍的长度可以根据宏 RT_TICK_PER_SECOND 的定义来调整,该宏定义在头文件 rtconfig.h 中,一个时钟节拍等于 1/RT_TICK_PER_SECOND 秒。默认的 RT_TICK_PER_SECOND 为 100,即一秒会产生 100 个 tick,每个 tick 为 10ms。
/* RT-Thread Kernel */ #define RT_TICK_PER_SECOND 100
时钟节拍由配置为中断触发模式 的硬件定时器 产生,当中断到来时,将调用一次 rt_tick_increase()
函数,通知操作系统已经过去一个系统时钟,不同的硬件定时器中断实现都不同,下面的中断函数以 STM32 定时器作为示例:
/** * 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_increase()
函数实现对全局变量 rt_tick
的自加,该函数定义在 clock.c
中,程序如下所示:
/** * @brief 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; rt_base_t level; RT_OBJECT_HOOK_CALL(rt_tick_hook, ()); level = rt_hw_interrupt_disable(); /* increase the global tick */ #ifdef RT_USING_SMP rt_cpu_self()->tick ++; #else ++ rt_tick; #endif /* RT_USING_SMP */ /* check time slice */ thread = rt_thread_self(); -- thread->remaining_tick; if (thread->remaining_tick == 0) { /* change to initialized tick */ thread->remaining_tick = thread->init_tick; thread->stat |= RT_THREAD_STAT_YIELD; rt_hw_interrupt_enable(level); rt_schedule(); } else { rt_hw_interrupt_enable(level); } /* check timer */ rt_timer_check(); }
通过 rt_tick_t rt_tick_get(void)
函数可获取当前的系统节拍,可用于记录系统的当前运行时间,该函数定义在 clock.c
中,程序如下所示:
/** * @brief This function will return current tick from operating system startup. * * @return Return current tick. */ rt_tick_t rt_tick_get(void) { /* return the global tick */ return rt_tick; } RTM_EXPORT(rt_tick_get);
可通过 void rt_tick_set(rt_tick_t tick)
函数设定当前系统的 tick 值,该函数定义在 clock.c
中,程序如下所示:
/** * @brief This function will set current tick. * * @param tick is the value that you will set. */ void rt_tick_set(rt_tick_t tick) { rt_base_t level; level = rt_hw_interrupt_disable(); rt_tick = tick; rt_hw_interrupt_enable(level); }
在 clock.c
中还定义了一个 rt_tick_get_millisecond
虚函数,通过该函数可获取当前系统运行的毫秒数,建议在 RT_TICK_PER_SECOND
为 1000 时使用,程序如下:
/** * @brief This function will return the passed millisecond from boot. * * @note if the value of RT_TICK_PER_SECOND is lower than 1000 or * is not an integral multiple of 1000, this function will not * provide the correct 1ms-based tick. * * @return Return passed millisecond from boot. */ RT_WEAK rt_tick_t rt_tick_get_millisecond(void) { #if 1000 % RT_TICK_PER_SECOND == 0u return rt_tick_get() * (1000u / RT_TICK_PER_SECOND); #else #warning "rt-thread cannot provide a correct 1ms-based tick any longer,\ please redefine this function in another file by using a high-precision hard-timer." return 0; #endif /* 1000 % RT_TICK_PER_SECOND == 0u */ }
可以使用 rt_tick_get_millisecond
函数通过以下方式计算某个任务的耗时时间:
{ rt_tick_t start,end; start = rt_tick_get_millisecond(); function_to_get_time(); end = rt_tick_get_millisecond(); rt_kprintf("The time consumed is %d ms. \n", end - start); }
参考来源:RT-Thread