ラズパイのSPI通信で8チャネルADコンバータMCP3008を使ってみた (Raspberry Pi, Python)



今回は10bit、8chのADコンバータMCP3008をラズパイ(Raspberry Pi)で扱ってみた。

以前「ラズパイで照度と温度を測定してみた」 の記事で、2チャネルのADコンバータMAX1118を使った。その後もっとセンサーを取り付けたくなり、2チャネルでは足らなくなったので、8チャネルあるMCP3008を使ってみることにした。温度や照度、水分量を測定するだけなので、分解能は10bitあれば十分であろう。

MCP3008は秋月電子で190円で購入した。

ラズパイは、Raspberry Pi zeroを使用した。
PythonでSPIを使えるようにするため、事前にSPIモジュールのインストールを終えている。





MCP3008の配線




MCP3008データーシートより


MCP3008 の各ピンの役割は次のようになる。

MCP3008名称役割
1CH0アナログ電圧入力
2CH1アナログ電圧入力
3CH2アナログ電圧入力
4CH3アナログ電圧入力
5CH4アナログ電圧入力
6CH5アナログ電圧入力
7CH6アナログ電圧入力
8CH7アナログ電圧入力
9DGNDデジタルGND
10CS/SHDNチップセレクト/シャットダウン
11DinシリアルデータIN
12DoutシリアルデータOUT
13CLKシリアルクロック
14AGNDアナログGND
15Vrefリファレンス電圧
16Vdd電源電圧 (+2.7〜5.5V)


ラズパイMCP3008 を次のように配線した。

MCP3008名称ラズパイ物理番号ラズパイ名称
9DGND6GND
10CS/SHDN24CS0 (GPIO 8)
11Din19MOSI (GPIO 10)
12Dout21MISO (GPIO 9)
13CLK23SCLK (GPIO 11)
15Vref173.3V
16Vdd13.3V




MOSIMISO はマスターから信号を送るか、スレーブから信号を受け取るかの違いで、MOSIはマスターアウトスレーブイン、MISOはマスターインスレーブアウトの略である。

今回の場合、マスターはラズパイであり、スレーブはADコンバータのMCP3008となる。
ラズパイではこのようにSPIで使う端子が決まっているので、それに合わせて配線する。



チャネルをどうやって切り替えるのか?


MCP3008 ではコンフィギュレーションビットに送るデータによって、チャネルを選択できるようになっている。




次の表はコンフィギュレーションビットの仕様の一部だ。

Single/DiffD2D1D0
1000CH0
1001CH1
1010CH2
1011CH3
1100CH4
1101CH5
1110CH6
1111CH7


今回の用途ではSingle/Diffを1に固定しているが、0に設定すると differential となり、チャネル間での差分信号を読み取ることができるようになるようである。
詳しくはMCP3008データーシートを参照




温度センサーTMP36をつけて動作確認


こちらの記事でも使った温度センサーTMP36で、ちゃんと電圧を読み取れるか動作確認してみたいと思う。




以前にTMP36の温度計算方法を書いたので、詳しい説明は省略する。

プログラムの中でサンプリングレートを明示してあげないと、うまく動かず正しいデータが取り出せないので注意が必要だ。
MCP3008のサンプリングレートはVddが5Vのとき最大で200ksps、2.7Vの時では75kspsまでとなっている。今回Vddは3.3Vに設定するので、サンプリングレートを100kspsに設定した。


さて、このようにMCP3008で温度を測定することができた。
次はもうすこし詳しくPythonプログラムの中を見ていく。



spi.xfer2([1, (8 + channel) << 4, 0])の謎


最大の謎であったこの一行。

adc = spi.xfer2([1, (8 + channel) << 4, 0])

spi.xfer2 の引数のリストはなぜ3つなのか...
そして返り値 adc とはいったい?



色々と調べてようやく、自分なりに理解できたので解説してみる。


はじめに重要なことをお伝えする。

spi.xfer2 の引数に渡すリストは8ビットデータとして解釈される。

このことを頭におきながら、先へ進んでもらいたい。


MCP3008のデータシートから、送受信データのフォーマットを見てみよう。


MCP3008データーシートより


データシートを読むと、3バイト(8ビットx3)のデータで送受信する仕様となっている。


