|

【CIRCUS Pi】ESP32教學系列:硬體中斷

   
作者/圖片來源:CIRCUS Pi

常見的微控制器系列,例如Arduino的ATmega系列(像是ATmega328P)、STM32系列、PIC系列,或是ESP32,通常都支援多種不同的中斷類型。ESP32可以用硬體中斷來處理外部硬體或模組引起的中斷,像是GPIO或是觸碰(TOUGH)中斷;用軟體中斷處理定時器中斷,本篇主要說明的是硬體中斷。

什麼是中斷?

中斷(Interrupt)是一種在微控制器在執行主要工作時,仍然能夠立即回應外部事件的一種機制。一個設計得當的中斷,不僅可以簡化程式邏輯,還能提高處理器的執行效率。我們可以用中斷來偵測開關、旋轉編碼器,或是光遮斷器等的變化。要理解中斷,讓我們先用一個例子來說明。

假如要偵測一個按鈕是否被按下,我們可能會這樣寫:

int buttonPin = 25; // 將按鈕連接到 GPIO 25

bool buttonState = 0;

void setup() {

pinMode(buttonPin, INPUT);

}

void loop() {

// 反覆檢查按鈕狀態

buttonState = digitalRead(buttonPin);

if (buttonState == HIGH) {

// 執行按下按鈕的相應處理

delay(30); // 避免開關彈跳

}

// 執行主程式的其他任務

// ...

}

像這樣依照程式流程定時且反覆檢查數值的方法就稱做輪詢。在不使用中斷的情況下,通常會使用輪詢來檢查外部事件,優點是程式寫起來直覺、好理解,但是這其實會讓ESP32的CPU在很低的效率下運作,因為系統需要在主程式迴圈中不斷的檢查GPIO的狀態。如果主程式區塊還有很多需要處理的任務,檢查的速度也會變慢。

而使用中斷的好處是,只要特定的接腳偵測到狀態發生變化,就能立即「中斷」CPU現在正在做的事情,優先處理目前的事件下要完成的任務。

換句話說,中斷機制允許系統只在事件發生時才進行處理,這麼一來就能節省不必要的處理器運算和電力消耗,而我們也能確保特定事件發生時可以被即時的處理,是不是一舉多得呢?

ISR(Interrupt Survice Routine)

從上面的例子中,我們可以知道中斷的核心概念是「事件驅動」。當有更優先、更需要即時處理的事件發生時,CPU就能夠在最短的時間內反應並且處理完畢,不需要經過輪詢的等待時間。

當中斷發生時,CPU會暫時停止執行主程式,轉而執行相應的處理程序。用中斷的術語來說,這個處理程序叫做「中斷服務程序 (Interrupt Survice Routine, ISR)」。 ISR是專門用來處理中斷事件的一段特殊函式,負責處理中斷發生後要執行的任務或是操作,它不能傳入任何參數,也不會回傳任何內容。當ISR完成任務後,CPU會返回主程式繼續執行原本的程式。

ISR具有以下特點:

  • CPU一次只能處理一個ISR;
  • 發生多個中斷時,會依照ISR的優先順序執行;
  • 每個ISR都專注於處理特定的事件;
  • ISR越簡單越好,要盡可能保持很短的執行時間,才能減少對系統的干擾;
  • 處理中斷時,通常會使用全域變數在ISR和主程式之間傳遞資料,為了確保ISR跟主程式共享的變數可以正常更新,會將變數宣告成volatile型態(讓變數可以被多個執行緒訪問)。

ESP32的GPIO中斷

ESP32的內部使用中斷矩陣來處理許多不同的中斷來源。

所有ESP32能使用的GPIO都可以拿來當作GPIO中斷接腳,其中10隻接腳支援觸碰感測器(touch sensor)中斷(請參考進階功能章節)。

接下來說明中斷常用的語法:

設定中斷

在Arduino IDE中,我們透過將GPIO接腳與對應的ISR函式綁定來啟用中斷,設定中斷時可以使用 attachInterrupt

attachInterrupt(GPIO_pin, ISR, mode);

參數說明:

  • GPIO_pin: 將其設定為中斷接腳
  • ISR: 當此中斷發生後要執行的ISR函式
  • mode: 定義中斷觸發的條件。有八種模式可以選擇。

//Interrupt Modes

#define DISABLED 0x00

#define RISING 0x01

#define FALLING 0x02

#define CHANGE 0x03

#define ONLOW 0x04

#define ONHIGH 0x05

#define ONLOW_WE 0x0C

#define ONHIGH_WE 0x0D

 

Tips:

在Arduino-esp32核心函式庫的esp32-hal-gpio.h檔案中可以找到這些模式的定義。

說明:

  • DISABLED: 禁用GPIO中斷
  • RISING: 上升邊沿觸發(rising edge trigger)
  • FALLING: 下降邊沿觸發(falling edge trigger)
  • CHANGE: 任意邊沿觸發 (any edge trigger)
  • ONLOW: 低電位觸發(low level trigger)
  • ONHIGH: 高電位觸發(high level trigger)
  • ONLOW_WE和ONHIGH_WE是當ESP32在 Light-sleep模式下用來喚醒CPU的中斷,一般比較少使用到。”WE”是wakeup enable的縮寫。

關閉中斷

detachInterrupt語法可以用來關閉中斷,取消ESP32對特定接腳的監聽。

detachInterrupt(GPIO_pin);

當我們關閉特定接腳的中斷時,需要再次呼叫attachInterrupt 或是重新啟動系統才能重新啟用中斷。

中斷服務程序(ISR)

ISR函式會在中斷被呼叫時執行,它的語法結構看起來會像這樣:

void IRAM_ATTR ISR() {

// 中斷函式內容

}

其中ISR是自訂的函式名稱,而IRAM_ATTR的意思是將ISR函式存放在IRAM(Instruction RAM),而不是flash。從IRAM讀取ISR 函式可以加快載入速度。

接下來,讓我們用實際的範例來了解如何使用GPIO中斷。

範例1:使用按鈕改變LED狀態

這個範例使用按鈕觸發ESP32的GPIO中斷,當按鈕狀態有變化(上升或下降)時,LED的狀態也會跟著改變。

本文為會員限定文章

立即加入會員! 全站文章無限看~

                               

已經是會員? 按此登入

只需不到短短一分鐘...

輸入您的信箱與ID註冊即可享有一切福利!

會員福利
1

免費電子報

2

會員搶先看

3

主題訂閱

4

好文收藏

CIRCUS Pi

Author: CIRCUS Pi

分享有趣的創作與教學,提供Maker們創作的軍火庫,DIY 零件 | 套件| 工具,官網連結

Share This Post On

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *