Pico WのPIOの割り込み機能をプッシュスイッチと3つのLEDの点灯・消灯で確認しよう。

【 当サイトには広告リンクが含まれています。 】


Raspberry Pi Pico W(以下 PicoW)にはメインプロセッサとは独立して動作する、Programmable Input/Output(以下 PIO)と呼ばれる2機のプロセッサがあります。

それぞれのPIOにはステートマシンと呼ばれる、4個の独立して動作する処理ユニットがあり、PIO用のアセンブラ(以下 PIOASM)を使ってGPIOを制御できます。

センサー等の電子部品をPicoWに複数接続して処理する場合、一部の電子部品の制御に処理時間を取られ、別の電子部品の処理に支障をきたす場合があります。

たとえば、LEDとスイッチをPicoWに接続し、LEDの制御に時間を取られた場合、スイッチからの入力を検知できないことが考えられます。

PIOでスイッチ等の一部の電子部品を制御することで、この問題を解決することができます。

このようにPIOはI/Oに特化したプロセッサと言えます。

詳細はRP2040 Datasheet: A microcontroller by Raspberry Piを参照してください。

GPIOピン(以下 GPピン)にプッシュスイッチと赤、緑、青の3つのLEDを接続し、プッシュスイッチでPIO機能の割込みを発生させて、赤、緑、青の3つのLEDを制御するプログラムをC/C++で作成します。

赤と緑のLEDが500ms間隔で交互に点灯・消灯をしている途中で、プッシュスイッチを押すと、赤と緑のLEDの点灯・消灯が停止します。

その後、青のLEDが500ms間隔で点灯・消灯を3回繰り返した後、消灯し、再び赤と緑のLEDが500ms間隔で交互に点灯・消灯します。




実験準備

実験に必要な機器と部品を準備します。

機器

「Windows PCとC/C++でRaspberry Pi Pico Wの開発を始めよう。」記事で書きましたラズパイPicoWと、Visual Studio Code(以下 VSCode)をインストールしたWindows PCを準備します。


使う部品

LED(発光ダイオード)、固定抵抗など実験に使う部品を準備します。

部 品 名規 格数 量取扱い店(参考)
LED5mm 赤色1電子工作ステーション
LED5mm 緑色1電子工作ステーション
LED5mm 青色1電子工作ステーション
タクトスイッチ高さ5mm1電子工作ステーション
カーボン抵抗1/4W 330Ω3電子工作ステーション
ブレッドボード830穴
(訳アリ品を除く)
1電子工作ステーション
ジャンパーワイヤオス-メス(約20cm)1電子工作ステーション


配線

GPIOピン(以下 GPピン)に接続された2つのLEDを、PIOを使って交互に点灯、消灯させるプログラムをC/C++で作成します。

配線リスト

ラズパイPicoWのGPピンと抵抗、LED、プッシュスイッチを接続します。

ラズパイPicoW部 品部 品
GP26カーボン抵抗 R1LED1 アノード(足の長い方)
GP27カーボン抵抗 R2LED2 アノード(足の長い方)
GP16カーボン抵抗 R3LED3 アノード(足の長い方)
GP17SW 2
GNDSW 1
GNDLED1 カソード(足の短い方)
GNDLED2 カソード(足の短い方)
GNDLED3 カソード(足の短い方)


配線図



ライセンス

プロジェクトのビルドに必要なソースファイル、ソースコードをビルドするための設定ファイル等は、3条項BSDライセンスのもとで配布します。

3条項BSDライセンスの概要(意訳)は次のとおりです。

  • サンプルファイルのソースコードまたはバイナリ形式の再配布時には、著作権表示とライセンス条文を記載(SPDX-License-Identifier: BSD-3-Clauseなど)してください。

  • サンプルファイルはコピー/配布/変更/変更後の配布/商用利用/有料販売など、自由に使うことができます。

  • 書面による許可なしに、サンプルファイルから派生した製品の宣伝や販促に、本ライセンス記載の組織や貢献者(ラズパイ実験室)の名前を使うことはできません。

  • サンプルファイルにはなんの保証もついていません。
    サンプルファイルを利用し、なにか問題が発生した場合でも、作者(ラズパイ実験室)は一切の責任を負いませんので、使用に伴うリスクを理解し、自己責任で利用してください。


プロジェクト

GPIOに接続した2つのLEDを交互に点灯・消灯させるプロジェクト(pio_switch)をVSCodeのC/C++を使って作成します。

pio_switchプロジェクトは、コンパイルに必要な、ソースファイル(pio_switch.c)、ソースコードをビルドするための設定ファイル(CMakeLists.txt)、PicoのSDKインポート用のファイル(pico_sdk_import.cmake)で構成されています。

