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])とまったく同じデータが観測できます。