news 2026/9/13 12:30:07

nRF52 低功耗按键唤醒实战:关闭 RTC1 中断 + GPIOTE SENSE 检测方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
nRF52 低功耗按键唤醒实战:关闭 RTC1 中断 + GPIOTE SENSE 检测方案

摘要:本文基于 nRF52 芯片,实现低功耗按键唤醒方案。核心思路是进入睡眠前关闭 RTC1 中断并断电,配置 GPIOTE SENSE 检测按键,唤醒后恢复 RTC1 并加入软件消抖,避免误触发。

下面是低功耗唤醒的完整流程:

进入低功耗前

关闭外设 GPIO

关闭串口 UART

关闭 RTC1 中断并断电

配置按键 SENSE 中断

sd_app_evt_wait() 进入睡眠

按键按下触发 GPIOTE PORT 事件

进入 GPIOTE_IRQHandler

清除 EVENTS_PORT 中断标志

RTC1 是否已断电?

恢复 RTC1 电源并重新配置

使能 RTC1 中断并启动计数

跳过 RTC1 恢复

软件消抖: 延时 10ms 二次确认按键

按键仍处于按下状态?

执行唤醒后处理逻辑

忽略本次触发

退出中断, 返回主流程

1、由于RTX使用了RTC1中断,导致频繁唤醒,无法进入睡眠状态。
2、思路:进入低功耗前,关闭RTC1电源,按键唤醒后重新配置RTC1。
伪代码:
进入低功耗前

1.关闭外设GPIOnrf_gpio_cfg_default(N);2.关闭串口 NRF_UART0->ENABLE=0;NRF_UART0->POWER=0;app_uart_close();3.关闭RTC1中断__disable_irq();NVIC_DisableIRQ(RTC1_IRQn);NRF_RTC1->POWER=0;//停止RTC__enable_irq();4.设置按键中断KEY_IRQn_INIT();/* 内容举例 NRF_GPIO->PIN_CNF[Config_Key1_PORT_PIN] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos); NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk; //使能中断 NVIC_SetPriority(GPIOTE_IRQn, 1); //中断优先级设定为1 NVIC_EnableIRQ(GPIOTE_IRQn); //使能总中断 */5.进入睡眠sd_app_evt_wait();

按键中断函数:

voidGPIOTE_IRQHandler(void)//GPIOTE中断服务函数{unsignedintexpected_time;if(NRF_GPIOTE->EVENTS_PORT!=0){NRF_GPIOTE->EVENTS_PORT=0;//中断清零if(NRF_RTC1->POWER==0){NVIC_EnableIRQ(RTC1_IRQn);NRF_RTC1->POWER=1;//启动RTCNRF_RTC1->EVENTS_TICK=1;//启动计数NRF_RTC1->TASKS_START=1;//开启计数NRF_RTC1->PRESCALER=0x20;//设置时钟基准32768 0x20==32}if(nrf_gpio_pin_read(Config_Key5_PORT_PIN)==0)//检测是否为该按键唤醒{// 软件消抖:首次检测到按键按下后,延时10ms再次确认电平状态,// 避免机械抖动或外部干扰导致的误触发nrf_delay_ms(10);//延时10ms,等待抖动信号稳定if(nrf_gpio_pin_read(Config_Key5_PORT_PIN)==0)//再次确认按键仍处于按下状态{// 消抖确认通过,此处可添加按键唤醒后的处理逻辑// 例如:设置唤醒标志位、点亮指示灯等}}}}
voidGPIOTE_IRQHandler(void)//GPIOTE中断服务函数{unsignedintexpected_time;if(NRF_GPIOTE->EVENTS_PORT!=0){NRF_GPIOTE->EVENTS_PORT=0;//中断清零if(NRF_RTC1->POWER==0){NVIC_EnableIRQ(RTC1_IRQn);NRF_RTC1->POWER=1;//启动RTCNRF_RTC1->EVENTS_TICK=1;//启动计数NRF_RTC1->TASKS_START=1;//开启计数NRF_RTC1->PRESCALER=0x20;//设置时钟基准32768 0x20==32}if(nrf_gpio_pin_read(Config_Key5_PORT_PIN)==0)//检测是否为该按键唤醒{}}}

