应用程序计时器
Application timers
应用程序计时器是内核对象,为任务提供简单的方法来计时事件,或者更常见的是,定期执行活动。介绍了Nucleus SE中计时功能的所有细节——准确性、中断处理等。
Using Timers
应用程序计时器可以配置为一次性的-即,它们被启动,然后,在指定的时间段之后,它们只是终止。或者,可以将计时器配置为重复,即当计时器过期时,它会自动重新启动;重新启动周期的时间间隔可能与初始时间不同。定时器也可以选择性地配置为在定时器过期(或每次)时运行特定的功能-过期例程。
Configuring Timers
Number of Timers
与Nucleus SE的大多数方面一样,计时器的配置主要由nuse_config.h中的#define语句控制。键设置是NUSE_TIMER_NUMBER,它确定为应用程序配置了多少计时器。默认设置为0(即不使用计时器),您可以将其设置为16以内的任何值。错误的值将导致编译时错误,该错误由nuse_config_check.h中的测试生成(此错误包含在nuse_config.c中,因此使用此模块进行编译),从而导致编译一个#错误语句。
选择非零值是计时器的“主启用”。这将导致一些数据结构被相应地定义和调整大小,本文稍后将对此进行详细介绍。它还激活API启用设置。
Expiration Routine Enable
过期例程启用
在Nucleus SE中,我寻找机会使功能成为可选的,这样可以节省内存。一个很好的例子就是对计时器过期例程的支持。除了对每个单独的计时器是可选的之外,还可以通过NUSE_config.h中的NUSE_timer_EXPIRATION_ROUTINE_SUPPORT设置为整个应用程序启用(或不启用)。将其设置为FALSE将禁止定义两个ROM数据结构,本文稍后将介绍这两个数据结构。
API Enables
Nucleus SE中的每个API函数(服务调用)在nuse_config.h中都有一个启用的#define符号。对于计时器,这些是:
NUSE_TIMER_CONTROL
NUSE_TIMER_GET_REMAINING
NUSE_TIMER_RESET
NUSE_TIMER_INFORMATION
NUSE_TIMER_COUNT
默认情况下,所有这些都设置为FALSE,从而禁用每个服务调用并禁止包含任何实现代码。要为应用程序配置计时器,需要选择要使用的API调用并将其启用符号设置为TRUE。
默认情况下,从配置文件nuse_config.h中提取。
#define NUSE_TIMER_NUMBER
0 /* Number of application timers in
the system – 0-16 */
/* Service call enablers */
#define
NUSE_TIMER_CONTROL FALSE
#define
NUSE_TIMER_GET_REMAINING FALSE
#define
NUSE_TIMER_RESET
FALSE
#define
NUSE_TIMER_INFORMATION FALSE
#define
NUSE_TIMER_COUNT
FALSE
如果启用计时器API函数且未配置计时器(除非始终允许使用NUSE_timer_Count()),则会导致编译时错误。如果您的代码使用尚未启用的API调用,则会导致链接时间错误,因为应用程序中不会包含任何实现代码。
Timer Service Calls
Nucleus RTOS支持八个与计时器相关的服务调用,它们提供以下功能:
控制(启动/停止)计时器。由Nucleus SE中的NUSE_Timer_Control()实现。
从计时器获取剩余时间。由Nucleus SE中的NUSE_Timer_Get_Remaining()实现。
将计时器恢复到未使用状态(重置)。由Nucleus SE中的NUSE_Timer_Reset()实现。
提供有关指定计时器的信息。由Nucleus SE中的NUSE_Timer_Information()实现。
返回(当前)为应用程序配置的计时器数。由Nucleus SE中的NUSE_Timer_Count()实现。
向应用程序添加新计时器(创建)。未在Nucleus SE中实现。
从应用程序中删除计时器(删除)。未在Nucleus SE中实现。
返回指向应用程序中所有计时器(当前)的指针。未在Nucleus SE中实现。
将详细检查每个服务调用的实现。
Timer Services
可以在计时器上执行的基本操作是控制计时器-启动和停止-并读取其当前值。Nucleus RTOS和Nucleus SE各自为这些操作提供了两个基本的API调用,这里将对此进行讨论。
Controlling a Timer
The Nucleus RTOS API call for controlling a timer simply permits the timer to be enabled or disabled (i.e. started or stopped). Nucleus SE provides the same service.
Nucleus RTOS API Call for Controlling a Timer
Service call prototype:
STATUS NU_Control_Timer(NU_TIMER *timer, OPTION enable);
Parameters:
timer – pointer to the user-supplied timer control block
enable – required function; may
be NU_ENABLE_TIMER or NU_DISABLE_TIMER
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_TIMER – the timer
pointer is invalid
NU_INVALID_ENABLE – the specified
function is invalid
Nucleus SE API Call for Controlling a Timer
This API call supports the full functionality of the Nucleus RTOS API.
Service call prototype:
STATUS NUSE_Timer_Control(NUSE_TIMER timer, OPTION enable);
Parameters:
timer – the index (ID) of the timer to be utilized
enable – required function; may
be NUSE_ENABLE_TIMER or NUSE_DISABLE_TIMER
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_TIMER – the timer
index is invalid
NUSE_INVALID_ENABLE – the
specified function is invalid
Nucleus SE Implementation of Timer Control
The code of the NUSE_Timer_Control() API function – after parameter checking – is reasonably straightforward:
NUSE_CS_Enter();if (enable == NUSE_ENABLE_TIMER){ NUSE_Timer_Status[timer] = TRUE; if (NUSE_Timer_Expirations_Counter[timer] == 0) { NUSE_Timer_Value[timer] = NUSE_Timer_Initial_Time[timer]; } else { NUSE_Timer_Value[timer] = NUSE_Timer_Reschedule_Time[timer]; }}else /* enable == NUSE_DISABLE_TIMER */{ NUSE_Timer_Status[timer] = FALSE;}NUSE_CS_Exit();
如果指定的函数是NUSE_DISABLE_TIMER,则计时器的状态(NUSE_TIMER_status[]项)设置为FALSE,这将导致时钟ISR忽略它。
如果指定了NUSE_ENABLE_TIMER,则计时器计数器(NUSE_TIMER_Value[])设置为NUSE_TIMER_Initial_Time[],前提是计时器自上次重置后从未过期。否则,它将被设置为“使用计时器”“重新计划”“时间[]”。然后计时器的状态(NUSE_timer_status[]项)设置为TRUE,这将导致时钟ISR对其进行处理。
读取计时器
Nucleus RTOS API调用从计时器获取剩余时间就是这样做的——返回过期前的计时点数。Nucleus SE提供相同的服务。
Nucleus RTOS API Call for Getting Remaining Time
Service call prototype:
STATUS NU_Get_Remaining_Time (NU_TIMER *timer,
UNSIGNED *remaining_time);
Parameters:
timer – pointer to the user-supplied timer control block.
remaining_time – a pointer to
storage for the remaining time value, which is a single variable of type UNSIGNED
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_TIMER – the timer
pointer is invalid
Nucleus SE API Call for Getting Remaining Time
This API call supports the full functionality of the Nucleus RTOS API.
Service call prototype:
STATUS
NUSE_Timer_Get_Remaining(NUSE_TIMER timer,
U16 *remaining_time);
Parameters:
timer – the index (ID) of the timer to be utilized
remaining_time – a pointer to
storage for the remaining time value, which is a single variable of type U16
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_TIMER – the timer
index is invalid
NUSE_INVALID_POINTER – the
remaining time pointer is NULL
Nucleus SE Implementation of Timer Read
The bulk of the code of the NUSE_ Timer_Get_Remaining() API function – after parameter checking – is almost trivially simple. The value of NUSE_Timer_Value[] is obtained and returned within a critical section.
计时器实用程序服务
Nucleus RTOS有四个API调用,它们提供与计时器相关的实用函数:重置计时器、返回有关计时器的信息、返回应用程序中计时器的数量以及返回指向应用程序中所有计时器的指针。前三个在Nucleus SE中实现。
重置计时器
此API调用将计时器恢复到其未使用的初始状态。在完成此调用后,可以启用或禁用计时器。只有在禁用计时器后才允许(使用NUSE_timer_Control())。下一次启用计时器时,将使用NUSE_timer_Initial_Time[]中的条目初始化计时器。Nucleus RTOS允许在重置计时器时提供新的初始和重新计划时间,并指定过期例程;在Nucleus SE中,这些值在配置时设置,不能更改,因为它们可能存储在ROM中。
Nucleus RTOS API Call for Resetting a Timer
Service call prototype:
STATUS
NU_Reset_Timer(NU_TIMER *timer,
VOID
(*expiration_routine)(UNSIGNED), UNSIGNED initial_time,
UNSIGNED
reschedule_time, OPTION enable);
Parameters:
timer – pointer to the timer to be reset
expiration_routine – specifies
the application routine to execute when the timer expires
initial_time – the initial number
of timer ticks for timer expiration
reschedule_time – the number of
timer ticks for expiration after the first expiration
enable – required state after
reset; may be NU_ENABLE_TIMER or NU_DISABLE_TIMER
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_TIMER – the timer
control block pointer is not valid
NU_INVALID_FUNCTION – the
expiration function pointer is NULL
NU_INVALID_ENABLE – the specified
state is invalid
NU_NOT_DISABLED – the time is
currently enabled (disable required before reset)
Nucleus SE API Call for Resetting a Timer
This API call supports a simplified version of the key functionality of the Nucleus RTOS API.
Service call prototype:
STATUS NUSE_Timer_Reset(NUSE_TIMER timer, OPTION enable);
Parameters:
timer – the index (ID) of the timer to be reset
enable – required state after
reset; may be NUSE_ENABLE_TIMER or NUSE_DISABLE_TIMER
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_TIMER – the timer
index is not valid
NUSE_INVALID_ENABLE – the
specified state is invalid
NUSE_NOT_DISABLED – the time is
currently enabled (disable required before reset)
Nucleus SE Implementation of Timer Reset
The bulk of the code of the NUSE_Timer_Reset() API function – after parameter and current status checking – is quite straightforward:
NUSE_CS_Enter();NUSE_Init_Timer(timer);if (enable == NUSE_ENABLE_TIMER){ NUSE_Timer_Status[timer] = TRUE;}/* else enable == NUSE_DISABLE_TIMER and status remains FALSE */NUSE_CS_Exit();
调用NUSE_Init_Timer()初始化时间值并清除过期计数器。然后检查所需状态并启用计时器(如果需要)。
定时器信息
此服务调用获取有关计时器的信息选择。Nucleus SE实现与Nucleus RTOS的不同之处在于它返回的信息较少,因为不支持对象命名。
对计时器信息的Nucleus RTOS API调用
Service call prototype:
STATUS NU_Timer_Information(NU_TIMER *timer, CHAR *name,
OPTION
*enable, UNSIGNED *expirations, UNSIGNED *id,
UNSIGNED
*initial_time, UNSIGNED *reschedule_time);
Parameters:
timer – pointer to the timer about which information is being
requested
name – pointer to an 8-character
destination area for the timer’s name.
enable – a pointer to a variable,
which will receive the timer’s current enable state: NU_ENABLE_TIMER or NU_DISABLE_TIMER
expirations – a pointer to a
variable of type which will receive the count of the number of times the timer
has expired since it was last reset
id – a pointer to a variable
which will receive the value of the parameter passed to the timer’s expiration
routine
initial_time – a pointer to a
variable which will receive the value to which the timer is initialized on reset
reschedule_time – a pointer to a
variable which will receive the value to which the timer is initialized on
expiration
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_TIMER – the timer
pointer is not valid
Nucleus SE API Call for Timer Information
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
STATUS
NUSE_Timer_Information(NUSE_TIMER timer, OPTION *enable,
U8
*expirations, U8 *id, U16 *initial_time, U16 *reschedule_time);
Parameters:
timer – the index of the timer about which information is being
requested
enable – a pointer to a variable,
which will receive a value of TRUE or FALSE depending on whether the
timer is enabled or not
expirations – a pointer to a
variable of type U8 which
will receive the count of the number of times the timer has expired since it
was last reset
id – a pointer to a variable of
type U8 which will receive the value
of the parameter passed to the timer’s expiration routine (nothing returned if
expiration routines are disabled)
initial_time – a pointer to a
variable of type U16 which
will receive the value to which the timer is initialized on reset
reschedule_time – a pointer to a
variable of type U16 which
will receive the value to which the timer is initialized on expiration
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_TIMER – the timer
index is not valid
NUSE_INVALID_POINTER – one or
more of the pointer parameters is invalid
Nucleus SE Implementation of Timer Information
The implementation of this API call is quite straightforward:
NUSE_CS_Enter();if (NUSE_Timer_Status[timer]){ *enable = NUSE_ENABLE_TIMER;}else{ *enable = NUSE_DISABLE_TIMER;}*expirations = NUSE_Timer_Expirations_Counter[timer];#if NUSE_TIMER_EXPIRATION_ROUTINE_SUPPORT *id = NUSE_Timer_Expiration_Routine_Parameter[timer];#endif*initial_time = NUSE_Timer_Initial_Time[timer];*reschedule_time = NUSE_Timer_Reschedule_Time[timer];NUSE_CS_Exit();
函数返回计时器状态。只有在应用程序中启用了过期例程时,才会返回expiration例程参数的值。
获取计时器的数量
此服务调用返回应用程序中配置的计时器数。在Nucleus RTOS中,这将随时间而变化,返回的值将表示当前的计时器数量,而在Nucleus SE中,返回的值在构建时设置,不能更改。
用于计时器计数的Nucleus RTOS API调用
Service call prototype:
UNSIGNED NU_Established_Timers(VOID);
Parameters:
None
Returns:
The number of created timers in the system.
Nucleus SE API Call for Timer Count
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
U8 NUSE_Timer_Count(void);
Parameters:
None
Returns:
The number of configured timers in the application.
定时器计数的实现
这个API调用的实现非常简单:返回#define symbol NUSE_TIMER_NUMBER的值。
数据结构
定时器使用五到七个数据结构——在RAM和ROM中——与其他Nucleus SE对象一样,这些数据结构是一系列表,根据配置的计时器数量和选择的选项进行标注。
我强烈建议应用程序代码不要直接访问这些数据结构,而是使用提供的API函数。这避免了与Nucleus SE未来版本的不兼容和不必要的副作用,并简化了将应用程序移植到Nucleus RTOS的过程。这里包含数据结构的详细信息,以便更容易地理解服务调用代码的工作方式和调试。
RAM数据
这些数据结构包括:
NUSE_Timer_Status[]–这是一个U8类型的数组,每个配置的计时器都有一个条目,是存储计时器状态(运行或停止:TRUE或FALSE)的位置。
其中一个定时器的值uUse是一个定时器值,它是一个定时器值。
NUSE_Timer_Expirations_Counter[]–此类型的U8数组包含计时器自上次重置后达到过期的次数的计数。
当Nucleus SE启动时,这些数据结构都由NUSE_Init_Timer()初始化。未来的文章将全面描述Nucleus SE的启动过程。
以下是nuse_init.c文件中这些数据结构的定义:
RAM U8 NUSE_Timer_Status[NUSE_TIMER_NUMBER];
RAM
U16 NUSE_Timer_Value[NUSE_TIMER_NUMBER];
RAM
U8 NUSE_Timer_Expirations_Counter[NUSE_TIMER_NUMBER];
ROM Data
这些数据结构包括:
NUSE_Timer_Initial_Time[]–这是一个U16类型的数组,每个配置的计时器有一个条目,是存储每个计时器计数器的初始值的地方。
NUSE_Timer_Reschedule_Time[]–这是一个U16类型的数组,每个配置的计时器都有一个条目,其中包含过期时每个计时器的计数器应设置的值。值为零表示计时器是“一次性”的,不应自动重新启动。
NUSE_Timer_Expiration_Routine_Address[]–此类型的ADDR数组包含计时器过期例程的地址。此数组仅在启用计时器过期例程支持时存在。
NUSE_Timer_Expiration_Routine_Parameter[]–此类型的U8数组包含将传递给计时器的过期例程的参数值。此数组仅在启用计时器过期例程支持时存在。
这些数据结构都在nuse_config.c中声明和初始化(当然是静态的),因此:
ROM U16 NUSE_Timer_Initial_Time[NUSE_TIMER_NUMBER] ={ /* timer initial times ------ */};ROM U16 NUSE_Timer_Reschedule_Time[NUSE_TIMER_NUMBER] ={ /* timer reschedule times ------ */};#if NUSE_TIMER_EXPIRATION_ROUTINE_SUPPORT || NUSE_INCLUDE_EVERYTHING /* need prototypes of expiration routines here */ ROM ADDR NUSE_Timer_Expiration_Routine_Address[NUSE_TIMER_NUMBER] = { /* addresses of timer expiration routines ------ */ /* can be NULL */ }; ROM U8 NUSE_Timer_Expiration_Routine_Parameter[NUSE_TIMER_NUMBER] = { /* timer expiration routine parameters ------ */ };#endif
Timer Data Footprint
Like all kernel objects in Nucleus SE, the amount of data memory required for timers is readily predictable.
The RAM data footprint (in bytes) for all the timers in an application may be computed thus:
NUSE_TIMER_NUMBER * 4
The ROM data footprint (in bytes) for all the timers in an application, if expiration routines are not supported, may be computed thus:
NUSE_TIMER_NUMBER * 4
Otherwise, it is:
NUSE_TIMER_NUMBER * (sizeof(ADDR) + 5)
Unimplemented API Calls
Three timer API calls found in Nucleus RTOS are not implemented in Nucleus SE:
Create Timer
This API call creates a timer. It is not needed with Nucleus SE, as timers are created statically.
Service call prototype:
STATUS NU_Create_Timer(NU_TIMER *timer, CHAR *name,
VOID
(*expiration_routine)(UNSIGNED), UNSIGNED id,
UNSIGNED
initial_time, UNSIGNED reschedule_time, OPTION enable);
Parameters:
timer – pointer to a user-supplied timer control block; this
will be used as a “handle” for the timer in other API calls
name – pointers to a 7-character,
null-terminated name for the timer
expiration_routine – s pecifies the application
routine to execute when the timer expires
id – a n UNSIGNED data element supplied to
the expiration routine; the parameter may be used to help identify timers that
use the same expiration routine
initial_time – specifies the
initial number of timer ticks for timer expiration
reschedule_time – specifies the
number of timer ticks for expiration after the first expiration; if this
parameter is zero, the timer only expires once
enable – valid options for this
parameter are NU_ENABLE_TIMER and NU_DISABLE_TIMER; NU_ENABLE_TIMER activates
the timer after it is created; NU_DISABLE_TIMER leaves the timer
disabled; timers created with the NU_DISABLE_TIMER must be enabled
by a call to NU_Control_Timer later
Returns:
NU_SUCCESS – indicates successful completion of the service
NU_INVALID_TIMER – indicates the
timer control block pointer is NULL or
already in use
NU_INVALID_FUNCTION – indicates
the expiration function pointer is NULL
NU_INVALID_ENABLE – indicates
that the enable parameter
is invalid
NU_INVALID_OPERATION – indicates
that initial_time parameter was zero
Delete Timer
This API call deletes a previously created timer. It is not needed with Nucleus SE, as timers are created statically and cannot be deleted.
Service call prototype:
STATUS NU_Delete_Timer(NU_TIMER *timer);
Parameters:
timer – pointer to timer control block
Returns:
NU_SUCCESS – indicates successful completion of the service
NU_INVALID_TIMER – indicates the
timer pointer is invalid
NU_NOT_DISABLED – indicates the
specified timer is not disabled
Timer Pointers
This API call builds a sequential list of pointers to all timers in the system. It is not needed with Nucleus SE, as timers are identified by a simple index, not a pointer, and it would be redundant.
Service call prototype:
UNSIGNED NU_Timer_Pointers(NU_TIMER **pointer_list,
UNSIGNED
maximum_pointers);
Parameters:
pointer_list – pointer to an array of NU_TIMER pointers;
this array will be filled with pointers to established timers in the system
maximum_pointers – the maximum
number of pointers to place in the array
Returns:
The number of NU_TIMER pointers placed into the array
与Nucleus RTOS的兼容性
对于Nucleus SE的各个方面,我的目标是尽可能保持与Nucleus RTOS的高级别应用程序代码兼容性。计时器也不例外,从用户的角度来看,它们的实现方式与Nucleus RTOS中的实现方式大致相同。有一些不兼容的地方,我认为这样的不兼容是可以接受的,因为生成的代码更容易理解,或者更有可能提高内存效率。否则,Nucleus RTOS API调用几乎可以直接映射到Nucleus SE调用上。未来的一篇文章将进一步介绍如何为Nucleus RTOS用户使用Nucleus SE。
对象标识符
在Nucleus RTOS中,所有对象都由具有特定数据类型的数据结构(控制块)来描述。指向此控制块的指针用作计时器的标识符。在Nucleus SE中,我决定需要一种不同的方法来提高内存效率,所有的内核对象都由RAM和/或ROM中的许多表来描述,这些表的大小由配置的每个对象类型的数量决定。特定对象的标识符只是这些表的索引。因此,我将NUSE_TIMER定义为等同于U8;这种类型的变量(而不是指针)将充当计时器标识符。这是一个小的不兼容性,如果代码被移植到Nucleus RTOS或从Nucleus RTOS移植过来,就很容易处理这个问题。对象标识符通常只是存储和传递,而不是以任何方式操作。
Nucleus RTOS还支持计时器的命名。这些名称仅用于基于目标的调试工具。为了节省内存,我把它们从Nucleus SE中省略了。
计时器大小
在Nucleus RTOS中,定时器是用32位计数器实现的。我决定把这个减少到16位。这种改变显著提高了内存和执行时间效率。如果需要更长的时间,Nucleus-SE可以很容易地被修饰。
过期例程
Nucleus SE实现过期例程的方式与Nucleus rto中的方法基本相同,只是它们可能被完全禁用(这可以节省一些内存),并且它们是静态定义的。当定时器复位时,不可能改变过期程序。
未实现的API调用
Nucleus RTOS支持8个服务调用来使用计时器。其中三个在Nucleus SE中没有实现。在本文前面的未实现的API调用中可以找到这些调用以及省略它们的决定的详细信息。
RTOS的下一篇文章将讨论中断。