引き続きコチラの書籍で学習継続中。今日は第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程度になっていました。
下図赤枠で囲った部分が、明るいときと、手をかざして暗くしたときの境目です。

