首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

STM32 中斷後軟件復位返回 main 函數實踐與避坑

     編輯:關於C語言

STM32 中斷後軟件復位返回 main 函數實踐與避坑

應用場景

長時間運行任務(如電機運動、數據采集)需支持用戶中途取消並重置系統。方案:配置外部中斷(如按鍵),在 ISR 中觸發軟件復位,系統重新從 main() 執行。

核心代碼

void EXTI_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_LineX) != RESET) {
        EXTI_ClearITPendingBit(EXTI_LineX);
        __set_FAULTMASK(1);        // 關閉所有中斷,防止復位過程被打斷
        NVIC_SystemReset();        // 請求系統復位
    }
}

關鍵點解析

  • __set_FAULTMASK(1):設置 Fault Mask 寄存器,屏蔽所有可屏蔽中斷與 Fault 異常,保證復位序列原子性。
  • NVIC_SystemReset():向 SCB->AIRCR 寫入 VECTKEY | SYSRESETREQ,觸發內核級系統復位(等效於按下復位鍵)。

遇到的問題與解決

問題 1:卡在 NVIC_SystemReset() 的 while(1) 死循環

static __INLINE void NVIC_SystemReset(void) {
    SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
                  (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
                  SCB_AIRCR_SYSRESETREQ_Msk);
    __DSB();
    while(1);  // 等待復位發生
}

現象:程序停在 while(1),復位未發生。
原因:硬件復位電路(如 SP809 復位芯片)干擾內核復位請求,導致 NRST 引腳無法被內核拉低。
解決**:移除板載復位芯片(SP809),改用 MCU 內部復位電路或簡單 RC 復位電路。
注意**:同事另一項目同款復位芯片卻正常工作,具體差異待進一步分析(可能涉及電源序列、電容充放電時間等)。

問題 2:單次中斷觸發進入兩次 ISR

現象**:按鍵按下一次,EXTI_IRQHandler 執行兩次。
解決**:在 ISR 入口立即關閉該外部中斷通道(EXTI->IMR &= ~EXTI_LineX),ISR 末尾重新開啟(EXTI->IMR |= EXTI_LineX)。
根因分析**:ST 官方 FAQ 指出,若中斷標誌位清除過晚,外設可能再次觸發。嘗試將 EXTI_ClearITPendingBit 前移仍無效,最終採用「進 ISR 即屏蔽中斷」策略繞過。具體硬件時序原因待深究。

最佳實踐總結

  1. ISR 中**第一時間**清除中斷標誌位,並**立即屏蔽該中斷源**,防止重入。
  2. 調用 NVIC_SystemReset() 前**務必**關閉全局中斷(__set_FAULTMASK(1) 或 __disable_irq())。
  3. 若系統復位失效,排查硬件復位電路是否干擾 NRST 線(特別是專用復位芯片)。
  4. 考慮使用「軟件標誌位 + Watchdog 復位」替代方案:ISR 置標誌位 → 主循環檢測到標誌 → 飼狗超時復位,避免在 ISR 中直接操作復位寄存器。

總結

STM32 軟件復位雖有標準庫函數,但硬件復位電路干擾、中斷重入等實際工程問題需具體分析。「ISR 屏蔽中斷 + 關全局中斷 + 復位請求」是相對穩健的組合拳;若條件允許,優先考慮主循環協作式復位,避免在中斷上下文執行復位操作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved