前言
- 此处,介绍对delay 时钟 timer 这几部分之间的关联和相关的知识点;
- 本来只是想介绍一下 delay的,但是发现说到delay 不先 提到 先验知识 晶振\时钟\时钟节拍\定时器 好像没法解释透彻,所以就变成了 晶振\时钟\时钟节拍\定时器\delay 的很简单的概括一遍;
- 并附带上能直接运行的示例代码;
一个可以跳过的Tip -> 为了大家方便跳过,我设置成了图片,赶时间可以不点开
晶振 \ 时钟 \ 时钟节拍 \ 定时器 \ delay
定义
- 晶振(Crystal Oscillator):
晶振是硬件级别的时钟源,为微控制器(MCU)提供基准频率。它是系统所有时间相关功能的根基。晶振的频率决定了MCU的主时钟频率,通常称为HCLK(主时钟)。这个频率是非常重要的,因为它直接影响到微控制器的执行速度和整个系统的性能。
- 时钟(Clock):
在 RT-Thread 中,时钟通常指的是系统时钟,它是由晶振通过分频、倍频等方式产生的。系统时钟为操作系统和应用程序提供时间基准。系统时钟可以分为不同的类别,如核心时钟、外设时钟等,它们由晶振经过不同的处理得到。
- 时钟节拍(Tick):
时钟节拍是操作系统的基本时间单位,RT-Thread 通过硬件定时器来产生固定频率的时钟节拍。每一个时钟节拍代表操作系统中一个最小的时间片段。操作系统利用这些时钟节拍来进行任务调度、延时处理等操作。时钟节拍的频率(通常称为Tick Rate)决定了系统调度的精度和响应速度。例如,一个Tick Rate为1000Hz的系统每个时钟节拍代表1ms。
- 定时器(Timer):
定时器是基于时钟节拍工作的,用于执行定时任务。在 RT-Thread 中,定时器可以是一次性的或周期性的。定时器使用时钟节拍来计算时间,当达到指定的时钟节拍数时,定时器超时并执行相应的回调函数。
- delay:
delay 函数(在 RT-Thread 中通常为 rt_thread_delay())用于暂停当前线程执行指定的时间段。这个延时是以时钟节拍为单位的。当线程调用 rt_thread_delay() 时,它会被挂起,直到指定的时钟节拍数过去。在这段时间内,调度器会将CPU控制权转移给其他就绪状态的线程。
前面的解释可能太长了,我们再精简一点
- 晶振(Crystal Oscillator):
晶振提供了硬件级别的时钟源,它确定了微控制器(MCU)的主时钟频率(HCLK),这直接影响微控制器的执行速度和整个系统的性能。晶振是所有时间管理和计时功能的基础。
- 时钟(Clock):
系统时钟是由晶振产生的,可以通过分频、倍频等方式调整,为操作系统和应用程序提供时间基准。时钟可以有不同的类型(如核心时钟、外设时钟),它们支持系统各个部分的运作和时间管理。
- 时钟节拍(Tick):
时钟节拍是由系统时钟驱动的,表示操作系统的基本时间单位,用于任务调度和时间管理。时钟节拍的频率(Tick Rate)决定了系统的调度精度和响应速度,每个时钟节拍代表了系统中的一个固定时间片。
- 定时器(Timer):
定时器利用时钟节拍来计划和执行定时任务。它可以设置为一次性或周期性,用于在特定的时间点或经过特定时间段后执行任务。定时器的工作是基于时钟节拍的,它们使得在精确的时间执行任务成为可能。
- delay:
rt_thread_delay() 函数用于使当前线程暂停执行特定的时钟节拍数,从而提供延时功能。如果调用官方api,在此期间,CPU的控制权会转移给其他就绪状态的线程,实现有效的多任务处理。
一句话概括
- 晶振为系统提供基本的时间频率,系统时钟根据晶振调整形成不同的时间基准
- 时钟节拍根据系统时钟生成,为操作系统提供一个均匀的时间度量
- 定时器和延时功能(delay)则是基于这些时钟节拍来安排和管理时间和任务的执行。
- 观察 \ 运行 \ 修改 下方代码,获得更深入了解
示例代码
- 通过这个示例,可以展示 RT-Thread 如何处理线程延时和定时器回调,以及如何利用系统的时钟节拍来进行时间管理和任务调度。
- 在这个示例中,我们首先创建了一个线程 my_thread,它在一个循环中每隔一秒打印一次计数器 count 的值,并通过 rt_thread_delay() 函数实现延时。RT_TICK_PER_SECOND 定义了一秒内的时钟节拍数,因此 rt_thread_delay(RT_TICK_PER_SECOND) 将使线程延时一秒。
- 接下来,我们创建了一个周期性定时器 my_timer,它每秒触发一次,并在每次触发时打印出 “Timer tick”。定时器使用 RT_TICK_PER_SECOND 作为超时时间,设置为周期性定时器 RT_TIMER_FLAG_PERIODIC,这意味着它会每隔一秒自动重启并触发回调函数 timer_callback。
#include <rtthread.h>
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
/* 定义线程控制块 */
static struct rt_thread my_thread;
/* 定义线程栈 */
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t my_thread_stack[THREAD_STACK_SIZE];
/* 线程入口函数 */
static void my_thread_entry(void *parameter)
{
rt_uint32_t count = 0;
/* 线程主循环 */
while (1)
{
/* 打印信息并延时一秒 */
rt_kprintf("Thread count: %d\n", count++);
rt_thread_delay(RT_TICK_PER_SECOND); // 延时1秒,RT_TICK_PER_SECOND是系统时钟节拍数,代表一秒
}
}
/* 定时器回调函数 */
static void timer_callback(void *parameter)
{
rt_kprintf("Timer tick\n");
}
/* 应用程序入口 */
int main(void)
{
rt_timer_t my_timer;
rt_err_t result;
/* 初始化线程 */
result = rt_thread_init(&my_thread,
"mythread",
my_thread_entry,
RT_NULL,
&my_thread_stack[0],
sizeof(my_thread_stack),
THREAD_PRIORITY,
THREAD_TIMESLICE);
if (result == RT_EOK)
{
rt_thread_startup(&my_thread);
}
/* 创建定时器 */
my_timer = rt_timer_create("mytimer", // 定时器名称
timer_callback, // 定时器到期时回调的函数
RT_NULL, // 调用回调函数时传递的参数
RT_TICK_PER_SECOND, // 定时时间,这里设置为1秒
RT_TIMER_FLAG_PERIODIC); // 定时器模式,周期性执行
/* 启动定时器 */
if (my_timer != RT_NULL)
{
rt_timer_start(my_timer);
}
return 0;
}
- 写到这里了,其实对 delay 定时器 基本的了解已经搭建起来了,其实对于开发而言,差不多够用了
- 感兴趣的话,可以继续往下翻,我们看一下更深入的准确的定义
定义
- delay 和 sleep 是两种差不多的操作在不同平台上的叫法
- 一般不需要太过关注如何区分,在这里我们看作是一样的
- delay 我们这里提到两种实现方式,一种是通过估计计算耗时来实现延时;另一种是 Timer定时器实现;通过估计计算耗时的方式我们没什么好说的,我们关注的是 相对智能的\高效的 基于 时钟(timer)实现的
- 在介绍之前,我们需要一起提到 晶振\时钟\时钟节拍\定时器\delay 之间的关系
在 RT-Thread 实时操作系统中,delay 函数(如 rt_thread_delay())用于挂起当前线程一定的时间。在这段时间内,CPU 将不会执行当前线程,而是转而执行其他的就绪状态线程。如果没有其他线程处于就绪状态,则可能执行空闲线程(idle thread),该线程通常用于执行低优先级的后台任务,如内存清理和系统监视。
RT-Thread 的 rt_thread_delay() 函数是专门设计用于多任务环境的,不同于 MicroPython 的 time.sleep(),RT-Thread 的延时操作是为多线程设计的,确实会将 CPU 时间让给其他的线程。这是因为 RT-Thread 是一个完整的实时操作系统,支持多线程和任务调度,所以它可以在一个线程暂停执行时调度其他线程运行。
在 RT-Thread 中,当你调用 rt_thread_delay() 时,你实际上是将当前线程放入睡眠状态直到指定的延时时间过去。这个功能使得 CPU 资源可以被有效地分配给其他需要执行的线程,从而提高系统的总体效率和响应性。
总结来说,RT-Thread 中的 delay 类操作(如 rt_thread_delay())确实会导致当前线程挂起,并允许其他线程使用 CPU。这与 MicroPython 中的 time.sleep() 在操作系统层面上有相似的效果,尽管底层的实现机制和支持的功能可能不同,因为 RT-Thread 是一个多线程的实时操作系统,而 MicroPython 通常运行在单线程环境中。