組み込みシステムにおけるC言語のI/O割り込み入門:仕組みと実装パターン
組み込みシステムの開発では、外部からの入力(スイッチ、センサー、通信など)に即座に反応する必要があります。こうしたイベントに効率よく対応する仕組みとして、I/O割り込み(Input/Output Interrupt)が活用されます。
本記事では、C言語でのI/O割り込みの基礎、割り込みハンドラの実装方法、代表的なマイコンでの使用例を通して、組み込み開発における割り込み制御をわかりやすく解説します。
1. 割り込みとは?
割り込みの基本
割り込みとは、外部または内部のイベントが発生した際に、現在のプログラムの流れを一時的に中断し、割り込み処理(ISR)を実行する仕組みです。
種類 | 例 |
---|---|
外部割り込み | GPIOピンの立ち上がり・立ち下がり、ボタン押下 |
内部割り込み | タイマ割り込み、UART受信完了、ADC変換完了など |
2. ポーリングと割り込みの違い
特徴 | ポーリング | 割り込み |
---|---|---|
処理方法 | 常に状態をチェック | イベント発生時に自動で処理呼び出し |
CPU負荷 | 高い(無駄なループが発生) | 軽い(必要時のみ処理) |
応答速度 | 遅延あり | 高速応答 |
実装の複雑度 | 低め | 高め(割り込み管理が必要) |
3. C言語での割り込みハンドラ実装の基本構造
割り込み処理は、通常「割り込みベクタテーブル」に登録された関数によって処理されます。
例:AVRマイコン(ATmega328pなど)での外部割り込み
#include <avr/io.h> #include <avr/interrupt.h> void init_interrupt() { EIMSK |= (1 << INT0); // INT0割り込み許可 EICRA |= (1 << ISC01); // フォールトリガ(低→高) sei(); // 全体の割り込みを有効にする } ISR(INT0_vect) { // 割り込み時の処理 PORTB ^= (1 << PB0); // LEDトグル }
4. 割り込みの流れ(一般的なマイコン)
- ハードウェアイベント(例:GPIO変化)
- 割り込みコントローラが対応する割り込みラインをアクティブに
- CPUは現在の処理を一時保存し、ISR(割り込みハンドラ)へジャンプ
- ISR終了後、元の処理へリターン
5. 実践例:タイマ割り込み + UART送信(STM32 HAL)
// HAL_TIM_PeriodElapsedCallback(タイマ割り込み)を使う void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { HAL_UART_Transmit(&huart2, (uint8_t*)"Hello\r\n", 7, 100); } }
→ 定期的なタイマ割り込みにより、UARTでメッセージを送信
6. 注意点とベストプラクティス
注意点
ベストプラクティス
- フラグ変数でイベントを記録 → メインループで処理
- 周辺モジュール(UART, SPI)との併用時は、DMA+割り込み併用を検討
- デバッガ対応のため、ISR内に
breakpoint
を多用しない(割り込みハングの原因)
7. よく使うマイコン別の割り込みAPI例
マイコン | 使用API例 | 特徴 |
---|---|---|
AVR(Arduino) | ISR() + sei() / cli() |
C言語で直接制御しやすい |
STM32 (HAL) | HAL_XXX_IRQHandler() |
CMSIS+HAL抽象化レイヤー |
Renesas RX | __interrupt + vector定義 |
コンパイラ依存強め |
ESP32(ESP-IDF) | gpio_install_isr_service() |
FreeRTOSベースで複雑 |
8. まとめ
- 割り込みは、組み込みシステムにおけるリアルタイム処理の要
- C言語での割り込み制御はマイコンごとに違いがあるが、基本概念は共通
- ISRは軽量・短時間・副作用最小限で設計する
- 複雑な処理や同期が必要な場合は、RTOS導入も視野に
参考リンク
参考書籍
リンク
リンク
リンク