使用 Arduino 轻松制作超低功耗蓝牙低功耗(BLE)设备


碳基码牛
转载
发布时间: 2025-08-29 16:36:35 | 阅读数 0收藏数 0评论数 0
封面
本文将介绍如何使用 Arduino 轻松制作超低功耗 BLE 设备,无需编写 Android 代码。新手用户也能制作出仅用一枚纽扣电池或 2 节 AAA 电池就能连续运行一年以上的 BLE 设备。

准备工作:

材料:

材料:

注意:在《2022 年制作超低功耗 BLE 设备》教程中,编程器中的保护电阻已从本文的 1KΩ 改为 100Ω,因为 CMSIS-DAP 模块通过 1KΩ 电阻编程时会出现问题,而 DAPLink 模块则无此问题。此外,新增 “编程失败怎么办” 章节,提供编程问题的解决方案。本文档已被《2022 年使用 Arduino 制作功耗 < 20 微安的超低功耗 BLE 设备》教程替代 —— 本文中提及的大多数编程器和模块已停产,替代教程涵盖了目前可采购的编程器与模块,并对代码进行了优化,使功耗降低至原来的 1/4,数据传输速度提升 4 倍。

=======================================================================

更新记录:


  1. 2019 年 11 月 26 日 —— 新增 nRF5 Flash 协议栈(SoftDevice)工具的安装说明
  2. 2019 年 3 月 24 日 ——pfod_lp_nrf52.zip 的第 4 版新增对 GT832E_01 模块的支持;nRFChipInfo 功能新增高驱动输出模式,并修复定时器漏洞
  3. 2019 年 2 月 11 日 —— 发布 pfod_lp_nrf52.zip 的第 2 版
  4. 2018 年 1 月 6 日 —— 用成本更低(但稳定性稍差)的 Particle 调试器替代 BlackMagic 调试器,用于编程操作

项目概述

本文《使用 Arduino 轻松制作超低功耗 BLE 设备》是系列教程的第 1 部分,共 3 个部分:


  1. 第 1 部分(本文):介绍如何配置 Arduino 以编写 nRF52 低功耗设备代码、搭建编程模块、测量供电电流,同时涵盖专用低功耗定时器、比较器、消抖输入的使用,以及如何通过 pfodApp 连接并控制 nRF52 设备。
  2. 第 2 部分《超低功耗温湿度监测器:介绍如何使用 RedBear Nano V2 模块和 Si7021 温湿度传感器制作低功耗电池 / 太阳能供电监测器,包括修改 Si7021 库以实现低功耗、将 BLE 设备功耗优化至 < 25 微安,以及为手机设计定制化温湿度显示界面。
  3. 第 3 部分《RedBear Nano V2 替代方案:介绍如何使用其他基于 nRF52 的模块替代 Nano V2,包括供电元器件选型、硬件搭建、移除 nRF52 芯片编程保护、将 NFC 引脚用作普通 GPIO,以及在 Arduino 中定义新的 nRF52 开发板。


本教程旨在帮助新手制作超低功耗 BLE 设备 —— 无论设备处于 “等待连接” 状态还是 “已连接并收发数据” 状态,持续功耗均可 < 100 微安。所需条件仅为:熟悉 Arduino IDE 操作、具备基础焊接能力,以及拥有一台万用表,无需编写任何 Android 代码。


此外,另有《超低功耗 BLE 第 2 部分 —— 温湿度监测器》教程,展示超低功耗编程的实际应用场景,并介绍供电电流优化方法。最终完成的温湿度监测器在 “已连接并向手机更新数据” 状态下功耗约 25 微安,仅用一枚纽扣电池即可运行数年。


本详细教程使用 Nordic Semiconductor(北欧半导体)的 nRF52832 芯片,演示如何通过 Arduino IDE 为其编写代码,以及如何通过 Android 手机连接 BLE 设备、设计定制化菜单与图形化显示界面。


教程提供基于 Nordic SDK(软件开发工具包)、BLE 支持库Sandeepmistry 的 nRF5 IDE 插件与 BLEPeripheral 库修改的定制化库,这些库已优化低功耗性能并简化使用流程。在 Android 端,教程使用多款免费的 Nordic Android 应用进行测试与基础控制;若需定制 Android 显示界面,无需编写 Android 代码 —— 免费的 pfodDesigner Android 应用可生成低功耗 Arduino 代码,在 pfodApp 中实现自定义菜单、图表、数据记录等功能,也可在 Arduino 代码中为 pfodApp 搭建定制化交互式图形控件,所有 Android 端操作均由 pfodApp 自动处理。


本教程的最新版本也可在线查看:Arduino 中的超低功耗 BLE 制作教程



1

快速入门

  1. 连接编程器(详见步骤 2)
  2. 安装低功耗支持库(详见步骤 3、4)
  3. 使用免费的 pfodDesigner 创建定制化控制菜单 / 数据记录器,并生成低功耗程序草图(sketch),通过 pfodApp 连接设备、显示控件与图表并记录数据(详见步骤 13)


开发板与编程器

虽然Sandeepmistry的nRF5 Arduino扩展最初支持多种nRF51/52开发板,但本项目仅支持nRF52832芯片。为实现最低功耗,建议使用仅包含nRF52832芯片的开发板(额外器件如加速度计会增加功耗)。

测试设备采用体积小巧的RedBear Nano V2(适合实际设备应用)。pfod_lp_nrf52.zip还支持精简型模块,例如SkyLab蓝牙模块SKB369GT832E_01(均可通过https://www.aliexpress.com 购买)。

尽管Nano V2开发板自带低功耗稳压器,但需使用外部稳压器以兼容裸片编程,并确保从极微弱电流源启动。


======================指导性大纲======================


编程工具

使用Particle Debugger对nRF52832芯片编程。该调试器支持深入Nordic SDK代码的底层调试(但本项目仅使用Arduino串口打印调试)。替代方案可使用BlackMagic Probe相关构建与编程说明详见此处)。


教程结构

搭建编程/测试板 — 步骤2

安装Arduino的nRF52832低功耗支持 — 步骤3

低功耗编程技巧

延迟是耗电元凶:使用定时器替代

供电电流测量:Blink_millisDelay.ino

低功耗定时器:Blink_lp_timer.ino

额外元件增加功耗

低功耗调试

低功耗BLE串口:lp_BLE_temp.ino

通过lp_BLESerial传输数据

lp_comparator比较器:lp_BLE_comparator.ino

lp_pinChange引脚变化检测

高驱动输出模式

nrf52芯片信息

低功耗按键消抖:lp_BLE_debounce.ino

自定义低功耗控制与数据记录:lp_BLE_NanoV2_example.ino

