PR
スポンサーリンク

【初心者】MCP3008/3004/3208/3204の使い方とは?ラズパイで試してみた

皆さんこんにちは!メカ旦那です。

ADコンバータでよく聞く「MCP3008/3004/3208/3204」 ですが、データシートが英語だし、色々難しい事書かれてるしよくわからない・・・という方も多いのではないでしょうか?そんな方向けにわかりやすく解説してみました。

そもそもADコンバータって何?・・・という方はまずこちらの記事をご覧ください!

MCP3xxx とは

外観

MCP3xxx はアメリカの半導体メーカー「Microchip Technology(マイクロチップテクノロジー)」が作るADコンバータになります。

秋月電子やAmazonなど様々なサイトで販売されており、在庫数も多いため、入手性が良いです。

データシートは秋月電子でダウンロードできますが、英語長文なので読みづらいです。。。そこでそれぞれの特徴を共通点、違いに分けて解説します。

共通点

まずはMCP3xxxの共通点です。

MCP3xxxの共通点
  • ピン配置がほぼ同じ
    • 左にアナログ入力、右に電源入力とSPI出力があるという点で共通しています。Ch数の違いでアナログ入力数や、GND位置が異なっていますが、全体的な配置は似ています。
  • 2.7~5.0Vで駆動
    • 入力電圧範囲は2.7~5.5Vになります。通常はマイコンから電源供給することになりますが、3.3V、5.0V出力が多いので、基本どのマイコンからでも給電できます。
  • SPI出力
    • どのADコンバータも出力はデジタルとなり、I2C等様々ありますが、MCP3xxxはSPI出力になります。
    • 品番により多少異なりますが、SPIの流れはマスターから5bitの入力を受けた後、11~13bitのデータを出力するという形になります。詳しくはこちらで解説します。

SPIについてはこちらで解説しています!

違い

続いてMCP3xxxの違いはこちらです。

MCP3xxxの違い
  • チャンネル数
    • アナログ入力できる端子数をチャンネル数と言いますが、型番の1桁目がその数になります。つまりMCP3004/3204は「4」、MCP3008/3208は「8」になります。
  • サンプリングレート
    • 入力されたアナログ信号(振幅)を一定周期で読み取る事をサンプリングと言い、その周期をサンプリングレートと呼びます(単位はHz、sps、s/s、sa/sなど)。
    • MCP3208/3204は最大 100 ksps、MCP3008/3004は 200 kspsになります。つまりサンプリングレートはMCP300x系の方が速いです。
  • 分解能
    • サンプリングした振幅を予め設定した段階に区切って数値化しますが、その細かさを分解能(bit 数)と言います。
    • 型番の3桁目が、bit数の1桁目に当たります。つまりMCP3208/3204は12 bit (0–4095)、MCP3008/3004は10 bit (0–1023)になります。MCP32xxの方が分解能が大きいです。

サンプリングレート、分解能はこちらで詳しく解説しています!

通信の流れ

MCP3xxxはセンサ等からアナログ入力を受けた後、AD変換し、コンピュータ等のマスターにSPI出力します。通信の流れについて解説します。

通信の流れ
  1. アナログ入力
    • センサ等外部デバイスのアナログ出力を受けます。
  2. MOSI(マスター → スレーブ)
    • 次にコンピュータ等のマスター出力を受けます。
    • 3 byte が入力されますが、特に以下の bit が重要になります。
      1 bit:Start bit(1)
      1 bit:シングルエンド(1)/差動通信(0)
      1 ~ 3 bit:アナログ入力のチャンネル番号
  3. MISO(スレーブ → マスター)
    • 続いてマスターへ出力します。
    • 3 byte を出力しますが、特に以下の bit が重要になります。
      1 bit : Null (0)
      1 ~ 10,12 bit : AD変換後のデータ(MCP3208/3204は12 bit、MCP3008/3004は10 bit)
メカ旦那
メカ旦那

マスター側では関数「spi.xfer2()」を用いる事で、MCP3xxxよりデータを読み取ります。実際の関数の使い方は複雑なため後ほど解説します

MCP3208とラズパイを繋いでみた

手を動かした方がわかりやすいので、実際にMCP3208とラズパイ3A+を通信してみました。

動画

イメージはこんな感じになります。

可変抵抗からのアナログ出力を、MCP3208でAD変換しラズパイに入力。その後入力データに合わせてラズパイからLEDの明るさを変えるという構成です。

ラズパイにはアナログ入力がない!

今回なぜラズパイと繋いだかと言うと、アナログ入力機能がないからです。

Arduino Unoなど一部のマイコンにはアナログ入力ピンがあり、ADコンバータ不要になります。しかしラズパイ(ピコ以外)は無いため、ADコンバータが無いとアナログ入力を行うことができません。その為今回ラズパイを繋いでみました。

メカ旦那
メカ旦那

ラズパイにアナログ入力が無い理由についてはこちらをご覧ください!

使用部品

使用するのはこちらです。

部品はまとめて購入することも可能です。

回路

回路図はこちらです。

回路図のポイント
  • 信号の流れは以下です。
    • 可変抵抗からのアナログ出力を、MCP3208でAD変換しラズパイにSPI出力。
    • ラズパイからArduino Leonard へI2C出力。間にレベル変換基板があり、3.3V→5.0Vに変換。
    • Arduinoで入力に合わせてLEDの明るさをPWMで変える
  • ラズパイの信号電圧は3.3Vですが、Arduinoは5Vの為、直結では通信できません。そこで「4ch双方向ロジックレベル変換モジュール」を間に接続し、3.3V⇔5Vの電圧変換を行っています。

