てきとうなさいと べぇたばん

Raspberry PiでA/DコンバーターMCP3002を使ってAD変換をしました

MCP3002にセンサーをくっつけるところ。

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の間に収まる、というわけである。

感想

つかれた。あと、コンピュータシステムの理論と実装読んでて結構理解捗るもんだなーと思った。