ソースコードをVSCodeにコピーしてビルドします。

プロジェクト・フォーマットの作成

プロジェクト作成のためのフォーマットを作成します。

作成方法については、こちらを参照してください。

「Basic Setting」は以下のように設定します。

項 目説 明
Namepio_switch
Board typePico W
Location任意(全角文字、半角カタカナが含まれていないこと。)
※自身のユーザ内に任意のファルダを作成します。
Select Pico SDK versionv2.1.1
FeaturesPIO interface :✔
Stdio supportConsole over UART :✔

「build」の中に「build.ninja」が存在し、2つのソースコード、「pio_switch.c」と「blink.pio」が作成されていることを確認します。


プロジェクトの作成

作成したプロジェクト・フォーマットに、ソースコードを入力またはコピーして、プロジェクトを作成します。

▶️pio_switch.cの作成

  1. 「エクスプローラー」アイコンをクリックして、「pio_switch.c」を表示します

  2. 現在、VSCodeに表示されている内容をすべて削除します

  3. 下記「pio_switch.c」のソースコードを入力またはコピー/貼り付けし保存します


pio_switch.c

//
// Copyright (c) 2025 ラズパイ実験室
//
// SPDX-License-Identifier: BSD-3-Clause
//

//********************************
//
//PIO機能でプッシュスイッチの割り込み処理 
//
//********************************

#include <stdio.h>
#include <stdbool.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "mypio1.pio.h"

//プッシュスイッチ接続 GPIOピン基準番号
#define INPUT_PIN_BASE 17

//Lプッシュスイッチ接続 GPIOピン数
#define NUM_INPUT_PIN 1

//クロック分周値(125000000Hz / 62500 = 2000Hz)
#define CLOCK_DIV 62500

//メイン処理で使うGPIOピン
#define LED_PIN_RED 27
#define LED_PIN_GREEN 26
#define LED_PIN_BLUE 16

//割り込みフラグ クリア
int blue_led_flg = 0;

//プッシュスイッチの割り込みハンドラ
void pio0_pushsw() {
    irq_clear(PIO0_IRQ_0);
    pio0_hw->irq = 1;

    // 割り込みが視覚的に分かるようにLEDを光らせる
    if (blue_led_flg == 0)
    {
        //割り込みフラグ セット
        blue_led_flg = 1;
    }
    else
    {
        //割り込みフラグ クリア
        blue_led_flg = 0;
    }
   
}

int main()
{
    stdio_init_all();
    
    //メイン処理で使うLEDピン 初期化
    gpio_init(LED_PIN_RED);
    gpio_init(LED_PIN_GREEN);   
    gpio_init(LED_PIN_BLUE);  

    //メイン処理で使うLEDピンを出力ピンに設定
    gpio_set_dir(LED_PIN_RED, GPIO_OUT);    
    gpio_set_dir(LED_PIN_GREEN, GPIO_OUT); 
    gpio_set_dir(LED_PIN_BLUE, GPIO_OUT); 

    //プッシュスイッチピン プルアップ
    gpio_pull_up(INPUT_PIN_BASE);

    //使用するPIO番号を指定
    PIO pio = pio0;
    
    //使用するステートマシン番号を指定
    uint state_machine_id = 0;

    //ステートマシン0からの割り込み(プッシュスイッチ)を有効化

    //IRQ番号(PIO0_IRQ_0:7)に対応した割り込み処理ルーチンを設定
    irq_set_exclusive_handler(PIO0_IRQ_0, pio0_pushsw);
    //割り込みの有効化
    irq_set_enabled(PIO0_IRQ_0, true);
    pio0_hw->inte0 = PIO_IRQ0_INTE_SM0_BITS;

    //指定したPIOの命令モリにプログラムをロードする
    uint offset = pio_add_program(pio, &mypio1_program);
    
    //PIOプログラムの呼び出しと起動
    mypio1_program_init(pio, state_machine_id, offset, INPUT_PIN_BASE, NUM_INPUT_PIN, CLOCK_DIV);
  
    
    //メイン処理
    while (true) {

        //割り込み未発生
        if (blue_led_flg == 0)
        {
            //RED LED点灯
            gpio_put(LED_PIN_RED, 1);
            sleep_ms(500);
            //RED LED消灯
            gpio_put(LED_PIN_RED, 0);
            //GREEN LED点灯
            gpio_put(LED_PIN_GREEN, 1);
            sleep_ms(500);
            //GREEN LED消灯
            gpio_put(LED_PIN_GREEN, 0);
        }
        else
        {
            //割り込み発生
            int i;
            for (i = 0; i < 3; i++)
            {
                gpio_put(LED_PIN_BLUE, 1);
                sleep_ms(500);
                gpio_put(LED_PIN_BLUE, 0);
                sleep_ms(500);
            }

            //割り込みフラグ クリア
            blue_led_flg = 0;
        }
      
    }
}


