5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (9) A-Dコンバータの利用6 MCP3002/MCP3008

10ビットA-DコンバータMCP3002/3008

 前回のMCP3208は12ビットでしたが、MCP3002/3008は10ビットのA-Dコンバータです。日本では入手しやすいデバイスです。MCP3004は4チャネル、MCP3008は8チャネル入力で、同じタイミングで読み書きします。

 MCP3002は2チャネルで、チャネルの指定ビットがMCP3004/3008とは異なります。

 MCP3001という1チャネルのモデルがあります。MCP3002と同じ8ピンのパッケージに入っていますが、チャネル番号を送る必要がないので、MOSIからデータを読み出すだけで使えるところが異なります。

 したがって、チャネル数が異なる

  • MCP3001
  • MCP3002
  • MCP3004/3008

3組のグループがあって、SPIを直接制御する読み書きのプログラムはそれぞれ別個に作ります。ここではMC3001は扱いません。

MCP3002/3008の主なスペック

  •  ビット数;10
  •  チャネル数;MCP3002は2チャネル、MCP3008は8チャネル
  •  基準電圧;外部から入力
  •  電源電圧; 2.7~5.5V
  •  入力;シングルエンド、疑似差動
  •  変換方式;SAR(逐次比較)方式
  •  サンプリング・レート;200ksps(電圧によって異なる)
  •  インターフェース;SPI

接続

MCP300x信号名 ラズパイのGPIO  
チップ・セレクト/CS(/SS) CE0が24番、CE1が26番 Chip Enable
 Din 19番 データ出力MOSI Master Out Slave In
 Dout 21番 データ入力MISO Master In Slave Out
 CLK 23番 クロックSCLK Serial CLocK
電源3.3V 17番が近い  
GND 25番が近い  

MCP3008のプログラム例 gpiozeroを使う

 ピン配置はMCP3208と同じです。

CH0 1番ピン 16 Vdd 3.3V電源
CH1 2 15 Vref 基準電圧入力
CH2 3 14 AGND アナログ・グラウンド
CH3 4 13 CLK
CH4 5 12 Dout
CH5 6 11 Din
CH6 7 10 /CS・SHDN
CH7 8 9 DGND ディジタル・グラウンド

 前回のMCP3208と同様に、ライブラリの中にMCP3008用が入っているので、プログラムは簡単に記述できます。

#!/usr/bin/env python
from gpiozero import MCP3008
Vref = 3.29476
pot = MCP3008(channel=0)
print(str(pot.value * Vref) + "V")

MCP3008のプログラム例 spidevを使う

 MCP3208の設定データは、

スタートは'1'、シングル入力は'0'、チャネル0はD2、D1、D0='000'

でした。1バイト目は先頭にダミーの'0'が五つ入るのでのb000001100=0x06でした。MCP3008は同じ構成です。送られてくるデータが12ビットから10ビットに減少するところが異なります。先頭のダミーは'0'を七つにします。3バイトのデータのやりとりをタイムチャートにしました。

 MCP3008の送る設定データを次に示します。MCP3004はチャネル0からチャネル3までのデータを使います。

 spidevのxfer2()の最初の1バイトは0x01の固定値、2バイト目は次の値になります。3バイト目は0x00のままです。

チャネル 2nd byte
0 0x80
1 0x90
2 0xa0
3 0xb0
4 0xc0
5 0xd0
6 0xe0
7 0xf0

 チャネル0用プログラム例です。

#!/usr/bin/env python
# channel 0 pin1-GND
import spidev
Vref = 3.29476
spi = spidev.SpiDev()
spi.open(0,0) #port 0,cs 0

adc = spi.xfer2([0x01,0x80,0x00])
data = ((adc[1] & 3) << 8) | adc[2]
print (str(Vref*data/1024) + "V")

spi.close()

(2020/05/07)1023は間違いなので、1024に変更した。

(adc[1] & 3) '3'はb00000011なので、&=論理積によって上位6ビットを0でマスクし、最後の2ビットだけを取り出します。前回は12ビットだったので、4ビット分を取り出すのに0x0fを論理積で使いました。マスクするのは、読み出したデータが不定だからです。

(※)2018年後半から、speedの指定が必須になっています。open後に記述します。
spi.open(0, 0) # port 0,cs 0
spi.max_speed_hz = 1000000 # 1MHz

MCP3002のプログラム例 gpiozeroを使う

 ピン配置です。

CS/SHDN 1番ピン 8 Vdd&Vref 3.3V電源
CH0 2 7 CLK
CH1 3 6 Dout
Vss 4 5 Din

 チャネル0用プログラムです。

#!/usr/bin/env python
from gpiozero import MCP3002
Vref = 3.29476
pot = MCP3002(channel=0)
print(str(pot.value * Vref) + "V")

MCP3002のプログラム例 spidevを使う

 MCP3002の設定用バイトはMCP3008用とは異なります。タイミングも異なります。Startビットの次にシングルエンドもしくは差動を選ぶビットSGL/DIFFが続くところは同じですが、ODD/SIGNという1ビットがあり、そのあとはMSBFという1ビットで終了です。MSBFは'1'でMSBから、'0'であればLSBからデータを送ってくれるので、MCP3008と合わすために'1'にします。

 チャネル・セレクトは、SGL/DIFFとODD/SIGNで行います。シングルエンドのときです。

  SGL/DIFF ODD/SIGN
チャネル0 1 0
チャネル1 1 1

 最初に送る設定データが短くなったので、合計2バイトの送信になります。2バイトちょうどにするために、先頭に'0'を一つ追加します。タイムチャートを示します。チャネル0はb01001000=0x68、チャネル1はb01011000=0x78です。

 チャネル0用プログラムです。

#!/usr/bin/env python
# channel 0 pin1-GND
import spidev
Vref = 3.29476
spi = spidev.SpiDev()
spi.open(0,0) #port 0,cs 0
adc = spi.xfer2([0x68,0x00])
data = ((adc[0] & 3) << 8) | adc[1]
print (str(Vref*data/1024) + "V")
spi.close()

  オシロスコープPicoScopeで、実際に入力電圧1.0V時のクロック(青色)とMISOデータ(赤色)の受信信号を見ます。期待通りに動いていることがわかります。この測定は、MSBFビットを'0'にしてspi.xfer2([0x60,0x00])としたときです。データシートによれば、設定値を送った後、MSBからのデータが送ってきて、続いてLSBからのデータが送られるはずですが、送信では2バイトしか送っていないので、LSBからのデータが消えてしまっています。したがって、spi.xfer2([0x68,0x00])とまったく同じデータが観測できます。