nrf52840蓝牙学习(定时器的应用)
和其他 MCU 处理器一样,在 nrf52840 中定时器的功能是十分强大的。其内部包含了 5 个定时
器 TIMER 模块 :TIMER0 、 TIMER1 、 TIMER2 、 TIMER3 、 TIMER4 ,如下表 10.1 所示。

1. 时钟源
首先定时器 TIMER 工作在高频时钟源( HFLCK )下,同时包含了一个 4bit ( 1 / 2X )的分频

出。
计数模式下,每次触发 COUNT 任务时, TIMER 的内部计数器 Counter 寄存器都会递增 1 ,同
时,计数器模式下是不使用定时器的频率和预分频器, COUNT 任务在定时器模式下无效。通过设
定一个 CAPTURE Task ,捕获的计数器的值存储到 CC[n] 寄存器内,然后对 CC[n] 寄存器进行读取计
数的值。
5. 任务延迟和优先级
任务延迟: TIMER 启动后, CLEAR 任务, COUNT 任务和 STOP 任务将保证在 PCLK16M 的一
个时钟周期内生效。
任务优先级:如果同时触发 START 任务和 STOP 任务,即在 PCLK16M 的同一时段内,则优先
执行 STOP 任务。
下表是定时器的寄存器列表,详细说明如下 10.5 表示所示:

定时器首先需要设置的三个参数,分别为:定时器的模式、定时器的位宽、定时器的时钟频率。
本例中需要进行定时操作,因此还需要设置比较寄存器里的值。如果初始化完成后,定时器就开始
定时,当定时时间的值跟 CC[n] 寄存器的值相等时,将触发一个 COMPARE [n] event ,这时候我们
关掉定时器定时。这样根据 CC[n] 寄存器的值就是实现了一个指定的时间长度的。
文件一:
/******************** (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) 来确保输入参数的有效性,并通过日志模块记录关键操作,便于调试。条件编译的使用使得代码可以根据配置灵活启用不同的定时器实例,提高了代码的可配置性和可维护性。