プログラム マスター側

//ライブラリインポート
import spidev	//ラズパイ向けSPIライブラリ
import time	
import smbus	//ラズパイ向けI2Cライブラリ

//SPI初期設定
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1350000	
spi.mode = 0b00			// SPIモード [0,0]

//I2C初期設定
i2c = smbus.SMBus(1)
ARDUINO_ADDR = 0x09		//スレーブ側I2Cアドレス

//アナログ値読み取り関数
def read_adc(channel):

    //チャンネル0~7以外はエラー扱い
    if channel < 0 or channel > 7:
        raise ValueError("channel must be 0-7")

    //spi.xfer2の引数作成
    byte0 = 0x06 | ((channel & 0x04) >> 2)  // スタート(1) + シングルエンド(1) + チャンネル(0)
    byte1 = (channel & 0x03) << 6           // チャンネル(1,0 bit目)
    byte2 = 0x00

    //引数に格納されたデータを出力
    //その後スレーブより3byte分の値が戻される為、変数「result」に格納
    result = spi.xfer2([byte0, byte1, byte2])

    //受領した3byteを12bitに変換
    adc_value = ((result[1] & 0x0F) << 8) | result[2]

    return adc_value  

//メイン処理
try:
    while True:
        adc_raw = read_adc(0)			//引数にチャンネル№(0)を格納し、関数呼び出し
        adc_8bit = adc_raw >> 4			//12bit→8bitに変換
        i2c.write_byte(ARDUINO_ADDR, adc_8bit)	//I2C出力
        print(f"Sent : {adc_8bit}")		//出力値をシリアルモニタに表示
        time.sleep(0.5)

except KeyboardInterrupt:
    print("終了しました。")

finally:
    spi.close()

プログラムについては、マスター・スレーブそれぞれに書き込む必要があります。まずはマスター側(ラズパイ)のポイントです。

プログラムのポイント
  • ラズパイ向けSPIライブラリ「spidev」、I2Cライブラリ「smbus」を利用する事で簡単に通信ができます。冒頭でインストールします。
  • メイン処理の中で、関数「read_adc()」を呼び出します。
  • read_adc内にはspi.xfer2()というMCP3208とSPI通信をする関数があります。使い方は後述します。
  • spi.xfer2によって取得した値は12 bitの為、I2Cで出力できる8 bit 変換します。出力値はシリアルモニタに表示します。
  • キーボードで任意のキーを押すと処理が終了します。
result = spi.xfer2([byte0, byte1, byte2]) について
  • 引数(byte0, byte1, byte2)はMOSIに該当します
    • マスターから 3 byte を出力しますが、特に以下の bit が重要です。
      1 bit:Start bit(1)
      1 bit:シングルエンド(1)/差動(0)
      0 ~ 2 bit:アナログ入力のチャンネル番号
    • この5 bit を3 byte の指定位置に格納します。画像が格納のイメージです。
  • 戻り値(result)はMISOに該当します
    • スレーブから 3 byte が戻ってきますが、特に以下の bit が重要です。
      1 bit : Null (0)
      0 ~ 10,12 bit : AD変換後のデータ。MCP3208/3204は12 bit、MCP3008/3004は10 bit。
    • この 3 byte を 12 bitに変換します。画像がイメージです。

プログラム スレーブ側

//ライブラリインポート 
#include <Wire.h>                   //Arduino向けI2Cライブラリ「Wire.h」をインポート

//初期設定
volatile byte receiveData;          //LEDに出力する変数receiveDataを宣言

void setup() {
  Wire.begin(9);                    //Arduinoにスレーブアドレス9を設定
  Wire.onReceive(turnOnLED);        //マスターからのデータ受信時に関数「turnOnLED」を呼び出す
  pinMode(5, OUTPUT);               //LEDが接続されている5ピンを出力に設定
}

//呼び出し関数
void turnOnLED(int Number) {
  if (Wire.available()) 
   receiveData = Wire.read();       //マスターから受信した数値を変数receiveDataに格納
}

//メイン処理
void loop() {
  analogWrite(5, receiveData);      //LEDピンに変数receiveDataを出力。つまりPWMでLEDの明るさを制御。
}

続いてスレーブ(Arduino Leonard)側のコードです。ポイントは以下です。

  • Arduino向けライブラリ「Wire.h」を利用する事で簡単にI2Cを行うことができます。冒頭でインストールします。
  • 関数「Wire.begin()」でスレーブアドレスを任意に設定できます。今回は9にします。
  • マスターからのデータ受信時に関数turnOnLEDを呼び出し、変数に値を書き込みます。そしてメイン処理でLEDピンに変数をPWM出力し明るさを変えます。
メカ旦那
メカ旦那

PWMについてはこちらで解説しています!

まとめ

まとめはこちらになります。

まとめ
  • MCP3xxxxは様々なサイトで販売されている入手性の良いADコンバータ。
  • アナログ入力Ch数は4もしくは8、サンプリングレートは100もしくは200 ksps、分解能は10もしくは12 bit。
  • 出力はSPI通信。マスターとは 3 byte のデータをやり取りする。

この解説が少しでもわかりやすければ幸いです!

メカ旦那

旧帝大工学部を卒業後、電気制御設計職をしています。生産設備や産業用ロボット等、様々な開発に取り組んでいます。電験三種も保持しています。イラストや画像を用いて電気・電子・制御をわかりやすく解説します!

メカ旦那をフォローする
Raspberry Pi
スポンサーリンク

コメント