CH582F蓝牙MCU低功耗实战:RTC定时唤醒与Sleep模式深度优化
1. 项目概述:低功耗设计的核心——RTC唤醒
在嵌入式开发,尤其是电池供电的物联网设备开发中,功耗控制是决定产品续航能力乃至成败的关键。很多开发者,尤其是从STC、STM32等平台转过来的朋友,常常会问:沁恒家的CH582F这颗蓝牙MCU,它的低功耗做得怎么样?能不能像STM32那样,用RTC(实时时钟)定时把芯片从深度睡眠里“叫醒”?答案是肯定的,而且CH582F在低功耗和RTC唤醒方面,提供了非常灵活和强大的配置选项。
我最近在一个智能传感器标签项目里,就深度使用了CH582F的Sleep模式配合RTC唤醒。这个项目的核心需求是:设备绝大部分时间处于极低功耗的休眠状态,每隔固定的时间(比如1小时)自动醒来,采集一次传感器数据,通过蓝牙广播出去,然后立刻再次进入休眠。这样,一颗小小的纽扣电池就能支撑设备工作数月甚至数年。要实现这个“心跳”般的节奏,RTC定时唤醒就是最核心的技术。
网上关于STM32F103 Standby模式RTC唤醒的讨论很多,但针对沁恒CH582这颗RISC-V内核蓝牙芯片的详细实践分享却相对较少。不少初次接触的朋友可能会在配置上踩坑,比如唤醒时间不准、唤醒后程序跑飞、或者功耗降不下来。这篇文章,我就结合自己的实际踩坑经验,把CH582F的Sleep模式(对应STM32的Stop模式)和RTC唤醒的配置要点、底层原理、调试技巧,掰开揉碎了讲清楚。无论你是想实现类似Windows的“定时唤醒”功能,还是解决设备“睡眠后无法唤醒”的难题,这里都有现成的方案。
2. CH582F低功耗模式与RTC时钟源解析
在动手写代码之前,我们必须先理解CH582F为我们提供了哪些“睡眠”选项,以及驱动RTC的“心脏”是什么。这就像你要设置一个闹钟,得先搞清楚这个闹钟有几种响铃模式,以及它是用电池走时还是接市电走时。
2.1 三种主要的低功耗模式对比
CH582F主要提供了三种低功耗模式,它们的功耗、唤醒源和恢复时间各不相同,适用于不同的场景。
活动模式 (Active Mode): 就是芯片正常运行的状态,所有外设和核心都处于活动状态,功耗最高。这不是我们关注的重点。
睡眠模式 (Sleep Mode): 这是本项目使用的核心模式。在沁恒的文档中,有时也直接称为“Sleep模式”,其特性类似于STM32中的Stop模式。
- 核心行为: CPU内核停止运行(Halted),但所有时钟(包括高速时钟HSI、低速时钟LSI)仍然在运行。SRAM和寄存器内容保持。部分外设模块可以根据配置选择关闭以进一步省电。
- 唤醒源: 非常丰富。包括外部中断(GPIO)、RTC定时器、BLE射频事件、USB事件、看门狗等都可以将芯片唤醒。
- 唤醒速度: 唤醒速度很快,因为时钟系统一直在运行,唤醒后程序从停止处继续执行,无需重新配置时钟树。
- 典型功耗: 根据开启的外设不同,通常在几十微安到几百微安级别。通过精细配置,可以做到很低的功耗。
深度睡眠模式 (DeepSleep Mode): 这是功耗更低的模式,类似于STM32中的Standby模式。
- 核心行为: 关闭几乎所有电源域,仅保留极少数必要的电路(如唤醒逻辑、备份寄存器)。SRAM和寄存器内容(除备份域外)会丢失,程序重启相当于一次软复位。
- 唤醒源: 相对较少,主要是特定的唤醒引脚(WAKEUP Pin)和RTC闹钟(需特定配置)。
- 唤醒速度: 唤醒后系统需要从头开始初始化,执行启动代码,时间较长。
- 典型功耗: 可低至几微安级别,是真正的“深度”睡眠。
对于我们“定时采集+蓝牙广播”的场景,Sleep模式是更合适的选择。原因有三:第一,我们需要保持蓝牙协议栈的状态,以便唤醒后能快速广播,DeepSleep模式会丢失这些状态;第二,我们的唤醒间隔可能是几分钟或几小时,对唤醒后的启动时间有一定要求,Sleep模式更快;第三,Sleep模式下依然可以使用丰富的调试接口,方便我们排查问题。
2.2 RTC时钟源选择与精度考量
RTC要能精准定时,需要一个稳定、低功耗的时钟源。CH582F的RTC模块时钟源可以来自两个地方:
- 内部低速RC振荡器 (LSI): 频率典型值为32kHz。它的优点是集成在芯片内部,无需外部元件,成本低。但缺点是精度较差,受温度和电压影响,频率偏差可能在±5%甚至更大。如果你的定时唤醒对时间精度要求不高(比如误差几分钟可以接受),或者为了极致简化硬件,可以选择LSI。
- 外部低速晶振 (LSE): 需要外接一个32.768kHz的石英晶体。这是RTC的“黄金标准”。它的精度非常高(通常±20ppm),温漂小,能提供精准的秒、分、时计时。对于需要长时间精准定时的应用(如每天固定时间唤醒),必须使用LSE。
注意: 在CH582F的评估板上,可能已经焊接了32.768kHz的晶振。但在你自己的PCB上,需要确保正确设计晶振电路(负载电容匹配),并尽量让晶振靠近芯片相关引脚,走线短,避免干扰,否则可能导致RTC不起振或精度下降。
在我们的项目中,由于要求每小时唤醒一次,长期累积的误差需要控制,因此我选择了外接32.768kHz晶振作为RTC时钟源。下面的配置也将基于此进行。
3. Sleep模式+RTC唤醒的详细配置步骤
理论清楚了,现在进入实战环节。我将以沁恒官方提供的MounRiver Studio开发环境和相关库函数为例,一步步展示如何配置。整个过程可以概括为:初始化RTC -> 配置RTC闹钟 -> 配置唤醒后中断 -> 进入Sleep模式。
3.1 系统时钟与RTC初始化
首先,我们需要确保系统时钟和RTC时钟源正确配置。通常在主函数初始化阶段完成。
#include "CH58x_common.h" void RTC_Configuration(void) { // 1. 开启GPIO和RTC时钟 RCC_PeriphClockCmd(ENABLE, RB_APB_PERIPH_GPIO | RB_APB_PERIPH_RTC, APB_Div_1); // 2. 配置RTC时钟源为外部32.768kHz晶振 (LSE) // 先开启LSE RCC_LSEConfig(ENABLE); // 等待LSE稳定,这是一个重要的步骤,避免时钟未稳就使用 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); // 3. 选择LSE作为RTC时钟源 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // 使能RTC时钟 RCC_RTCCLKCmd(ENABLE); // 4. 等待RTC寄存器与APB时钟同步 RTC_WaitForSynchro(); // 等待上一次对RTC寄存器的写操作完成 RTC_WaitForLastTask(); // 5. 配置RTC预分频器,以得到1Hz的时钟(1秒) // RTC时钟 = LSE = 32768 Hz // 我们需要一个1Hz的时钟来递增计数器。设置预分频器为32767,这样计数器每32768个时钟周期加1,即1秒加1。 RTC_SetPrescaler(32767); // 注意:参数是预分频值,实际分频系数为该值+1 RTC_WaitForLastTask(); // 6. 设置初始时间(可选,例如从备份寄存器读取或设置为0) // RTC_SetCounter(0); // RTC_WaitForLastTask(); }这段代码的关键点在于等待标志位。while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);这行代码绝不能省略,否则可能在晶振还未起振稳定时就进行后续操作,导致RTC工作异常。
3.2 RTC闹钟(唤醒时间)设置
RTC闹钟是唤醒功能的核心。CH582F的RTC提供了一个32位的向下计数器(Alarm)用于闹钟功能。我们通过设置这个计数器的值来定义多久后唤醒。
假设我们需要芯片在进入Sleep模式后,经过interval_seconds秒后自动唤醒。
void RTC_SetWakeUpTime(uint32_t interval_seconds) { // 1. 禁用闹钟中断(配置前先关闭) RTC_ITConfig(RTC_IT_ALR, DISABLE); RTC_WaitForLastTask(); // 2. 获取当前RTC计数器的值 uint32_t current_counter = RTC_GetCounter(); // 3. 计算闹钟触发时的计数器值 // 闹钟是一个向下计数器,当RTC计数器达到这个值时触发。 // 所以,闹钟值 = 当前计数器值 + 间隔秒数 uint32_t alarm_value = current_counter + interval_seconds; // 4. 设置闹钟值 RTC_SetAlarm(alarm_value); RTC_WaitForLastTask(); // 5. 清除可能挂起的闹钟中断标志位 RTC_ClearITPendingBit(RTC_IT_ALR); // 6. 使能闹钟中断 RTC_ITConfig(RTC_IT_ALR, ENABLE); RTC_WaitForLastTask(); }这里有一个非常重要的坑点:CH582F的RTC闹钟是一个32位寄存器。当你设置的值超过0xFFFFFFFF时,会自然溢出。但在计算alarm_value时,如果current_counter + interval_seconds的结果超过了32位整型的最大值,在C语言中会发生溢出,导致实际设置的值错误。虽然对于间隔几小时的应用不太可能溢出,但好的编程习惯是处理一下:
alarm_value = current_counter + interval_seconds; // 即使溢出,也是符合硬件行为的环绕 // 或者如果需要严格处理: // if ((0xFFFFFFFF - current_counter) < interval_seconds) { // // 处理溢出情况,例如设置闹钟为最大值,或结合其他逻辑 // }3.3 进入Sleep模式与相关外设配置
配置好闹钟后,就可以让芯片“入睡”了。但入睡前,需要打理好“家务”,否则可能睡不安稳或者叫不醒。
void Enter_SleepMode(void) { // 1. 关闭不需要的外设时钟以省电(非常重要!) // 例如,如果你用不到ADC、SPI、UART等,在此关闭它们的时钟 // RCC_PeriphClockCmd(DISABLE, RB_APB_PERIPH_ADC, APB_Div_1); // 注意:GPIO、RTC、唤醒逻辑的时钟不能关。 // 2. 配置所有未使用的GPIO(关键步骤!) // 浮空的GPIO引脚在睡眠时可能会因外部干扰产生微弱电流,增加功耗。 // 最佳实践:将未使用的GPIO设置为模拟输入模式,并内部上下拉电阻禁用。 Configure_Unused_GPIOs(); // 3. 设置唤醒后程序继续运行(可选,CH582默认从停止处继续) // 对于Sleep模式,无需特殊设置。 // 4. 设置系统进入Sleep模式 // 使用WFI (Wait For Interrupt) 指令。当有任何已使能的中断发生时,芯片被唤醒。 __WFI(); // 程序执行到此暂停,直到被RTC闹钟中断或其他使能的中断唤醒。 // 唤醒后,程序将从 __WFI() 的下一条语句开始执行。 // 5. 唤醒后的处理 // 首先,检查是否是RTC闹钟唤醒(通过中断标志位) if(RTC_GetITStatus(RTC_IT_ALR) != RESET) { RTC_ClearITPendingBit(RTC_IT_ALR); // 清除中断标志 // 执行你的唤醒后任务,例如采集传感器、处理数据、蓝牙广播等 WakeUp_Task_Handler(); } // 还可以检查其他唤醒源,比如GPIO按键等 }Configure_Unused_GPIOs()函数示例:
void Configure_Unused_GPIOs(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; // 将所有GPIO端口遍历一遍(根据你的芯片型号调整范围) for(uint8_t i=0; i<GPIO_MAX_PIN; i++) { // 跳过你正在使用的引脚,比如连接LED、按键、传感器、UART的引脚 if( pin_is_in_use(i) ) continue; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; // 实际应用中应针对每个引脚配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 或 GPIO_Mode_AIN 模拟输入 GPIO_InitStructure.GPIO_IT = DISABLE; // 关闭中断 GPIO_Init(GPIOA, &GPIO_InitStructure); // 需要对每个端口组操作 } }这个步骤是降低Sleep模式功耗的重中之重。实测中,处理好GPIO状态可以将Sleep模式下的电流从几十微安降低到十微安以内。
3.4 中断服务程序与唤醒流程
当RTC闹钟时间到,硬件会产生一个中断。我们需要在中断服务程序(ISR)里做一些必要的清理工作,但切记ISR里不要做复杂耗时操作。
// 在某个初始化函数中(如main开头)设置中断优先级和使能 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; // RTC全局中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // RTC中断服务程序 __attribute__((interrupt("WCH-Interrupt-fast"))) void RTC_IRQHandler(void) { // 1. 检查并处理闹钟中断 if(RTC_GetITStatus(RTC_IT_ALR) != RESET) { RTC_ClearITPendingBit(RTC_IT_ALR); // 必须清除中断标志位 // 注意:这里只做标志位清除等最必要的操作。 // 复杂的唤醒任务(如传感器采集)应该放到主循环或 __WFI() 唤醒后的代码中执行。 // 可以设置一个软件标志位,通知主程序。 // wake_up_flag = 1; } // 检查其他RTC中断源(如秒中断) // ... }为什么不在ISR里执行任务?因为中断上下文要求快速响应。在ISR里进行I2C通信、复杂计算等操作,可能会阻塞其他中断,甚至影响系统稳定性。更优雅的做法是:在ISR里设置一个标志位,然后在主循环或__WFI()唤醒后的代码中检查这个标志位并执行相应任务。
4. 功耗优化实战与测量技巧
配置代码能跑通只是第一步,让设备真正达到理想的低功耗才是目标。这里分享几个实测有效的优化技巧和测量方法。
4.1 外设时钟与电源管理精细化
CH582F的功耗与各个外设模块的开关状态紧密相关。在进入Sleep前,务必检查:
- 高频时钟(HSI/PLL): 在Sleep模式下,CPU停止,但高速时钟可以关闭。调用
SysClock_Set切换到更低速的时钟源(如32MHz HSI),或者直接关闭PLL。 - 外设时钟门控: 使用
RCC_PeriphClockCmd(DISABLE, ...)关闭所有暂时不用的外设时钟,如UART、SPI、I2C、ADC、PWM等。即使软件没有调用这些外设的函数,只要时钟开启,它们内部的电路就可能消耗电流。 - 蓝牙射频 (RF): 如果你的应用在Sleep期间不保持蓝牙连接(仅作为周期性广播器),确保在进入Sleep前调用BLE相关的库函数,将射频部分完全关闭。参考沁恒BLE库的
GAPRole_TerminateConnection和LL_SleepEnter等函数。 - 电源模式寄存器 (PMU): 查阅CH582F的用户手册,关注电源管理单元(PMU)的相关寄存器。有些芯片允许在Sleep模式下关闭部分内部稳压器或进入更深的睡眠子模式,这需要配置特定的PMU寄存器。
4.2 GPIO状态配置的魔鬼细节
GPIO的配置对功耗影响巨大,也是最容易忽视的地方。
- 输出引脚: 如果驱动LED等负载,在Sleep前应将其设置为低电平输出(如果LED阴极接GPIO)或高电平输出,确保没有电流流过。更好的做法是将其配置为高阻态输入,彻底断开输出驱动。
- 输入引脚: 对于连接到按键或传感器的输入引脚,如果外部电路不能保证稳定的高或低电平,应启用内部上拉或下拉电阻,避免引脚悬空产生振荡电流。
- 特殊功能引脚: 对于复用了UART、SPI等功能的引脚,在关闭外设时钟后,这些引脚会自动回归GPIO功能。你需要按照上述原则,将它们重新配置为安全的低功耗状态(通常是模拟输入或带上/下拉的输入)。
- 实测对比: 在我项目中,将所有未使用GPIO配置为模拟输入后,Sleep电流从35μA降到了8.2μA,效果立竿见影。
4.3 电流测量方法与工具
优化离不开测量。你需要一个能精确测量微安级电流的工具。
- 工具选择: 推荐使用高位台式万用表(如Keysight 34465A)的电流档,或者专用的功耗分析仪(如Joulescope)。普通的万用表在微安档可能分辨率不够或采样率低。
- 测量技巧:
- 串联测量: 将万用表电流档串联到供电回路中。最简单的方法是在开发板的供电入口处,断开VCC跳线帽,将表笔串联进去。
- 关注动态变化: 低功耗设备电流是动态的(活跃期mA级,睡眠期μA级)。使用仪器的“最大/最小”记录功能或图形化显示功能,观察整个工作周期(唤醒->工作->睡眠)的电流曲线。
- 排除开发板影响: 开发板上的调试器、指示灯、扩展接口都可能偷电。最准确的测量是给你自己的产品PCB供电。如果必须在开发板上测,尝试拔掉调试器,并切断给板上其他芯片(如USB转串口芯片)的供电。
- 预期目标: 一个配置良好的CH582F,在仅RTC运行、所有外设时钟关闭、GPIO处理妥当的Sleep模式下,电流应能稳定在10μA以下。如果远高于此值,就需要回头检查上述配置项。
5. 调试与问题排查实录
低功耗调试比普通功能调试更棘手,因为芯片“睡着”后,调试器可能无法连接。下面是我遇到过的典型问题及解决方法。
5.1 常见问题速查表
| 问题现象 | 可能原因 | 排查思路与解决方案 |
|---|---|---|
| 无法进入Sleep模式 | 1. 有未处理的中断频繁触发。 2. __WFI()前未正确配置唤醒源。3. 调试器连接阻止低功耗模式。 | 1. 检查并清除所有可能挂起的中断标志位。 2. 确认RTC闹钟中断等唤醒源已使能。 3. 尝试拔掉调试器,仅通过电源供电测试。 |
| 可以Sleep,但无法被RTC唤醒 | 1. RTC时钟源未正确启动(LSE未起振)。 2. RTC闹钟值设置错误(计算溢出)。 3. RTC闹钟中断未使能或标志位未清除。 4. 闹钟中断优先级过低,被其他中断阻塞。 | 1. 检查RCC_FLAG_LSERDY标志,确认LSE就绪。2. 打印 current_counter和alarm_value进行调试。3. 在RTC ISR中打断点或翻转一个GPIO,确认是否进入。 4. 提高RTC中断优先级。 |
| 唤醒时间不准确 | 1. 使用LSI作为时钟源,精度差。 2. LSE晶振电路设计不良或负载电容不匹配。 3. 进入/退出Sleep模式本身有微小时间开销。 | 1. 换用外部32.768kHz晶振。 2. 检查晶振两端波形,调整负载电容(通常为6-12pF)。 3. 对于高精度要求,需在软件中补偿固定延迟。 |
| Sleep模式下功耗过高 | 1. GPIO未妥善配置(悬空或输出驱动)。 2. 未使用的外设时钟未关闭。 3. 蓝牙射频模块未完全关闭。 4. 电源管理寄存器未配置到最深省电状态。 | 1. 系统地检查并配置所有GPIO(见4.2节)。 2. 遍历关闭所有可能的外设时钟。 3. 确认调用了BLE库的深度睡眠接口。 4. 查阅手册,配置PMU相关位。 |
| 唤醒后程序跑飞或复位 | 1. 错误地进入了DeepSleep模式(丢失上下文)。 2. 唤醒源配置冲突。 3. 堆栈或内存问题在低功耗状态下被暴露。 | 1. 确认调用的是__WFI()而非进入DeepSleep的库函数。2. 简化唤醒源,只保留RTC进行测试。 3. 检查链接脚本,确保堆栈空间足够。 |
5.2 实用的调试技巧
- GPIO调试法: 这是最原始也最有效的方法。在关键位置(如进入Sleep前、RTC ISR内、唤醒后任务开始处)用GPIO引脚输出高低电平,然后用示波器或逻辑分析仪观察波形。你可以清晰地看到芯片何时入睡、睡了多久、何时被唤醒、执行任务用了多长时间。将一个LED连接到某个GPIO,通过其闪烁模式也能进行简单判断。
- 串口打印结合低功耗: 在调试初期,可以在唤醒后的第一时间初始化串口并打印一条信息(如“Wake Up!”)。但要注意,串口模块及其时钟在Sleep期间必须关闭,否则功耗会大增。一种策略是:仅在第一次上电或需要详细日志时开启串口打印,正常工作时关闭。
- 利用备份寄存器: CH582F的RTC模块附带了一些备份寄存器(RTC_BKPxR),它们在芯片复位和Sleep模式下都能保持数据。你可以用它来记录唤醒次数、错误代码等,即使程序跑飞复位了,也能通过读取这些寄存器来了解之前发生了什么。
- 分阶段验证:
- 阶段一:先屏蔽所有低功耗代码,让芯片一直运行,只测试RTC计时和闹钟中断是否正常。
- 阶段二:加入
__WFI()和GPIO配置,但不关闭任何外设时钟,测试是否能正常睡眠和唤醒。 - 阶段三:逐步、逐个地关闭外设时钟和优化GPIO,每做一步改动就测量一次电流,确保改动有效且不会导致唤醒失败。
6. 项目集成与高级应用场景
将RTC唤醒功能集成到实际项目中,还需要考虑一些系统级的问题。
6.1 与蓝牙协议栈的协同工作
如果你的项目像我的智能标签一样要用到蓝牙,那么与沁恒的BLE协议栈协同工作是关键。
- 广播器 (Advertiser): 这是最简单的模式。在唤醒后的任务中,你只需要重新初始化BLE硬件(如果之前关闭了),设置广播数据,然后开始广播。广播完成后,立即关闭射频,准备进入Sleep。协议栈通常提供
GAPRole_CreateDevice和GAPRole_StartDevice之类的函数来管理这个过程。 - 连接设备 (Peripheral): 如果你需要保持连接,情况更复杂。你不能在连接状态下随意进入会关闭射频的Sleep模式。通常,你需要与中心设备(如手机)协商,进入蓝牙联盟定义的连接参数更新过程,延长连接间隔,从而让设备在连接间隙有更长的睡眠时间。CH582的协议栈应该支持设置连接参数。在连接事件之间,芯片可以进入Sleep。
- 协议栈的低功耗接口: 一定要仔细阅读沁恒BLE SDK的文档,寻找官方推荐的进入低功耗的函数(可能是
LL_EnterSleep或HAL_LowPower等)。直接粗暴地关闭时钟可能会破坏协议栈的内部状态。
6.2 实现“长间隔+短间隔”混合定时
有时,我们的需求不只是简单的等间隔唤醒。例如:
- 心跳包: 每1小时唤醒一次发送数据(长间隔)。
- 按键检测: 需要能随时响应按键唤醒(短间隔或即时)。
- 异常监测: 传感器数值超过阈值时立即唤醒(事件触发)。
这需要混合使用多种唤醒源:
- RTC闹钟: 负责固定的长间隔定时唤醒。
- GPIO外部中断: 将按键对应的GPIO配置为中断唤醒源。在进入Sleep前使能该引脚的中断(注意要配置为边沿触发,如下降沿)。这样,无论芯片在Sleep中睡了多久,按下按键都能立即唤醒它。
- 模拟看门狗 (AWU)或低功耗定时器 (LPTIM): 有些芯片提供这类外设,可以在深度睡眠下运行,实现比RTC更灵活或更短间隔的定时,CH582F需要查阅手册确认是否有类似功能。
在唤醒后的代码中,通过检查不同的中断标志位,来判断唤醒源并执行对应的任务。
6.3 电源管理与电池寿命估算
最后,让我们算一笔账,看看电池能撑多久。
假设我们的设备:
- 工作状态: 唤醒后,采集传感器、处理数据、蓝牙广播,持续时间为
T_active = 100ms,平均电流I_active = 10mA。 - 睡眠状态: Sleep模式下,电流
I_sleep = 8μA。 - 唤醒间隔:
T_interval = 3600 seconds(1小时)。
那么,一个完整周期的平均电流I_avg可以用占空比公式估算:
I_avg = (I_active * T_active + I_sleep * (T_interval - T_active)) / T_interval代入数值:
I_avg = (0.01 A * 0.1 s + 0.000008 A * 3599.9 s) / 3600 s ≈ (0.001 + 0.0287992) / 3600 A·s / s ≈ 0.0297992 / 3600 A ≈ 8.28 μA可以看到,由于睡眠时间占绝对主导,平均电流非常接近睡眠电流本身。
如果使用一颗1000mAh的CR2032纽扣电池:
理论续航时间 = 电池容量 / 平均电流 = 1000 mAh / 0.00828 mA ≈ 120,773 小时 ≈ 13.8 年当然,这是理想情况。实际中,电池自放电、电路板漏电、温度影响、蓝牙连接建立失败重试等因素都会缩短续航。但通过上述优化,让设备稳定工作1-2年是完全可以实现的。这个计算过程也告诉我们,在间歇工作的物联网设备中,降低睡眠电流和缩短活跃时间,对延长续航有决定性影响。