マイクロチップのMCP3304は13ビットA-Dコンバータです。最上位は符号ビットなので、-4096~+4095までの分解能がある12ビットADCです。インターフェースはSPIバスで、転送速度は最大2.1MHz(5V)です。動作電圧は5Vが推奨されていますが、3.3Vでも動きました。
###MCP3304のおもなスペック
- ビット数 13
- チャネル数 8(シングルエンド)、4(差動)
- 基準電圧 内蔵なし、端子あり
- 変換速度 100ksps(5V時)
- インターフェース SPI(モード0,0および1,1)、クロック最大2.1MHz(5V時)
- 動作電圧 4.5(2.7)~5.5V
- ピン数 16ピンDIP
###接続
MCP3304の端子 | Picoの端子(GPIO) | 名称 |
---|---|---|
1 ch0 | - | - |
2 ch1 | - | - |
3 ch2 | - | - |
4 ch3 | - | - |
5 ch4 | - | - |
6 ch5 | - | - |
7 ch6 | - | - |
8 ch7 | - | - |
9 DGND | GND | GND |
10 /CS | GP8 | GP8 |
11 Din | GP3 | MOSI SPI0 TX |
12 Dout | GP4 | MISO SPI0 RX |
13 CLK | GP2 | SPI0 SCK |
14 AGND | GND | GND |
15 Vref | 3V3 | 3.3V |
16 Vdd | 3V3 | 3.3V |
ch0-ch1差動入力には、電池駆動の簡易電源TL431の出力をつないでいます。約2.5Vです。 |
###プログラム
コマンドを送るフォマットは次のとおりです。
Startbit チャネル指定4バイト
例えば、差動ch0-ch1であれば、
0000
です。最後のチャネル指定ビットD0がMCP3304へ送られるタイミングで、約1ビットおいて、NULLビットに引き続き、
Sign D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
のA-D変換結果データが、MCP3304からPicoへ送られてきます。
SPIは基本8ビット単位なので、LSBのD0から前にさかのぼって、8ビット単位で送るべきデータを整理します。差動ch0-ch1の場合です。
x x x x 1 0 0 0
0 x x x x x x x
x x x x x x x x
SPIは、クロックを送り続けないとデータはやってきません。上記のxはダミーなので、0でも1でもかまいません。ただし、最初の4ビットのいずれかを'1'にすると、Startbitと解釈されるかもしれないので、'0'にします。'0'でもクロックは発生します。したがって、ここでは、ch0-ch1差動のデータは、次のようにしました。
0x08
0x00
0xff
本プログラムは、差動入力だけを対象にしています。
チャネル指定 | 1バイト目 | 2バイト目 | 3バイト目 |
---|---|---|---|
ch0 = IN+ ch1 = IN- | 0b00001000 | 0b00000000 | 0xff |
ch2 = IN+ ch3 = IN- | 0b00001001 | 0b00000000 | 0xff |
ch4 = IN+ ch5 = IN- | 0b00001010 | 0b00000000 | 0xff |
ch6 = IN+ ch7 = IN- | 0b00001011 | 0b00000000 | 0xff |
3バイト送ったので、読み出したデータは3バイトです。1バイト目はごみなので捨てます。2バイト目は上位桁Sign D11 D10 D9 D8
が右詰めで入っています。3バイト目は、D7 D6 D5 D4 D3 D2 D1 D0
です。
Signビットを見て符号をつけます。
12ビットのデータなので、Vrefの3.3Vをかけ、4096で割って電圧を求めます。Vrefは、できるだけ正確にテスタで測った値を記入しておきます。
from board import *
import busio
import time
import digitalio
print('\n start\n')
spi = busio.SPI(GP2, GP3, GP4) # SPI0BUS clock MOSI MISO
while not spi.try_lock():
pass
spi.configure(baudrate=1_000_000, phase=0, polarity=0)
cs = digitalio.DigitalInOut(GP8)
cs.direction = digitalio.Direction.OUTPUT
cs.value = 1
def readADC():
result = bytearray(3)
cs.value = 0
spi.write_readinto(bytearray([0x08,0x00,0xff]), result) # cho-ch1
cs.value = 1
temp = (result[1] & 0b00011111) << 8 | result[2]
Volts = -(temp & 0b1000000000000) | (temp & 0b0111111111111)
#print(result[0], result[1], result[2])
#print(bin(Volts))
return(Volts)
while 1:
print(str(readADC()*3.3/4096) + 'V')
time.sleep(3.14)