
?

?

?
文件一:
/******************** (C) COPYRIGHT 2023 青風電子 ********************* 文件名 :main* 出品論壇 :www.qfv8.com * 實驗平臺:青云nRF52840藍牙開發板* 描述 :定時器定時* 作者 :青風* 店鋪 :qfv5.taobao.com
**********************************************************************/#include <stdbool.h>
#include <stdint.h>
//#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "led.h"
#include "time.h"int main(void)
{// LED_Init();while (1){LED1_Toggle();//使用定時器0產生1s定時nrf_timer_delay_ms(TIMER0, TIMER_DELAY_MS);LED2_Toggle();// 使用定時器1產生1s定時nrf_timer_delay_ms(TIMER1, TIMER_DELAY_MS);LED3_Toggle();// 使用定時器2產生1s定時nrf_timer_delay_ms(TIMER2, TIMER_DELAY_MS);}
}
?文件二:
#ifndef __LED_H
#define __LED_H#include "nrf52840.h"#define LED_0 NRF_GPIO_PIN_MAP(0,13)
#define LED_1 NRF_GPIO_PIN_MAP(0,14)
#define LED_2 NRF_GPIO_PIN_MAP(0,15)
#define LED_3 NRF_GPIO_PIN_MAP(0,16)void LED_Init(void);
void LED1_Open(void);
void LED1_Close(void);
void LED1_Toggle(void);
void LED2_Open(void);
void LED2_Close(void);
void LED2_Toggle(void);
void LED3_Open(void);
void LED3_Close(void);
void LED3_Toggle(void);#endif /* __LED_H */
文件 三:
#include "nrf52840.h"
#include "led.h"
#include "nrf_gpio.h"
#include "time.h"
#include <stdbool.h>
#include <stdint.h>/*** @brief Function for timer initialization.*/
static volatile NRF_TIMER_Type * timer_init(timer_t timer)
{volatile NRF_TIMER_Type * p_timer;// 開始16 MHz晶振.NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;NRF_CLOCK->TASKS_HFCLKSTART = 1;// 等待外部振蕩器啟動while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {// Do nothing.}switch (timer){case TIMER0:p_timer = NRF_TIMER0;break;case TIMER1:p_timer = NRF_TIMER1;break;case TIMER2:p_timer = NRF_TIMER2;break;default:p_timer = 0;break;}return p_timer;
}/** @brief Function for using the peripheral hardware timers to generate an event after requested number of milliseconds.** @param[in] timer Timer to be used for delay, values from @ref p_timer* @param[in] number_of_ms Number of milliseconds the timer will count.* @note This function will power ON the requested timer, wait until the delay, and then power OFF that timer.*/void nrf_timer_delay_ms(timer_t timer, uint_fast16_t volatile number_of_ms)
{volatile NRF_TIMER_Type * p_timer = timer_init(timer);if (p_timer == 0) {while(true) {// Do nothing.}}p_timer->MODE = TIMER_MODE_MODE_Timer; // 設置為定時器模式p_timer->PRESCALER = 10; // Prescaler 9 produces 31250 Hz timer frequency => 1 tick = 32 us.p_timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // 16 bit 模式.p_timer->TASKS_CLEAR = 1; // 清定時器.// With 32 us ticks, we need to multiply by 31.25 to get milliseconds.p_timer->CC[0] = number_of_ms * 31;p_timer->CC[0] += number_of_ms / 4; p_timer->TASKS_START = 1; // Start timer.while (p_timer->EVENTS_COMPARE[0] == 0){// Do nothing.}p_timer->EVENTS_COMPARE[0] = 0;p_timer->TASKS_STOP = 1; // Stop timer.
}
/** @} */
?文件四:
#include "nrf52840.h"
#include "nrf_gpio.h"
#include "led.h"void LED_Init(void)
{// Configure LED-pins as outputsnrf_gpio_cfg_output(LED_0);nrf_gpio_cfg_output(LED_1);nrf_gpio_cfg_output(LED_2);
}void LED1_Open(void)
{nrf_gpio_pin_clear(LED_0);}void LED1_Close(void)
{nrf_gpio_pin_set(LED_0);}
void LED1_Toggle(void)
{nrf_gpio_pin_toggle(LED_0);
}void LED2_Open(void)
{nrf_gpio_pin_clear(LED_1);}void LED2_Close(void)
{nrf_gpio_pin_set(LED_1);}
void LED2_Toggle(void)
{nrf_gpio_pin_toggle(LED_1);
}void LED3_Open(void)
{nrf_gpio_pin_clear(LED_2);}void LED3_Close(void)
{nrf_gpio_pin_set(LED_2);}
void LED3_Toggle(void)
{nrf_gpio_pin_toggle(LED_2);
}
第一節:?nrf_timer_delay_ms函數
void nrf_timer_delay_ms(timer_t timer, uint_fast16_t volatile number_of_ms)
{volatile NRF_TIMER_Type * p_timer = timer_init(timer);if (p_timer == 0) {while(true) {// Do nothing.}}p_timer->MODE = TIMER_MODE_MODE_Timer; // 設置為定時器模式p_timer->PRESCALER = 10; // Prescaler 9 produces 31250 Hz timer frequency => 1 tick = 32 us.p_timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // 16 bit 模式.p_timer->TASKS_CLEAR = 1; // 清定時器.// With 32 us ticks, we need to multiply by 31.25 to get milliseconds.p_timer->CC[0] = number_of_ms * 31;p_timer->CC[0] += number_of_ms / 4; p_timer->TASKS_START = 1; // Start timer.while (p_timer->EVENTS_COMPARE[0] == 0){// Do nothing.}p_timer->EVENTS_COMPARE[0] = 0;p_timer->TASKS_STOP = 1; // Stop timer.
}
這段代碼實現了基于 nRF 系列 MCU 定時器的毫秒級延時功能,下面從多個維度進行詳細解析:
函數接口與參數
void nrf_timer_delay_ms(timer_t timer, uint_fast16_t volatile number_of_ms);
- timer:指定使用的定時器編號(如 TIMER0~TIMER4)
- number_of_ms:延時毫秒數,使用
uint_fast16_t
確保最快處理速度 - volatile 修飾:告知編譯器不優化該變量,確保每次都從內存讀取
定時器初始化與配置
volatile NRF_TIMER_Type * p_timer = timer_init(timer);
if (p_timer == 0) { while(1); } // 初始化失敗則進入死循環
- timer_init():底層初始化函數,返回定時器寄存器基址
- 錯誤處理:初始化失敗時進入無限循環,防止后續代碼異常
定時器核心配置
p_timer->MODE = TIMER_MODE_MODE_Timer; // 定時器模式
p_timer->PRESCALER = 10; // 預分頻=1024
p_timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // 16位計數
p_timer->TASKS_CLEAR = 1; // 清除定時器計數
- 時鐘頻率:假設系統時鐘 16MHz,分頻后為 15625Hz (64μs/tick)
- 計數范圍:0~65535,最大延時約 4.2 秒
延時計算原理與誤差分析
p_timer->CC[0] = number_of_ms * 31;
p_timer->CC[0] += number_of_ms / 4;
- 計算公式分解:
- 理論上 1ms 對應 15.625 個 tick (15625Hz)
- 代碼實現:CC [0] = ms×31 + ms/4 ≈ ms×31.25
- 實際換算:31.25×64μs = 2000μs = 2ms
- 誤差結論:實際延時是設定值的 2 倍,屬于代碼實現錯誤
正確計算方式
// 正確換算公式
uint32_t ticks = number_of_ms * 15625 / 1000;
if (ticks > 65535) ticks = 65535; // 防止溢出
p_timer->CC[0] = ticks;
- 原理:將毫秒轉換為定時器 tick 數
- 溢出處理:限制最大延時時間不超過 4.2 秒
延時實現機制
p_timer->TASKS_START = 1; // 啟動定時器
while (p_timer->EVENTS_COMPARE[0] == 0) // 等待比較事件
{ /* 忙等待 */ }
p_timer->EVENTS_COMPARE[0] = 0; // 清除事件標志
p_timer->TASKS_STOP = 1; // 停止定時器
- 同步機制:基于忙等待的阻塞式延時
- 事件處理:比較事件觸發后清除標志位
- 資源管理:延時結束后停止定時器,降低功耗
性能與優化建議
-
時間精度:
- 理論精度:±1 個 tick (64μs)
- 實際誤差:約 100%(因計算錯誤導致)
-
優化方向:
// 低功耗優化版本 while (!p_timer->EVENTS_COMPARE[0]) {__WFI(); // 進入等待中斷模式,CPU休眠 }
-
功能增強:
// 非阻塞式延時接口 bool nrf_timer_delay_start(timer_t timer, uint16_t ms); bool nrf_timer_delay_check(timer_t timer);
潛在問題與修復
- 計算錯誤:修正 CC [0] 計算公式
- 溢出風險:添加輸入參數驗證
- 資源沖突:多任務環境需要互斥訪問
- 功耗問題:長時間延時建議使用 RTC 替代
修正后的完整代碼示例:
void nrf_timer_delay_ms(timer_t timer, uint16_t ms)
{NRF_TIMER_Type * p_timer = timer_init(timer);if (!p_timer) while(1); // 錯誤處理// 配置定時器p_timer->MODE = TIMER_MODE_MODE_Timer;p_timer->PRESCALER = 10; // 15625Hzp_timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit;p_timer->TASKS_CLEAR = 1;// 正確計算tick數uint32_t ticks = ms * 15625 / 1000;if (ticks > 65535) ticks = 65535;p_timer->CC[0] = ticks;// 啟動并等待p_timer->TASKS_START = 1;while (!p_timer->EVENTS_COMPARE[0]) {__SEV(); // 維持事件信號__WFE(); // 等待事件}// 清理資源p_timer->EVENTS_COMPARE[0] = 0;p_timer->TASKS_STOP = 1;
}
這種基于硬件定時器的延時方案比軟件循環延時更精確,適用于對時間精度要求較高的場合,如通信協議時序控制、PWM 信號生成等。
?NRF_TIMER_Type結構體
這個結構體定義了 Nordic nRF 系列微控制器的定時器外設寄存器映射。下面是對該結構體的詳細解析:
寄存器組織概述
typedef struct {__OM uint32_t TASKS_START; // 啟動定時器任務__OM uint32_t TASKS_STOP; // 停止定時器任務__OM uint32_t TASKS_COUNT; // 計數遞增任務(計數器模式)__OM uint32_t TASKS_CLEAR; // 清除定時器任務__OM uint32_t TASKS_SHUTDOWN; // 停用定時器任務(已棄用)__IM uint32_t RESERVED[11];__OM uint32_t TASKS_CAPTURE[6]; // 捕獲當前計數值到CC[n]__IM uint32_t RESERVED1[58];__IOM uint32_t EVENTS_COMPARE[6]; // 比較事件寄存器組__IM uint32_t RESERVED2[42];__IOM uint32_t SHORTS; // 短連接配置寄存器__IM uint32_t RESERVED3[64];__IOM uint32_t INTENSET; // 中斷使能寄存器__IOM uint32_t INTENCLR; // 中斷禁用寄存器__IM uint32_t RESERVED4[126];__IOM uint32_t MODE; // 定時器模式選擇__IOM uint32_t BITMODE; // 位寬配置__IM uint32_t RESERVED5;__IOM uint32_t PRESCALER; // 預分頻器配置__IM uint32_t RESERVED6[11];__IOM uint32_t CC[6]; // 捕獲/比較寄存器組
} NRF_TIMER_Type;
核心功能模塊詳解
-
任務寄存器組 (Tasks)
TASKS_START
: 啟動定時器計數TASKS_STOP
: 停止定時器計數TASKS_CLEAR
: 清零當前計數值TASKS_CAPTURE[n]
: 將當前計數值捕獲到 CC [n] 寄存器
-
事件寄存器組 (Events)
EVENTS_COMPARE[n]
: 當計數值與 CC [n] 匹配時觸發事件- 可用于實現 PWM、定時中斷等功能
-
配置寄存器
MODE
: 選擇工作模式 (定時器 / 計數器)BITMODE
: 配置計數位寬 (8/16/24/32 位)PRESCALER
: 配置預分頻值 (2^n,n=0~9)
-
捕獲 / 比較寄存器組
CC[0-5]
: 6 個 16/24/32 位寄存器- 支持捕獲當前計數值或設置比較值
- 用于 PWM 生成、定時觸發等功能
-
中斷控制
INTENSET
: 使能特定中斷INTENCLR
: 禁用特定中斷- 支持比較事件中斷、溢出中斷等
-
短連接功能
SHORTS
: 配置事件與任務之間的直接連接- 例如:比較事件發生時自動清除計數器
典型應用場景
-
延時功能實現
// 基于CC[0]比較事件的延時函數 p_timer->CC[0] = current_value + delay_ticks; p_timer->TASKS_START = 1; while(p_timer->EVENTS_COMPARE[0] == 0); // 等待比較事件 p_timer->EVENTS_COMPARE[0] = 0; // 清除事件標志
-
PWM 信號生成
- 使用 SHORTS 自動實現周期循環
// 配置PWM周期和占空比 p_timer->CC[0] = period; // 周期值 p_timer->CC[1] = duty_cycle; // 占空比值 p_timer->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; // 比較事件0觸發計數器清零
-
輸入捕獲功能
// 捕獲外部信號的周期 p_timer->TASKS_CAPTURE[0] = 1; // 手動觸發一次捕獲 // 當外部事件發生時,可通過SHORTS自動觸發捕獲 p_timer->SHORTS = TIMER_SHORTS_COMPARE1_CAPTURE0_Msk;
設計亮點分析
-
任務 - 事件架構
- 任務驅動操作,避免直接寫寄存器
- 事件標志統一管理,簡化狀態檢測
-
靈活的預分頻配置
- 支持 2^0~2^9 預分頻
- 適配不同時鐘頻率和應用場景
-
多通道捕獲 / 比較
- 6 個獨立 CC 通道
- 可同時實現多個 PWM 輸出或定時功能
-
短連接機制
- 硬件級事件 - 任務連接
- 減少 CPU 干預,提高實時性
這種寄存器映射方式充分體現了 Nordic MCU 定時器的靈活性和高性能,為嵌入式系統提供了強大的定時、計數和 PWM 控制能力。
?NRF_CLOCK_Type結構體
typedef struct {__OM uint32_t TASKS_HFCLKSTART; // 啟動高頻晶體振蕩器__OM uint32_t TASKS_HFCLKSTOP; // 停止高頻晶體振蕩器__OM uint32_t TASKS_LFCLKSTART; // 啟動低頻時鐘__OM uint32_t TASKS_LFCLKSTOP; // 停止低頻時鐘__OM uint32_t TASKS_CAL; // 啟動LFRC校準__OM uint32_t TASKS_CTSTART; // 啟動校準定時器__OM uint32_t TASKS_CTSTOP; // 停止校準定時器__IM uint32_t RESERVED[57];__IOM uint32_t EVENTS_HFCLKSTARTED; // 高頻時鐘啟動完成事件__IOM uint32_t EVENTS_LFCLKSTARTED; // 低頻時鐘啟動完成事件__IM uint32_t RESERVED1;__IOM uint32_t EVENTS_DONE; // LFRC校準完成事件__IOM uint32_t EVENTS_CTTO; // 校準定時器超時事件__IM uint32_t RESERVED2[5];__IOM uint32_t EVENTS_CTSTARTED; // 校準定時器啟動事件__IOM uint32_t EVENTS_CTSTOPPED; // 校準定時器停止事件__IM uint32_t RESERVED3[117];__IOM uint32_t INTENSET; // 中斷使能寄存器__IOM uint32_t INTENCLR; // 中斷禁用寄存器__IM uint32_t RESERVED4[63];__IM uint32_t HFCLKRUN; // 高頻時鐘運行狀態__IM uint32_t HFCLKSTAT; // 高頻時鐘狀態__IM uint32_t RESERVED5;__IM uint32_t LFCLKRUN; // 低頻時鐘運行狀態__IM uint32_t LFCLKSTAT; // 低頻時鐘狀態__IM uint32_t LFCLKSRCCOPY; // 低頻時鐘源復制寄存器__IM uint32_t RESERVED6[62];__IOM uint32_t LFCLKSRC; // 低頻時鐘源選擇__IM uint32_t RESERVED7[3];__IOM uint32_t HFXODEBOUNCE; // 高頻晶體去抖時間配置__IM uint32_t RESERVED8[3];__IOM uint32_t CTIV; // 校準定時器間隔配置__IM uint32_t RESERVED9[8];__IOM uint32_t TRACECONFIG; // 跟蹤端口時鐘配置__IM uint32_t RESERVED10[21];__IOM uint32_t LFRCMODE; // LFRC模式配置
} NRF_CLOCK_Type;
1. 時鐘控制任務寄存器(Tasks)
- 高頻時鐘控制:
TASKS_HFCLKSTART
:啟動 HFXO(高頻晶體振蕩器),通常用于需要高精度時鐘的場景(如射頻通信)。TASKS_HFCLKSTOP
:停止 HFXO 以降低功耗。
- 低頻時鐘控制:
TASKS_LFCLKSTART
:啟動低頻時鐘(可選擇 LFRC 或 LFXO),用于低功耗定時器(如 RTC)。TASKS_LFCLKSTOP
:停止低頻時鐘。
- 校準任務:
TASKS_CAL
:觸發 LFRC(低頻 RC 振蕩器)校準,提高時鐘精度。TASKS_CTSTART/CTSTOP
:控制校準定時器的啟停,用于 LFRC 校準過程的時間基準。
2. 時鐘事件寄存器(Events)
- 狀態事件:
EVENTS_HFCLKSTARTED
:HFXO 啟動完成標志(需軟件清零)。EVENTS_LFCLKSTARTED
:LFCLK 啟動完成標志。
- 校準事件:
EVENTS_DONE
:LFRC 校準完成標志。EVENTS_CTTO
:校準定時器超時標志,用于校準失敗處理。
3. 時鐘狀態寄存器
- 高頻時鐘狀態:
HFCLKRUN
:只讀,指示 HFXO 是否已啟動(由 TASKS_HFCLKSTART 觸發)。HFCLKSTAT
:包含 HFXO 的穩定狀態等信息。
- 低頻時鐘狀態:
LFCLKRUN
:指示 LFCLK 是否運行。LFCLKSTAT
:包含 LFCLK 的當前源(LFRC/LFXO)及穩定狀態。LFCLKSRCCOPY
:記錄 LFCLK 啟動時的時鐘源配置。
4. 時鐘配置寄存器
- 低頻時鐘源選擇:
LFCLKSRC
:配置 LFCLK 的時鐘源(0=LFRC,1=LFXO,2 = 外部 32.768kHz)。
- 高頻晶體去抖:
HFXODEBOUNCE
:設置 HFXO 啟動時的去抖時間,防止噪聲干擾。
- 校準定時器配置:
CTIV
:設置校準定時器的時間間隔,用于 LFRC 校準過程。
- LFRC 模式配置:
LFRCMODE
:配置 LFRC 的工作模式(如低功耗模式或高精度模式)。
5. 中斷控制寄存器
INTENSET/INTENCLR
:用于使能或禁用時鐘相關事件的中斷(如 HFXO 啟動完成、LFRC 校準完成)。
典型應用場景
1. 高頻時鐘啟動流程
// 啟動HFXO并等待穩定
NRF_CLOCK->TASKS_HFCLKSTART = 1; // 觸發啟動任務
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); // 等待啟動完成
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; // 清除事件標志
2. 低頻時鐘配置(以 LFXO 為例)
// 配置LFCLK為LFXO源并啟動
NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_LFXO; // 設置時鐘源
NRF_CLOCK->TASKS_LFCLKSTART = 1; // 啟動LFCLK
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0); // 等待啟動完成
3. LFRC 校準流程
// 校準LFRC以提高精度
NRF_CLOCK->CTIV = 100; // 設置校準定時器間隔
NRF_CLOCK->TASKS_CAL = 1; // 啟動校準
while (NRF_CLOCK->EVENTS_DONE == 0); // 等待校準完成
uint32_t cal_value = NRF_CLOCK->LFCLKCAL; // 獲取校準值(假設結構體包含此寄存器)
設計亮點分析
- 低功耗時鐘管理:
- 獨立控制高頻 / 低頻時鐘的啟停,支持精細化功耗優化(如僅在需要時啟動 HFXO)。
- 時鐘源靈活切換:
- LFCLKSRC 支持多種低頻時鐘源,平衡精度與功耗(LFXO 精度高但功耗大,LFRC 功耗低但精度低)。
- 自動校準機制:
- 通過 TASKS_CAL 和校準定時器自動優化 LFRC 精度,減少外部晶振依賴。
- 硬件去抖設計:
- HFXODEBOUNCE 寄存器防止晶體振蕩器啟動時的抖動干擾,提高時鐘穩定性。
關鍵寄存器映射表
寄存器名稱 | 地址偏移 | 訪問權限 | 功能描述 |
---|---|---|---|
TASKS_HFCLKSTART | 0x0000 | 只寫 | 啟動高頻晶體振蕩器 |
EVENTS_HFCLKSTARTED | 0x0100 | 讀寫 | 高頻時鐘啟動完成事件 |
LFCLKSRC | 0x0518 | 讀寫 | 低頻時鐘源選擇 |
HFXODEBOUNCE | 0x0528 | 讀寫 | 高頻晶體去抖時間配置 |
LFRCMODE | 0x05B4 | 讀寫 | LFRC 工作模式配置 |
該時鐘系統架構充分體現了嵌入式系統對功耗、精度和靈活性的平衡需求,尤其適合藍牙低功耗(BLE)等對時鐘管理要求嚴格的場景。
nrfx_time.c文件解讀
#include <nrfx.h>#if NRFX_CHECK(NRFX_TIMER_ENABLED)#if !(NRFX_CHECK(NRFX_TIMER0_ENABLED) || NRFX_CHECK(NRFX_TIMER1_ENABLED) || \NRFX_CHECK(NRFX_TIMER2_ENABLED) || NRFX_CHECK(NRFX_TIMER3_ENABLED) || \NRFX_CHECK(NRFX_TIMER4_ENABLED))
#error "No enabled TIMER instances. Check <nrfx_config.h>."
#endif#include <nrfx_timer.h>#define NRFX_LOG_MODULE TIMER
#include <nrfx_log.h>/**@brief Timer control block. */
typedef struct
{nrfx_timer_event_handler_t handler;void * context;nrfx_drv_state_t state;
} timer_control_block_t;static timer_control_block_t m_cb[NRFX_TIMER_ENABLED_COUNT];nrfx_err_t nrfx_timer_init(nrfx_timer_t const * const p_instance,nrfx_timer_config_t const * p_config,nrfx_timer_event_handler_t timer_event_handler)
{timer_control_block_t * p_cb = &m_cb[p_instance->instance_id];
#ifdef SOFTDEVICE_PRESENTNRFX_ASSERT(p_instance->p_reg != NRF_TIMER0);
#endifNRFX_ASSERT(p_config);NRFX_ASSERT(timer_event_handler);nrfx_err_t err_code;if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED){err_code = NRFX_ERROR_INVALID_STATE;NRFX_LOG_WARNING("Function: %s, error code: %s.",__func__,NRFX_LOG_ERROR_STRING_GET(err_code));return err_code;}/* Warning 685: Relational operator '<=' always evaluates to 'true'"* Warning in NRF_TIMER_IS_BIT_WIDTH_VALID macro. Macro validate timers resolution.* Not necessary in nRF52 based systems. Obligatory in nRF51 based systems.*//*lint -save -e685 */NRFX_ASSERT(NRF_TIMER_IS_BIT_WIDTH_VALID(p_instance->p_reg, p_config->bit_width));//lint -restorep_cb->handler = timer_event_handler;p_cb->context = p_config->p_context;uint8_t i;for (i = 0; i < p_instance->cc_channel_count; ++i){nrf_timer_event_clear(p_instance->p_reg,nrf_timer_compare_event_get(i));}NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),p_config->interrupt_priority);NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));nrf_timer_mode_set(p_instance->p_reg, p_config->mode);nrf_timer_bit_width_set(p_instance->p_reg, p_config->bit_width);nrf_timer_frequency_set(p_instance->p_reg, p_config->frequency);p_cb->state = NRFX_DRV_STATE_INITIALIZED;err_code = NRFX_SUCCESS;NRFX_LOG_INFO("Function: %s, error code: %s.",__func__,NRFX_LOG_ERROR_STRING_GET(err_code));return err_code;
}void nrfx_timer_uninit(nrfx_timer_t const * const p_instance)
{NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));#define DISABLE_ALL UINT32_MAXnrf_timer_shorts_disable(p_instance->p_reg, DISABLE_ALL);nrf_timer_int_disable(p_instance->p_reg, DISABLE_ALL);#undef DISABLE_ALLnrfx_timer_disable(p_instance);m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED;NRFX_LOG_INFO("Uninitialized instance: %d.", p_instance->instance_id);
}void nrfx_timer_enable(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON;NRFX_LOG_INFO("Enabled instance: %d.", p_instance->instance_id);
}void nrfx_timer_disable(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_SHUTDOWN);m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;NRFX_LOG_INFO("Disabled instance: %d.", p_instance->instance_id);
}bool nrfx_timer_is_enabled(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);return (m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_POWERED_ON);
}void nrfx_timer_resume(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);NRFX_LOG_INFO("Resumed instance: %d.", p_instance->instance_id);
}void nrfx_timer_pause(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP);NRFX_LOG_INFO("Paused instance: %d.", p_instance->instance_id);
}void nrfx_timer_clear(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_CLEAR);
}void nrfx_timer_increment(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(nrf_timer_mode_get(p_instance->p_reg) != NRF_TIMER_MODE_TIMER);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_COUNT);
}uint32_t nrfx_timer_capture(nrfx_timer_t const * const p_instance,nrf_timer_cc_channel_t cc_channel)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(cc_channel < p_instance->cc_channel_count);nrf_timer_task_trigger(p_instance->p_reg,nrf_timer_capture_task_get(cc_channel));return nrf_timer_cc_read(p_instance->p_reg, cc_channel);
}void nrfx_timer_compare(nrfx_timer_t const * const p_instance,nrf_timer_cc_channel_t cc_channel,uint32_t cc_value,bool enable_int)
{nrf_timer_int_mask_t timer_int = nrf_timer_compare_int_get(cc_channel);if (enable_int){nrf_timer_event_clear(p_instance->p_reg, nrf_timer_compare_event_get(cc_channel));nrf_timer_int_enable(p_instance->p_reg, timer_int);}else{nrf_timer_int_disable(p_instance->p_reg, timer_int);}nrf_timer_cc_write(p_instance->p_reg, cc_channel, cc_value);NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",p_instance->instance_id,cc_value,cc_channel);
}void nrfx_timer_extended_compare(nrfx_timer_t const * const p_instance,nrf_timer_cc_channel_t cc_channel,uint32_t cc_value,nrf_timer_short_mask_t timer_short_mask,bool enable_int)
{nrf_timer_shorts_disable(p_instance->p_reg,(TIMER_SHORTS_COMPARE0_STOP_Msk << cc_channel) |(TIMER_SHORTS_COMPARE0_CLEAR_Msk << cc_channel));nrf_timer_shorts_enable(p_instance->p_reg, timer_short_mask);nrfx_timer_compare(p_instance,cc_channel,cc_value,enable_int);NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",p_instance->instance_id,cc_value,cc_channel);
}void nrfx_timer_compare_int_enable(nrfx_timer_t const * const p_instance,uint32_t channel)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(channel < p_instance->cc_channel_count);nrf_timer_event_clear(p_instance->p_reg,nrf_timer_compare_event_get(channel));nrf_timer_int_enable(p_instance->p_reg,nrf_timer_compare_int_get(channel));
}void nrfx_timer_compare_int_disable(nrfx_timer_t const * const p_instance,uint32_t channel)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(channel < p_instance->cc_channel_count);nrf_timer_int_disable(p_instance->p_reg,nrf_timer_compare_int_get(channel));
}static void irq_handler(NRF_TIMER_Type * p_reg,timer_control_block_t * p_cb,uint8_t channel_count)
{uint8_t i;for (i = 0; i < channel_count; ++i){nrf_timer_event_t event = nrf_timer_compare_event_get(i);nrf_timer_int_mask_t int_mask = nrf_timer_compare_int_get(i);if (nrf_timer_event_check(p_reg, event) &&nrf_timer_int_enable_check(p_reg, int_mask)){nrf_timer_event_clear(p_reg, event);NRFX_LOG_DEBUG("Compare event, channel: %d.", i);p_cb->handler(event, p_cb->context);}}
}#if NRFX_CHECK(NRFX_TIMER0_ENABLED)
void nrfx_timer_0_irq_handler(void)
{irq_handler(NRF_TIMER0, &m_cb[NRFX_TIMER0_INST_IDX],NRF_TIMER_CC_CHANNEL_COUNT(0));
}
#endif#if NRFX_CHECK(NRFX_TIMER1_ENABLED)
void nrfx_timer_1_irq_handler(void)
{irq_handler(NRF_TIMER1, &m_cb[NRFX_TIMER1_INST_IDX],NRF_TIMER_CC_CHANNEL_COUNT(1));
}
#endif#if NRFX_CHECK(NRFX_TIMER2_ENABLED)
void nrfx_timer_2_irq_handler(void)
{irq_handler(NRF_TIMER2, &m_cb[NRFX_TIMER2_INST_IDX],NRF_TIMER_CC_CHANNEL_COUNT(2));
}
#endif#if NRFX_CHECK(NRFX_TIMER3_ENABLED)
void nrfx_timer_3_irq_handler(void)
{irq_handler(NRF_TIMER3, &m_cb[NRFX_TIMER3_INST_IDX],NRF_TIMER_CC_CHANNEL_COUNT(3));
}
#endif#if NRFX_CHECK(NRFX_TIMER4_ENABLED)
void nrfx_timer_4_irq_handler(void)
{irq_handler(NRF_TIMER4, &m_cb[NRFX_TIMER4_INST_IDX],NRF_TIMER_CC_CHANNEL_COUNT(4));
}
#endif#endif // NRFX_CHECK(NRFX_TIMER_ENABLED)
版權和許可信息部分
/*** Copyright (c) 2015 - 2021, Nordic Semiconductor ASA** All rights reserved.** Redistribution and use in source and binary forms, with or without modification,* are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice, this* list of conditions and the following disclaimer.* ...(中間條件省略)...* 5. Any software provided in binary form under this license must not be reverse* engineered, decompiled, modified and/or disassembled.** THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE* DISCLAIMED. * ...(后續免責聲明省略)...*/
- 這部分是標準的版權聲明和許可協議,規定了代碼的使用、修改和分發條件
- 明確了 Nordic Semiconductor ASA 對代碼的版權所有
- 列出了 5 個 redistribution 條件,包括保留版權聲明、限制二進制形式的使用等
- 包含免責聲明,說明軟件按 "原樣" 提供,不提供任何明示或暗示的保證
頭文件和條件編譯部分
c
#include <nrfx.h>#if NRFX_CHECK(NRFX_TIMER_ENABLED)#if !(NRFX_CHECK(NRFX_TIMER0_ENABLED) || NRFX_TIMER1_ENABLED || \NRFX_CHECK(NRFX_TIMER2_ENABLED) || NRFX_CHECK(NRFX_TIMER3_ENABLED) || \NRFX_CHECK(NRFX_TIMER4_ENABLED))
#error "No enabled TIMER instances. Check <nrfx_config.h>."
#endif#include <nrfx_timer.h>#define NRFX_LOG_MODULE TIMER
#include <nrfx_log.h>
#include <nrfx.h>
:包含 nRFx 框架的主要頭文件#if NRFX_CHECK(NRFX_TIMER_ENABLED)
:檢查定時器功能是否在配置中啟用- 嵌套的條件編譯檢查是否有任何定時器實例 (NRFX_TIMER0 到 NRFX_TIMER4) 被啟用,若無則拋出編譯錯誤
#include <nrfx_timer.h>
:包含定時器驅動的頭文件#define NRFX_LOG_MODULE TIMER
:定義日志模塊為 TIMER,用于 nrfx_log.h 的日志輸出#include <nrfx_log.h>
:包含 nRFx 日志模塊的頭文件
結構體定義和全局變量部分
c
/**@brief Timer control block. */
typedef struct
{nrfx_timer_event_handler_t handler; // 定時器事件處理函數指針void * context; // 上下文指針,傳遞給事件處理函數nrfx_drv_state_t state; // 驅動狀態,記錄定時器當前狀態
} timer_control_block_t;static timer_control_block_t m_cb[NRFX_TIMER_ENABLED_COUNT];
- 定義了
timer_control_block_t
結構體,作為定時器的控制塊handler
:事件處理函數指針,用于處理定時器事件context
:上下文指針,通常用于傳遞用戶數據state
:定時器驅動狀態,可能的值包括未初始化、已初始化、已啟動等
m_cb
數組:靜態全局數組,存儲每個定時器實例的控制塊,大小由啟用的定時器數量決定
nrfx_timer_init 函數實現
c
nrfx_err_t nrfx_timer_init(nrfx_timer_t const * const p_instance,nrfx_timer_config_t const * p_config,nrfx_timer_event_handler_t timer_event_handler)
{timer_control_block_t * p_cb = &m_cb[p_instance->instance_id];
#ifdef SOFTDEVICE_PRESENTNRFX_ASSERT(p_instance->p_reg != NRF_TIMER0);
#endifNRFX_ASSERT(p_config);NRFX_ASSERT(timer_event_handler);nrfx_err_t err_code;if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED){err_code = NRFX_ERROR_INVALID_STATE;NRFX_LOG_WARNING("Function: %s, error code: %s.",__func__,NRFX_LOG_ERROR_STRING_GET(err_code));return err_code;}/* Warning 685處理 *//*lint -save -e685 */NRFX_ASSERT(NRF_TIMER_IS_BIT_WIDTH_VALID(p_instance->p_reg, p_config->bit_width));//lint -restorep_cb->handler = timer_event_handler;p_cb->context = p_config->p_context;uint8_t i;for (i = 0; i < p_instance->cc_channel_count; ++i){nrf_timer_event_clear(p_instance->p_reg, nrf_timer_compare_event_get(i));}NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), p_config->interrupt_priority);NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));nrf_timer_mode_set(p_instance->p_reg, p_config->mode);nrf_timer_bit_width_set(p_instance->p_reg, p_config->bit_width);nrf_timer_frequency_set(p_instance->p_reg, p_config->frequency);p_cb->state = NRFX_DRV_STATE_INITIALIZED;err_code = NRFX_SUCCESS;NRFX_LOG_INFO("Function: %s, error code: %s.",__func__,NRFX_LOG_ERROR_STRING_GET(err_code));return err_code;
}
- 函數功能:初始化定時器實例
- 參數:
p_instance
:定時器實例指針,包含寄存器地址和通道數等信息p_config
:定時器配置指針,包含模式、位寬、頻率等配置timer_event_handler
:定時器事件處理函數
- 實現步驟:
- 獲取對應實例的控制塊指針
- 在軟設備存在時,斷言定時器寄存器不是 NRF_TIMER0(可能與軟設備沖突)
- 斷言配置指針和事件處理函數不為空
- 檢查定時器狀態,若未初始化則繼續,否則返回錯誤
- 檢查位寬有效性(抑制 lint 警告)
- 保存事件處理函數和上下文
- 清除所有通道的比較事件
- 設置中斷優先級并啟用中斷
- 配置定時器模式、位寬和頻率
- 設置狀態為已初始化并返回成功
nrfx_timer_uninit 函數實現
c
void nrfx_timer_uninit(nrfx_timer_t const * const p_instance)
{NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));#define DISABLE_ALL UINT32_MAXnrf_timer_shorts_disable(p_instance->p_reg, DISABLE_ALL);nrf_timer_int_disable(p_instance->p_reg, DISABLE_ALL);#undef DISABLE_ALLnrfx_timer_disable(p_instance);m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED;NRFX_LOG_INFO("Uninitialized instance: %d.", p_instance->instance_id);
}
- 函數功能:反初始化定時器,釋放資源
- 實現步驟:
- 禁用定時器中斷
- 定義宏 DISABLE_ALL 為 UINT32_MAX,禁用所有短接功能和中斷
- 調用 nrfx_timer_disable 函數禁用定時器
- 將控制塊狀態設置為未初始化
- 記錄日志
定時器控制函數(enable/disable/is_enabled 等)
c
void nrfx_timer_enable(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON;NRFX_LOG_INFO("Enabled instance: %d.", p_instance->instance_id);
}void nrfx_timer_disable(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_SHUTDOWN);m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;NRFX_LOG_INFO("Disabled instance: %d.", p_instance->instance_id);
}bool nrfx_timer_is_enabled(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);return (m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_POWERED_ON);
}void nrfx_timer_resume(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);NRFX_LOG_INFO("Resumed instance: %d.", p_instance->instance_id);
}void nrfx_timer_pause(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP);NRFX_LOG_INFO("Paused instance: %d.", p_instance->instance_id);
}
- 這些函數提供了定時器的基本控制功能:
nrfx_timer_enable
:啟用定時器,觸發 START 任務,更新狀態nrfx_timer_disable
:禁用定時器,觸發 SHUTDOWN 任務,更新狀態nrfx_timer_is_enabled
:檢查定時器是否啟用,通過狀態判斷nrfx_timer_resume
:恢復定時器運行,觸發 START 任務nrfx_timer_pause
:暫停定時器,觸發 STOP 任務
定時器操作函數(clear/increment/capture 等)
c
void nrfx_timer_clear(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_CLEAR);
}void nrfx_timer_increment(nrfx_timer_t const * const p_instance)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(nrf_timer_mode_get(p_instance->p_reg) != NRF_TIMER_MODE_TIMER);nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_COUNT);
}uint32_t nrfx_timer_capture(nrfx_timer_t const * const p_instance,nrf_timer_cc_channel_t cc_channel)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(cc_channel < p_instance->cc_channel_count);nrf_timer_task_trigger(p_instance->p_reg, nrf_timer_capture_task_get(cc_channel));return nrf_timer_cc_read(p_instance->p_reg, cc_channel);
}
- 這些函數提供了定時器的高級操作功能:
nrfx_timer_clear
:清除定時器計數,觸發 CLEAR 任務nrfx_timer_increment
:手動增加定時器計數(要求非 TIMER 模式)nrfx_timer_capture
:捕獲指定通道的計數值,觸發捕獲任務并返回值
定時器比較功能函數
c
void nrfx_timer_compare(nrfx_timer_t const * const p_instance,nrf_timer_cc_channel_t cc_channel,uint32_t cc_value,bool enable_int)
{nrf_timer_int_mask_t timer_int = nrf_timer_compare_int_get(cc_channel);if (enable_int){nrf_timer_event_clear(p_instance->p_reg, nrf_timer_compare_event_get(cc_channel));nrf_timer_int_enable(p_instance->p_reg, timer_int);}else{nrf_timer_int_disable(p_instance->p_reg, timer_int);}nrf_timer_cc_write(p_instance->p_reg, cc_channel, cc_value);NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",p_instance->instance_id,cc_value,cc_channel);
}void nrfx_timer_extended_compare(nrfx_timer_t const * const p_instance,nrf_timer_cc_channel_t cc_channel,uint32_t cc_value,nrf_timer_short_mask_t timer_short_mask,bool enable_int)
{nrf_timer_shorts_disable(p_instance->p_reg,(TIMER_SHORTS_COMPARE0_STOP_Msk << cc_channel) |(TIMER_SHORTS_COMPARE0_CLEAR_Msk << cc_channel));nrf_timer_shorts_enable(p_instance->p_reg, timer_short_mask);nrfx_timer_compare(p_instance, cc_channel, cc_value, enable_int);NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",p_instance->instance_id,cc_value,cc_channel);
}void nrfx_timer_compare_int_enable(nrfx_timer_t const * const p_instance,uint32_t channel)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(channel < p_instance->cc_channel_count);nrf_timer_event_clear(p_instance->p_reg, nrf_timer_compare_event_get(channel));nrf_timer_int_enable(p_instance->p_reg, nrf_timer_compare_int_get(channel));
}void nrfx_timer_compare_int_disable(nrfx_timer_t const * const p_instance,uint32_t channel)
{NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);NRFX_ASSERT(channel < p_instance->cc_channel_count);nrf_timer_int_disable(p_instance->p_reg, nrf_timer_compare_int_get(channel));
}
- 這些函數處理定時器的比較功能:
nrfx_timer_compare
:設置比較值,可選擇啟用中斷nrfx_timer_extended_compare
:擴展比較功能,支持短接功能配置nrfx_timer_compare_int_enable/disable
:單獨控制比較中斷的啟用和禁用
中斷處理函數部分
c
static void irq_handler(NRF_TIMER_Type * p_reg,timer_control_block_t * p_cb,uint8_t channel_count)
{uint8_t i;for (i = 0; i < channel_count; ++i){nrf_timer_event_t event = nrf_timer_compare_event_get(i);nrf_timer_int_mask_t int_mask = nrf_timer_compare_int_get(i);if (nrf_timer_event_check(p_reg, event) &&nrf_timer_int_enable_check(p_reg, int_mask)){nrf_timer_event_clear(p_reg, event);NRFX_LOG_DEBUG("Compare event, channel: %d.", i);p_cb->handler(event, p_cb->context);}}
}#if NRFX_CHECK(NRFX_TIMER0_ENABLED)
void nrfx_timer_0_irq_handler(void)
{irq_handler(NRF_TIMER0, &m_cb[NRFX_TIMER0_INST_IDX],NRF_TIMER_CC_CHANNEL_COUNT(0));
}
#endif// 類似地處理TIMER1到TIMER4的中斷處理函數(代碼結構相同)
irq_handler
函數:通用中斷處理函數,處理指定定時器的所有通道事件- 遍歷所有通道,檢查是否有比較事件發生且中斷已啟用
- 清除事件標志,記錄日志,并調用注冊的事件處理函數
- 各個定時器實例的中斷處理函數(如 nrfx_timer_0_irq_handler):
- 條件編譯檢查對應定時器是否啟用
- 調用通用中斷處理函數,傳遞對應的寄存器、控制塊和通道數
結尾條件編譯
c
#endif // NRFX_CHECK(NRFX_TIMER_ENABLED)
- 結束最外層的條件編譯,確保只有在定時器功能啟用時才包含這些代碼
總結
這段代碼是 nRF5 SDK 中定時器驅動的核心實現,主要功能包括:
- 定時器的初始化與反初始化
- 定時器的啟用、禁用、暫停和恢復
- 定時器的計數清除、手動遞增和值捕獲
- 定時器的比較功能配置和中斷處理
- 各個定時器實例的中斷處理函數
代碼采用了控制塊 (control block) 的設計模式,通過結構體數組管理每個定時器實例的狀態和回調函數。大量使用了斷言 (assert) 來確保輸入參數的有效性,并通過日志模塊記錄關鍵操作,便于調試。條件編譯的使用使得代碼可以根據配置靈活啟用不同的定時器實例,提高了代碼的可配置性和可維護性。