Python Raspbeyyi Pi プログラム 回路 電子工作 高専3年生

【Raspberry Pi】電子工作入門①~デジタル入力・アナログ入力~【Python】

前回はこちら

デジタル入力とアナログ入力は、外部デバイスからの情報を取得して処理する際に使われる基本的な入力の方法です。

これを理解するために、具体的な例として「タクトスイッチ」と「可変抵抗」を使って説明してゆきます。

デジタル入力(タクトスイッチ)

デジタル入力とは、「オン」か「オフ」の2つの状態しか持たない入力方法です。これは二進数(0または1)で表され、スイッチの押下や離す動作を検知するのに適しています。デジタル入力の最も身近な例がタクトスイッチです。

タクトスイッチの動作

  • オン状態:スイッチを押すと、回路が閉じて電流が流れるため、「1」(HIGH)として検知されます。
  • オフ状態:スイッチが離されていると、回路が開いて電流が流れないため、「0」(LOW)として検知されます。

実際の使い方

  • タクトスイッチは、押されたかどうかだけを判断するので、状態がはっきりと「押されている(1)」か「押されていない(0)」のどちらかしかありません。たとえば、ボタンを押すことでLEDが点灯する、あるいはプログラムの特定の動作を実行する、というようなシンプルな制御に使われます。
from gpiozero import LED, Button  # LEDとButtonクラスをインポート
from signal import pause  # プログラムを無限待機させるために使用

# GPIO 17番ピンに接続されたLEDオブジェクトを作成
led = LED(17)

# GPIO 18番ピンに接続されたタクトスイッチオブジェクトを作成
button = Button(18)

# ボタンが押されたときにLEDを点灯
button.when_pressed = led.on

# ボタンが離されたときにLEDを消灯
button.when_released = led.off

# プログラムを無限ループで待機状態にする
pause()

配線図

アナログ入力(可変抵抗)

アナログ入力は、デジタル入力(0か1の状態)とは異なり、連続した電圧値を取得して扱う入力方法です。

アナログ信号は無限の値を取ることができ、典型的には電圧の変化を使ってこれを表現します。

Raspberry Piにはアナログ入力の機能がありませんが、ADC(アナログ-デジタルコンバータ)を使うことでアナログ信号をデジタル値に変換し、Raspberry Piで読み取ることが可能になります。

ADC0834の概要

ADC0834は、4チャンネルのアナログ-デジタルコンバータです。

ADC0834は、0〜5Vの範囲のアナログ信号を受け取り、それを0〜256のデジタル値に変換します(8ビットの分解能)。

SPI(シリアル・ペリフェラル・インターフェース)を介してRaspberry Piと通信し、アナログ信号をデジタルデータに変換して送信します。

可変抵抗(ポテンショメータ)

可変抵抗器(ポテンショメータ)は、抵抗値を手動で変えることができるデバイスです。

回転軸を回すことで、電圧を連続的に調整できます可変抵抗を使用して、回転角度に応じた電圧の変化をRaspberry Piで読み取り、それを利用して入力値の調整や制御を行うことができます。

ラズベリーパイの設定>SPI通信がONになっていることを確認しておいてください。

配線の手順

  1. 可変抵抗の中央ピンをADC0834のCH0(アナログ入力チャンネル0)に接続します。
  2. 可変抵抗の一方の端3.3Vに接続し、もう一方の端を**GND(グランド)**に接続します。
  3. ADC0834のデジタル出力ピンをRaspberry PiのGPIOピンに接続します:
    • CS(チップセレクト)をGPIO 8(SPI CE0)に接続。
    • CLK(クロック)をGPIO 11(SPI SCLK)に接続。
    • DIN(データ入力)をGPIO 10(SPI MOSI)に接続。
    • DOUT(データ出力)をGPIO 9(SPI MISO)に接続。
    • VCCを5Vに、V+VREFを3.3Vに、 GNDをGNDに接続します。

プログラムの概要

Raspberry Piを使って、ADC0834を介して可変抵抗のアナログ値を読み取り、その値を表示するプログラムを作成します。

import spidev   # Raspberry Pi用のSPI通信ライブラリ
import time
from statistics import median  # ノイズ対策でメディアンを使うため

# ================================
# SPIデバイスの初期設定
# ================================
spi = spidev.SpiDev()   # SPIデバイスを扱うためのオブジェクトを作成
spi.open(0, 0)          # SPIバス0, CE0(チップイネーブル0)を使用
spi.mode = 0            # SPIモードを「0」に設定(CPOL=0, CPHA=0)
spi.max_speed_hz = 250000  # 通信速度を250kHzに設定(ADC0834は400kHz以下が推奨)
spi.bits_per_word = 8   # 1回でやりとりするビット数(基本は8)

