关于RTOS的全部真相。 第27条。 系统时间

先前的文章之一中介绍了RTOS上下文中的时间概念,以及RTOS中可用的与时间相关的功能。




滴答计时器


所有与时间相关的功能均由硬件时钟控制。 这是一个简单的振荡器,可以定期产生中断请求。 为了使时钟编号对应用程序有意义,必须知道发生器的频率。

定时器中断处理


硬件计时器生成的中断必须以某种方式在中断处理程序(Interrupt Service Routine,ISR)中进行服务,该中断处理程序实现所有与时间相关的RTOS功能。 以下文章之一将讨论Nucleus SE中计时器中断处理程序的详细信息。

与时间有关的功能


Nucleus RTOS和Nucleus SE包含几种与时间相关的机制:

  • 系统滴答时钟(Tick clock) :一个简单的计数器,使用计时器中断处理程序进行递增。 Nucleus RTOS和Nucleus SE都具有32位计数器,并且任务具有读取和写入其值的机制。 在Nucleus SE中,时钟计时器是可选的。
  • 应用程序计时器 :Nucleus RTOS和Nucleus SE均支持计时器对象。 在下一篇文章中将详细讨论它们在Nucleus SE中的使用和实现。
  • 时间片调度 :在Nucleus RTOS中,具有优先级的任务使用循环算法进行服务,但是您也可以使用时间片。 在Nucleus SE中,时间分片调度程序是可选的。 在先前的文章( TS调度程序(时间片)Nucleus SE 中的TS一般视图)中对此进行了详细讨论。
  • 暂停任务(任务睡眠) :任务可以将自己暂停(“入睡”)一段固定的时间。 前面已经详细描述了此机制。
  • API调用超时 :在Nucleus RTOS和Nucleus SE中,某些API调用都允许您在等待资源可用时暂停任务。 暂停可能是不确定的,或者在Nucleus RTOS的情况下,可能会指示可选的超时时间(等待时间)。 Nucleus SE不支持API调用超时。

准确度


现在,值得简要介绍一下系统计时器的准确性。

时间函数的准确性直接取决于时钟发生器的频率。 例如,如果脉冲每10毫秒到达一次,并且应用程序任务需要100毫秒的延迟,则显然需要10个脉冲。 但是,尚不清楚何时收到前一个脉冲:它可能在大约10毫秒前发生。 因此,100毫秒的延迟最多可能需要110毫秒。

解决此问题的一种明显方法是增加发电机的频率。 如果脉冲以1毫秒的间隔跟随,则100毫秒的延迟将永远不会超过110毫秒。 该解决方案的缺点是计时器中断处理程序将花费10倍以上的处理器时间,这将是过多的时间。 系统设计人员必须在计时器的必要精度和可用处理器功率之间找到平衡。

系统时间设定


与大多数Nucleus SE对象一样,系统时间设置大部分由nuse_config.h文件中的#define指令控制。 主要参数是NUSE_SYSTEM_TIME_SUPPORT ,它激活系统时间支持机制。 您无需指定对象数:系统时间是否已激活。

非零值的选择是系统时间的主要激活因素。 定义数据结构时将使用此参数,本文稍后将详细讨论。 此外,非零值会激活API设置。

API激活


Nucleus SE中的每个API函数(实用程序调用)在nuse_config.h文件中都有一个激活的#define指令。 对于系统时间,这些符号是:
NUSE_CLOCK_SET
NUSE_CLOCK_RETRIEVE

默认情况下,它们设置为FALSE ,因此所有服务调用都被禁用,从而阻止了包含实现它们的代码。 要在应用程序中配置系统时间,您需要选择必要的API服务调用并将其设置为TRUE

以下是默认nuse_config.h文件中的代码片段。

#define NUSE_SYSTEM_TIME_SUPPORT FALSE /*    */ #define NUSE_CLOCK_SET FALSE /*   */ #define NUSE_CLOCK_RETRIEVE FALSE /*    */ 

如果您在系统时间激活器关闭时尝试使用系统时间API服务调用,则会发生编译错误。 如果您的代码使用尚未激活的API调用,则会发生布局错误,因为实现代码未包含在应用程序中。

系统时间实用程序调用


Nucleus RTOS支持两个与系统时间相关的实用程序调用,并提供以下功能:

  • 设置系统时间值。 Nucleus SE在NUSE_Clock_Set()函数中实现。
  • 获取系统时间值。 Nucleus SE在NUSE_Clock_Retrieve()函数中实现。

请更详细地考虑每个调用的实现。

服务电话以设置并获取系统时间


对于系统时间,您只能执行设置为给定值并获取当前值的操作。 Nucleus RTOS和Nucleus SE提供了两个基本的API调用来实现这些操作。

系统时间值的解释取决于应用程序,因为它本质上是自上次重置计数器以来发生的“时钟周期”数量的计数器。 要使用此信息,必须知道发生器的频率。

时间设定


任何任务都可以通过调用此API函数来设置系统时间。

调用以在Nucleus RTOS中设置系统时间

服务电话原型:
VOID NU_Set_Clock(UNSIGNED new_value);

参数:
new_value-要分配给系统时间的值

返回值:无。

调用以在Nucleus SE中设置系统时间
该API调用支持Nucleus RTOS API的核心功能。

服务电话原型:
NUSE_Clock_Set(U32新值);

参数:
new_value-要分配给系统时间的值

返回值:无

Nucleus SE中时间设置的实现
代码很简单。 所提供的值将写入临界区中的NUSE_Tick_Clock

获取系统时间


任务可以使用此API函数获取系统时间值。

致电以获取Nucleus RTOS中的系统时间

服务电话原型:
未签名的NU_Retrieve_Clock(VOID);

参数:无

返回值:系统时间的当前值

调用以获取Nucleus SE中的系统时间
服务电话原型:
U32 NUSE_Clock_Retrieve(无效);

参数:无

返回值:系统时间的当前值

在Nucleus SE中实现时间获取
代码很简单。 该函数返回在关键部分中获得的NUSE_Tick_Clock值。

资料结构


系统时间使用一个数据结构(位于RAM中),它是一个32位字。

我强烈建议应用程序代码不要直接访问此数据结构,而是通过提供的API函数访问它。 这将避免与Nucleus SE的未来版本不兼容以及不必要的副作用,并简化将应用程序移植到Nucleus RTOS的过程。 下面提供了数据结构的详细信息,以简化对服务调用代码和调试的理解。

RAM数据


资料结构:
NUSE_Tick_Clock-类型为U32的变量,用于存储系统时间的时钟计数器。

Nucleus SE启动时,该数据结构由NUSE_Init_Task()函数初始化为零。 以下文章之一将完整描述Nucleus SE的启动过程。

ROM数据


ROM中没有与系统时间相关的数据结构。

系统时间的内存量


像所有其他Nucleus SE对象一样,系统时间所需的内存量是可以预测的。

ROM中的内存量为0。

RAM中的内存量(以字节为单位)始终为4。

未实现的API调用


所有系统时间Nucleus RTOS API服务调用在Nucleus SE中都具有等效功能。

与Nucleus PLUS兼容


与所有其他Nucleus SE对象一样,我的目标是确保应用程序代码与Nucleus RTOS的最高兼容性。 系统时间也不例外,从用户的角度来看,它的实现方式与Nucleus RTOS中的实现方式几乎相同。 Nucleus RTOS API调用可以直接移植到Nucleus SE。

在下面的文章中,我们将考虑软件计时器。

Source: https://habr.com/ru/post/zh-CN454272/


All Articles