マイコンでボタンやセンサーなどの変化を検出するとき、何度も状態を確認する方法だけでなく、変化が発生した瞬間に処理を開始する「割り込み」という仕組みがあります。
割り込みを使うと、通常のプログラムを実行しながら、ボタン入力などのイベントが発生したときに専用の処理を実行できます。
この記事では、割り込み処理の基本から、ポーリングとの違い、ISR、RISING・FALLINGといった割り込み条件、Arduino・ESP32でGPIO割り込みを使用する方法まで解説します。
割り込み処理とは?
割り込み(Interrupt)とは、特定のイベントが発生したときに、実行中の処理を一時的に中断して、別の処理を実行する仕組みです。
たとえばマイコンが通常の処理を実行している途中で、GPIOに接続されたボタンが押されたとします。
そのGPIOに割り込みを設定しておけば、ボタン入力の変化をきっかけとして割り込み処理を実行できます。
- 通常の処理を実行する
- ボタンなどのイベントが発生する
- 通常処理を一時中断する
- 割り込み処理を実行する
- 割り込み処理が終わったら元の処理へ戻る
この一連の動作が、割り込み処理の基本です。
上図①のように、割り込みが発生すると通常処理を一時中断して割り込み処理を実行し、終了後に元の処理へ戻ります。図②ではポーリングとの違い、図③ではGPIOにボタンを接続した場合の具体例を示しています。
ポーリングとは?
割り込みと比較されることが多い方法がポーリング(Polling)です。
ポーリングでは、プログラム側から入力の状態を繰り返し確認します。
たとえばArduinoでボタンの状態を確認する場合、次のような処理が考えられます。
void loop() {
if (digitalRead(BUTTON_PIN) == LOW) {
// ボタンが押されたときの処理
}
}
loop()が繰り返されるたびに、digitalRead()を使ってボタンの状態を確認しています。
このように、プログラムから定期的に機器や入力の状態を確認する方法をポーリングと呼びます。
ポーリングと割り込みの違い
ポーリングと割り込みでは、イベントを検出する考え方が異なります。
| ポーリング | 割り込み | |
|---|---|---|
| 検出方法 | プログラムから状態を確認する | イベント発生によって処理が開始される |
| 処理 | 繰り返し確認する | 必要なときに実行する |
| プログラム | 比較的分かりやすい | 割り込みを意識した設計が必要 |
| 向いている用途 | 定期的な状態確認 | 素早く検出したいイベントなど |
割り込みが常にポーリングより優れているわけではありません。処理内容や必要な応答速度などに応じて使い分けます。
ISR(割り込みサービスルーチン)とは?
割り込みが発生したときに実行される処理をISR(Interrupt Service Routine:割り込みサービスルーチン)と呼びます。
たとえばボタンが押されたことをGPIO割り込みで検出した場合、ISRでは「ボタンが押された」という情報を記録します。
ISRでは一般に、できるだけ短時間で処理を終わらせることが重要です。
時間のかかる処理をISR内ですべて実行するのではなく、フラグだけを変更し、実際の処理を通常のプログラム側で行う方法がよく使われます。
割り込みではフラグを使う
たとえば、ボタンが押されたらLEDの処理を行いたい場合を考えてみましょう。
ISRの中で複雑な処理を行うのではなく、次のようにフラグを変更します。
volatile bool buttonFlag = false;
void buttonISR() {
buttonFlag = true;
}
通常処理側では、このフラグを確認します。
void loop() {
if (buttonFlag) {
buttonFlag = false;
// 実際に行いたい処理
}
}
こうすることで、ISR自体を短く保ち、時間のかかる処理を通常処理側で実行できます。
volatileとは?
割り込み処理と通常処理の両方から使用する変数では、volatileが登場することがあります。
volatile bool buttonFlag = false;
volatileは、その変数の値がプログラムの通常の流れとは別の要因によって変更される可能性があることをコンパイラへ伝えるための指定です。
ISRによって値が変更される変数はその代表例です。
ただし、volatileを付けるだけで複数の処理からのアクセスがすべて安全になるわけではありません。複数バイトのデータや複雑な共有処理では、排他制御やクリティカルセクションなどが必要になる場合があります。
GPIO割り込みとは?
初心者が割り込みを試す場合、分かりやすいのがGPIO割り込みです。
GPIO入力がHIGHからLOW、またはLOWからHIGHへ変化したことをきっかけとして割り込みを発生させます。
GPIOの基本については「GPIOとは?マイコンの入力・出力の仕組みを初心者向けに解説」でも詳しく解説しています。
RISING・FALLING・CHANGEとは?
GPIO割り込みでは、「信号がどのように変化したときに割り込みを発生させるか」を設定できます。
| 設定 | 意味 |
|---|---|
| RISING | LOW → HIGHになったとき |
| FALLING | HIGH → LOWになったとき |
| CHANGE | HIGHとLOWが切り替わったとき |
たとえば内部プルアップを使用して、ボタンを押したときにGPIOがGNDへ接続される回路では、通常時はHIGH、押した瞬間にLOWになります。
そのため、ボタンを押した瞬間を検出したい場合はFALLINGを利用できます。
KUMITATE-C3で割り込みを試してみる
KUMITATE-C3はESP32-C3を搭載しているため、GPIO割り込みを使ったプログラムも試すことができます。
ESP32のArduino環境では、attachInterrupt()を使ってGPIOに割り込み処理を設定できます。
const int BUTTON_PIN = 21;
volatile bool buttonFlag = false;
void buttonISR() {
buttonFlag = true;
}
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(
BUTTON_PIN,
buttonISR,
FALLING
);
}
void loop() {
if (buttonFlag) {
buttonFlag = false;
Serial.println("ボタンが押されました");
}
}
この例では、GPIO21を内部プルアップ付きの入力として設定し、HIGHからLOWへ変化したときにbuttonISR()が呼び出されます。
ISRではbuttonFlagをtrueにするだけにして、シリアル出力はloop()側で行っています。
ISRの中では重い処理を避ける
割り込み処理を使うときは、ISRをできるだけ短くすることを意識します。
ISRの中で長時間処理を続けると、通常処理やほかの割り込み処理に影響する可能性があります。
そのため、ISRでは次のような最低限の処理だけを行い、実際の処理は通常処理側へ渡す設計がよく使われます。
- フラグを立てる
- カウンタを更新する
- 必要なデータを保存する
- 後続処理へイベントを伝える
使用するマイコンや開発環境によって、ISR内から安全に利用できる関数やAPIには制約があります。
ボタン割り込みではチャタリングにも注意
ボタンをGPIO割り込みで検出するときに問題になりやすいのがチャタリングです。
機械式スイッチは、ボタンを1回押しただけでも接点が瞬間的に何度もON・OFFすることがあります。
その結果、1回押しただけなのに複数回の割り込みが発生する場合があります。
これを防ぐために、ソフトウェアまたは回路によるチャタリング対策(デバウンス)を行います。
チャタリングについては、別の記事で詳しく解説します。
割り込みはGPIO以外でも使われる
割り込みはボタンなどのGPIO入力だけで使われる機能ではありません。
- タイマー
- UART通信
- SPI通信
- I2C通信
- ADC
- 各種周辺回路
など、マイコン内部のさまざまな周辺機能でも割り込みが利用されています。
組み込み開発では「何かが起きるまでCPUがずっと待つ」のではなく、通常処理を進めながら必要なイベントへ対応するために割り込みが重要な役割を持っています。
割り込みがうまく動かないときの確認ポイント
- 使用しているGPIOが割り込みに対応しているか
- GPIOの入力設定が正しいか
- RISING・FALLING・CHANGEの設定が目的と合っているか
- プルアップ・プルダウンが適切か
- 入力端子が浮いていないか
- チャタリングによって複数回発生していないか
- ISR内で時間のかかる処理をしていないか
- 共有する変数の扱いが適切か
まとめ
割り込みは、特定のイベントが発生したときに通常処理を一時中断し、専用の処理を実行する仕組みです。
- 割り込みはイベント発生をきっかけに処理を開始する
- 割り込み時に実行する処理をISRと呼ぶ
- ISR終了後は通常の処理へ戻る
- ポーリングはプログラム側から繰り返し状態を確認する
- GPIO割り込みではRISING・FALLING・CHANGEなどを利用できる
- ISRはできるだけ短くする
- 時間のかかる処理は通常処理側で行う
- ボタン入力ではチャタリングにも注意する
割り込みを理解すると、ボタン入力だけでなく、タイマーや通信など、マイコンがさまざまなイベントへどのように対応しているのか理解しやすくなります。

