好的,我已经完整阅读了该帖子的内容,并结合 STC8G 系列手册(F17)中的相关信息,下面给出专业分析。
问题分析:STC8G1K08 系列休眠唤醒后复位重启
一、问题现象总结
从帖子描述来看,核心现象是:
- 部分芯片休眠后使用 INT2/INT3 外部中断唤醒,唤醒后发生复位重启,而非正常继续执行唤醒后的代码。
- 同一批板子中,大部分芯片正常,少部分芯片有问题,且问题可复现(重新烧录后依然存在)。
- 唤醒后复位的行为不稳定:有时 INT2 正常 INT3 不正常,有时反过来,有时两个都不正常。
- 如果去掉休眠函数,系统运行一切正常。
- 修改唤醒后 NOP 指令的个数,会影响复位行为(加多 NOP 可能某个中断变正常)。
- 电源端有 100nF + 10μF 电容,3V 电池供电。
二、可能原因排查(按可能性从高到低排列)
🔴 原因 1:I/O 口未在休眠前正确配置(最可能的原因)
根据 STC8G 系列手册「附录A 应用注意事项」 中明确强调:
特别注意:由于 STC8G 系列的所有 I/O(除了 ISP 下载口 P3.0/P3.1 外)在上电后都是高阻输入模式,I/O 外部电平不固定,此时如果 MCU 直接进入掉电模式/停机模式,会导致 I/O 有额外的耗电,所有在 MCU 进入掉电模式/停机模式前,必须将所有 I/O 口都根据实际情况设置好 I/O 口的模式,对于所有没有使用的外部悬空的 I/O 都需要设置为准双向口,并固定输出高电平。特别是部分管脚的芯片,由于芯片内部有部分 I/O 口并没有打线到外部管脚,所以这些 I/O 也是处于悬空状态的,这部分 I/O 也需要设置为准双向口,并固定输出高电平。
分析: 帖子中未看到在进入休眠前对所有 I/O 口进行统一配置的代码。如果存在悬空的 I/O 口处于高阻输入状态,在休眠/唤醒过程中,外部噪声或电平浮动可能导致 I/O 口状态异常,进而引发电源毛刺或异常中断触发,最终导致复位。
🔴 原因 2:唤醒后的 NOP 延时不足,中断标志未稳定清除
帖子中提到修改 NOP 个数会影响复位行为,这是一个重要线索。STC8G1K08 系列手册中明确指出:
STC8G1K08 系列 C 版芯片和 D 版芯片的 LVD 中断、定时器2中断、INT2中断、INT3中断和INT4中断的关闭中断指令无法在一个时钟内完成,用户必须在关闭中断指令后多加1个NOP指令。
这意味着:
- 唤醒后如果立即关闭中断或操作相关寄存器,由于中断关闭指令需要额外 1 个 NOP 才能生效,可能导致中断标志未清除干净,在唤醒瞬间再次触发中断,造成异常流程。
- 帖子中提到的 25 个 NOP 虽然看起来不少,但如果中断服务函数中只是
_nop_() 而没有正确清除中断标志,唤醒后中断可能反复触发,导致程序跑飞或复位。
🔴 原因 3:看门狗未在休眠前暂停
如果程序中使能了看门狗(WDT),进入掉电模式前必须暂停看门狗,否则唤醒后看门狗计数可能已接近溢出,导致复位。帖子中未提及看门狗的配置情况。
🔴 原因 4:电源瞬间跌落
虽然楼主排除了电压低于 2V 的情况,但唤醒瞬间的电流冲击(尤其是射频模块上电瞬间)可能导致电源电压出现短暂跌落,虽然未低于 2V,但可能低于芯片的掉电检测(LVD)阈值,触发 LVD 复位。帖子中未提及 LVD 的配置情况。
三、建议的解决方案
✅ 1. 休眠前统一配置所有 I/O 口
在进入 sys_dormancy() 函数之前,必须将所有未使用的 I/O 口设置为准双向口并输出高电平。示例代码:
// 进入休眠前,将所有未使用的I/O口设置为准双向口并输出高电平
// 以STC8G1K08A为例(SOP8/SOP16等封装,根据实际封装调整)
P0M0 = 0x00; P0M1 = 0x00; // P0口全部准双向口
P1M0 = 0x00; P1M1 = 0x00; // P1口全部准双向口
P3M0 = 0x00; P3M1 = 0x00; // P3口全部准双向口
P5M0 = 0x00; P5M1 = 0x00; // P5口全部准双向口
P0 = 0xFF; // 所有I/O输出高电平
P1 = 0xFF;
P3 = 0xFF;
P5 = 0xFF;
注意: 对于实际使用的 I/O(如 INT2/INT3 引脚),根据实际电路需求设置模式,不要强行设为准双向口输出高电平,否则会与外部电路冲突。
✅ 2. 唤醒后正确清除中断标志并加 NOP
在 INT2/INT3 的中断服务函数中,不要只放一个 _nop_(),而应该:
void INT2_ISR(void) interrupt 10
{
// 清除中断标志(如果有)
// INT2中断标志位在INTCLKO寄存器中
INTCLKO &= ~0x40; // 清除INT2中断标志(具体位定义请查手册)
_nop_(); // 多加1个NOP确保关闭指令生效
}
✅ 3. 检查看门狗配置
如果使能了看门狗,在进入休眠前必须暂停:
// 进入休眠前暂停看门狗
WDT_CONTR = 0x00; // 关闭看门狗(或根据实际配置)
✅ 4. 检查 LVD 配置
如果使能了 LVD 低电压检测,检查其阈值是否设置过低,或者直接关闭 LVD 中断进行测试:
// 关闭LVD中断
LVDF = 0; // 清除LVD标志
ELVD = 0; // 关闭LVD中断
✅ 5. 唤醒后增加足够的稳定时间
在唤醒后、操作外设(如发送串口指令)之前,增加一段延时,让电源和时钟稳定:
// 唤醒后
Delay_ms(2); // 等待系统稳定
// 然后再发送AT指令
四、总结
| 可能原因 |
可能性 |
排查方法 |
| I/O 口未配置导致休眠异常 |
⭐⭐⭐⭐⭐ |
休眠前统一配置所有 I/O 为准双向口输出高电平 |
| 中断标志未正确清除 |
⭐⭐⭐⭐ |
中断服务函数中清除标志并加 NOP |
| 看门狗未暂停 |
⭐⭐⭐ |
休眠前关闭看门狗 |
| LVD 触发复位 |
⭐⭐⭐ |
关闭 LVD 测试 |
| 电源唤醒瞬间跌落 |
⭐⭐ |
增加唤醒后延时,加大电源电容 |
最建议优先尝试的步骤: 在 sys_dormancy() 函数调用之前,将所有未使用的 I/O 口设置为准双向口并输出高电平,这是手册中明确强调的注意事项,也是最容易被忽略的原因。
🔍 搜索 "https://www.stcaimcu.com/thread-24777-1-1.html"
⏱️ 查找用时 19.9s | 总回答用时 37.6s