아두이노를 2대 혹은 그 이상 서로 연결해서 통신하는 방법을 모아봤습니다. 적외선, BT, WiFi 등 장치간 연결 방법이 아닌 시리얼(UART), I2C, SPI 통신을 이용해서 연결하는 방법입니다.

시리얼(UART) 통신으로 연결

시리얼 통신은 1:1 통신만 지원되므로 2대 연결시에만 사용 가능합니다. (단방향 통신일 때만 1:N 가능) 먼저 하드웨어 시리얼(아두이노 0, 1 번 핀)을 이용하는 방법입니다.

테스트를 위해 2 대의 아두이노를 사용합니다. 아두이노 2 는 주기적으로 문자 ‘1’ 과 ‘0’ 을 번갈아 전송합니다. 아두이노 1은 데이터를 받아 문자 ‘1’ 인 경우 내장한 LED 를 on 시키고 다른 문자인 경우 LED 를 off 시킵니다.

아두이노 두 대를 아래와 같이 TX – RX 크로스 해서 연결하면 됩니다. 각각의 아두이노는 USB를 통해 전원이 공급되는 상태여야 합니다.

연결 방법

  • 아두이노1 ==> 아두이노 2
  • 1번 핀(TX) ==> 0번 핀(RX)
  • 0번 핀(RX) ==> 1번 핀(TX)
  • GND ==> GND

스케치를 확인해 보겠습니다.

아두이노 1 (데이터 받아 LED 표시)

void setup(){
  Serial.begin(115200);
  pinMode(13, OUTPUT);
}

void loop(){
  if(Serial.available()){
   char c = (char)Serial.read();
    if(c == '1') {
      digitalWrite(13, HIGH);
    } else {
      digitalWrite(13, LOW);
    }
  }  
}

아두이노 SLAVE (데이터 보내는 부분)

void setup(){
  Serial.begin(115200);
}

void loop(){
  Serial.print("1");   // LED on
  delay(500);
  Serial.print("0");   // LED off
  delay(500);
}

아두이노 1 이 내장한 LED가 0.5 초 간격으로 on/off 를 반복하면 정상입니다.

하드웨어 시리얼 대신 SoftwareSerial 을 사용해도 같은 결과를 얻을 수 있습니다.

I2C 통신으로 연결

I2C 통신은 Master/Slave 구분이 있습니다.

앞서와 같이 아두이노 2(Master)에서 데이터를 보내고 아두이노 1(Slave) 에서 데이터를 받아 내장 LED를 깜빡이도록 하겠습니다.

연결은 간단합니다. GND-GND 연결, A4(SDA, 데이터 라인) – A4 연결, A5(SCL, 클럭 라인) – A5 연결해주면 됩니다.

  • 아두이노1 (Slave) ==> 아두이노 2 (Master)
  • SDA ==> SDA
  • SCL ==> SCL
  • GND ==> GND

https://hardcopyworld.com/wp-content/uploads/2021/06/Master_Sender_bb-1.png

연결이 되면 코드는 아래와 같이 작성해서 올립니다.

아두이노 2 MASTER  코드 (데이터 보내는 부분)

#include <Wire.h>

boolean isOn = false;

void setup() {
  Wire.begin(); // join i2c bus (address optional for master)
}

void loop() {
  Wire.beginTransmission(8);    // send to address #8 (0x08)
  if(isOn)
    Wire.write('1'); 
  else
    Wire.write('0'); 
  Wire.endTransmission();  

  isOn = !isOn;
  delay(500);
}

아두이노 1 SLAVE (데이터 받는 부분)

#include <Wire.h>

void setup() {
  Wire.begin(8);                // use address #8 (0x08)
  Wire.onReceive(receiveData); 
}

void loop() {
  delay(100);
}

void receiveData(int size) {
  while(1 < Wire.available()) {
    char c = Wire.read(); 
    if(c == '1')
      digitalWrite(13, HIGH);
    else
      digitalWrite(13, LOW);
  }
}

SPI 통신으로 연결

SPI 도 I2C 와 마찬가지로 Master/Slave 가 나뉩니다. 아두이노 1을 Slave(데이터 받는 용도), 아두이노 2를 Master(데이터 보내는 용도)로 설정해서 쓰겠습니다.

SPI 는 연결을 위해 4개의 디지털 핀을 사용합니다. D10(SS, Slave Select), D11(MOSI, Master Out Slave In), D12(MISO, Master In Slave Out), D13(SCLK, Serial Clock). 각각의 핀을 서로 연결해주면 됩니다.

그런데 SPI 경우 아두이노 내장 LED가 연결된 13번 핀과 겹칩니다. 앞서처럼 LED를 on/off 하기 위해 LED 하나를 디지털 5번 핀에 붙이도록 하겟습니다.

연결 방법

  • 아두이노 1 (Slave) ==> 아두이노 2 (Master)
  • (D10) SS ==> (D10) SS
  • (D11) MOSI ==> (D11) MOSI
  • (D12) MISO ==> (D12) MISO
  • (D13) SCLK ==> (D13) SCLK
  • GND ==> GND
  • 아두이노 1 – 디지털 5번 핀에 LED, 저항을 연결

스케치는 아래와 같이 올립니다.

아두이노 2 MASTER  코드 (데이터 보내는 부분)

#include <SPI.h>

void setup (void) {
  digitalWrite(SS, HIGH);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8);
}

void loop (void) {
  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  // send test string
  SPI.transfer('1');

  // disable Slave Select
  digitalWrite(SS, HIGH);

  delay (1000);
}

아두이노 1 SLAVE (데이터 받는 부분)

#include <SPI.h>

volatile boolean isOn = false;

void setup() {
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
  // now turn on interrupts
  SPI.attachInterrupt();

  pinMode(5, OUTPUT);
}


// SPI interrupt routine
ISR (SPI_STC_vect) {
  byte c = SPDR;  // grab byte from SPI Data Register

  if (c == '1')
    isOn = true;
  else
    isOn = false;

  // turn on interrupts
  SPCR |= _BV(SPIE);
}

void loop() {
  if(isOn) {
    digitalWrite(5, HIGH);
  } else {
    digitalWrite(5, LOW);
  }
  delay(50);
}

SPI 통신 라이브러리는 인터럽트 서비스 루틴(ISR) 으로 데이터를 받습니다. 데이터가 오면 ISR 함수가 자동으로 호출됩니다. 따라서 ISR 함수 내부에서 변경하는 전역 변수(isOn)는 volatile 로 선언되어야 합니다.

참고자료

.