和其他 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; 

  • 计算公式分解
    1. 理论上 1ms 对应 15.625 个 tick (15625Hz)
    2. 代码实现:CC [0] = ms×31 + ms/4 ≈ ms×31.25
    3. 实际换算: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. 时间精度

    • 理论精度:±1 个 tick (64μs)
    • 实际误差:约 100%(因计算错误导致)
  2. 优化方向

    // 低功耗优化版本
    while (!p_timer->EVENTS_COMPARE[0]) {__WFI(); // 进入等待中断模式,CPU休眠
    }
    
  3. 功能增强

    // 非阻塞式延时接口
    bool nrf_timer_delay_start(timer_t timer, uint16_t ms);
    bool nrf_timer_delay_check(timer_t timer);
    

潜在问题与修复

  1. 计算错误:修正 CC [0] 计算公式
  2. 溢出风险:添加输入参数验证
  3. 资源冲突:多任务环境需要互斥访问
  4. 功耗问题:长时间延时建议使用 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;

核心功能模块详解

  1. 任务寄存器组 (Tasks)

    • TASKS_START: 启动定时器计数
    • TASKS_STOP: 停止定时器计数
    • TASKS_CLEAR: 清零当前计数值
    • TASKS_CAPTURE[n]: 将当前计数值捕获到 CC [n] 寄存器
  2. 事件寄存器组 (Events)

    • EVENTS_COMPARE[n]: 当计数值与 CC [n] 匹配时触发事件
    • 可用于实现 PWM、定时中断等功能
  3. 配置寄存器

    • MODE: 选择工作模式 (定时器 / 计数器)
    • BITMODE: 配置计数位宽 (8/16/24/32 位)
    • PRESCALER: 配置预分频值 (2^n,n=0~9)
  4. 捕获 / 比较寄存器组

    • CC[0-5]: 6 个 16/24/32 位寄存器
    • 支持捕获当前计数值或设置比较值
    • 用于 PWM 生成、定时触发等功能
  5. 中断控制

    • INTENSET: 使能特定中断
    • INTENCLR: 禁用特定中断
    • 支持比较事件中断、溢出中断等
  6. 短连接功能

    • SHORTS: 配置事件与任务之间的直接连接
    • 例如:比较事件发生时自动清除计数器

典型应用场景

  1. 延时功能实现

    // 基于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; // 清除事件标志
    
  2. PWM 信号生成

    • 使用 SHORTS 自动实现周期循环
    // 配置PWM周期和占空比
    p_timer->CC[0] = period;        // 周期值
    p_timer->CC[1] = duty_cycle;    // 占空比值
    p_timer->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; // 比较事件0触发计数器清零
    
  3. 输入捕获功能

    // 捕获外部信号的周期
    p_timer->TASKS_CAPTURE[0] = 1;  // 手动触发一次捕获
    // 当外部事件发生时,可通过SHORTS自动触发捕获
    p_timer->SHORTS = TIMER_SHORTS_COMPARE1_CAPTURE0_Msk;
    

设计亮点分析

  1. 任务 - 事件架构

    • 任务驱动操作,避免直接写寄存器
    • 事件标志统一管理,简化状态检测
  2. 灵活的预分频配置

    • 支持 2^0~2^9 预分频
    • 适配不同时钟频率和应用场景
  3. 多通道捕获 / 比较

    • 6 个独立 CC 通道
    • 可同时实现多个 PWM 输出或定时功能
  4. 短连接机制

    • 硬件级事件 - 任务连接
    • 减少 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;      // 获取校准值(假设结构体包含此寄存器)

设计亮点分析

  1. 低功耗时钟管理
    • 独立控制高频 / 低频时钟的启停,支持精细化功耗优化(如仅在需要时启动 HFXO)。
  2. 时钟源灵活切换
    • LFCLKSRC 支持多种低频时钟源,平衡精度与功耗(LFXO 精度高但功耗大,LFRC 功耗低但精度低)。
  3. 自动校准机制
    • 通过 TASKS_CAL 和校准定时器自动优化 LFRC 精度,减少外部晶振依赖。
  4. 硬件去抖设计
    • HFXODEBOUNCE 寄存器防止晶体振荡器启动时的抖动干扰,提高时钟稳定性。

关键寄存器映射表

