STM32マイコン入門|GPIO制御・タイマー・割り込みの基礎をHALライブラリで学ぶ
2026年5月時点、ARM Cortex-M 系の STM32 を題材に、HAL を使った GPIO・タイマー・割込コールバックの読みどころを整理します。組み込み初学者や HAL から触る人向けで、シリーズ/型番ごとにクロックやバスが違う前提で、最終確認は STM32CubeMX とリファレンスマニュアルに寄せます。
読み進める前提:クロックツリーが一度、データシートと実機の挙動が一致するところまで通っていること。確認のコツは、UART か SWO で周期・デューティ・GPIO トグルを数値ログで1本取ること。うまくいかない典型は、クロックゲート未解放のまま GPIO だけ触る、ISR に処理を詰め込みすぎる、最適化でウォッチが嘘をつく、などです。
メモリ配置の考え方は [メモリマップ入門|組み込みエンジニアが知るべきメモリ配置とリンカスクリプト](/posts/memory-map-explained/) と通じますが、ベクタ表・リンカシンボルは教材より Cube/BSP 生成物を正にしてください。
STM32のシリーズは何を基準に選べばいい?
STM32 は ST の ARM コア MCU ファミリーで、シリーズごとに性能と周辺 IP が異なります(数値はデータシートで必ず確認)。
- STM32F0/F1(Cortex-M0/M3):エントリー向け。実効クロック〜数十MHz帯など低〜中性能の構成が多い
- STM32F4(Cortex-M4):単精度FPU を持つ構成が多く、PWM や処理余力のある処理向き。最大180MHz級などデータシートの範囲は型番依存
- STM32H7(Cortex-M7):高クロック構成が多く、画像や通信処理の親機向きにも使われる
- STM32L4(Cortex-M4):抑えめ消費電力寄り。性能と消費のトレードオフはブロック設計依存
開発に最低限そろえるものは?
- STM32CubeMX:GUI でペリフェラル設定と HAL コード生成を行う無料ツール。ピン配置やクロック設定をビジュアルに行える(公式)
- STM32CubeIDE:Eclipse ベースの統合開発環境(無料)。CubeMX 統合済み
- ST-Link:デバッガ/プログラマ。Nucleoボードには搭載済み
GPIO を触る前に何を必ずする?
GPIO は LED やボタンなど外部との入出力口です。STM32 では触る前に必ずクロック有効化が必要、という順番を忘れがちです。
/* GPIO初期化: PA5を出力(プッシュプル)として設定 */
void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // クロック有効化が必須
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* LED制御 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // 点灯
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 消灯
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 反転 GPIOモード一覧
- OUTPUT_PP(プッシュプル):LED駆動など一般用途
- OUTPUT_OD(オープンドレイン):I2Cバスなどプルアップ必要な用途
- INPUT:ボタン読み取り等のデジタル入力
- IT_RISING / IT_FALLING:エッジ検出で割り込みを発生
- AF_PP(オルタネートファンクション):UART/SPI/I2C等のペリフェラル接続用
タイマ周期と PWM の数値はどこで確かめる?
タイマーは時間計測・PWM・イベントカウントに使います。数値の当てはめは次の式と CubeMX のクロック表示をセットで見てください。
周期や PWM の数値は (Prescaler+1)×(Period+1) と、タイマに供給される実クロック(APB プリスケーラ等を踏まえた値)で決まります。下の数字は読みどころ用の一例であり、自分の MCU では CubeMX のクロックツリーで確認してください。
周期 = (Prescaler + 1) × (Period + 1) / タイマークロック
例: 1秒間隔(タイマークロック 84MHz)
Prescaler = 83 → 84MHz / 84 = 1MHz
Period = 999999 → 1MHz / 1000000 = 1Hz(1秒)
例: 1kHz PWM(デューティ比50%)
Prescaler = 83 → 1MHz
Period = 999 → 1kHz
Pulse = 500 → 50% duty PWM出力のコード例(数値もプロジェクト依存)
htim3.Instance = TIM3;
htim3.Init.Prescaler = 84 - 1; // 1MHz
htim3.Init.Period = 1000 - 1; // 1kHz PWM
HAL_TIM_PWM_Init(&htim3);
sConfigOC.Pulse = 500; // 50% duty
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); 割り込みに書く処理の線引きは?
割り込みは、外部イベントやタイマーによって通常の処理を一時中断し、緊急度の高い処理を実行する仕組みです。STM32ではHALのコールバック関数で割り込み処理を記述します。
/* タイマー割り込みコールバック */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // LED反転
}
}
/* GPIO外部割り込みコールバック */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_13) {
// ボタン押下時の処理
}
} まずどこにログを出して切り分ける?
- UART経由のprintf:HAL_UART_Transmit()で変数値やステータスを確認
- SWV(Serial Wire Viewer):ITM_SendChar()でprintf出力をSWO経由でリアルタイム表示
- ブレークポイント:デバッガでウォッチ(最適化 -O2 では見え方が変わることも)
まとめ:持ち帰りチェック(CubeMX とデータシートを正に)
- STM32 は CubeMX でクロックとバスを固めてから HAL の数字を信じるのが安全
- GPIO は クロックゲート有効化が手順の最初
- タイマーは Prescaler×Period と 実効タイマクロックのセットで読む
- ISR は短く、重い処理はメインやタスクへ