はじめてのAD変換（RaspberryPi3で試すアナログ・デジタル変換）

# 今日のゴール

----
# アナログ値をデジタル値に変換する

----
# "AD変換"

----
# 本記事の登場人物

----
# 主役

彼らがAD変換の主役です。本記事で解説します。

* **12ビットADコンバータ MCP3208-CI/P x 1**
    * アナログ値をデジタル値に変換します
* **半固定抵抗 x 1**
    * 抵抗値を変化させアナログ値をセンシングします
* **フォトレジスタ x 1**
    * 抵抗値を変化させアナログ値をセンシングします

----
# 脇役

ちなみに彼らも必要ですが、本記事では解説しません。

* RaspberryPi一式
* 抵抗(330Ω) x 1
* 赤色LED x 1
* ブレッドボード x 1
* ジャンパワイヤ
    * オス-メス x 1セット
    * オス-オス x 1セット

----
# AD変換とは？

アナログ値をデジタル値に変換します。

----
# なぜデジタル値が必要なのか？

RaspberryPiへの入力は基本的には、2進数として、LOW(0)/HIGH(1) 2つの状態のどちらかになる。
これは、部屋の明るさだと、明かりがついているか消えているか、の2段階として理解します。
↓
これをデジタル値、0-4095のような段階的な値として入力することを狙います。

----
# そもそもアナログ値、デジタル値って？

* アナログ値
    * 連続値
    * e.g. 明るさ、温度、電圧など
* デジタル値
    * 飛び飛びの値（離散値)
    * e.g. 計測して桁を切り捨てた値（デジタル時計）など

----
# AD変換 (画像引用元: [Raspberry Piで学ぶ電子工作|ブルーバックス](http://bluebacks.kodansha.co.jp/special/rspi1.html))
![adc.jpg](https://qiita-image-store.s3.amazonaws.com/0/5707/819d9bc3-1813-35b3-bc71-5e0aa877cd4f.jpeg)

* 1. センサからのアナログ値の取得
* 2. AD変換
* 3. デジタル値の通信

----
# 1. センサからのアナログ値の取得:
特定の地点での抵抗値を変化させ、端子から出力させるアナログ電圧を変化させる（0V-3.3V）1.65V

* 半固定抵抗
* フォトレジスタ (CdSセル)

----
# 半固定抵抗?

<img width="400" alt="P-06110.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/5707/c3b78d58-4300-a316-deb2-a749c6aed22d.jpeg">

> 画像引用元: [akizukidenshi.com](http://akizukidenshi.com/catalog/g/gP-06110/)

* 可変抵抗の一つで抵抗の大きさを調整可能

----
# フォトレジスタ (CdSセル)?

<img width="400" alt="I-00110.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/5707/6911d98c-647c-eb65-9e5a-02d6b980b63f.jpeg">

> 画像引用元: [akizukidenshi.com](http://akizukidenshi.com/catalog/g/gI-00110/)

----
# 2. AD変換

アナログ電圧を測定しその値を、ADコンバータにてAD変換しデジタル値にする(0-4095->12bit) 2048

* ADコンバータ

----
# ADコンバータ?
(12ビットADコンバータ MCP3208-CI/P)

<img width="400" alt="I-00238.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/5707/276740b5-98ad-d23a-33f5-9020e9f81a17.jpeg">

> 画像引用元: [akizukidenshi.com](http://akizukidenshi.com/catalog/g/gI-00238/)

----
# ADコンバータ特徴
* 16ピンを持つ回路
    * 0ch-7chの8つのアナログ値を読み取れるチャネル
* アナログ値をデジタル値に変換する
* 12ビット精度で送れる
    * $2^12=4096=4*10^3$

<img width="150" alt="スクリーンショット 2016-11-22 1.59.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/5707/48ee580c-9790-a6a6-6639-e82505be4101.png">

> [MCP3204/3208データシート](http://ww1.microchip.com/downloads/en/DeviceDoc/21298e.pdf)

----
# 3. シリアル通信
デジタル値を2進数 (1000_0000_0000 = 2048) としてSPI通信で送る

* SPI通信
* I2C通信

----
# 3. シリアル通信

<img width="500" alt="スクリーンショット 2016-11-22 1.55.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/5707/aa493d3c-cc4d-901f-d3e3-8dc9048c941a.png">

> [MCP3204/3208データシート](http://ww1.microchip.com/downloads/en/DeviceDoc/21298e.pdf)

----
# code

```py3
# MCP3208からSPI通信で12ビットのデジタル値を取得。0から7の8チャンネル使用可
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
    if adcnum > 7 or adcnum < 0:
        return -1
    GPIO.output(cspin, GPIO.HIGH)
    GPIO.output(clockpin, GPIO.LOW)
    GPIO.output(cspin, GPIO.LOW)

    commandout = adcnum
    commandout |= 0x18  # スタートビット＋シングルエンドビット
    commandout <<= 3    # LSBから8ビット目を送信するようにする
    for i in range(5):
        # LSBから数えて8ビット目から4ビット目までを送信
        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
    # 13ビット読む（ヌルビット＋12ビットデータ）
    for i in range(13):
        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
```

```py3
inputVal0 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
```

----
# 演習1

<img width="500" alt="スクリーンショット 2016-11-21 0.22.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/5707/3585f1a4-55dd-c712-db66-39d429cad1b6.png">
> 画像引用元: [Raspberry Piで学ぶ電子工作|ブルーバックス](http://bluebacks.kodansha.co.jp/special/rspi1.html)

```py3:06-01-print.py
    while True:
        inputVal0 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
        print(inputVal0)
```

----
# 演習2

<img width="500" alt="スクリーンショット 2016-11-21 0.22.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/5707/57732f69-de67-d967-495b-4addabca05e4.png">
> 画像引用元: [Raspberry Piで学ぶ電子工作|ブルーバックス](http://bluebacks.kodansha.co.jp/special/rspi1.html)

```py3:06-02-led.py
    while True:
        inputVal0 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
        if inputVal0 < 2000:
            GPIO.output(LED, GPIO.HIGH)
        else:
            GPIO.output(LED, GPIO.LOW)
```

----
# 演習3

```py3:06-03-volume.py
    while True:
        inputVal0 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
        vol = "{0}%".format(int(inputVal0*100/4095))
        if vol != vol_old:
            print(vol)
            args = ['amixer','-q','cset','numid=1',vol]
            subprocess.Popen(args)
            vol_old = vol
```

----
# まとめ

* AD変換することで、センサーに入力されたアナログ値をデジタル値として回路から利用することができる
* AD変換はADコンバーターを使って行う
* デジタル値の通信はSPI通信でおこなう

なお、AD変換の仕組みは[Raspberry Piで学ぶ電子工作(ブルーバックス)](https://www.amazon.co.jp/dp/4062578913)にわかりやすくまとまっているので、みなさん買って読みましょう。

---
# 参考
## 書籍
* [Raspberry Piで学ぶ電子工作 超小型コンピュータで電子回路を制御する (ブルーバックス) | 金丸 隆志 |本 | 通販 | Amazon](https://www.amazon.co.jp/dp/4062578913)

## 回路
* [MCP3204/3208](http://ww1.microchip.com/downloads/en/DeviceDoc/21298e.pdf)