0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi で GPIO ボタンを使って OLED 表示モードを切り替える

Last updated at Posted at 2026-01-26

📝 はじめに

前回作成した OLED ディスプレイ表示機能に、GPIO ボタンによるモード切り替え機能を追加します。ボタンを押すとセンサーデータ表示とシステム情報表示を切り替えられるようになります。

対象読者

  • Raspberry Pi で GPIO を使った入力制御をしたい人
  • 物理ボタンで IoT デバイスを操作したい人

前提条件

  • 前回の記事(OLED ディスプレイ表示)が完了していること
  • GPIO の基本を理解している

DF30A959-5B10-45B3-AB8D-6416C6AE56B3(大).jpeg

🎯 背景・動機

OLED ディスプレイにセンサーデータを表示できるようになりましたが、IP アドレスやホスト名も確認したい場面があります。物理ボタンを追加して表示モードを切り替えられるようにしました。


🛠️ 手順

1. ハードウェア接続

タクトスイッチを GPIO 21 に接続します。

タクトスイッチ Raspberry Pi
片側 GPIO 21
反対側 GND

2. GPIO ボタン制御の実装

import RPi.GPIO as GPIO

class SensorClient:
    def __init__(self, button_pin=21):
        self.button_pin = button_pin
        self.display_mode = 0  # 0: センサーデータ, 1: システム情報
        self.button_available = False
        self.last_button_state = GPIO.HIGH

    def init_button(self):
        """GPIO ボタンを初期化(ポーリング方式)"""
        try:
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(self.button_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
            self.button_available = True
            return True
        except Exception as e:
            print(f'GPIO 初期化失敗: {e}')
            return False

    def check_button(self):
        """ボタン状態をチェック(ポーリング)"""
        if not self.button_available:
            return

        current_state = GPIO.input(self.button_pin)

        # HIGH → LOW の遷移を検出(ボタン押下)
        if self.last_button_state == GPIO.HIGH and current_state == GPIO.LOW:
            self.toggle_display()

        self.last_button_state = current_state

    def toggle_display(self):
        """ディスプレイモードを切り替え"""
        self.display_mode = 1 - self.display_mode  # 0 ↔ 1 を切り替え
        print(f'表示モード変更: {self.display_mode}')

ポーリング方式を選んだ理由: 割り込み方式より安定動作し、デバッグが容易。100ms 間隔のチェックで十分な応答性が得られます。

3. メインループへの統合

def run(self):
    """メインループ"""
    # 初期化
    self.oled.init_display()
    self.init_button()

    loop_count = 0
    while True:
        # ボタンをチェック(100ms 間隔)
        self.check_button()

        # 10秒ごとにセンサーデータを更新
        if loop_count >= 100:  # 100ms × 100 = 10秒
            data = self.read_sensor_data()
            if data:
                self.send_sensor_data(data)
                self.update_display(data)
            loop_count = 0

        time.sleep(0.1)
        loop_count += 1

def update_display(self, data):
    """表示モードに応じてディスプレイを更新"""
    if self.display_mode == 0:
        self.oled.show_sensor_data(data['temperature'], data['humidity'])
    else:
        self.oled.show_system_info(self.hostname, self.get_ip_address())

4. IP アドレス取得

import socket

def get_ip_address(self):
    """自身の IP アドレスを取得"""
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except:
        return "No IP"

🚨 つまずきポイント

チャタリング対策

機械式スイッチは押下時に信号が振動します。ポーリング間隔を 100ms に設定することで、追加のデバウンス処理なしでも安定動作します。

Docker コンテナでの GPIO 使用

compose.yml で /dev/gpiomem をマウントし、privileged: true を設定する必要があります。


📈 まとめ

  • ポーリング方式で安定動作: 割り込みよりもシンプルで信頼性が高い
  • 状態遷移の検出: HIGH → LOW の変化を検出してボタン押下を判定
  • メインループとの統合: センサー読み取りと並行してボタンをチェック
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?