久世浮砚 发表于 2026-7-6 14:54:32

STC8G1K08系列休眠问题

各位大佬,最近开发新产品,使用STC8G1K08系列的mcu ,在休眠模式下产生了一些问题。
具体情况是在一批板子中,部分芯片休眠后使用外部引脚中断唤醒,在唤醒后会产生复位重启问题,但是绝大部分芯片在使用时又没有问题,导致比较困惑。
不过好在出问题的芯片重新烧录程序后还是一样的问题,导致问题能复现。
问题现象:
先描述正常情况下芯片功能:
程序开机后进行初始化,初始化完毕后运行10秒左右进入休眠模式。
进入休眠模式后使用外部引脚进行芯片唤醒,正常情况下使用INT2 与 INT3 芯片进行芯片唤醒,
在按下不同的中断引脚后,后续执行不同的指令发送。
不正常芯片的问题描述:
程序开机,初始化这些都没有问题,也能正常进入休眠,
但是在休眠过后用外部引脚唤醒时,INT2 或者INT3引脚按下后会导致系统复位。有可能INT2正常 INT3不正常 有可能INT3正常 INT2 不正常 ,要不就是两个引脚都不正常,部分芯片在唤醒后也不是立即复位,有些会复位慢一些,有些按下后立即复位。同样的芯片现象不太一样。
如果没有休眠函数,系统运行一切正常。

为此
我在出问题的芯片上我进行源代码修改,进行调试,以下一些调试过程


先发未修改的代码部分:
下面是系统准备进入休眠模式前后期间做的操作,主要是唤醒前后给射频模块发送休眠数据与唤醒射频模块的串口指令。
//下面函数是模块进入正计时时间到后进入到函数处理端,当时间就到达后进该函数,发送休眠指令,程序在这里停留5ms 这里5ms用作串口发送时间的延时,在11520波特率下5ms能发送完上述指令且有余量。
//等5ms过后串口发送数据完毕系统进入休眠。唤醒后在进行唤醒模块操作,因为购置的模块在115200下单独发送一次AT指令不一定能唤醒模块,在这里发送两次唤醒射频模块。
void button_time_out_handle(void)
{
    if (button_time_out_status.count == 10)
    {
      Uart_Printf_String(USART1, "AT+MODE=1\r\n"); // 在这写无线休眠函数 在第1次时休眠模块 2026.06.21 修改
      LED_TURN_OFF();
      Delay_ms(5); // 添加延时
      button_time_out_status.count = 0;
      sys_dormancy();                     // 休眠代码-执行到这程序将在这个函数休眠,唤醒后继续执行下面代码
      Uart_Printf_String(USART1, "AT\r\n"); // 在这写无线休眠函数-唤醒模块后 按钮消都大概15MS 消抖完毕无线也唤醒完成,可发送数据
      Uart_Printf_String(USART1, "AT\r\n"); // 在这写无线休眠函数-唤醒模块后 按钮消都大概15MS 消抖完毕无线也唤醒完成,可发送数据
    }
   button_time_out_status.count++;
}


//下面函数是具体的休眠逻辑,在一开始时使用这个单片机调试时也有发生重启问题,但那时考虑可能我代码写的有问题,什么地方没考虑好导致重启,当时换了一颗芯片就好了,当时就没有在意。
首先当时调试时重启问题困扰了我好久,有时候这个函数变量使用idata xdata 这些来进行调试,倒是会触发重启问题,当时未排查到问题。换位u8时又不重启,那时不理解,先暂时用着,
休眠上面的nop循环是给中断或者其他寄存器操作的缓存,主要是在开启中断后怕有些硬件没稳定,串口数据没发送完成等,进入休眠后导致其他问题,添加的延时。
休眠下面的_NOP指令是官方说要加使得系统稳定,执行后后面跟着中断引脚关闭,,中断功能只需要唤醒MCU就可以了,所以在唤醒MCU后中断就可以关掉了。中断处理函数里面没有什么逻辑处理,就是一个NOP指令。主要处理有软件状态机来实现按钮状态的判断。
下面跟着的25个NOP指令是主要的疑问来源,如果修改下面NOP的执行个数这些,会产生不同的效果,如果加多,可能这个有问题的芯片它INT2正常,INT3唤醒会重启也有一个芯片在我调试时在循环里面将调试的引脚放在循环里面跑,
这时芯片能INT2 与 Int3 中断都能触发,且不重启,如果将引脚去掉旧又不正常了,如果你增加循环次数,不删除引脚,那么有可能INT2不能用 INT3能用??如果你将测试引脚去掉,将循环次数加多,可能INT2能用,int3不能用。-----神了------不理解???