寄存器名称地址偏移访问权限功能描述
TASKS_HFCLKSTART0x0000只写启动高频晶体振荡器
EVENTS_HFCLKSTARTED0x0100读写高频时钟启动完成事件
LFCLKSRC0x0518读写低频时钟源选择
HFXODEBOUNCE0x0528读写高频晶体去抖时间配置
LFRCMODE0x05B4读写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:定时器事件处理函数
  • 实现步骤:
    1. 获取对应实例的控制块指针
    2. 在软设备存在时,断言定时器寄存器不是 NRF_TIMER0(可能与软设备冲突)
    3. 断言配置指针和事件处理函数不为空
    4. 检查定时器状态,若未初始化则继续,否则返回错误
    5. 检查位宽有效性(抑制 lint 警告)
    6. 保存事件处理函数和上下文
    7. 清除所有通道的比较事件
    8. 设置中断优先级并启用中断
    9. 配置定时器模式、位宽和频率

  1. 设置状态为已初始化并返回成功
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);
}

  • 函数功能:反初始化定时器,释放资源
  • 实现步骤:
    1. 禁用定时器中断
    2. 定义宏 DISABLE_ALL 为 UINT32_MAX,禁用所有短接功能和中断
    3. 调用 nrfx_timer_disable 函数禁用定时器
    4. 将控制块状态设置为未初始化
    5. 记录日志
