停止模式1(Stop1)调试:进入方法与调试器保持
Stop1 模式,说白了就是 STM32L4 在低功耗和唤醒速度之间取了个中间值。我刚开始接触 L4 系列时,总觉得 Stop 模式就一种,后来在项目里踩了坑才发现——Stop1 和 Stop2 的差别,直接影响了你的调试策略。
这一节,我们专门聊 Stop1。怎么进去?调试器会不会掉线?电流到底能压到多少?
进入 Stop1 模式的标准流程
进入 Stop1 其实不复杂。核心就两步:配置寄存器,然后执行 WFI 或 WFE 指令。
我个人习惯用 HAL 库的接口,但也会直接操作寄存器来确认状态。先看代码:
/* 进入 Stop1 模式的标准配置 */
void Enter_Stop1_Mode(void)
{
/* 1. 配置电源控制寄存器 */
HAL_PWREx_EnableLowPowerRunMode(); // 可选,用于更低电压
__HAL_RCC_PWR_CLK_ENABLE();
/* 2. 设置 Stop1 模式 */
HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);
/* 3. 醒来后恢复时钟 */
SystemClock_Config();
}
嗯,这里要注意:PWR_STOPENTRY_WFI 和 PWR_STOPENTRY_WFE 的区别。WFI 是等待中断,WFE 是等待事件。我建议调试阶段用 WFI,因为你可以用调试器手动触发中断来唤醒。
调试器在 Stop1 下的连接保持
这是很多工程师头疼的地方。进入 Stop1 后,调试器会不会断开?
答案是:取决于你的调试器配置和芯片选项。
STM32L4 有个叫 DBGMCU 的外设,专门控制调试接口在低功耗模式下的行为。你需要确保 DBGMCU_CR 寄存器的 DBG_STOP 位被置 1。
我曾经在一个电池供电的项目里,调试器一进 Stop1 就掉线,每次都要重新连接。后来发现是 DBGMCU 没配置。那叫一个郁闷。
/* 保持调试器在 Stop1 下连接 */
void Keep_Debug_Alive_In_Stop1(void)
{
/* 使能 DBGMCU 时钟 */
__HAL_RCC_DBGMCU_CLK_ENABLE();
/* 设置 DBG_STOP 位,保持调试接口时钟 */
DBGMCU->CR |= DBGMCU_CR_DBG_STOP_Msk;
/* 可选:保持定时器在 Stop1 下继续运行 */
// DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM2_STOP;
}
实测电流与调试响应
我拿 STM32L496ZG 开发板做了几组实测。环境是 3.3V 供电,室温 25°C。结果如下:
| 配置条件 | 典型电流 | 调试器状态 | 唤醒时间 |
|---|---|---|---|
| Stop1 默认(无调试保持) | ~3.5 µA | 断开 | ~5 µs |
| Stop1 + DBG_STOP 使能 | ~12 µA | 保持连接 | ~5 µs |
| Stop1 + DBG_STOP + 定时器保持 | ~18 µA | 保持连接 | ~5 µs |
| Stop1 + RAM 保持全部 | ~8 µA | 断开 | ~5 µs |
你看,调试器保持连接要多花将近 9 µA。对于低功耗设计来说,这个代价不小。所以我建议:调试阶段开 DBG_STOP,量产阶段关掉。
另外,唤醒时间基本不受影响。Stop1 的唤醒速度比 Stop2 快很多,这也是它最大的优势。
调试响应:你能做什么?不能做什么?
进入 Stop1 后,如果调试器保持连接,你可以:
- 查看变量值(RAM 内容保持)
- 设置断点(但不会立即触发,需要唤醒后)
- 单步执行(需要先唤醒)
- 查看外设寄存器状态
你不能做的:
- 直接修改 Flash(写保护)
- 实时跟踪外设行为(时钟已关闭)
- 使用 ITM/SWO 输出(需要时钟)
常见故障与定位
我在项目里遇到过几个典型问题,列出来供你参考:
- 进不去 Stop1 —— 检查是否有未处理的中断挂起。WFI 指令会被挂起的中断直接唤醒。
- 电流降不下来 —— 检查 GPIO 是否配置为模拟模式。浮空引脚会漏电。
- 调试器频繁断开 —— 检查 DBGMCU 配置,以及调试器供电是否稳定。
- 唤醒后程序跑飞 —— 检查时钟恢复配置。Stop1 退出后需要重新配置系统时钟。
我曾经遇到一个特别隐蔽的问题:某个外设在 Stop1 下没有正确关闭,导致电流比预期高了 20 µA。后来用调试器逐个外设排查,才发现是 USART 的 RX 引脚没拉高。
Stop1 模式知识结构图
下面这张图总结了 Stop1 调试的核心要点,你可以对照着梳理自己的代码:
这张图把 Stop1 调试分成了五个维度。你调试时遇到问题,可以对照着看是哪个环节出了岔子。
调试实战:一个完整的例子
最后,我给你一个完整的调试流程。假设你要验证 Stop1 模式下的功耗和唤醒:
/* 调试用:进入 Stop1 并保持调试连接 */
void Debug_Stop1_Test(void)
{
volatile uint32_t status;
/* 1. 配置调试保持 */
__HAL_RCC_DBGMCU_CLK_ENABLE();
DBGMCU->CR |= DBGMCU_CR_DBG_STOP_Msk;
/* 2. 记录进入前状态 */
status = PWR->CR1;
/* 3. 进入 Stop1 */
HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);
/* 4. 醒来后检查状态 */
/* 在这里设置断点,查看 status 和当前功耗 */
}
你在第 4 步设置断点。进入 Stop1 后,调试器不会断开。你可以用电流表测量实际功耗。然后通过调试器发送一个中断(比如按键中断),芯片会立即唤醒并停在断点处。
这个方法我用了很多次,定位问题效率很高。