Tanuki_Bayashin’s diary

電子工作を趣味としています。最近はラズベリーパイPicoというマイコンを使って楽しんでいます

【A/D変換】Raspberry Pi PicoにてMCP3208を動かす

※なにか気になる点がありましたらコメント欄にご記入ください。また、工作や回路を製作する場合には、細かい作業などに対して、細心の注意を払われるようお願いいたします。

【目次】

1.はじめに

 ラズベリー・パイ Pico(以下Picoと表記)のA/D変換のポートを増やしたかったので、Picoを用いてMCP3208という、マイクロチップ社製のA/D変換機能を持ったICを動かすことを考えてみました。

写真1 マイクロチップ社製MCP3208
写真2 実験風景

マチュアの電子工作erが書いたブログです。いたらない点があるかと思いますが、大目に見て頂けると幸いです。
(;´∀`)

2.MCP3208について

 おおよそこちらの方の記事を参考にさせて頂きました。MCP3208の基本的な使い方など参照して頂けたらと思います。

リンク先:
www.denshi.club

 実体配線図を図1に示します。

図1 実体配線図

 Picoとは下の対応表の通りに接続します。

対応表:

Pico側 MCP3208側
4番 SCK 13番 CLK
5番 TX 11番 Din
6番 RX 12番 Dout
7番 CSn 10番 /CS/SHDN

 MCP3208とはSPI機能を用いてPicoとやり取りをします。

  • 具体的なコードは3章で見ていきますが、データを読み出すときは、1chずつcs(0)(チップセレクト)を入れ有効にし、データを読みだしたらcs(1)にして選択を解除します。

(チャンネルを変えない場合でも、その都度cs(0)をしないとデータの読み出しはできないみたいです)

  • またMCP3208は、1~8番ピンがA/D変換の入力chとなっています(他のモードもあるようです)。
  • 今回は1番と2番ピンからVR0、1の電圧を読み取ることとします。(ch0,1)

※今さらですが、このMCP3208は12ビットの分解能を持ちます。ここでは、0~3.3Vを0~4095の値に変換します。

  • また、値を読み取るときは、次に示すような3つのデータを送信し、その度ごとに1バイトずつデータをPicoが受け取ります。(図2~図4)
図2 送信するデータ

図2の中のD0~D2はチャンネルを指定するのに使用します。具体的には図3のように値をセットします。

図3 D0~D2とchの関係
図4 読み取った値の中身

Pico側で読み取った値は図4のようになります。a0~a11 とありますが、A/D変換の結果である12bitのデータを意味しています。

具体的なコードを見ていく中で、さらに解説していきます。

3.ソースコード

 実装したソースコードをリスト1に示します。

リスト1 実装したソースコード

from machine import SPI, Pin
import utime

#ここから処理がスタートします
if __name__ == '__main__':

    spi_sck = Pin(2)
    spi_tx  = Pin(3)
    spi_rx  = Pin(4)
    # 周波数 400kHz で SPI ペリフェラル 0 を作成
    spi = SPI(0, baudrate=400000, sck=spi_sck\
              , mosi=spi_tx, miso=spi_rx)
    # ピン 5 でチップセレクトを作成。
    cs = Pin(5, mode=Pin.OUT, value=1)
    
    # Process arguments
    print('Press Ctrl-C to quit.')

    rxdata = bytearray(6)
    try:
        while True:
            # ペリフェラルを選択。
            cs(0)
            rxdata[0] = spi.read(1, 0x06)[0]
            rxdata[1] = spi.read(1, 0x00)[0]
            rxdata[2] = spi.read(1, 0x00)[0]
            # ペリフェラルを選択解除。
            cs(1)
            
            # ペリフェラルを選択。
            cs(0)
            rxdata[3] = spi.read(1, 0x06)[0]
            rxdata[4] = spi.read(1, 0x40)[0]
            rxdata[5] = spi.read(1, 0x00)[0]
            # ペリフェラルを選択解除。
            cs(1)
            
            data0 = ((rxdata[1] & 0x0f) << 8) + rxdata[2]
            data1 = ((rxdata[4] & 0x0f) << 8) + rxdata[5]
            print(rxdata, data0, data1)
            utime.sleep(1)
            
    # ctl-C が押されたときの処理です
    except KeyboardInterrupt:
        # ペリフェラルを選択解除。
        cs(1)
        spi.deinit()

解説:
① 7,8,9行でピンを指定し、11行でSPIの処理を扱うインスタンスを生成します。

② 14行でGP5(7番ピン)をcsに指定します。

③ 21行からメインループに入ります。

④ 24~26行でch0から電圧値を読み取ります。
 
 関数 spi.read(a, data) は1バイトのdataを送信し、a バイトデータを読み出します。
 2章で見たとおり、dataにはchを指定する値をセットします。

 データを読み出す関数には [0] をお尻に付けて、リスト(?)の中身を取り出します。

 要素が1つだけの場合でも”[0]”を付けないと、数値としてはみなされず、型が合っていないとしてエラーになります。

※ここの処理は2章で示したサイト内のArduino用のスケッチが大きな助けとなりました。
 結構はまってしまって、ChatGPTの力を借りたりもしました。
(Pyhtonの基本ができてないので(汗))

⑤ 32~34行ではch1の値を読み取っています。

⑥ 38、39行では読み取った値を12ビットのデータに成形し、意味のあるものにしています。

⑦ 40行で結果を表示しています。

⑧ 48行以降。選択を解除し、SPIバスをオフにします。(終了処理です)

おおよその処理は以上です。

4.動画

 動作のようすを示します。

youtu.be

ボリュームを動かすと、PC画面の数字が変化しています。
A/D変換により値を読み取っているわけですね。(^_^)

以上となります。お付き合い下さり、ありがとうございました。