定时器控制函数(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 中定时器驱动的核心实现,主要功能包括:

  1. 定时器的初始化与反初始化
  2. 定时器的启用、禁用、暂停和恢复
  3. 定时器的计数清除、手动递增和值捕获
  4. 定时器的比较功能配置和中断处理
  5. 各个定时器实例的中断处理函数

代码采用了控制块 (control block) 的设计模式,通过结构体数组管理每个定时器实例的状态和回调函数。大量使用了断言 (assert) 来确保输入参数的有效性,并通过日志模块记录关键操作,便于调试。条件编译的使用使得代码可以根据配置灵活启用不同的定时器实例,提高了代码的可配置性和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87202.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87202.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/87202.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Bluedroid】蓝牙启动之BTM_reset_complete源码解析

当蓝牙控制器完成硬件重置后,协议栈需通过一系列初始化操作恢复各模块状态。本文深入分析BTM_reset_complete核心函数及其调用链,详解 L2CAP 连接清理、安全模块重置、扫描参数恢复、BLE 隐私功能初始化等关键流程,揭示蓝牙设备在重置后如何通过标准化状态恢复确保互操作性、…

containerd 项目主要目录简要说明

containerd 项目结构清晰&#xff0c;核心代码分布在若干主目录下。以下是 client、cmd、core、internal、pkg、plugins 这六个主要包/目录的简要作用说明&#xff1a; 1. client 作用&#xff1a;封装与 containerd 守护进程通信的 Go 客户端 API&#xff0c;主要基于 gRPC。…

有线转无线工具,轻松创建WiFi热点

软件介绍 今天为大家推荐一款实用的无线网络共享工具——MyPublicWiFi。这款软件能够将电脑的有线网络转换为无线WiFi&#xff0c;方便其他设备连接使用。 安装与设置 该软件为安装版程序&#xff0c;安装完成后会自动识别当前电脑的IP地址。用户可在软件界面中自定义设…

Linux下,通过标准I2C驱动读取Sensor ID

sensor型号&#xff1a;OS04L10&#xff0c;sensor引脚以及时钟要先配置好&#xff0c;源码如下&#xff1a; #include <fcntl.h> #include <linux/i2c-dev.h> #include <linux/i2c.h> #include <stdint.h> #include <stdio.h> #include <sy…

人工智能基石:SVM支持向量机全解析(附Python实战)

大家好&#xff01;今天我们来深入探讨支持向量机&#xff08;Support Vector Machine, SVM&#xff09;——这个在​​图像识别、文本分类​​等领域广泛应用的强大算法。既能处理分类问题&#xff0c;又能解决回归任务&#xff0c;甚至在非线性数据面前也能游刃有余。本文将带…

mysql查看数据库

在 MySQL 中查看当前数据库的创建语句&#xff0c;使用 SHOW CREATE DATABASE 命令&#xff0c;以下是详细操作指南&#xff1a; 1. 查看当前数据库的创建语句 SHOW CREATE DATABASE database_name; 替换 database_name 为你的数据库名使用反引号 包裹特殊名称或保留字 2.…

ArrayList剖析

大家天天在用List&#xff0c;ArrayList一般来讲应该是程序员用的最多的集合类了。 我们今天研究一下ArrayList。 总体来讲&#xff0c;从底层数据结构或者源码的角度看&#xff0c;List比Map或者Set要简单。 底层数据结构 ArryList其实就是可变长数组。 初始化的时候&…

回顾JAVA中的锁机制

Java中的锁机制 在Java中&#xff0c;锁机制是多线程编程里保障数据一致性与线程安全的关键技术。 1. 内置锁&#xff1a;synchronized关键字 synchronized是Java的内置锁机制&#xff0c;能够保证在同一时刻&#xff0c;只有一个线程可以执行被其修饰的代码块或方法。 用法…

YOLOv11: AN OVERVIEW OF THE KEY ARCHITECTURAL ENHANCEMENTS目标检测论文精读(逐段解析)

YOLOv11: AN OVERVIEW OF THE KEY ARCHITECTURAL ENHANCEMENTS目标检测论文精读&#xff08;逐段解析&#xff09; 论文地址&#xff1a;https://www.arxiv.org/abs/2410.17725 Rahima Khanam and Muhammad Hussain Ultralytics公司发布 CVPR 2024 论文写的比较简单&#xff…

【Erdas实验教程】025:遥感图像辐射增强(雾霾去除)

文章目录 一、雾霾去除原理二、雾霾去除案例一、雾霾去除原理 遥感影像雾霾去除的核心原理是消除大气散射对电磁波的干扰,恢复地物真实反射信息。Haze Reduction 工具的原理: 该工具基于暗目标法(Dark Object Subtraction, DOS),适用于去除因大气散射(雾霾本质是大气颗…

Language Models are Unsupervised Multitask Learners :语言模型是无监督的多任务学习者

摘要 自然语言处理任务&#xff0c;如问答、机器翻译、阅读理解和摘要&#xff0c;通常通过在特定任务的数据集上进行监督学习来解决。我们展示了语言模型在训练于一个包含数百万网页的新数据集——WebText——时&#xff0c;可以无需任何显式监督就开始学习这些任务。当模型以…

SQL语句全攻略:从基础到进阶的编程之旅

目录 一、引言二、SQL 基础语法2.1 SQL 语句写法顺序2.2 关联查询2.3 数据处理常用函数和运算符 三、数据库和表的基本操作3.1 创建数据库3.2 使用数据库3.3 创建表 四、基础增删改查操作4.1 插入数据&#xff08;增&#xff09;4.2 查询数据&#xff08;查&#xff09;4.3 更新…

Kafka的下载安装

目录 一、前期准备 1、查看网卡&#xff1a; 2、配置静态IP 3、设置主机名 4、配置IP与主机名映射 5、关闭防火墙 6、配置免密登录 二、JDK的安装 三、Zookeeper的安装 四、Kafka的安装 1、Kafka的下载安装 2、修改配置文件 4、分发文件 5、修改其他节点broker.i…

opencv入门(6) TrackBar调整图片和键盘响应

文章目录 1 创建trackbar2 使用userdata传入函数3 键盘响应 1 创建trackbar 1.trackbar名称 2.创建在哪个窗口上 3.拖动trackbar改变的值 4.trackBar的最大值 5.trackbar改变时的回调函数 6. 带入回调函数的数据&#xff0c;可以不用带,是一个void指针 createTrackbar(“Value …

QT<33> 修改窗口标题栏背景颜色

前言&#xff1a; 在做项目或者开发QT软件时&#xff0c;如果想要修改窗口标题栏背景颜色&#xff0c;发现没有代码可以直接设置&#xff0c;目前有两种方法可以设置。 第一种&#xff0c;自定义一个界面类&#xff0c;用QLabelQWidget实现&#xff0c;QLabel当作标题栏。 第…

JavaEE-博客系统项目

项目介绍 准备工作 创建数据表 创建项目 添加依赖 创建对应目录 除了基本的数据层mapper&#xff0c;业务层service&#xff0c;交互层controller&#xff0c;还创建了公共类的层common&#xff0c;枚举类层enums&#xff0c;异常类层&#xff0c;和实体类层pojo。 配置项目配…

Java项目:基于SSM框架实现的软件工程项目管理系统【ssm+B/S架构+源码+数据库+毕业论文+开题报告】

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本项目管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…

[按键手机安卓/IOS脚本插件开发] 按键插件调试与判断循环结构辅助工具

实现按键插件的核心原理 通过一个table类型的QMPlugin变量实现按键精灵调用Lua函数&#xff0c;例如 -- Lua代码 -- 实现两数相加求和 function QMPlugin.Add(a, b) return a b end 将以上代码保存成.lua文件&#xff0c;例如test.lua后&#xff0c;放入按键精灵手机助手的p…

提示词框架(9)--CARE

提示词框架不止是AI的框架&#xff0c;也可以是我们的思考框架&#xff0c;拆解问题的方法&#xff01;&#xff01;&#xff01; CARE框架是一种用于优化提示词设计的方法&#xff0c;它帮助用户更有效地与AI进行交互&#xff0c;特别是在需要获取特定信息或实现某些任务时。…

uniapp+vue2 input不显示明文密码,点击小眼睛显示或隐藏密码

<u-input placeholder"请输入密码" prefixIcon"lock" :password"showPassword" v-model"formData.password"prefixIconStyle"font-size: 25px;color: #3C9CFF" border"none"><template slot"suffix…