注:

  1. 专有工具名(如pfodDesigner、RedBear Nano V2)和文件名(如*.ino)保留英文,便于用户检索
  2. 开发板型号和编程器名称采用行业通用译法
  3. 关键技术概念(如BLE串口、比较器)使用嵌入式领域标准术语



2

制作编程 / 测试板

本项目使用Particle 调试器对 nRF52832 芯片进行编程与调试(通过 Arduino 的 Serial 打印语句实现)。该调试器还支持 GDB 单步源码级调试,但本项目开发低功耗库时未使用此功能 —— 您只需通过常规的 Arduino 打印语句即可完成程序草图的调试。


以下是编程 / 测试板的原理图(PDF 版本)。

零件清单


零件名称

规格 / 型号

用途说明

Particle 调试器

——

用于 nRF52832 芯片的编程与串口调试

USB 延长线

1.5 英尺(约 0.46 米)

连接 Particle 调试器

SWD(2×5 1.27mm)排线转接板

——

适配 Particle 调试器的排线

SparkFun USB Mini-B 转接板

或 Adafruit Mini-B 版本

也可使用 Micro-B 转接板 + 配套数据线替代

USB 数据线

A/Mini-B 接口,3 英尺(约 0.91 米)

适配 SparkFun Mini-B 转接板

USB 电源

——

通过转接板和 MAX8881EUT33 稳压器为 nRF52832 供电

3.3V 稳压器

MAX8881EUT33+T(Digikey 型号:MAX8881EUT33+TCT-ND)

为 nRF52832 提供稳定 3.3V 电压

SparkFun SOT23 转 DIP 适配器

——

用于焊接 MAX8881EUT33(SOT23 封装),方便在洞洞板上使用

RedBear Nano V2 模块

基于 nRF52832

测试用 nRF52832 开发模块

陶瓷电容

2 个 10 微法 / 25V(Digikey 型号:445-7705-1-ND)

焊接在洞洞板铜箔面的线路之间,用于滤波

陶瓷电容

1 个 0.1 微法 / 50V(Digikey 型号:478-10836-1-ND)

焊接在洞洞板铜箔面的线路之间,用于滤波

陶瓷电容

1 个 0.1 微法(Digikey 型号:478-2472-ND)

电源滤波

电阻

1 个 330 欧 / 1/4W/1%(Digikey 型号:S330CACT-ND)

电流采样电阻

电阻

1 个 1.5K 欧 / 1/4W/1%(Digikey 型号:RNF14FTD1K50CT-ND)

电流采样电阻

电阻

4 个 1K 欧 / 1/4W/1%(Digikey 型号:RNF14FTD1K00CT-ND)

保护电阻

低 ESR 电容

1 个 470 微法 / 25V(Digikey 型号:399-6127-ND)

滤波 nRF52832 发射时的电流脉冲,便于万用表测量平均供电电流

排母

2 个 6Pin+2 个 5Pin(SparkFun 型号:PRT-11269)

将 8Pin 排母裁剪后使用,适配 Particle 调试器编程转接板

排针

6 个 6Pin(SparkFun 型号:PRT-00116)

用于模块与洞洞板的连接

杜邦线(母对母)

Adafruit 型号:1950

临时连接电路

尼龙螺丝

3mm×12mm(Jaycar 型号:HP0140)

固定洞洞板与外壳

尼龙带螺纹间隔柱

3mm×12mm(Jaycar 型号:HP0924)

支撑洞洞板

洞洞板(铜箔条型)

Jaycar 型号:HP9540

搭建编程 / 测试板的基底

塑料片

从塑料盖子裁剪而来

隔离洞洞板底部,防止短路


制作说明

编程 / 测试板搭建在洞洞板上,MAX8881 稳压器从 5V USB 电源获取电压并输出 3.3V。虽然 Nano V2 自带板载稳压器,但若需为 SkyLab 等无板载稳压器的 “裸芯片模块” 编程,则需搭配 MAX8881 或类似稳压器。MAX8881 的典型供电电流为 3.5 微安,与 Nano V2 的板载稳压器相近。


当超低功耗 BLE 项目由极低电流源供电时,可利用 MAX8881 的 Power OK(POK,电源正常)引脚和 Shutdown(SHDN,关断)引脚,确保 470 微法供电电容充电至足够电量后,再启动 nRF52 芯片(避免芯片因启动电流不足无法正常工作)。


电路中,470 微法低 ESR(等效串联电阻)电容用于滤波 nRF52832 发射数据时的电流脉冲,便于万用表准确测量平均供电电流。供电电流通过 GND 线路中的两个分流电阻测量:


  1. 若测量大电流,短接 1-3 号端子以移除分流电阻;
  2. 若测量中等电流,短接 2-3 号端子以移除 1.5KΩ 电阻;
  3. 若测量本教程目标的超低电流,保持 1、2、3 号端子开路。


将万用表或示波器连接至 “电流监测测试点”:若使用示波器,需将 GND 夹线连接至分流电阻的 USB GND 侧。


本电路中,Nano V2 模块直接插拔,便于编程与供电电流测量,后续可移植至最终电路。通常,为 nRF52 芯片编程需满足:连接 SWCLK、SWDIO、GND 引脚,并在编程时为 nRF52 提供 3.3V(Vdd)电压。


与需通过 Vref 引脚检测目标设备供电电压的 BlackMagic 调试器不同,Particle 调试器的供电电压固定为 3.3V,且无隔离缓冲器,因此编程时目标设备(nRF52)的供电电压必须为 3.3V。


为防止 “目标设备与调试器供电电压不一致”(如一方通电、另一方未通电)导致设备损坏,在 SWCLK、SWDIO、TX、RD 引脚串联 1KΩ 保护电阻,限制 IO 保护二极管的最大导通电流。


3

安装 nRF52832 低功耗支持库

本项目基于 Sandeepmistry 的《适用于 Nordic Semiconductor nRF5 系列开发板的 Arduino 核心库》及其 BLEPeripheral 库开发,但已做修改:仅支持 Nordic nRF52 系列芯片,并新增低功耗功能。项目已通过 RedBear Nano V2(nRF52832 开发板)测试,修改后的库提供多种低功耗工具,如sleep(休眠)、lp_timer(低功耗定时器)、lp_comparator(低功耗比较器),还提供通用低功耗 Nordic UART BLE 服务lp_BLESerial—— 该服务可与 Nordic 免费应用及 pfodApp 兼容。


免费的 pfodDesigner 应用可生成低功耗 Arduino 程序草图,在 Android 手机的 pfodApp 中实现定制化菜单或图形化界面,无需编写 Android 代码。关于创建菜单、子菜单、图表与图形化界面的详细方法,可参考 pfodDesigner 教程


若不使用 pfodApp,也可通过 pfodDesigner 设计菜单,再将菜单指令编入 Nordic nRF Toolbox 应用的 UART 控制功能中。本项目也使用 Nordic nRF UART v2.0 应用进行测试。


