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