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

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

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

##使用機材
- Raspberry Pi 3 model B+
- MCP3002（ADコンバータ）
- 可変抵抗10kΩ
- ジャンパー線など

##配線図
![配線図.PNG](https://qiita-image-store.s3.amazonaws.com/0/346401/a0a9b609-2a4a-f0ea-e791-df3393f941f6.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コード

```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で学ぶ電子工作](https://raspibb1.blogspot.com/)
[5ドル！ラズパイ・ゼロ（Raspberry pi Zero）でIoT　(9)　A-Dコンバータの利用6　MCP3002/MCP3008](https://www.denshi.club/pc/raspi/5raspberry-pi-zeroiot9a-d6mcp3002.html)