一、時間管理
- 軟件定時器
概述
軟件定時器提供了一套從軟件層次實現的定時器機制,相對應的概念是硬件定時器。用戶可以創建一系列的軟件定時器,並指定軟件定時器到期的條件以及執行回調,當軟件定時器到期時會執行註冊的回調。
通常來說,用戶註冊的軟件定時器回調中很可能包含延遲動作或同步等待操作,或者回調函數本身邏輯複雜執行耗時較長,因此係統將軟件定時器管理邏輯設計成一個任務,在這個任務中掃描定時器是否過期並執行定時器回調。但是如你所知,創建一個任務是需要消耗系統內存資源的(任務的棧、任務句柄本身的內存空間等等),而如果用戶註冊的軟件定時器回調中並不包含延遲動作也不包含同步等待操作,或者回調本身執行耗時很短,這種情況下軟件定時器管理邏輯無需被設計成任務,而是可以被設計成時鐘中斷中被調用的一個函數。當軟件定時器管理邏輯被設計成一個函數時,就可以節省創建任務所需的資源。
系統默認採用的實現是將定時器管理邏輯設計爲任務,當用戶的定時器回調都是耗時極短的操作時,用戶可以通過將軟件定時器管理邏輯配置爲函數來節省內存資源。通過在tos_config.h中打開TOS_CFG_TIMER_AS_PROC開關來講軟件定時器管理邏輯配置爲函數:
#define TOS_CFG_TIMER_AS_PROC 1u
API講解
k_err_t tos_timer_create(k_timer_t *tmr,
k_tick_t delay,
k_tick_t period,
k_timer_callback_t callback,
void *cb_arg,
k_opt_t opt)
這裏詳細講解此api參數意義:
-
tmr
軟件定時器句柄。
-
delay
該定時器延遲多久後執行。
-
period
一個定時器的執行週期。
-
callback
定時器到期後的執行回調。
-
cb_arg
執行回調的入參。
-
opt
此opt的傳入主要是界定tmr的屬性,如果傳入的是TOS_OPT_TIMER_ONESHOT,表明此tmr是一次性的,當delay時間到期,tmr的執行回調調用完畢後此tmr生命週期就結束了;如果傳入的是TOS_OPT_TIMER_PERIODIC,表明此tmr是週期性定時器,當tmr定時時間到期,tmr的執行回調調用完畢後,系統會重新按period參數爲到期時間將tmr加入到定時隊列,開啓下一個週期。
編程實例
1、在tos_config.h中,配置軟件定時器組件開關TOS_CFG_TIMER_EN:
#define TOS_CFG_TIMER_EN 1000u
2、編寫main.c示例代碼:
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "cmsis_os.h"
#include "stdio.h"
#include "tos_k.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define STK_SIZE_TASK_DEMO 512
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
k_stack_t stack_task_demo[STK_SIZE_TASK_DEMO];
k_task_t task_demo;
extern void entry_task_demo(void *arg);
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
void oneshot_timer_cb(void *arg)
{
printf("this is oneshot timer callback, current systick: %ld\n", tos_systick_get());
}
void periodic_timer_cb(void *arg)
{
printf("this is periodic timer callback, current systick: %ld\n", tos_systick_get());
}
void entry_task_demo(void *arg)
{
k_timer_t oneshot_tmr;
k_timer_t periodic_tmr;
// 這是一個一次性的timer,且超時時間是3000個tick之後
tos_timer_create(&oneshot_tmr, 3000, 0, oneshot_timer_cb, K_NULL, TOS_OPT_TIMER_ONESHOT);
// 這是一個週期性的timer,第一次超時時間是2000個tick之後,之後按3000個tick爲週期執行回調
tos_timer_create(&periodic_tmr, 2000, 3000, periodic_timer_cb, K_NULL, TOS_OPT_TIMER_PERIODIC);
printf("current systick: %ld\n", tos_systick_get());
tos_timer_start(&oneshot_tmr);
tos_timer_start(&periodic_tmr);
while (K_TRUE) {
tos_task_delay(1000);
}
}
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
tos_knl_init();
(void)tos_task_create(&task_demo, "receiver_higher_prio", entry_task_demo, NULL,
4, stack_task_demo, STK_SIZE_TASK_DEMO, 0);
tos_knl_start();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
3、運行效果
源碼鏈接:Git