安装步骤

  1. 下载并安装 Arduino IDE
  2. 本文使用 Windows 7 系统下的 Arduino 1.8.7 版本。
  3. 安装 Sandeepmistry 的 nRF5 Arduino 核心库
  4. 打开 Arduino IDE,进入 “文件(File)→首选项(Preferences)”;
  5. 在 “额外开发板管理器 URL(Additional Board Manager URL)” 中添加链接:https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_index.json
  6. 从 “工具(Tools)→开发板(Board)” 菜单打开 “开发板管理器(Boards Manager)”,搜索并安装 “Nordic Semiconductor nRF5 Boards”(本文使用 0.6.0 版本,其他版本的功能与漏洞可能不同);
  7. 注意:安装过程中,Arduino IDE 需耗时几分钟解压已下载的工具,请耐心等待。
  8. 添加 nRF5 Flash 协议栈(SoftDevice)工具
  9. (说明摘抄自 Sandeepmistry 官网
  10. 进入 Arduino 草图文件夹(路径如下):
  11. macOS 系统:~/Documents/Arduino
  12. Linux 系统:~/Arduino
  13. Windows 系统:~/Documents/Arduino
  14. 创建目录:tools/nRF5FlashSoftDevice/tool/
  15. 下载 nRF5FlashSoftDevice.jar 文件至上述目录(本地备份文件链接);
  16. 重启 Arduino IDE。
  17. 安装 Particle 调试器驱动
  18. 本项目使用的 Particle 调试器在 Windows 7/8/9 系统中需安装 mbed 串口驱动(驱动安装说明参考 Particle 官网),macOS、Linux 与 Windows 10 系统可自动识别。
  19. 驱动安装完成后,插入 Particle 调试器,Windows 7 系统会显示驱动正在安装。如上文截图所示,新增的 COM 端口(如 COM115)即为 Arduino 中用于 “编程” 和 “串口监视器” 的端口。
  20. 安装 pfod_lp_nrf52 硬件支持库
  21. 下载 pfod_lp_nrf52.zip 压缩包(下载链接);
  22. 打开 Arduino IDE,进入 “文件(File)→首选项(Preferences)”,在窗口底部找到preferences.txt文件所在的目录(Windows 7 系统可点击路径直接在资源管理器中打开该目录);
  23. 打开packages子目录,进入sandeepmistry目录(内含hardwaretools子目录);
  24. 删除原有的hardware目录;
  25. pfod_lp_nrf52.zip 解压至sandeepmistry目录,完成低功耗支持库的安装(解压后会生成新的hardware目录);
  26. 关闭并重启 Arduino IDE。


4

将 Particle 调试器连接至 nRF52832 芯片

连接说明

为 nRF52832 芯片编程需满足:


  1. 为芯片提供 3.3V 供电;
  2. 连接 Particle 调试器的 GND、SWCLK、SWDIO 引脚;
  3. 若需通过 Arduino 打印语句调试,还需将调试器的 TX、RX 引脚连接至芯片的 UART 引脚。


前文搭建的小型开发板可提供 3.3V 供电、电流测量分流电阻与串口调试功能,并可快速断开与 Particle 调试器的连接。该调试器还支持通过开发板进行源码级调试,但本项目未使用此功能。

烧录 Nordic 协议栈(SoftDevice)

在运行程序草图前,需先向 nRF52832 芯片烧录 “协议栈”(SoftDevice)。本项目使用 s132 协议栈(s132_nrf52_2.0.1_softdevice.hex,下载链接),pfod_lp_nrf52.zip 压缩包中已包含该协议栈,无需从 Nordic 官网单独下载,但仍需烧录至芯片。


烧录步骤:


  1. 连接 NanoV2 模块与 Particle 调试器的编程线、串口杜邦线,插入 USB 电源为 NanoV2 供电;
  2. 确保 “电流分流短接片” 处于闭合状态(避免电流采样电阻限制编程时的供电电压);
  3. 打开 Arduino IDE,确认 “编程器(Programmer)” 选择为 “CMSIS-DAP”,“端口(Port)” 选择为 mbed 串口(如 COM115);
  4. 在 “工具(Tools)” 菜单中选择 “nRF5 Flash SoftDevice”(不要选择底部的 “Burn Bootloader” 选项),烧录的协议栈为 “Softdevice” 选项中显示的版本(pfod_lp_nrf52.zip 已预设所有 nRF52832 开发板的协议栈为 S132)。

注意事项

  1. Arduino 有时会丢失 COM 端口识别,若上传程序草图失败,可关闭 Arduino IDE、拔下 Particle 调试器的 USB 线,重启 IDE 后重新插回 USB 线;
  2. 若 USB 连接识别失败,可重启电脑;
  3. 若协议栈烧录失败,可能是 nRF52 模块开启了编程保护,解决方案参考《移除 nRF52 编程保护标志并烧录程序草图》。


5

低功耗编程要点

实现超低功耗的核心技巧是:大部分时间让芯片处于 “闲置状态”,同时最小化输入引脚上外部上拉 / 下拉电阻的电流消耗,且不使用任何多余元器件。


在常规 Arduino 编程中,所有执行代码通常放在loop()函数中,该函数会被 Arduino 反复调用 —— 这意味着芯片大部分时间都在 “空转”,既浪费处理器资源,又消耗电能。


以 Arduino 的 Blink 示例(“文件→示例→01.Basic→Blink”)为例:

(注:Instructables 平台的代码显示可能丢失头文件等内容,建议下载代码文件查看完整版本)

int led = 13;

// setup函数在按下复位键时运行一次
void setup() {
// 将数字引脚初始化为输出模式
pinMode(led, OUTPUT);
}

// loop函数会无限循环执行
void loop() {
digitalWrite(led, HIGH); // 点亮LED(HIGH表示高电平)
delay(1000); // 等待1秒
digitalWrite(led, LOW); // 熄灭LED(LOW表示低电平)
delay(1000); // 等待1秒
}

Arduino 会不断执行上述loop()代码:点亮 LED→等待 1 秒→熄灭 LED→等待 1 秒,循环往复。


避免使用 delay () 函数,改用定时器

深入delay()函数的内部实现可发现,其本质是通过 “空循环” 等待时间,期间会持续消耗电能,且无法响应外部触发 / 输入:

void delay( uint32_t ms ) {
if ( ms == 0 ) {
return ;
}
uint32_t start = millis() ;
do {
} while ( millis() - start < ms ) ; // 空循环等待,直至时间达到ms
}

对于常规 Arduino 编程,应使用定时器库(如millisDelay)替代delay(),详细用法可参考《Arduino 中的定时器与延迟编程方法》。


以下是使用millisDelay改写的 Blink 程序(Blink_millisDelay.ino):

#include <millisDelay.h>

// 大多数Arduino开发板(包括Nano V2)的13号引脚均连接LED
int led = 13;
bool ledOn = false;
millisDelay ledDelay;
const unsigned long DELAY_TIME = 1000; // 延迟时间:1000毫秒(1秒)

// setup函数在按下复位键时运行一次
void setup() {
// 将数字引脚初始化为输出模式
pinMode(led, OUTPUT);
ledDelay.start(DELAY_TIME); // 启动定时器
}

// loop函数会无限循环执行
void loop() {
// 此处可添加其他执行代码
if (ledDelay.justFinished()) { // 若定时器达到延迟时间
ledDelay.repeat(); // 重复启动定时器
ledOn = !ledOn; // 切换LED状态(亮→灭/灭→亮)
if (ledOn) {
digitalWrite(led, HIGH); // 点亮LED
} else {
digitalWrite(led, LOW); // 熄灭LED
}
}
}

Blink_millisDelay.ino 不会阻塞loop()函数的执行,仅在每次循环时检查定时器是否超时 —— 这意味着loop()可同时处理其他任务。


上传程序草图至 Nano V2

通过 Particle 调试器将 Blink_millisDelay.ino 上传至 Nano V2 模块。若 Arduino 丢失与编程 COM 端口的连接,可尝试拔下 Particle 调试器的 USB 线后重新插回;若问题仍存在,可关闭并重启 Arduino IDE。


6

测量供电电流

烧录 Blink_millisDelay.ino 后,按以下步骤测量供电电流:


  1. 保持 “电流分流短接片” 闭合,将程序草图上传至 Nano V2;
  2. 拔下为 Nano V2 供电的 USB 线(上文截图中的黑色线),复位 nRF52 芯片(确保测量的供电电流准确);
  3. 拔下 Particle 调试器的编程排针与串口杜邦线;
  4. 调整 “电流分流短接片”:短接 1.5KΩ 电阻,仅保留 330Ω 电阻在 GND 线路中(若测量极低电流,可完全移除短接片);
  5. 重新连接 USB 电源时,先临时短接 330Ω 电阻,待电源稳定后移除临时短接,测量 330Ω 电阻两端的电压降。

测量结果与分析

对于 Blink_millisDelay.ino 程序,供电电流约为 6 毫安(Nano V2 上的 LED 仅消耗少量电流):


  1. 330Ω 电流分流电阻两端的电压降约为 2 伏;
  2. 根据欧姆定律,供电电流 = 电压 / 电阻 = 2 伏 / 330 欧≈0.006 安(即 6 毫安)。


分流电阻两端 2 伏的电压降意味着 Nano V2 的实际供电电压仅约 3 伏(USB 电源为 5V,经稳压器输出 3.3V,再经分流电阻压降后为 3V)。若供电电流过高(如 8 毫安),则芯片可能因电压不足无法正常工作 —— 这也是 330Ω 分流电阻测量电流的上限。

注意事项

  1. 若万用表显示分流电阻两端电压为 2.6 伏,说明 nRF52 芯片未正常启动,原因是供电电流不足;
  2. nRF51 意外进入调试模式的问题:nRF52 可能因 SWCLK 线路噪声意外进入调试模式,导致供电电流从 100 微安升至数毫安。请参阅 NRF51 意外进入调试模式的问题
  3. 解决方案:在 SWCLK 引脚与 GND 之间并联一个小阻值电阻(如 470Ω)和小容量电容(如 1nF),且尽量靠近芯片;同时,编程完成后断开 SWCLK 引脚的长导线。
  4. 极端情况下,可将 nRF51822 的闲置 GPIO 直接连接至 SWCLK 引脚,上电后将该 GPIO 设为低电平输出(但此方法会导致芯片无法重新编程,需预留解除引脚连接的方式,或切断 GPIO 与 SWCLK 的板载线路)。
  5. 测试发现:SWCLK 引脚并联 1nF 电容后,芯片无法编程,但仍可正常运行;即使移除电容,Particle 调试器或 RedBear DAP V1.5 调试器也无法编程,需重新烧录协议栈才能恢复编程功能。因此,建议编程完成后再添加滤波电容 / 电阻。

nRF52 低功耗优化补充

在 nRF52 相关论坛中,常见两种低功耗优化建议,但本项目的程序草图未采用:


  1. 启用 nRF52 的 DC-DC 转换器:需额外元器件支持,Nano V2 虽具备该硬件,但 SkyLab 等 “裸芯片模块” 无此设计,因此未采用;
  2. 禁用 Serial UART:本项目库已优化 —— 只要程序草图不调用Serial.begin(),UART 的功耗(约 100 纳安)可忽略不计。


此外,通过限流电源测试发现,上述两种优化会增加芯片的启动电流,详细分析可参考《超低功耗 BLE 第 2 部分 —— 供电电源》(待更新)。


7

低功耗定时器(lp_timer)

如前文所述,实现超低功耗的核心是 “大部分时间让芯片休眠”。在 Blink_millisDelay.ino 中,loop()函数反复循环检查定时器状态,仅每秒执行一次 “点亮 / 熄灭 LED” 的有效操作 —— 其余时间芯片均在空转,浪费电能。


因此,需让微处理器在 “无任务时休眠”,直至有任务需执行(如定时器超时)。以下是使用lp_timer(低功耗定时器)实现的低功耗 Blink 程序(Blink_lp_timer.ino):

#include <lp_timer.h>

// 大多数Arduino开发板(包括Nano V2)的13号引脚均连接LED
int led = 13;
bool ledOn = false;
lp_timer ledTimer;
const unsigned long DELAY_TIME = 1000; // 延迟时间:1000毫秒(1秒)

// setup函数在按下复位键时运行一次
void setup() {
// 将数字引脚初始化为输出模式
pinMode(led, OUTPUT);
// 启动定时器:延迟时间DELAY_TIME,超时后调用handleLedTimer函数
ledTimer.startTimer(DELAY_TIME, handleLedTimer);
}

// loop函数会无限循环执行
void loop() {
sleep(); // 休眠,等待定时器触发唤醒
}

// 定时器超时处理函数
void handleLedTimer() {
ledOn = !ledOn; // 切换LED状态
if (ledOn) {
digitalWrite(led, HIGH); // 点亮LED
} else {
digitalWrite(led, LOW); // 熄灭LED
}
}


工作原理

  1. 每间隔DELAY_TIME(1 秒),ledTimer定时器触发,从sleep()函数中唤醒loop()
  2. sleep()函数唤醒后,先调用handleLedTimer处理函数,再执行loop()中剩余的代码(本文中无剩余代码);
  3. 下次loop()调用时,芯片再次进入休眠,等待下一次定时器触发。


需重点注意:handleLedTimer不是中断服务函数,而是从loop()函数的sleep()中调用的常规草图函数 —— 这意味着它可直接访问草图中的所有变量与方法,无需使用volatile变量或多任务锁。本低功耗库中的所有处理函数均遵循此设计。


供电电流测量结果

使用 1.5KΩ+330Ω=1830Ω 的分流电阻(完全移除短接片)测量:


  1. 万用表读数在 220 毫伏至 480 毫伏之间波动(因 LED 亮灭导致 470 微法供电电容充放电,示波器显示为三角波);
  2. 平均电压降约 375 毫伏,平均供电电流 = 0.375 伏 / 1830 欧≈0.2 毫安。


若将DELAY_TIME改为 5000 毫秒(5 秒),可分别测量 LED 亮 / 灭时的电流:


  1. LED 亮时:电压降 610 毫伏,电流 = 0.61 伏 / 1830 欧≈0.31 毫安;
  2. LED 灭时:电压降 44 毫伏,电流 = 0.044 伏 / 1830 欧≈0.037 毫安(37 微安)。


可见,使用sleep()lp_timer后,供电电流从约 6 毫安降至 0.2 毫安,且 0.2 毫安的电流主要来自 LED——LED 熄灭时,电流仅 37 微安,较原方案降低 150 倍,电池续航也随之延长 150 倍。


lp_timer 的其他特性

  1. lp_timer类支持两种定时器模式:startDelay()(单次超时)、startTimer()(重复超时);
  2. lp_timer使用 nRF52 的低频率 / 低功耗时钟(RTC),定时器精度取决于低频时钟的精度:部分开发板使用片内 32.768kHz RC 振荡器(25℃时精度约 1 秒 / 小时),RedBear Nano V2 等开发板使用 32.768Hz 晶体(精度更高);
  3. 本库中,nRF52 的 RTC 计数器已配置为毫秒级计时,最大超时时间约 68 分钟(超过 4095000 毫秒(68 分 15 秒)的超时会被限制为 4095000 毫秒);
  4. 若需更长时间的定时器(如小时级),可通过 “小时级定时器计数小时数 + 分 / 秒 / 毫秒级定时器收尾” 的方式实现,示例程序 long_lp_timer.ino 支持最长 24.5 万年的定时器。


低功耗设计原则:避免多余元器件

上述程序也验证了另一个低功耗设计原则:多余元器件(LED、传感器、加速度计等)会增加功耗。当芯片本身仅消耗 40 微安时,即使 “低功耗” LED 或传感器,其功耗也会显著影响整体电流 —— 因此,制作超低功耗 BLE 项目时,应优先选择 “裸芯片模块”,而非功能冗余的开发板。


Nano V2 的多余元器件极少(忽略 D13 引脚的 LED),其板载 3.3V 稳压器在 “通过 Vin 引脚供电” 时功耗约 4 微安;本编程 / 测试板使用的 MAX8881 稳压器功耗与之相近,且其功耗已包含在测量结果中。


8

低功耗调试方法

Particle 调试器提供 GDB 调试服务器,但本库开发未使用此功能。低功耗程序草图通常仅在调试阶段使用 Serial 功能(常规 Serial 连接会消耗较多电能)。

Particle 调试器的串口调试

  1. setup()函数开头添加Serial.begin(115200);(初始化串口通信,波特率 115200);
  2. 编程完成后,打开 Arduino 串口监视器,选择与编程相同的 COM 端口(如 COM115);
  3. 保持 Nano V2 与 Particle 调试器的串口杜邦线连接(也可保留编程排针连接)。

替代方案:BlackMagic 调试器的串口调试

若使用 BlackMagic 调试器(而非 Particle 调试器),调试步骤如下:


  1. setup()函数开头添加Serial.begin(115200);
  2. 启动另一个 Arduino IDE 实例,将其 COM 端口设置为 BlackMagic 调试器的第二个端口(编号较高,如 COM114),打开串口监视器;
  3. 保持 Nano V2 与 BlackMagic 调试器的串口杜邦线连接(也可保留编程排针连接);
  4. 仍通过第一个 IDE 实例(COM113 等编程端口)编写与上传代码,在第二个 IDE 的串口监视器中查看调试输出。

Blink_lp_timer_debug.ino 的调试输出示例

首次loop()在 261 毫秒时唤醒,原因是ledTimer定时器启动;需注意:loop()可能被 “非用户显式编码的触发事件” 唤醒。随后,handleLedTimer在 1259 毫秒时从sleep()中调用,唤醒loop(),以此类推。

其他实用调试函数

  1. cprint () 与 cprintNum ():用于从 C/C++ 文件向 Serial 输出调试信息
  2. 在需调试的 C/C++ 文件开头添加以下代码:
#ifdef __cplusplus
extern "C"{
#endif // __cplusplus

void cprint(const char* str);
void cprintNum(const char* str, const uint32_t num);

#ifdef __cplusplus
} // extern "C"
#endif


  1. 在主程序草图(.ino 文件)中定义函数实现:
extern "C" void cprint(const char* str) {
Serial.println(str);
}

extern "C" void cprintNum(const char* str, uint32_t num) {
Serial.print(str); Serial.print(' '); Serial.println(num);
}
  1. 注意:调试字符串需简洁,且不要在CRITICAL_REGION_ENTER(); CRITICAL_REGION_EXIT();代码块中调用这些函数。


  1. app_sched_queue_utilization_get () 与 app_sched_queue_utilization_clear ()
  2. 定时器处理函数等在草图上下文(而非中断上下文)中执行,触发时会被加入队列,待sleep()唤醒loop()后执行。队列长度固定(默认 8,定义在 lp_timer_init.h 中),若触发频率超过草图处理能力,队列会溢出并丢失部分触发事件。
  3. 启用队列监测:在utility/app_scheduler.h开头取消#define SCHEDULER_PROFILER的注释;
  4. 调用app_sched_queue_utilization_get()查看队列最大使用率;
  5. 调用app_sched_queue_utilization_clear()重置最大使用率计数,重新开始监测。
  6. 请参阅下文 “低功耗按键消抖” 部分将演示该函数的使用。


9

低功耗 BLE UART(lp_BLESerial)

蓝牙低功耗(BLE)标准定义了多种服务,但未包含 “经典蓝牙” 的串口剖面(SPP)替代服务 —— 因此,各厂商需自定义 BLE UART 服务(如 RFduino、RedBearLab、BLUNO、HM-10 及 Nordic 均有各自的 UART 服务)。pfodApp 支持连接所有这些服务,但其他应用对 BLE UART 的支持有限。


本库使用Nordic UART 服务(应用最广泛的 BLE UART 服务之一),Nordic 提供多款支持该服务的免费应用,如 Nordic nRF Toolbox Nordic nRF UART v2.0 (注:MicroBit 最初实现的 Nordic 服务 / 特征值将 TX 与 RX 引脚颠倒,pfodApp 也支持该版本)。


以下是通过 BLE 控制 LED 亮灭的程序(Blink_lp_BLE.ino):

#include <lp_timer.h>
#include <lp_BLESerial.h>

// 大多数Arduino开发板(包括Nano V2)的13号引脚均连接LED
int led = 13;
bool ledOn = false;
lp_timer ledTimer;
const unsigned long DELAY_TIME = 1000; // 延迟时间:1000毫秒(1秒)
lp_BLESerial ble;

// setup函数在按下复位键时运行一次
void setup() {
// 将数字引脚初始化为输出模式
pinMode(led, OUTPUT);
ble.setName("Led Control"); // 设置BLE广播名称(默认名称为“Nordic BLE UART”)
ble.begin(); // 开始广播,准备接受连接
// 启动定时器:延迟时间DELAY_TIME,超时后调用handleLedTimer函数
ledTimer.startTimer(DELAY_TIME, handleLedTimer);
}

// loop函数会无限循环执行
void loop() {
sleep(); // 休眠,等待定时器触发唤醒
// 检查是否有新的BLE指令('a'启动闪烁,'b'停止闪烁)
while (ble.available() ) {
int i = ble.read();
if ('a' == i) {
ledTimer.startTimer(DELAY_TIME, handleLedTimer); // 启动LED闪烁
} else if ('b' == i) {
ledTimer.stop(); // 停止LED闪烁
}
}
}

// 定时器超时处理函数
void handleLedTimer() {
ledOn = !ledOn; // 切换LED状态
if (ledOn) {
digitalWrite(led, HIGH); // 点亮LED
} else {
digitalWrite(led, LOW); // 熄灭LED
}
}


工作原理

  1. sleep()函数被多种事件唤醒(定时器超时、BLE 连接 / 断开、接收数据等);
  2. loop()唤醒后,检查是否有 BLE 数据接收,根据指令('a'/'b')启动 / 停止 LED 闪烁;
  3. 使用 Nordic nRF UART v2.0 应用测试:连接设备后发送 'a' 启动闪烁,发送 'b' 停止闪烁。

BLE 供电电流优化

BLE 连接的功耗由以下参数决定,可通过lp_BLESerial的接口调整:


  1. TX 功率:默认 + 4dBm(最大),调用ble.setTxPower(-8);可降低功率(如 - 8dBm);
  2. 广播间隔:默认 500 毫秒,调用ble.setAdvertisingInterval(1000);可延长间隔(如 1000 毫秒);
  3. 连接间隔:默认最小 100 毫秒、最大 150 毫秒,调用ble.setConnectionInterval(200,250);可延长间隔(如最小 200 毫秒、最大 250 毫秒)。


参数调整后,供电电流会相应降低。实测结果:


  1. LED 熄灭时,BLE 广播状态下电流约 100 微安,BLE 连接状态下电流约 90 微安(万用表测量 1830Ω 分流电阻两端电压:广播时 140 毫伏,连接时 130 毫伏;示波器测量:广播时 180 毫伏,连接时 160 毫伏)。

lp_BLESerial 的其他特性

  1. 支持设置 “连接处理函数” 与 “断开连接处理函数”;
  2. 支持配置发送缓冲区大小(默认 1024 字节)。


10

通过 lp_BLESerial 发送数据

lp_BLESerial除接收指令外,还支持发送数据,但需注意:


  1. 每次最多发送 20 字节(BLE 特征值的默认最大长度);
  2. 仅当客户端(Android 应用)请求数据时才发送;
  3. 若发送数据过快或过量,可能导致数据丢失(lp_BLESerial的发送缓冲区会缓存数据,按最大连接间隔(默认 150 毫秒)每次发送 20 字节)。

示例:发送芯片温度数据(lp_BLE_temp.ino

nRF52 芯片内置温度传感器,可通过getChipTemperature()(获取温度值,单位℃)和getRawChipTemperature()(获取原始温度数据)访问。该传感器的分辨率为 0.25℃,精度一般,但可通过校准并在程序中应用校准系数,用作室温监测器(也可存储历史温度,按需发送)。


以下程序在 BLE 连接状态下,每秒发送一次芯片温度(未做校准与历史数据存储),同时演示 “连接 / 断开处理函数” 的使用(实际无需这些函数,因ble.print()会自动丢弃 “未连接时” 的发送数据;也可调用ble.isConnected()判断当前是否连接):

#include <lp_timer.h>
#include <lp_BLESerial.h>

lp_timer tempTimer;
const unsigned long DELAY_TIME = 1000; // 延迟时间:1000毫秒(1秒)
lp_BLESerial ble;

// setup函数在按下复位键时运行一次
void setup() {
ble.setName("Chip Temperature"); // 设置BLE广播名称(默认名称为“Nordic BLE UART”)
// 设置连接/断开处理函数
ble.setConnectedHandler(handleConnection); // 连接建立时调用
ble.setDisconnectedHandler(handleDisconnection); // 连接断开或超出范围时调用
ble.begin(); // 开始广播,准备接受连接
}

// loop函数会无限循环执行
void loop() {
sleep(); // 休眠,等待触发唤醒
// 清空BLE接收缓冲区(忽略接收数据)
while (ble.available()) {
int i = ble.read();
// 此处可添加“发送历史温度数据”的指令处理逻辑
}
}

// 温度定时器超时处理函数:发送当前时间与温度
void handleTempTimer() {
float temp = getChipTemperature();
ble.print(millis()); // 发送当前时间(毫秒)
ble.print(','); // 分隔符
ble.print(temp); // 发送温度值
ble.println(); // 换行
}

// BLE连接处理函数
void handleConnection(BLECentral& central) {
// 也可在setup中启动定时器并保持运行
tempTimer.startTimer(DELAY_TIME, handleTempTimer);
}

// BLE断开连接处理函数
void handleDisconnection(BLECentral& central) {
// 实际无需停止定时器,因ble.print()会丢弃未连接时的发送数据
tempTimer.stop();
}


11

低功耗比较器(lp_comparator)

除常规 Arduino 功能、lp_BLESerialgetChipTemperature()外,本低功耗库还提供 “低功耗引脚电压比较器”—— 当输入引脚的电压水平变化时,触发芯片唤醒,适用于超低功耗场景。

示例:通过 BLE 发送引脚电平变化(lp_BLE_comparator.ino

以下程序搭建 Nordic BLE UART 服务,将 2 号引脚配置为下拉输入,监测该引脚电压与 “1/2 Vdd(即 8/16 × Vdd)” 的比较结果,电平变化时唤醒芯片并发送数据:

#include <lp_BLESerial.h>
#include <lp_comparator.h>

// 大多数Arduino开发板(包括Nano V2)的13号引脚均连接LED
int led = 13;
int comparatorPin = 2; // 比较器引脚:D2/A2
lp_BLESerial ble;

// setup函数在按下复位键时运行一次
void setup() {
// 将比较器引脚配置为下拉输入(防止引脚悬空导致误触发)
// 注意:片内上拉/下拉电阻的阻值约13KΩ,若下拉输入引脚接Vdd,会额外消耗254微安电流;
// 若需超低功耗,建议配置为INPUT模式,并外接大阻值上拉/下拉电阻(如100KΩ,功耗约33微安)
pinMode(comparatorPin, INPUT_PULLDOWN);
// 将LED引脚配置为输出模式
pinMode(led, OUTPUT);
ble.setName("Pin Change"); // 设置BLE广播名称(默认名称为“Nordic BLE UART”)
ble.begin(); // 开始广播,准备接受连接
// 启动低功耗比较器:监测comparatorPin引脚,参考电压为8/16 Vdd,电平变化时调用handlePinLevelChange
// 注意:比较器首次触发始终为LOW,若引脚实际为HIGH,随后会触发HIGH
lp_comparator_start(comparatorPin, REF_8_16Vdd, handlePinLevelChange);
}

// loop函数会无限循环执行
void loop() {
sleep(); // 休眠,等待触发唤醒
// 清空BLE接收缓冲区(忽略接收数据)
while (ble.available()) {
int i = ble.read();
}
}

// 引脚电平变化处理函数:pinState为检测到的电平(高于参考电压为HIGH,低于为LOW)
void handlePinLevelChange(int pinState) {
if (ble.isConnected()) {
ble.print(millis()); // 发送当前时间(毫秒)
ble.print(','); // 分隔符
ble.print((pinState == HIGH) ? 'H' : 'L'); // 发送电平状态(H/L)
ble.println(); // 换行
}
digitalWrite(led, pinState); // 电平为HIGH时点亮LED,LOW时熄灭
}


功耗分析与优化

  1. 当比较器引脚悬空时,片内下拉电阻使引脚保持低电平,LED 熄灭 —— 此时无论 BLE 处于广播还是连接状态,功耗均 < 100 微安;
  2. 当引脚接 Vdd(电压 > 1/2 Vdd)时,下拉电阻会产生电流(约 250 微安),LED 点亮;
  3. 优化建议:将引脚配置为INPUT模式,外接大阻值上拉 / 下拉电阻(如 100KΩ,功耗仅 33 微安),避免片内电阻的额外功耗。

测试与注意事项

使用《Nordic nRF UART》应用测试:连接设备后,用杜邦线将 D2 引脚接 Vdd,会看到大量数据滚动输出 —— 原因是杜邦线连接时接触不稳定,导致频繁触发比较器。lp_BLESerial的发送缓冲区(最大 1024 字节)会缓存数据,再以较低速率发送至手机。


本低功耗库针对 “噪声比较器输入导致的触发洪流” 做了特殊优化:


  1. lp_comparator的触发事件与定时器、BLE 触发事件分属不同队列(比较器队列深度为 4);
  2. 若队列溢出,库会自动更新队列中最后一个触发事件的电平状态,确保草图处理完所有触发事件后,最终处理的是引脚当前的实际电平;
  3. 该优化的副作用:处理函数可能连续接收两次 HIGH 或两次 LOW(即使引脚电平实际在中间变化)。

关于 lp_pinChange

nRF52 芯片支持 “输入引脚电平跳变触发”,但芯片处理 BLE 功能时可能丢失跳变事件,因此本库未实现lp_pinChange功能 —— 建议使用lp_comparator并将参考电压设为 1/2 Vdd,替代电平跳变检测。


12

高驱动输出模式与 nRF52 芯片信息

1. 高驱动输出模式

Arduino 中通过pinMode(.., OUTPUT)配置的 nRF52 输出引脚,默认采用 “标准驱动模式(S0S1)”,而 nRF52 还支持 “高驱动模式(H0/H1)” 与 “断开模式(D0/D1)”,各模式的驱动能力如下:


驱动模式

灌电流(输出低电平)

拉电流(输出高电平)

适用场景

标准驱动(S0S1)

供电电压 > 1.7V 时,典型值 2mA(最小值 1mA)

供电电压 > 1.7V 时,典型值 2mA(最小值 1mA)

常规低电流负载(如 LED)

高驱动(H0/H1)

供电电压 > 2.7V 时,典型值 10mA(最小值 3mA)

供电电压 > 2.7V 时,典型值 9mA(最小值 3mA)

高电流负载(如大功率 LED)

断开模式(D0/D1)

输出低电平时断开引脚与驱动电路

输出高电平时断开引脚与驱动电路

开漏总线(如 I2C)


扩展 pinMode 配置选项

除常规OUTPUT外,本库支持以下扩展配置,用于设置高驱动 / 断开模式:


  1. OUTPUT_S0S1:标准驱动低电平 + 标准驱动高电平(与默认OUTPUT相同)
  2. OUTPUT_H0S1:高驱动低电平 + 标准驱动高电平
  3. OUTPUT_S0H1:标准驱动低电平 + 高驱动高电平
  4. OUTPUT_H0H1:高驱动低电平 + 高驱动高电平
  5. OUTPUT_D0S1:低电平时断开 + 标准驱动高电平
  6. OUTPUT_D0H1:低电平时断开 + 高驱动高电平
  7. OUTPUT_S0D1:标准驱动低电平 + 高电平时断开
  8. OUTPUT_H0D1:高驱动低电平 + 高电平时断开

2. nRF52 芯片信息(nrf52ChipInfo)

nRF52 芯片有多个版本,各版本存在不同漏洞。pfod_lp_nrf52 的第 4 版新增nrf52ChipInfo系列方法,用于查看芯片版本信息。

示例:读取芯片信息(nRF52ChipInfo.ino)

#include <nrf52ChipInfo.h>

void setup() {
// 初始化串口通信(波特率115200)
Serial.begin(115200);
// 延迟10秒,等待串口监视器启动
for (int i=10; i>0; i--) {
Serial.print(i); Serial.print(' ');
delay(500);
}
Serial.println();
// 输出芯片信息
Serial.print("芯片型号:nRF"); Serial.println(nRF52PartNo(), HEX);
Serial.print("芯片版本:"); Serial.println((char*)nRF52Variant());
Serial.print("RAM容量:"); Serial.print(nRF52RamKb()); Serial.println("KB");
Serial.print("Flash容量:"); Serial.print(nRF52FlashKb()); Serial.println("KB");
Serial.println("初始化完成");
}

void loop() {
// 无循环执行代码
}


示例输出(Nano V2 芯片)

10 9 8 7 6 5 4 3 2 1
芯片型号:nRF52832
芯片版本:AAE1
RAM容量:64KB
Flash容量:512KB
初始化完成


芯片版本解码规则

芯片版本(如 AAE1)的前缀与后缀含义如下:


前缀

Flash 容量

RAM 容量

AA

512KB

64KB

AB

256KB

32KB


  1. 前缀:表示 Flash 与 RAM 容量
  2. 后缀
  3. 第一个字符(A-Z):硬件版本 / 修订号(递增);
  4. 第二个字符(0-9):量产设备标识(递增)。


注意:部分 AB 版本芯片可能返回错误的容量信息(显示 RAM 64KB、Flash 512KB,实际应为 RAM 32KB、Flash 256KB)。


13

低功耗按键消抖

监测按键输入并忽略触点抖动是常见需求,以下程序(lp_BLE_debounce.ino)演示如何实现低功耗按键消抖:

#include <lp_BLESerial.h>
#include <lp_comparator.h>

// 大多数Arduino开发板(包括Nano V2)的13号引脚均连接LED
int led = 13;
int comparatorPin = 2; // 比较器引脚:D2/A2
lp_BLESerial ble;
lp_timer debounceTimer;
uint32_t debounceTimeOut = 20; // 消抖延迟:20毫秒(根据按键特性调整)

int lastButtonState = -1; // 上一次按键状态(初始未设置)
int buttonState = -1; // 当前按键状态(初始未设置)

// setup函数在按下复位键时运行一次
void setup() {
// 将比较器引脚配置为下拉输入(防止引脚悬空导致误触发)
pinMode(comparatorPin, INPUT_PULLDOWN);
// 将LED引脚配置为输出模式
pinMode(led, OUTPUT);
ble.setName("Button Debounce"); // 设置BLE广播名称(默认名称为“Nordic BLE UART”)
ble.begin(); // 开始广播,准备接受连接
// 启动低功耗比较器:监测comparatorPin引脚,参考电压为8/16 Vdd,电平变化时调用handlePinLevelChange
lp_comparator_start(comparatorPin, REF_8_16Vdd, handlePinLevelChange);
}

// loop函数会无限循环执行
void loop() {
sleep(); // 休眠,等待触发唤醒
// 清空BLE接收缓冲区(忽略接收数据)
while (ble.available()) {
int i = ble.read();
}
}

// 引脚电平变化处理函数:pinState为检测到的电平(HIGH/LOW)
void handlePinLevelChange(int pinState) {
if (pinState != lastButtonState) { // 若当前电平与上一次不同(排除重复触发)
lastButtonState = pinState; // 更新上一次电平状态
debounceTimer.stop(); // 停止之前的消抖定时器(若存在)
// 启动消抖定时器:延迟debounceTimeOut后调用handleDebounceTimeout
debounceTimer.startDelay(debounceTimeOut, handleDebounceTimeout);
}
}

// 消抖定时器超时处理函数:此时按键电平已稳定
void handleDebounceTimeout() {
buttonState = lastButtonState; // 更新当前稳定的按键状态
// 输出队列最大使用率(需在utility/app_schedule.h中取消#define SCHEDULER_PROFILER的注释)
// ble.print("maxQ:"); ble.print(app_sched_queue_utilization_get());
ble.print(' ');
ble.print((buttonState == HIGH) ? 'H' : 'L'); // 发送稳定的电平状态(H/L)
digitalWrite(led, buttonState); // 电平为HIGH时点亮LED,LOW时熄灭
}

工作原理

  1. 按键电平变化时,lp_comparator触发handlePinLevelChange
  2. 若当前电平与上一次不同,启动消抖定时器(20 毫秒),并停止之前可能存在的定时器(避免多次触发导致的定时器叠加);
  3. 消抖定时器超时后,调用handleDebounceTimeout,此时按键电平已稳定,更新状态并执行后续操作(点亮 LED、发送 BLE 数据)。


注意:lp_comparator_start首次触发始终为 LOW,若按键实际为 HIGH,随后会触发 HIGH—— 此机制可在启动时初始化按键状态。


队列溢出监测

定时器触发事件与lp_comparator、BLE 触发事件分属不同队列,定时器的 “停止 / 启动” 操作也会向队列添加触发事件。若按键噪声导致频繁触发,可能引发队列溢出。可通过以下方式监测:


  1. utility/app_schedule.h中取消#define SCHEDULER_PROFILER的注释;
  2. handleDebounceTimeout中调用app_sched_queue_utilization_get(),查看队列最大使用率(默认队列深度为 8,定义在 lp_timer_init.h 中)。


测试表明:即使输入噪声较大,队列使用率也仅为 1-2,实际按键的噪声更少,无需担心溢出问题。


14

定制化低功耗控制与数据记录

可使用免费的pfodDesigner Android 应用创建定制化控制菜单 / 子菜单、数据记录与图表功能,并生成对应的低功耗 Arduino 程序草图。需配合 pfodApp 连接设备并显示界面,无需编写任何 Android 代码(所有 Android 端逻辑均由 pfodApp 处理)。


操作步骤

  1. 安装 pfodDesigner:从 Google Play 下载并安装 pfodDesignerV3(3441 版本及以上);
  2. 创建新项目:启动 pfodDesigner,新建菜单,点击 “目标设备(Target)” 按钮,选择 “蓝牙低功耗(BLE)”→“Low Power nRF52 NanoV2”(选择低功耗版本,而非列表下方的 RedBearLab 版本),通过手机返回键回到菜单编辑界面;
  3. 设计菜单功能
  4. 参考 pfodDesigner 教程,添加 “LED 脉冲控制” 按钮(设置 D13 引脚高电平 2 秒);
  5. 添加 “数据显示” 菜单项,显示 A2 引脚的模拟输入电压(参考数据显示教程);
  6. 添加 “图表按钮”,设置 A2 引脚电压的实时图表,并将数据记录到手机日志文件(参考图表设计教程);
  7. 生成程序草图:点击 “生成代码(Generate Code)” 按钮,获取适用于 Nano V2 的低功耗 Arduino 程序草图(示例程序:lp_BLE_NanoV2_example.ino);
  8. 测试与使用:将草图上传至 Nano V2,通过 pfodApp 连接设备,即可看到定制化菜单、实时数据与图表 —— 此时设备无论处于 “等待连接” 还是 “已连接更新” 状态,功耗均 < 100 微安。


扩展:定制化图形控件

也可手动编写 Arduino 代码,为 pfodApp 设计定制化交互式图形控件,详细步骤参考《Android 定制化 Arduino 控件教程》。


阅读记录0
点赞0
收藏0
禁止 本文未经作者允许授权,禁止转载
猜你喜欢
评论/提问(已发布 0 条)
评论 评论
收藏 收藏
分享 分享
pdf下载 下载
pdf下载 举报