最初に送信データに絞って考えてみる。

送信データの1バイト目を見てみると、start bit として 1 を送信している。


spi.xfer2([1, (8 + channel) << 4, 0]) のリストの最初が1なのはそのためだ。


次に送信データの2バイト目を見てみよう。


わかりやすくするために、上位4ビット SGL/DIFF D2 D1 D0 だけ考えてみる。

コンフィギュレーションビットで説明した通り、今回はSGL/DIFFを1の値で固定する。
残りの3ビットはチャネル番号になるので、1 0 0 0 のような形にするにはチャネル番号に二進数で表される 1 0 0 0 すなわち8を足し合わせれば良いのである。

>>> bin(8)
'0b1000'


そして下位4ビットの X X X X の値は気にしなくて良いので、<< 4 で4ビット分を左にシフトして0で埋め合わせている。
だからリストの2番目は (8 + channel) << 4 で計算された値を代入しているのである。


ちなみに、<< 左ビットシフトは、その数だけ左にずらしてゼロで埋める演算だ。
bin(8 << 4)
> 0b10000000



最後に送信データの3バイト目を見ていこう。


これは8bit分データを送れば値は気にすることはない。
だから spi.xfer2([1, (8 + channel) << 4, 0]) の第3引数にはゼロを入れてあるが、べつにゼロでなくても構わないのだ。

第三引数まで入れる理由は、第二引数までだとシリアルクロック(CLK)が3バイト分働いてくれず、Doutからデータを取り出せないからである。

つまりは、spi.xfer2関数の引数のリストは、ひとつに付き8回のシリアルクロックを送信する仕組みとなっているようだ。


これで spi.xfer2([1, (8 + channel) << 4, 0]) がなぜ3つの引数をとるのか、お分かりいただけたであろう。



data = ((adc[1] & 3) << 8) + adc[2]の謎


はじめにひとつ、重要なポイント。

関数spi.xfer2は、例えばDinに3バイトデータ送信したら同時に、Doutから3バイトデータを取り出せる仕組みになっている。

adc = spi.xfer2([1, (8 + channel) << 4, 0]) の一行は3バイトのデータをDinへ書き込んでいるとともに、 Doutの値を3バイト分読み込んで、返り値 adc に格納しているのである。

だから返り値のリストは送信データと同じ数だけあり、その値は8ビットをlong型にした値である。

このことが分かれば、受信データのフォーマットの理解も簡単であろう。
データシートの受信データのフォーマットを一気に見ていく。

1バイト目


2バイト目


3バイト目


上の図から次のようなことがわかる。

1バイト目は無視してよい。
2バイト目も上位6ビット分は無視して、下位2ビットを取り出せばよい。
3バイト目には8ビットのデータがつまっている。

つまり、2バイト目の下位2ビットと3バイト目の8ビットをつなぎ合わせた形が、10bitで表現される電圧値となる。

だからチャネルから取り出す値は、data = ((adc[1] & 3) << 8) + adc[2] で計算されることがお分かりだろう。


論理演算がややこしいので、少し補足しておく。

adc[1] & 3& とはAND演算(論理積)の計算である。

例えば、3を二進数で表すと、
>>> bin(3)
'0b11'

となり、11を二進数で表すと、
>>> bin(11)
'0b1011'

となる。

この11と3のAND演算をやってみ。
>>> bin(11 & 3)
'0b11'

これは11の下位2ビットを取り出したことと同じことである。
つまり、11を3でマスクしたことになる。


それでは話を戻して、先ほどの ((adc[1] & 3) << 8) をもう一度みてみよう。

この式でやっていることは、2バイト目の受信データの下位2ビットを取り出して、左に8ビットシフトし、ゼロで埋め合わせているということだ。

だからこれに adc[2] を足すことで、10bitで表現されたアナログ電圧値を読み取ることができるわけだ。

以上でプログラムの説明を終わるが、データシートをよく見て送受信のやりとりをしっかりイメージできれば、プログラムの理解も難しいことではないことがお分かりいただけたであろう。




参考


MCP3008データーシート
ラズパイでアナログ電圧を扱う (5) MCP3208のプログラム①
ラズベリーパイのセンサの測定値変換のプログラムについて


あなたにおすすめ