株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。新規開発案件のご依頼をお待ちしております。

*

Arduino UnoでSPI通信(その1)Arduino Uno2台で通信

      2017/05/24

ArduinoでのSPI通信についてです。SPI通信(Serail Peripheral Interface:SPI)はマイコン系と周辺デバイス間の短距離間で利用されている同期型のシリアル通信の一種です。同様の通信方法としては、I2cがあります。ArduinoやRaspberry Piの周辺デバイスでは、LCDやADコンバータ等で採用されていると思います。I2Cと同様に使いこなしたい通信方法の一つだと思います。

ここでは、2台のArduino Unoを以下のように接続してマスタとスレーブにしてごく簡単な通信を確認しました。Arduino UnoはそれぞれPCに接続しています。

主に以下を参考にしました。ありがとうございます。
Arduinoリファレンス
Arduinoリファレンス日本語訳
ArduinoでSPIの双方向通信をしてみた

ここから具体的な内容です。

Arduino Uno間の配線について
SPIでは以下の配線を使います。
MISO (Master In Slave Out):スレーブからマスタへのライン
MOSI (Master Out Slave In):マスタからスレーブへのライン
SCK (Serial Clock) :データ転送同期用のクロック信号
SS (Slave Select):スレーブデバイスを選択、つまりマスタへのデータ転送を可能にするためのピン。

SSのピンがSPIの特徴の一つでこのピンを利用して複数のスレーブを制御することになります。このピンがLowの場合にマスタとの通信が有効になり、Highの場合はマスタとの通信を無視することになります。

マスタ、スレーブそれぞれ以下のように接続しました。
SS – Pin10
MOSI – Pin11
MISO – Pin12
SCK – Pin13

以下はマスタ側ですが、スレーブ側の同じピンに接続します。

スケッチの内容
Arduinoでは、SPI.hをインクルードして、SPIライブライが利用出来ます。以下のようなスケッチを書きました。処理としては、マスタ側のIDEのシリアルモニタから入力した文字をそのままスレーブ側から送信します。このようなスケッチで単純な通信の確認が出来たという内容です。

マスタ側

/*
 * SPIマスタ
 * SS   - Pin10
 * MOSI - Pin11
 * MISO - Pin12
 * SCK  - Pin13
 */

#include <SPI.h>

#define SSPin 10

void setup() {
  Serial.begin (9600); 
  Serial.println("Master");

  pinMode(SS,OUTPUT); //SSピンを出力設定

  SPI.setBitOrder(MSBFIRST);  //最上位ビット(MSB)から送信
  SPI.setClockDivider(SPI_CLOCK_DIV4);  //通信速度をデフォルト
  SPI.setDataMode(SPI_MODE2);   //アイドル5Vで0V→5Vの変化で送信する
  SPI.begin();  //開始
}

void loop() {
  char snd;
  char rcv;

  //UARTから読み込み
  snd = Serial.read();

  //データがあれば送信
  if(snd != -1){

    //このSlaveをセレクトする
    //(マスタ通信は有効です)
    SetSSPin(LOW);

    //送信
    SPI.transfer(snd);
    delay(100);

    //受信
    rcv = SPI.transfer(0);

    //データ確認
    Serial.println(rcv);
  }
}

/*
 * SSピンの設定
 * Lowでマスタからの通信が有効(セレクト)
 * (Highではマスタから通信出来ない(無視される)セレクト解除の状態)
 */
void SetSSPin(int val)
{ 
    digitalWrite(SSPin, val); 
}

SPIライブラリを利用していますので、詳細が必要な場合は上記の参考にしたサイトを参照して頂ければと思いますが、要点は以下です。

初期設定で以下を設定しています。
SSピンを出力
ビット送信の順序を最上位ビット(MSBFIRST)
通信速度をデフォルト(SPI_CLOCK_DIV4)
送信のタイミングをアイドル5Vで0V→5Vの変化で送信(SPI_MODE2)

loop() では、UARTで文字入力があれば、スレーブ側へ送信しています。ここでの要点は、やはりSSピンの設定です。SSピンをLOWに設定してこのマスタをスレーブの通信を有効にしています。実際には必要なタイミングに応じてHIGHにも設定
してまたLOWに設定する処理になると思います。ここでは単純にLOWに設定しているだけです。これだけでここでは通信が出来ました。

スレーブ側

/*
 * SPIスレーブ
 * SS   - Pin10
 * MOSI - Pin11
 * MISO - Pin12
 * SCK  - Pin13
 */

#include <SPI.h>

void setup() {
  pinMode(MISO,OUTPUT); //MISOを出力

  SPI.setBitOrder(MSBFIRST);  //最上位ビット(MSB)から送信
  SPI.setClockDivider(SPI_CLOCK_DIV4);  //通信速度をデフォルト
  SPI.setDataMode(SPI_MODE2);   //アイドル5Vで0V→5Vの変化で送信する
  SPCR |= _BV(SPE);
    
  SPI.attachInterrupt(); 
}

// SPI割り込み処理
ISR(SPI_STC_vect)
{
  byte ch = SPDR;    //SPIの受信バッファから取得
  SPDR = ch;  //送信バッファに書き込む
}

void loop() {
  // put your main code here, to run repeatedly:
}

MISOを出力に設定して、マスタ側と同様に初期設定をして割り込みを有効にしています。割り込み処理で受信データをそのまま送信しています。部分的にレジスタも使っています。(※必要な場合は以下等を参照して下さい。)
SPI関連レジスタ

動作確認
以下のようにマスタ側のシリアルモニタで確認出来ました。Hello!と送信すると1文字ずつ返ってきました。この時にシリアルモニタの下の部分で「改行なし」に設定すると分かりやすいです。

これで単純な通信がとりあえずは確認出来たということで、次回は以下で実際のデバイスの温度センサADT7310を使ってみます。
Arduino UnoでSPI通信(その2)温度センサADT7310


 - Arduino

AdSense

AdSense

  関連記事

Arduino CC3000 WiFi シールドでHTTP POST

Arduino CC3000 WiFi シールドでHTTP POST通信を試して …

Arduino Ethernetシールド(旧製品)を使ってみた

Arduino Ethernetシールド(旧製品)を使ってみました。Arduin …

Arduino UnoでSPI通信(その2)温度センサADT7310

Arduino UnoでSPI通信の2回目です。前回のArduino UnoでS …

温度センサADT7410(その2)Arduinoでの利用

温度センサADT7410の2回目です。前回はI2C通信の簡単な概要とADT741 …

Arduino CC3000 WiFi シールドを使ってみた

前回の記事では、Arduino Ethernetシールドの旧製品版を使ってみまし …

温度管理システム的なものを作ってみる(その1)システム概要

「温度管理システム的なものを作ってみる」の1回目です。AndroidでUSBシリ …

温度管理システム的なものを作ってみる(その2)Arduinoでの温度取得からスマホへ送信

「温度管理システム的なものを作ってみる」の2回目です。前回は全体的な内容について …

Arduino互換機の「びんぼうでいいの(S)」を使ってみた

Arduino互換機のびんぼうでいいの(S)という製品を買ってきて使ってみました …

AndroidでUSBシリアル通信(その2)ライブラリサンプルのArduinoスケッチ

AndroidでUSBシリアル通信の2回目です。前回はハードウェア構成、ソフトウ …