Raspberry Piを用いたデバイス制御には、温度センサーや距離センサーなどで周辺環境を検知することが必須です。でも、Raspberry PiにはA/Dコンバータが備わっていないんです…。
本記事では、Raspberry PiとA/DコンバータMCP3208を接続して、センサ値を読み取る方法について解説します。
Raspberry Piでアナログ計測するにはA/Dコンバータが必要
Raspberry PiはArduinoとは異なり、A/Dコンバータが搭載されていません。そのため、Raspberry Piでアナログ計測するには、A/Dコンバータを別途用意しなくてはなりません。
本記事では、Microchip Technology社のMCP3208というA/Dコンバータを使用します。
MCP3208のインターフェイスはSPIという規格が採用されていますので、Raspberry PiとMCP3208はSPI接続します。
A/Dコンバータ MCP3208の仕様
MCP3208は12bitのA/Dコンバータです。
12bit = 4096刻みでアナログ値を検出出来るということです。
また、MCP3208は8つのアナログ入力信号を読み取ることが出来ます。姉妹品としてMCP3204がありますが、こちらはアナログ入力信号が4つまでに限られること以外、仕様は同じです。
Raspberry PiとA/DコンバータをSPI通信する
SPIはSerial Peripheral Interfaceの略でマイコンと周辺IC間を接続するバスです。
Raspberry PiとMCP3208にはSPIが備わっています。
両者SPIを接続し通信することで、MCP3208で読み取った値をRaspberry Piが認識することが出来ます。
SPI通信するためのspidevモジュールの使い方
MCP3208が計測したアナログ値をRaspberry Piへ送信してもらうのに、決まった通信やりとりがあります。
データシートを見ながら、自分でプログラムすることも可能ですが、結構大変です。
spidevというAPIがあるので、今回はspidevを使います。
SpiDevインスタンス生成
spi = spidev.SpiDev()
クラス内の関数を実行するためにSpiDevインスタンスを生成します。
MCP3208との接続
spi.open(port,cs)
spi.open()でMCP3208との通信を開始します。
第1引数のportは、2系統あるSPIの内どちらを使用するか選択します。SPI0なら0、SPI1なら1の数値を設定します。
第2引数のcsは、どのデバイスと通信するかです。MCP3208がCE0と接続されているなら0、CEなら1を設定します。
通信周期の設定
spi.max_speed_hz = 1000000 # 1MHz
spi.max_speed_hzに通信周波数を代入すると、その周波数で通信します。通信周波数の逆数が通信周期となります。
データ転送
xfer2(list of values)
関数xfer2で引数の値をMCP3208へ転送します。
MCP3208がアナログ計測した値をRaspberry Piに転送してもらうには、Raspberry Piからどんなデータを転送すればよいの?
MCP3208のデータシートによると、1回の通信で8bit(1byte)×3のデータ転送が必要です。Raspberry Piから下記のように転送します。
1byte目
0 | 0 | 0 | 0 | 0 | 1 (start bit) | SGL/ DIFF | D2 |
2byte目
D1 | D0 | X | X | X | X | X | X |
3byte目
X | X | X | X | X | X | X | X |
説明にあたり、チャンネル0でアナログ計測することとします。
「SGL/DIFF」は、1(SGL): 絶対値計測か、0(DIFF): チャンネル間の差分値計測かの選択です。絶対値で計測したいので1を設定します。
絶対値計測を設定すると、3bitデータ 「D2/D1/D0」はチャンネルNo.の指定です。 チャンネルNo.指定方法は、チャンネルNo. = 4×D2 + 2×D1 + D0 となります。アナログ計測するチャンネルNo.は0ですので、D2=0、D1=0、D0=0を設定します。
「X」の値は問われませんので、0を設定します。
以上まとめると、Raspberry PiからMCP3208への転送データは、2進数表記で0b00000110、0b00000000、0b00000000、16進数表記で0x06、0x00、0x00となります。
Raspberry Piでアナログ計測してみる
準備したもの
- Raspberry Pi Zero WH
- ADコンバータ MCP3208
- 赤外線距離センサ
- 抵抗 33kΩ×1、680Ω×1
- ブレッドボード
- ジャンパワイヤ オス-メス
回路図
サンプルプログラム
import spidev
from time import sleep
Vref = 3.3
spi = spidev.SpiDev()
spi.open(0,0) #port 0,cs 0
spi.max_speed_hz = 1000000 # 1MHz
while True:
adc = spi.xfer2([0x06,0x00,0x00])
data = ((adc[1] & 0x0f) << 8) | adc[2]
print (str(Vref*data/4096) + "V")
sleep(1)
spi.close()
spi.xfer2()の戻り値は、MCP3208から受信したアナログ値含む8bit(1byte)×3のデータです。
データシートによるとMCP3208からの受信データは以下の定義となります。
1byte目
? | ? | ? | ? | ? | ? | ? | ? |
2byte目
? | ? | ? | 0 (Null) | B11 | B10 | B9 | B8 |
3byte目
B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
アナログ値は2byte目の下位4bitと3byte目ですので
data = ((adc[1] & 0x0f) << 8) | adc[2]
2byte目の下位4bitのみ抽出して8bit左にシフトし、3byte目とOR条件を取ることでアナログ値となります。
赤外線センサに物体を近づけたり遠ざけたりして、アナログ値が変化するか確認
サンプルプログラムを実行し、赤外線センサに物体を近づけたり遠ざけたりしてみました。
物体を近づけたときは、0.18Vを示していたのに対し、物体を遠ざけると2.82Vを示しました。
Raspberry PiとMCP3208はSPI通信を正常に行い、Raspberry Piはセンサ値を読み取れていることが分かります。
まとめ
Raspberry PiとA/DコンバータMCP3208を接続して、センサ値を読み取る方法について解説しました。
Raspberry PiはArduinoと異なり、A/Dコンバータが搭載されていないので、A/Dコンバータを別途用意することが必要です。
今回学んだことは
- A/Dコンバータ MCP3208の仕様について
- SPI通信するためのspidevモジュールの使い方
- 赤外線センサを用いたアナログ値の計測
です。
PWM制御でDCモーターの回転速度を制御する方法を学んだので、今後は周囲の環境をA/Dコンバータで検知し、DCモーターを制御する方法を解説していきたいと思います。
最後までお読み頂きありがとうございました。