▶️ mypio1.pioの作成

  1. 「エクスプローラー」に表示されている「blink.pio」の名前を、右クリックして「mypio1.pio」に変更します
  2. 現在、VSCodeに表示されている「mypio1.pio」の内容をすべて削除します

  3. 下記「mypio1.pio」のソースコードを入力またはコピー/貼り付けし保存します



mypio1.pio

//
// Copyright (c) 2025 ラズパイ実験室
//
// SPDX-License-Identifier: BSD-3-Clause
//

.program mypio1

//.wrap_target~.wrap間の処理を繰り返し実行
.wrap_target

    //プッシュスイッチが押される(High → Low)まで待つ
    wait 0 pin 0

    //チャタリング吸収(96ステップ X 0.5ms = 48ms)
    nop [31]
    nop [31]
    nop [31]
 
    //プッシュスイッチの割り込みを発生させる
    irq 0

    //プッシュスイッチが離される(Low → High)まで待つ
    wait 1 pin 0

     //チャタリング吸収(96ステップ X 0.5ms = 48ms)   
    nop [31]
    nop [31]
    nop [31]

.wrap 
 

% c-sdk {

//GPIO出力を設定して、SMが指定されたピンに出力するように設定
 static inline void mypio1_program_init(PIO pio, uint sm, uint offset, uint input_pin, uint num_input_pin, float clkdiv){

   
    //指定したPIOステートマシンの初期設定情報をメモリに格納する
    pio_sm_config config = mypio1_program_get_default_config(offset);

    
    //ステートマシンのクロック分周値を設定する。125000000Hz / clkdiv(62500) = 2000Hz
    sm_config_set_clkdiv(&config, clkdiv);


    //GPIOをPIOに割り当てる
    pio_gpio_init(pio, input_pin);


    //指定したPIOで使用するステートマシンのGPIOピンの方向を入力に設定する
    pio_sm_set_consecutive_pindirs(pio, sm, input_pin, num_input_pin, false);


    //ステートマシンの入力ピンの基準点(プッシュスイッチのピン17)を設定する
    sm_config_set_in_pins(&config, input_pin);


    //指定したPIOで使用するステートマシンにメモリに格納された初期設定情報を適用する
    pio_sm_init(pio, sm, offset, &config);


    //指定したPIOで使用するステートマシンを起動する
    pio_sm_set_enabled(pio, sm, true);
 
}
%}


▶️ CMakeLists.txtの変更

  1. 「エクスプローラー」に表示されている「CMakeLists.txt」をクリックすると、エディタエリアに内容が表示されます。

  2. 「Generate PIO header」のフィル名を、「blink.pio」から「mypio1.pio」に変更し、保存します。

# Generate PIO header
pico_generate_pio_header(pio_led_toggle ${CMAKE_CURRENT_LIST_DIR}/blink.pio)

pico_generate_pio_header(pio_led_toggle ${CMAKE_CURRENT_LIST_DIR}/mypio1.pio)


プログラムの実行

Raspberry Pi Pico Wに接続されているUSBケーブルを外し、「BOOTSEL」ボタンを押しながら、USBケーブルを差し込みます。

「F5」キーを押して実行すると、途中、Temporary breakpointsで一時停止します。


もう一度、「F5」キーを押して続行します。

赤と緑のLEDが500ms間隔で交互に点灯・消灯をしている途中で、プッシュスイッチを押すと、赤と緑のLEDの点灯・消灯が停止します。

その後、青のLEDが500ms間隔で点灯・消灯を3回繰り返した後、消灯し、再び赤と緑のLEDが500ms間隔で交互に点灯・消灯します。




確認後、「Shift + F5」キーを押して、停止します。


まとめ

GPIOピン(以下 GPピン)にプッシュスイッチと赤、緑、青の3つのLEDを接続し、プッシュスイッチでPIO機能の割込みを発生させて、赤、緑、青の3つのLEDを制御しました。

プッシュスイッチの状態の監視し、割り込みを発生させ、3つのLEDがスムーズに点灯・消灯できることで、メインプロセッサとは独立して動作する、Programmable Input/Output(PIO)のディジタル信号入力機能を確認することができました。


おすすめの一冊

本書を読むのにプログラム言語の知識は一切不要です。もっとも親しみやすいC言語の入門書として、現代の環境に合わせてアップデートされた、安心して勉強を始められる一冊です。