LoginSignup
0
2

More than 5 years have passed since last update.

spidevを使わずにRaspberry PiにA/DコンバータMCP3002をつなぐ

Last updated at Posted at 2019-02-09

電子工作初心者です。
Raspberry PiでADコンバータを利用したくて、Raspberry PiにA/DコンバータMCP3002をつなぐの記事を見ながらやってみたものの、応答が全部ゼロになってしまいます。どうやらspidevが正常に動作しなくなった模様。(~原因不明~ → 原因判明しました。再起動が必要だったようです。spidevを使った例はこちら

そこで、いつも参考にしているカラー図解 最新 Raspberry Piで学ぶ電子工作を見てみると、spidevを使わずにGPIOの制御だけで値を取得していたので、これを参考にコードを書いてみることにしました。
ただし、本書ではMCP3208を使用しているので、一部MCP3002用に書き換える必要があります。

使用機材

  • Raspberry Pi 3 model B+
  • MCP3002(ADコンバータ)
  • 可変抵抗10kΩ
  • ジャンパー線など

配線図

配線図.PNG

MCP3208とMCP3002の違い

MCP3002 MCP3208
チャンネル数 2 8
分解能 10bit 12bit

チャンネル数も分解能も違うので、Pythonコードでは入力も出力も変える必要があることが想像できます。そこでデータシートで詳しく見ていきます。

入力

MCP3002もMCP3208と似ていますが、チャンネル数が違うので多少差があります。

MCP3208

  • Start
  • SGL/DIFF : SINGLE ENDED MODEならば1、DIFFERENTIAL MODERNITYならば0。
  • D2
  • D1
  • D0

の5ビットで入力します。D2、D1、D0でチャンネル番号を指定します。
SINGLEモードでCH0からデータを取るなら0d11000を送信すれば良さそうです。

MCP3002

  • Start
  • SGL/DIFF
  • ODD/SIGN : アナログ値を取りたいチャネルを指定。
  • MSBF の4ビットで入力します。チャンネル数が2つになるのでその分少なくなりました。 最後のMSBFは出力するフォーマットの設定。1ならばMSB、0ならばLSB。今回は単純そうなMSBを選んでおくことにします。 SINGLEモードでCH0からデータを取るなら0d1101を送信すれば良さそうです。

出力

分解能が異なるので、出力されるビット数が異なります。

MCP3208

分解能が12ビットで、最初にNullがつくので、合計13ビット読む必要があります。
取得された値は4096段階のデータになります。

MCP3002

分解能が10ビットで、最初にNullがつくので、合計11ビット読む必要があります。
取得された値は1024段階のデータになります。

以上のことをふまえて、Pythonで書いてみました。

Pythonコード

import RPi.GPIO as GPIO
import time

#MCP3002からSPI通信で10ビットのデジタル値を取得。0から1の2チャンネル利用可。
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
    if adcnum > 1 or adcnum < 0:
        return -1
    GPIO.output(cspin, GPIO.HIGH)       #CSをONにする
    GPIO.output(clockpin, GPIO.LOW)     #SCSKをONにする
    GPIO.output(cspin, GPIO.LOW)        #CSをOFFにする。これで通信がスタートする。

    #commandout = 0b01101000
    commandout = adcnum   #データを取得するCH番号
    commandout |= 0x0d    #SGL/DEF=1 および MSBフォーマット
    commandout <<= 3      #LSBから8ビット目を送信するようにする
    for i in range(4):
        # LSBから数えて8ビット目から3ビット目までを送信
        if commandout & 0x80:
            GPIO.output(mosipin, GPIO.HIGH)
        else:
            GPIO.output(mosipin, GPIO.LOW)
        commandout <<= 1
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
    adcout = 0
    #11ビット読む(ヌルビット+10ビットデータ)
    for i in range(11):
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
        adcout <<= 1
        if i>0 and GPIO.input(misopin)==GPIO.HIGH:
            adcout |= 0x1
    GPIO.output(cspin, GPIO.HIGH)
    return adcout

GPIO.setmode(GPIO.BCM)

# ピンの名前を変数として定義
SPICLK = 11
SPIMOSI = 10
SPIMISO = 9
SPICS = 8
# SPI通信用の入出力を定義
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICS, GPIO.OUT)

vol_old = -1

try:
    while True:
        inputVal0 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
        vol = "{0}%".format(int(inputVal0*100/1023)) #分解能が10ビットなので1023で割る
        print(vol)
        time.sleep(0.2)

except KeyboardInterrupt:
    pass

GPIO.cleanup()

実行結果

実行して抵抗値を変えると以下のように出力されます。

21%
21%
21%
29%
34%
34%
64%
71%
72%
71%

かなり手間はかかりましたが、仕組みがよくわかったので勉強になりました。

参考

カラー図解 最新 Raspberry Piで学ぶ電子工作
5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (9) A-Dコンバータの利用6 MCP3002/MCP3008

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2