不过好在一点就是将源代码烧录进入去问题能复现。可以复现问题。

/*******************************************************************************
    函 数 名:   sys_dormancy()
    函数功能:   系统休眠指令
    备注:严禁修改下面代码任何参数,
    平衡休眠模式与晶体震荡的时间,修改极大概率导致单片机复位,(99%)
    有可能按钮1 有可能按钮2 有可能按钮3 有可能按钮4 延时改变会导致其中一个、
    两个或者3个按下会复位重启,而又不知道问题出在哪。
    变量定义也不要改为 idata 和 xdata 也会导致复位重启。
    ~~~~~~~~~~~~~~~~~~~~~~~~~~阿弥陀佛~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*******************************************************************************/
void sys_dormancy(void)
{
    u8 count;
    EXTI_EA(ENABLE); // 按键外部中断使能
    for (count = 0; count < 250; count++)
      _nop_();
    MCU_POWER_DOWN(); // 进入掉电模式
    _nop_();          // 唤醒后执行这一句后调转中断处理函数
    EXTI_EA(DISABLE); // 按键外部中断禁能
    for (count = 0; count < 25; count++)
      _nop_();
}


下面是我调试的一些过程,我调试顺序忘记了,我就按第一次调试,第二次调试这样述说
第一次调试怀疑中断问题,毕竟在休眠前后只操作中断的开启与关闭,所以将函数里面的:EXTI_EA(ENABLE); EXTI_EA(DISABLE); 这两个去掉,在进入main 初始化时启用中断,不在任何地方操作中断,问题依旧,芯片休眠正常,唤醒还是会重启,int2 int3引脚会重启复位。
第二次调试将代码复原,我怀疑是内部晶振没有起振好,我将休眠后面的for循环里面的的循环修改为1MS 2ms 10ms延时,故障依旧,还是有引脚会唤醒后重启服务,调试未果。
第三次调试我讲代码还原,怀疑是串口问题导致系统复位,将上面代码中的AT唤醒指令注释掉进行调试,系统还是会重启复位。调试未果。
第四次调试我去网上查询,有网友说在休眠唤醒过后要重新初始化串口,我跟着做了,发现还是没有作用,该重启还是会重启。
第五次调试我怀疑看门狗未及时喂狗导致重启,在唤醒后的NOP过后,进行喂狗操作,还是重启。
第六次调试我讲休眠函数去掉,系统能正常工作只是没有休眠,所有功能正常。

附上中断处理函数:

///********************* INT2中断函数 *************************/
void Ext_INT2 (void) interrupt INT2_VECTOR       
{
    _nop_();
}
///********************* INT3中断函数 *************************/
void Ext_INT3 (void) interrupt INT3_VECTOR
{
    _nop_();
       
}

