Raspberry Pi – ADコンバータでフォトレジスタ読み取り

投稿者: | 2019年3月19日

引き続きコチラの書籍で学習継続中。今日は第6章に記載されている、AD変換によるアナログ値の使用を試してみたいと思います。

[amazonjs asin=”4062579774″ locale=”JP” title=”カラー図解 最新 Raspberry Piで学ぶ電子工作 作って動かしてしくみがわかる (ブルーバックス)”]

 

ADコンバータ(MCP3208)を扱う回路図

ADコンバータにはMCP3208を使用するわけですが、Raspberry Piとの信号のやり取りには、SPI通信を使います。

SPI通信にはマスター・スレーブという概念があり、Raspberry Pi はマスター, ADコンバータであるMCP3208はスレーブとなります。

 

書籍のままですが、今回の回路図はこちらになります。

 

「SPI MOSI」「SPI MISO」 という記述がありますが、それぞれ以下の意味合いがあります。

  • MOSI : Master Output Slave Input – 制御信号がRaspberry Piから出力され、MCP3208(のD_IN)に入力されます。
  • MISO : Master Input Slave Output – MCP3208(のD_OUT)からの信号が現れます。CH0から読み取った抵抗の変換値が出力されることになります。

 

実際に接続した回路はこのようになります。配線が多くて何だか分りづらいですが・・・

 

ADコンバータ(MCP3208)に必要な入出力信号

MCP3208の仕様により、下図の信号のやり取りが発生します(MCP3208の仕様書より抜粋)。

これによると、最初にCS(チップ・セレクト)およびCLK(クロック)をLOWにし、D_INに対して開始信号および制御信号(SGL/IDFF, D2, D1, D0)を送ることがまず必要となります。

 

今回は0番チャネルのみを用いますので、制御信号は下表(MCP3208の仕様書より抜粋)の最上段の行が該当します。

これによると、制御ビットはそれぞれ、SINGLE/DIFF=1, D2=0, D1=0, D2=0 となることが分かります。

なので制御信号は 1、1、0、0、0 ということになります。

 

フォトレジスタによりLEDの点滅を制御するコード

上記までの情報を元にすると、MCP3208の信号を取得するコードは、冒頭の書籍に掲載されているように、以下のようになります。

こちらのソースコードは書籍に記載されているものの通りですが、自分なりの理解をコメントとして付加してみました。

# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
from time import sleep

def readadc(adcnum, clockpin, mosipin, misopin, cspin):
    if adcnum > 7 or adcnum < 0:
        return -1
        
    GPIO.output(cspin, GPIO.HIGH)
    GPIO.output(clockpin, GPIO.LOW)
    GPIO.output(cspin, GPIO.LOW)
    
    #制御ビットの構成
    commandout = adcnum # adcnum は 0 (CH0)なので、commandout は 00000000。
    commandout |= 0x18  # 0x18 は 00011000 なので、commandout は 00011000 になる。
    commandout <<= 3    # commandout は 11000000 になる。この上位5ビットを使い、制御信号の 11000 を送る。
    
    # MOSIからの出力(MCP3208のD_INへの信号)
    # このfor文の中で、commandoutが11000000->10000000->00000000->00000000->00000000と変化する
    # commandout & 0x80 は、true, true, false, false, falseと変遷
    # mosipinからは HIGH, HIGH, LOW, LOW, LOW が送られる
    for i in range(5):
        if commandout & 0x80:
            GPIO.output(mosipin, GPIO.HIGH)
        else:
            GPIO.output(mosipin, GPIO.LOW)
        commandout <<= 1
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
    
    # MISOからの入力(MCP3208のD_OUTからの信号)
    # Null Bit と B11 - B0 の12ビットを読む
    adcout = 0
    for i in range(13):
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
        adcout <<= 1
        # 初回のループ (i=0) を飛ばすと、misopinが常にHIGHなら adcout |= 0x1 は
        # 000000000001, 000000000011, 000000000111, ...  , 111111111111
        # 従ってここでは adcout として MCP3208 D_OUT からの信号が得られる
        if i>0 and GPIO.input(misopin) == GPIO.HIGH :
            adcout |= 0x1
            
    GPIO.output(cspin, GPIO.HIGH)
    return adcout

GPIO.setmode(GPIO.BCM) # Raspberry Pi のモードとして、GPIOの番号を物理番号ではなく役割番号で指定する
SPICS = 8
SPIMISO = 9
SPIMOSI = 10
SPICLK = 11

GPIO.setup(SPICS, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPICLK, GPIO.OUT)

LED = 25
GPIO.setup(LED, GPIO.OUT)

try:
    while True:
        # CH0の信号を取得する
        inputVal0 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
        if inputVal0 < 2000:
            GPIO.output(LED, GPIO.HIGH)
        else:
            GPIO.output(LED, GPIO.LOW)
        print(inputVal0)
        sleep(0.2)
        
except KeyboardInterrupt:
    pass

GPIO.cleanup()

 

フォトレジスタによりLEDの点滅を制御した結果

フォトレジスタの上部に手をかざし、光を遮ると、LEDが点灯します。手をどかして光を通すと、LEDが消灯します。

 

今回試した環境下では、明るいときの抵抗値は2500~2600超、暗くすると大体1660~1830程度になっていました。

下図赤枠で囲った部分が、明るいときと、手をかざして暗くしたときの境目です。