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