中断开启与关闭函数/************************************************/
/*               外部中断的配置               */
/************************************************/
void EXTI_EA(u8 cmd)
{
        if (cmd == ENABLE)
        {
                // IT0 = 0;        //使能INT0上升沿和下降沿中断
                // IT0 = 1; // 使能INT0下降沿中断
                // EX0 = 1; // 使能INT0中断
                // IT1 = 0;    //使能INT1上升沿和下降沿中断
                // IT1 = 1;                // 使能INT1下降沿中断
                // EX1 = 1;                // 使能INT1中断
                INTCLKO |= EX2; // 使能INT2下降沿中断
                INTCLKO |= EX3; // 使能INT3下降沿中断
                // INTCLKO |= EX4; // 使能INT4下降沿中断
        }
        else
        {
                // EX0 = 0;               // 禁止INT0中断
                // EX1 = 0;               // 禁止INT1中断
                INTCLKO &= ~EX2; // 禁止INT2下降沿中断
                INTCLKO &= ~EX3; // 禁止INT3下降沿中断
                                               // INTCLKO &= ~EX4; // 禁止INT4下降沿中断
        }
}




经过上述调试,我不知道哪里出现问题。有大佬能给点提示或解答吗?
我系统中断有看门狗中断 定时器中断 串口中断 外部中断 其他中断暂时没用到。
STC15W204S要1.5元 STC8G1K08A只要0.85元 在这价格差距下会不会是芯片个别体质原因导致这个问题的发生,因为大部分正常但是个别会有问题。这有问题的芯片不用作本产品拆去在其他地方使用完全也可以使用。


lcwswust 发表于 2026-7-6 15:23:35

是否能排除硬件干扰?比如在唤醒射频模块前后向串口助手发一些数据出来,看唤醒射频模块之前是否正常,或把射频模块去掉,怀疑射频模块启动时的瞬时大电流拉低了电源电压造成复位。

久世浮砚 发表于 2026-7-6 16:09:45

lcwswust 发表于 2026-7-6 15:23
是否能排除硬件干扰?比如在唤醒射频模块前后向串口助手发一些数据出来,看唤醒射频模块之前是否正常,或把 ...

休眠前是正常的,串口数据正常,休眠唤醒后,想使用串口发送数据是发不出的,其实唤醒后等待那25个NOP指令后,会发送两个AT指令,但是芯片还未走到那一步,之前调试,不发串口数据,射频未唤醒,但是还是重启复位了,单片机电源引脚有一个100nf和10uf电容,射频芯片也同样规格。使用3V电池供电。芯片电压要低于2V电压才会死机,因该不是电压问题

神农鼎 发表于 2026-7-7 12:27:29


神农鼎 发表于 2026-7-7 12:27:46

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

久世浮砚 发表于 2026-7-9 09:21:12

神农鼎 发表于 2026-7-7 12:27
好的,我已经完整阅读了该帖子的内容,并结合 STC8G 系列手册(F17)中的相关信息,下面给出专业分析。

问 ...
1,所以IO均已用上且初始化,芯片休眠后耗电2ua左右,加上射频 共7ua
2,中断引脚也使用上拉输入,在中断处理函数里面理论上是硬件自动清标志位,但是手动清楚,有部分有问题的芯片int2引脚可以正常唤醒,有一个会发生其他问题,比如我发送数据发送两次,还有一个完全唤醒不了。
3,关于看门狗,在调试中也考虑过该问题,在异常芯片唤醒时喂狗,也会导致重启问题。
4,唤醒后NOP延时,手册中值说加一些,一开始直接直接写NOP,后面使用for循环延时,软件延时也使用过,还是有重启现象。
电源跌落,芯片在唤醒时,总消耗电流月150ma左右,芯片配置100nf 与 10uf 电容 射频也有100nf 与 10uf 电容,在唤醒时电压跌0.1mv左右,唤醒流程先唤醒主芯片,等待系统稳定后再唤醒射频,且芯片2V以下才会复位,也未开启低压复位中断。

问过AI,说这批次有问题 。

只要换个正常的芯片,设备功能就没有问题。

神农鼎 发表于 2026-7-9 09:27:15









神农鼎 发表于 2026-7-9 09:28:32


页: [1]
查看完整版本: STC8G1K08系列休眠问题