Raspberry PiでA/DコンバーターMCP3002を使ってAD変換をしました
TOP > てきとうにこらむ > ゲーム作りとプログラミング日記 > Raspberry PiでA/DコンバーターMCP3002を使ってAD変換をしました
Raspberry PiはA/D変換に対応していない
Raspberry Piはアナログで電圧を取得することができないが、A/D変換ICがあればSPIを使ってアナログでの電圧を取得することができる。
SPIを許可する
まず最初に、raspi-configコマンドでSPIを許可する。
$ sudo raspi-config
Advanced OptionsをEnterしてからSPIにEnterするとSPI有効にするか?という質問が来るのでそこでEnabledを選択。終わったら再起動。
$ sudo reboot
再起動後、SPIが許可されているかを確認。
$ cat /boot/config.txt | grep dtparam
dtparam=spi=on
lsmodコマンドでも確認できる。
$ lsmod | grep spi
spi_bcm2835 7868 0
SPIを使う
py-spidevモジュールを使う。
$ git clone git://github.com/doceme/py-spidev
$ sudo python setup.py install
実行したのだけど、以下の様なエラーメッセージが出てしまった。
spidev_module.c:20:20: fatal error: Python.h: そのようなファイルやディレクトリはありません
#include <Python.h>
Python.hがないということは、python-devパッケージをaptでインストールすればいい。
$ sudo apt-get install python-dev
これでさきほどのsetup.pyを実行してあげれば、py-spidevモジュールが使えるようになる。
SPIというインターフェースの特徴
SPIというインターフェースは、データの命令方法については一定の仕様があるけど、データの中身は自由に決められる。これはすなわち、使うSPIデバイスのデータシートを読んで使い方を理解しろということである。SPIはそれぞれやり方が違うためなのだ。
コード
ch0には接続しているLM61CIZの電圧を取得して温度に変換するようにして、ch1には照度センサーであるNJL7502Lで明るさをそのまま10bitの分解能で示してもらおう。
import spidev
import time
import subprocess
spi = spidev.SpiDev()
spi.open(0, 0)
def voltageToTemperature(volt):
offset = (0.6 / 5) * 1024
base_temp = 5 / 1024.0
return (float)(volt - offset) * base_temp * 100.0
try:
while True:
# ch0
resp = spi.xfer2([0x68, 0x00])
value = ((resp[0] << 8) + resp[1]) & 0x3ff
print voltageToTemperature(value)
# ch1
resp = spi.xfer2([0x78, 0x00])
value = ((resp[0] << 8) + resp[1]) & 0x3ff
print value
time.sleep(1)
except KeyboardInterrupt:
spi.close()
チャンネルの選択方法
MCP3002は2つの入力をデジタルに変換できるが、それをどのように取得すればいいのだろうか。
xfer2メソッドにある、0x68と0x78と言うのは何か。MCP3002のデータシートを見ると以下のようになっている。
+-------+----------+----------+------+
| start | SGL/DIFF | ODD/SIGN | MSBF |
+-------+----------+----------+------+
0x68は2進数に直すと0b1101000である。先頭4ビットを見てみると「1101」である。ということは。
+-------+----------+----------+------+
| 1 | 1 | 0 | 1 |
+-------+----------+----------+------+
となる。さて、MCP3002のデータシートのTABLE5-1を見てみると以下のようになる。
- SINGLE ENDED MODEでSGL/DIFFは1、ODD/SIGNは0でCHANNELが0
- SINGLE ENDED MODEでSGL/DIFFは1、ODD/SIGNは1でCHANNELが1
すなわち、MCP3002では0x68でch0、0x78でch1を選択できるということになる。
データの取得方法
データを取得するには。
- 8bitで送られる
- ビッグエンディアンで返ってくる
- MCP3002の分解能は10bitである。
ということは、xfer2の返り値resp[0]は下位2ビットがデータの上位2ビット、resp[1]がデータの残り下位ビットであるということになる。resp[0]とresp[1]のビット配列を足し合わせるにはどうすればよいのかというと。resp[0]を8ビット左にシフトしてやればいい。
resp[0]は下位2ビットしか使っていない。ということはのこり上位6ビットの値も含まれてしまっているということである。あれれ〜?どうしたらいいのだ?と
というわけで
0x3ffをAND演算しているのである。0x3ffとは10進数で1023。2進数で0b1111111111。つまりそれ以上の値はすべて0にされる。これで0から1023の間に収まる、というわけである。
感想
つかれた。あと、コンピュータシステムの理論と実装読んでて結構理解捗るもんだなーと思った。