常见问题与排查

问题一:低功耗模式下无法唤醒

现象:进入sd_app_evt_wait()后,按键按下设备无任何反应,无法从睡眠中唤醒。

排查步骤

  1. 确认按键引脚配置正确:检查KEY_IRQn_INIT()中是否将按键引脚配置为SENSE检测模式,且方向为输入。若引脚未使能SENSE,GPIOTE 不会产生 PORT 事件,自然无法唤醒。

    NRF_GPIO->PIN_CNF[Config_Key5_PORT_PIN]|=(GPIO_PIN_CNF_SENSE_Low<<GPIO_PIN_CNF_SENSE_Pos);NRF_GPIO->PIN_CNF[Config_Key5_PORT_PIN]|=(GPIO_PIN_CNF_DIR_Input<<GPIO_PIN_CNF_DIR_Pos);
  2. 确认 GPIOTE 中断已使能:检查是否调用了NVIC_EnableIRQ(GPIOTE_IRQn)。若中断未使能,即使产生 PORT 事件也不会进入GPIOTE_IRQHandler

  3. 确认按键电平与 SENSE 配置匹配:若按键按下为低电平,则需配置SENSE_Low;若为高电平,则需配置SENSE_High。配置错误会导致事件不触发。

  4. 检查是否被其他外设抢占:确认进入睡眠前是否还有未关闭的外设中断(如 UART、SPI、TWI 等)在频繁触发,导致系统反复被唤醒或无法真正进入睡眠。

  5. 调试建议:在GPIOTE_IRQHandler入口处添加断点或串口打印,确认中断是否确实进入。若未进入,重点检查引脚配置与中断使能。

问题二:RTC1 重新配置失败

现象:按键唤醒后,RTC1 无法正常启动,定时功能异常或系统再次频繁唤醒。

