はじめに
Raspberry Pi にはアナログ入力がないので、電圧のような連続した値を読むには外付けのADコンバータ が要ります。ここで使う MCP3425 は、差動入力・16ビットまで対応の小さなADCで、I2C 2本の線でつなげます。
この石を使ううえでの肝は、ゲインや分解能といった設定が、コンフィギュレーションレジスタに書き込む1バイトにすべて詰まっているという点です。逆に言えば、この8ビットに何を立てるかさえ決まれば、あとは値を読むだけ。まずはラズパイ側でI2Cを有効にしておいてください。
Raspberry PiとMCP3425の配線
今回は動作確認が目的なので、センサは使わず、分圧抵抗でつくった一定のアナログ電圧を読ませます。3.3Vはラズパイから取り、10kΩ2本で半分に分けているので、Vin+には約1.65Vが現れます。

MCP3425は差動入力ですが、話を簡単にするためVin−をGNDに落とし、Vin+だけを使います。使ったのはRaspberry Pi Zero WHですが、I2Cが使えれば他のラズパイでも同じです。
配線は次のとおりです。

| MCP3425 | 役割 | Raspberry Pi接続先 | ラズパイ物理ピン |
|---|---|---|---|
| 1 | Vin+ | 分圧抵抗へ | – |
| 2 | Vss | GND | 6番 |
| 3 | SCL | GPIO3 | 5番 |
| 4 | SDA | GPIO2 | 3番 |
| 5 | Vdd | +3.3V | 1番 |
| 6 | Vin− | GND | – |

ラズパイ側のI2Cは、SDAがGPIO2、SCLがGPIO3に割り当てられています。ピンヘッダの物理位置と信号名は取り違えやすいので、下のGPIO配置図で確認しながら結線すると安心です。

MCP3425が認識されているか確認する
配線ができたら、i2cdetect でラズパイからMCP3425が見えているかを確かめます。正しくつながっていれば、アドレス0x68が表示されます。
$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
もしアドレスが出てこないときは、まずラズパイを再起動してみてください。MCP3425はVin+とVin−がどちらも未接続だとアドレスを返さないことがあるので、入力側の結線も合わせて見直します。
差動入力とはどう読むか
MCP3425は差動入力なので、読み取る電圧はVin+とVin−の差になります。
V_IN = V_IN+ − V_IN−
入力範囲はGNDを基準にプラスマイナス約2Vまでです。今回はVin−をGNDに落として0Vとしているので、差はそのままVin+の電圧、つまり約1.65Vになります。内部では、この差動電圧がゲイン付きのアンプ(PGA)を通ってから16ビットのΔΣ型ADCに入る、という構成です。

コンフィギュレーションレジスタに1バイトを書く
MCP3425の設定は、コンフィギュレーションレジスタと呼ばれる8ビットのレジスタに集約されています。ゲイン・分解能・変換モードといった項目が、この1バイトのどのビットを立てるかで決まります。今回の設定を組み立てると10011000(16進で0x98)になり、これがそのままI2Cで書き込む値になります。

ビットごとに、上位から順に見ていきます。まずbit7はRDY(データレディフラグ)で、これはワンショット変換のときに使うものですが、今回は連続変換モードなので1にします。続くbit6とbit5はチャネル選択用ですが、MCP3425はチャネルが1つしかないので使われず00です。
bit4は変換モードで、1が連続変換、0がワンショットです。今回はずっと読み続けたいので連続変換の1にします。
| bit4 | 動作 |
|---|---|
| 1 | 連続変換モード。変換を継続的に行い続ける |
| 0 | ワンショット変換モード。1回変換したら低消費電力のスタンバイに入る |
bit3とbit2は分解能とサンプリングレートを決めます。ここはトレードオフで、分解能を上げるほど1秒あたりに取れる回数は減ります。今回は16ビット・15SPSにしたいので10を書きます。
| bit3/2 | 分解能 | サンプリングレート |
|---|---|---|
| 10 | 16bit | 15 SPS |
| 01 | 14bit | 60 SPS |
| 00 | 12bit | 240 SPS |
最後のbit1とbit0は入力ゲイン(PGA)です。アナログ電圧が小さいときに増幅して読めるようにする機能ですが、今回は等倍でよいので00(1倍)にします。
| bit1/0 | ゲイン |
|---|---|
| 00 | 1倍 |
| 01 | 2倍 |
| 10 | 4倍 |
| 11 | 8倍 |
こうして上位から並べると1 00 1 10 00、詰めて10011000になります。
Pythonで電圧を読む
あとはI2Cで先ほどの10011000を書き込み、変換結果を読み出すだけです。MCP3425は上位バイトと下位バイトが入れ替わって届くのでswap16で並べ替え、値は2の補数の符号付き16ビットなのでsign16で10進に直しています。
import smbus
import time
i2c = smbus.SMBus(1)
addr=0x68
config = 0b10011000
Vref=2.048
i2c.write_byte(addr, config) #16bit
time.sleep(0.2)
def swap16(x):
return (((x << 8) & 0xFF00) | ((x >> 8) & 0x00FF))
def sign16(x):
return ( -(x & 0b1000000000000000) | (x & 0b0111111111111111) )
while True:
data = i2c.read_word_data(addr, config)
raw = swap16(int(hex(data), 16))
raw_s = sign16(raw)
volts = round((Vref * raw_s / 32767), 4)
print(volts)
time.sleep(1)
実行すると1.6055Vと表示されました。テスターでの実測は1.657Vだったので0.05Vほどの差はありますが、分圧抵抗の誤差も乗っていることを考えれば、動作確認としては十分でしょう。
参考サイト
関連記事
I2CでのADC読み取りに慣れたら、別のADCや、ラズパイでの計測・GPIO工作にも広げてみてください。
- ESP32でADS1115を使う方法 … 別のI2C接続ADCを同じ要領で
- 【Raspberry Pi】ステップ応答による抵抗値の測定 … アナログ入力なしで値を測るもう一つの手
- 【Raspberry Pi】ECMで音センサつくってみた … 読み取った電圧を使う応用例
- 物理ボタンを付けてRaspberry Piを安全にシャットダウンする方法 … 実運用で効くGPIO工作
