YAS's VB.NET Tips
 
ラズベリーパイ活用
ラズベリーパイ活用 >> 記事詳細

2019/08/08

起動スイッチ,リブート・シャットダウンスイッチ

| by:YAS
 ラズパイ工作の定番と言われる,起動・リブート・シャットダウンスイッチです。
 赤のタクトスイッチが起動ボタンです。出力として使用しているときに押されてもショートしないように330kΩの抵抗を挟んでいます。(1kΩでは起動しませんでした。330Ωであれば,電流は10mA(3.3 / 330 = 0.01)に抑えられるので,簡単に壊れたりはしないと思います。) 
 白のタクトスイッチがリブート・シャットダウンボタンです。プルアップし,Pythonで立ち下がりを検出するようにします。LEDが3回点滅するまで押し続けることでリブート,5回点滅するまで押し続けることでシャットダウンするようにPythonのコードを書きます。また,LEDは0.5秒ごとに点滅するようにします。
 ケースに組み込んだときなどに,外付けのボタンで操作できるように,タクトスイッチと平行にXHコネクタを付けておくことにします。

☆材料
 ラズパイZero用ユニバーサル基板 秋月 P-14031100円 
 ラズパイ用スタッキングコネクタ 秋月 C-10702150円 
 タクトスイッチ×2(赤・白) 秋月 P-03648 20円 
 XHコネクタ(2ピン)×2 秋月 C-1224720円 
 超高輝度5mmオレンジ色LED 秋月 I-06404 (10個)200円 
 カーボン抵抗 1/4W 0Ω 秋月 R-25000 (100本)100円 
 カーボン抵抗 1/4W 330Ω 秋月 R-25331 (100本)100円 
 カーボン抵抗 1/4W 1kΩ 秋月 R-25102 (100本)100円 
 カーボン抵抗 1/4W 10kΩ 秋月 R-25103 (100本)100円 
 合計  890円 

☆配線図 (抵抗のカラーコードの間違いを修正しました。R01.08.26)


☆できあがり


☆テストコード
 ①まずは,LEDチカチカ
  LEDを10回,0.5秒間隔で点けたり消したりする。
import RPi.GPIO as GPIO
import time

LED_PIN = 12

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)

for i in range(10):
    GPIO.output(LED_PIN, GPIO.HIGH)
    time.sleep(0.5)
    GPIO.output(LED_PIN, GPIO.LOW)
    time.sleep(0.5)
GPIO.cleanup()
 ②タクトスイッチの押下検出
  タクトスイッチを押すまで待ち,スイッチを押したら,"Button Pushed.”のメッセージを表示する。
import RPi.GPIO as GPIO
import time

BUTTON_PIN = 26

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_PIN, GPIO.IN)
GPIO.wait_for_edge(BUTTON_PIN, GPIO.FALLING)
print("Button Pushed.")
GPIO.cleanup()

☆リブート&シャットダウン
 ①タクトスイッチの押下でリブートまたはシャットダウンするコード
 ・wait_for_edge()を使うと,killしても待ち続け,すぐに終了しない。(killしたあと,タクトスイッチを押した時点で終了する。)そのため,add_event_detect()を使ってコールバック関数を呼ぶようにし,ループで待機する。
 ・コールバック関数で長い時間処理をすると,チャタリングが起きるのか,2回連続でコールバック関数が呼ばれることがあった。そのため,コールバック関数ではフラグをセットしてすぐに終了し,待機ループでフラグの変化を検知して必要な処理を行うようにした。
import RPi.GPIO as GPIO
import time
import sys
import os
import signal

LED_PIN = 12
BUTTON_PIN = 26
button_flag = False

def main():
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(LED_PIN, GPIO.OUT)
    GPIO.setup(BUTTON_PIN, GPIO.IN)
    GPIO.output(LED_PIN, GPIO.LOW)
    # 起動したサインとしてLEDを3回点滅させる
    blink_led(30.1)
    # 入力待ちのサインとしてLEDを点灯させる
    GPIO.output(LED_PIN, GPIO.HIGH)
    GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callback=button_pushed, bouncetime=300) 
    # killされた場合も終了処理(finally節)を行う
    signal.signal(signal.SIGTERM, sigterm_handler)
    # wait_for_edgeではkillしてもイベントが発生するまでフリーズするので、
    # ループで待機するようにする
    global button_flag
    try:
        while True:
            time.sleep(0.1)
            if button_flag:
                choose_action()
                button_flag = False
    except KeyboardInterrupt:
        pass
    finally:
        # 終了のサインとしてLEDを消灯させる
        GPIO.output(LED_PIN, GPIO.LOW)
        GPIO.remove_event_detect(BUTTON_PIN)
        GPIO.cleanup()   

# LEDを指定の回数、指定の間隔で点滅させる
def blink_led(times, wait):
    for i in range(times):
        GPIO.output(LED_PIN, GPIO.HIGH)
        time.sleep(wait)
        GPIO.output(LED_PIN, GPIO.LOW)
        time.sleep(wait)

# コールバック関数で時間のかかる処理をすると2回実行されることがあるので、
# グローバル変数のフラグの変更のみ行う。
def button_pushed(gpio_pin):
    global button_flag
    button_flag = True

# トグルボタンを押した長さでreboot、shutdownの処理を選ぶ
def choose_action():
    GPIO.output(LED_PIN, GPIO.LOW)
    time.sleep(0.2)
    count = 0
    while True:
        blink_led(10.5)
        count += 1
        if GPIO.input(BUTTON_PIN) == GPIO.HIGH:
            # 3回点滅した場合は再起動
            if count == 3:
                blink_led(30.1)
                os.system("sudo reboot")
                sys.exit()
            # 5回点滅した場合はシャットダウン
            if count == 5:
                blink_led(50.1)
                os.system("sudo shutdown -h now")
                sys.exit()
            # その他の場合は5回すばやくLEDを点滅させる
            blink_led(50.1)
            GPIO.output(LED_PIN, GPIO.HIGH)
            break

# killされた場合も終了処理(finally節)を行う
def sigterm_handler(signal_number, stack_frame):
    sys.exit()

if __name__ == "__main__":
    main()
 ②サービスとして自動起動するために,下のUnit定義ファイルをファイル名「reboot_shutdown.service」で保存する。
[Unit]
Description=for Reboot and Shutdown board

[Service]
ExecStart=/usr/bin/python3 /home/pi/reboot_shutdown.py

[Install]
WantedBy = multi-user.target
 ③「/etc/systemd/system/」にUnit定義ファイルをコピーする。
$ sudo mv reboot_shutdown.service /etc/systemd/system/
 ④サービスとして起動
  LEDが3回点滅したあと,点灯して待機することを確認。
$ sudo systemctl start reboot_shutdown
 ⑤サービス再起動
  LEDが一度消灯し,その後再起動することを確認。
$ sudo systemctl restart reboot_shutdown
 ⑥サービス終了
  LEDが消灯し,終了することを確認。
$ sudo systemctl stop reboot_shutdown
  ⑦サービス自動起動を有効にする
$ sudo systemctl enable reboot_shutdown
Created symlink /etc/systemd/system/multi-user.target.wants/reboot_shutdown.service ? /etc/systemd/system/reboot_shutdown.service.
 ⑧再起動
  再起動後,LEDが点灯し,自動起動したことを確認。
$ sudo reboot

17:00