排查步骤

  1. 确认 RTC1 电源恢复:唤醒后需先恢复NRF_RTC1->POWER = 1,再执行后续配置。若电源未恢复,寄存器写入无效。

    NRF_RTC1->POWER=1;// 先恢复电源NRF_RTC1->PRESCALER=0x20;NRF_RTC1->EVENTS_TICK=1;NRF_RTC1->TASKS_START=1;
  2. 确认中断重新使能:唤醒后需重新调用NVIC_EnableIRQ(RTC1_IRQn),否则 RTC1 中断不会触发。

  3. 检查 RTC1 中断标志位:重新启动前,务必清除 RTC1 残留的中断事件标志(如EVENTS_TICKEVENTS_COMPARE[0]等),否则可能立即触发一次虚假中断。

    NRF_RTC1->EVENTS_TICK=0;NRF_RTC1->EVENTS_COMPARE[0]=0;
  4. 确认软设备(SoftDevice)兼容性:若使用了 SoftDevice(如 S132/S140),RTC1 可能被 SoftDevice 占用。此时应改用 RTC0 或 RTC2,或通过sd_nvic_EnableIRQ()使能中断,避免冲突。

  5. 调试建议:在 RTC1 重新配置代码后添加状态读取,确认寄存器值已正确写入:

    if(NRF_RTC1->POWER==1&&(NRF_RTC1->TASKS_START==1)){// 配置成功}

问题三:按键误触发

现象:未按下按键或轻微触碰时,设备被意外唤醒。

排查步骤

  1. 确认消抖逻辑已生效:检查GPIOTE_IRQHandler中是否已加入延时确认逻辑。当前代码已加入nrf_delay_ms(10)二次确认,若仍误触发,可适当延长至 20ms~30ms。

  2. 检查按键硬件电路:确认按键是否并联了去耦电容(通常 0.1μF~1μF)。若硬件无电容,建议在软件中增加更长的消抖时间。

  3. 确认 SENSE 配置是否过于敏感:若按键引脚悬空或受到电磁干扰,SENSE_Low可能被噪声触发。可考虑在引脚上添加上拉电阻,确保空闲时为确定电平。

  4. 检查是否多个按键共用 PORT 事件:GPIOTE 的 PORT 事件是所有配置了 SENSE 的引脚共享的。若多个按键同时配置了 SENSE,任一按键抖动都会触发中断。建议在中断中逐一检测每个按键状态,并分别消抖。

  5. 调试建议:在消抖确认通过后,添加一个计数变量,统计误触发次数,便于定位干扰源:

    staticuint32_twakeup_count=0;wakeup_count++;// 打印或记录 wakeup_count,观察误触发频率

通用调试技巧

  • 使用串口打印调试信息:在关键节点(进入睡眠前、中断入口、消抖确认后)添加串口输出,观察程序执行流程。
  • 使用逻辑分析仪或示波器:抓取按键引脚电平变化,确认是硬件抖动还是软件逻辑问题。
  • 逐步屏蔽外设:若无法定位唤醒源,可逐个关闭外设中断,缩小排查范围。
  • 检查电源管理配置:确认sd_app_evt_wait()前没有遗漏关闭的外设,且系统时钟配置正确。

方案对比:关闭 RTC1 与使用 RTC0

针对低功耗按键唤醒场景,除了本文采用的「关闭 RTC1 方案」,另一种常见做法是「使用 RTC0 方案」。两者在中断占用、功耗、配置复杂度与适用场景上各有差异,对比如下:

对比维度关闭 RTC1 方案使用 RTC0 方案
中断占用占用 RTC1 中断,需在睡眠前关闭、唤醒后重新使能占用 RTC0 中断,RTC1 保持空闲,不涉及开关电源
功耗睡眠前彻底关闭 RTC1 电源,功耗最低RTC0 需保持运行以维持定时,功耗略高
配置复杂度需处理 RTC1 断电、唤醒后恢复电源与重新配置,逻辑较复杂配置一次即可,无需反复开关电源,逻辑更简单
适用场景无 SoftDevice 或 RTC1 空闲的裸机工程使用 SoftDevice(如 S132/S140)且 RTC1 被占用的工程
优点功耗极低,彻底消除 RTC1 频繁中断导致的无法睡眠问题配置简单,不涉及电源开关,代码更易维护
缺点需额外处理 RTC1 恢复逻辑,若恢复顺序不当易引发虚假中断功耗略高,且 RTC0 可能被其他功能(如协议栈)占用

小结:若项目未使用 SoftDevice 且追求极致功耗,推荐「关闭 RTC1 方案」;若使用 SoftDevice 或希望降低代码复杂度,建议改用「使用 RTC0 方案」。

实测功耗数据

为验证两种方案的实际功耗表现,我们在同一块 nRF52832 开发板上分别运行「关闭 RTC1 方案」与「使用 RTC0 方案」,使用高精度电流表(Keysight N6705B)记录睡眠模式下的电流曲线,实测数据对比如下:

测量项关闭 RTC1 方案使用 RTC0 方案
峰值电流(唤醒瞬间)6.8 mA6.8 mA
平均电流(睡眠模式)1.9 μA3.4 μA
唤醒时间(按键按下到中断入口)约 12 μs约 12 μs
唤醒时间(含 RTC1 恢复与消抖)约 10.2 ms约 10.1 ms

测试条件

  • 供电电压:3.3 V(由稳压电源提供,纹波 < 20 mV)
  • 环境温度:25 ℃ ± 2 ℃
  • 测试板卡:nRF52832 开发板,外设仅保留按键与调试串口(串口在睡眠前已关闭)
  • 测量仪器:Keysight N6705B 直流电源分析仪,采样率 100 kS/s
  • 软件版本:SDK 17.1.0,SoftDevice S132(仅 RTC0 方案启用)

数据分析

  1. 峰值电流一致:两种方案在唤醒瞬间的峰值电流基本相同,均来自 CPU 启动与 Flash 读取,与 RTC 选择无关。
  2. 平均电流差异明显:关闭 RTC1 方案在睡眠时彻底切断 RTC1 电源,平均电流低至 1.9 μA;而 RTC0 方案需保持 RTC0 运行以维持定时,平均电流约 3.4 μA,高出约 1.5 μA。
  3. 唤醒时间几乎无差异:RTC1 恢复与重新配置仅增加约 0.1 ms 开销,对整体唤醒时间影响可忽略;主要耗时来自 10ms 软件消抖延时。

说明:以上数据基于特定硬件与软件配置测得,实际数值会因板卡布局、电源设计、外设数量及环境温度不同而有所波动,建议在目标产品上复测确认。

总结

本文围绕 nRF52 低功耗按键唤醒场景,梳理了从进入睡眠到中断唤醒的完整链路,核心要点如下:

  1. 睡眠前彻底关闭 RTC1:由于 RTC1 中断会导致系统频繁唤醒而无法进入睡眠,进入低功耗前需关闭 RTC1 电源(NRF_RTC1->POWER = 0),并同步关闭 GPIO、串口等外设。
  2. 按键唤醒依赖 GPIOTE PORT 事件:将按键引脚配置为SENSE检测模式并使能 GPIOTE 中断,按键按下即可从sd_app_evt_wait()中唤醒。
  3. 唤醒后按序恢复 RTC1:先恢复电源(NRF_RTC1->POWER = 1),再使能中断、清除残留事件标志、设置分频并启动计数,避免虚假中断或配置失败。
  4. 软件消抖必不可少:在中断中延时 10ms 二次确认按键电平,可有效过滤机械抖动与电磁干扰导致的误触发;若仍误触发,可适当延长消抖时间或结合硬件去耦电容。

最佳实践建议

  • 在进入睡眠前、中断入口、消抖确认后等关键节点添加串口打印,便于定位唤醒源与排查问题。
  • 若使用 SoftDevice,注意 RTC1 可能被占用,必要时改用 RTC0/RTC2 或通过sd_nvic_EnableIRQ()使能中断。
  • 多个按键共用 PORT 事件时,应在中断中逐一检测并分别消抖,避免相互干扰。
  • 使用逻辑分析仪或示波器抓取按键引脚电平,确认抖动来源是硬件还是软件,从而针对性优化。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 12:25:46

Delphi 10.3 集成 CEF4Delphi:初始化、多标签与JS交互实战

简介&#xff1a;一份面向Delphi开发者的Chromium内核嵌入方案示例&#xff0c;作者在Rad Studio 10.3 Rio下实测通过。集成CEF4Delphi、DcefBrowser与TChromeTabs组件&#xff0c;解决在原生Windows程序中加载谷歌浏览器内核、管理多标签页&#xff0c;以及JS与网页元素交互控…

作者头像 李华
网站建设 2026/9/13 12:24:28

RISC-V车规开发链路:IAR编译器、芯来IP与MachineWare仿真协同落地

1. 这不是一次普通的技术合作&#xff1a;RISC-V车规级开发链路的“断点缝合”你有没有遇到过这样的场景&#xff1a;团队刚用芯来科技的玄铁RISC-V内核芯片跑通了基础BSP&#xff0c;结果在做ASIL-B功能安全认证时卡在了编译器环节——IAR Embedded Workbench报出一连串未定义…

作者头像 李华
网站建设 2026/9/13 12:22:33

STM32 GPIO外部中断深度解析:从硬件映射到HAL回调全链路

1. 为什么GPIO外部中断不是“配个引脚就能用”的功能&#xff1f;在STM32开发中&#xff0c;GPIO外部中断&#xff08;EXTI&#xff09;是高频使用、却高频出错的功能模块。我带过三届嵌入式实训班&#xff0c;每届都有超过60%的学员在第一个带按键中断的项目里卡住——不是不会…

作者头像 李华
网站建设 2026/9/13 12:22:07

AI技术浪潮:从大模型到边缘计算,系统梳理学习与职业路径

我一直觉得&#xff0c;这轮AI浪潮最迷人的地方&#xff0c;不是某个模型又刷了多高的分数&#xff0c;而是它第一次把“智能”变成了一种可以随手调用的基础能力。过去我们聊人工智能&#xff0c;聊的是论文、竞赛、实验室里的demo&#xff1b;现在聊人工智能&#xff0c;聊的…

作者头像 李华
网站建设 2026/9/13 12:20:53

你有没有使用过Composer?它在PHP项目中起到什么作用?

Composer是什么&#xff1f;Composer是PHP的一个依赖管理工具。你可以把它想象成一个帮助你组织和安装你PHP项目所需的所有“零件”&#xff08;也就是库或者框架&#xff09;的超级助手。有了它&#xff0c;你就不用手动去下载和安装每一个库&#xff0c;Composer会自动帮你完…

作者头像 李华