应用程序计时器
應用程序計時器
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];#endifinitial_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的下一篇文章將討論中斷。
總結
- 上一篇: 一种新的高级抖动分离解析方法
- 下一篇: 系统时间