# ================================
# コマンド生成の準備
# ================================
# ADC0834に送るときの制御ビット
# 「SGL=1(単端子モード)」を基本にして、読みたいチャネル番号を組み込む
CMD_BASE = 0x08   # SGL=1を表すビット

def _cmd_for_channel(ch: int) -> int:
    """
    指定したチャネル番号(ch=0..3)をもとに、ADC0834用のコマンドを作る関数
    """
    return (CMD_BASE | (ch & 0x03)) << 4

# ================================
# 実際に1回だけ値を読む関数
# ================================
def read_adc0834_once(ch: int = 0) -> int:
    """
    指定したチャネルのアナログ値を1回だけ読み取って返す関数
    戻り値は 0〜255 の整数(8ビット)
    """
    # 3バイトのやりとり
    # [1バイト目: スタートビット, 2バイト目: チャネル指定, 3バイト目: ダミー]
    r = spi.xfer2([0x01, _cmd_for_channel(ch), 0x00])

    # 返ってくるデータの並びは
    #   [ダミー0] [MSB→LSBの8bit] [LSB→MSBの8bit]
    # なので「真ん中の8bit」を切り出す必要がある
    # v4の式: (r[1]の下位4ビットと r[2]の上位4ビットを組み合わせる)
    value = ((r[1] & 0x0F) << 4) | (r[2] >> 4)
    return value

# ================================
# ノイズを減らした安定値を返す関数
# ================================
def read_adc0834(ch: int = 0, samples: int = 5) -> int:
    """
    指定チャネルの値を複数回読み取って、中央値を返す関数
    → 値のチラつきを抑えて安定させる
    """
    read_adc0834_once(ch)  # 最初の1回は捨て読み(安定化のため)
    vals = [read_adc0834_once(ch) for _ in range(samples)]
    return int(median(vals))   # 中央値を返す(平均よりノイズに強い)

# ================================
# メインループ
# ================================
try:
    while True:
        raw = read_adc0834(0)   # CH0を読み取る
        print(f"アナログ値: {raw}")   # 0〜255の範囲で表示
        time.sleep(0.1)         # 0.1秒待ってから次の測定へ
finally:
    spi.close()  # プログラム終了時にSPIを閉じる

ボリュームの回し具合によってアナログ値が変化すれば成功です。

問題3

CH0の値を取得し、生のADC値(0〜255)換算した電圧(V)0.1秒ごとに表示するプログラムを書け。
表示書式は例にならい、少なくとも小数点以下2桁を表示すること。

raw=128  voltage=1.65 V
raw=129  voltage=1.67 V
...

・ポイント

ADC0834は8ビットのA/Dコンバータなので、読み取り値 raw0〜255

基準電圧を Vref(今回は 3.3V) とすると、
電圧[V] = raw / 255 × Vref(Pythonなら raw * 3.3 / 255 でOK)

小数点表示は f"{voltage:.2f}V" のようにフォーマット指定を使うと見やすい

解答例はこちら
import spidev
import time

# === SPI 初期化 ===
spi = spidev.SpiDev()
spi.open(0, 0)                 # bus=0, CE0
spi.mode = 0                   # CPOL=0, CPHA=0
spi.max_speed_hz = 250_000     # 200〜400kHzが安定
spi.bits_per_word = 8

VREF = 3.3                     # 基準電圧(今回は3.3V)
CMD_BASE = 0x08                # SGL=1(単端子)ビット

def _cmd_for_channel(ch: int) -> int:
    """ADC0834へ送る2バイト目のコマンドを生成(chは0..3)"""
    return (CMD_BASE | (ch & 0x03)) << 4

def read_adc0834_once(ch: int = 0) -> int:
    """指定チャネルを1回だけ読み取る(0..255)"""
    r = spi.xfer2([0x01, _cmd_for_channel(ch), 0x00])
    # ダミー0の後の MSB→LSB 8bit を取り出す(v4式)
    return ((r[1] & 0x0F) << 4) | (r[2] >> 4)

try:
    while True:
        raw = read_adc0834_once(0)           # CH0
        voltage = raw * VREF / 255           # 0..VREF に線形換算
        print(f"raw={raw:3d}  voltage={voltage:.2f} V")
        time.sleep(0.1)
finally:
    spi.close()

次回はこちら

Follow me!

-Python, Raspbeyyi Pi, プログラム, 回路, 電子工作, 高専3年生
-, , , , ,

PAGE TOP