본문으로 바로가기

  아두이노(Arduino) 중급 아두이노끼리 통신하기(Serial, I2C, ISP)  


애드라이프의 아두이노 모든 포스팅 리스트를 보고 싶으신 분은 공지 읽어주세요.


참고로 중급편 부터는 응용편이 없습니다. 

왜냐하면 고급편에서 중급에 사용했던 부품의 응용편을 다룰 예정이기 때문이죠!!



안녕하세요. 애드라이프 입니다.

이번 포스팅에서는 아두이노 우노 2대를 가지고 서로 통신을 해보는 시간을 갖겠습니다.

총 3가지 방법으로 아두이노끼리 통신을 해보겠습니다.





1. Serial통신으로 아두이노끼리 통신하기.


시리얼통신 자체는 아두이노 기초포스팅에 더 자세하게 포스팅 되어있으니 참고해주세요.

아두이노끼리 시리얼 통신회로 ▼

아두이노끼리 시리얼 통신 회로

/= 수신부 =/             /= 송신부 =/

GND                       GND

TX(D1)                    RX(D0)

RX(D0)                    TX(D1)

회로 구성시에 주의 해야할 것은 TX와 RX를 서로 교차시켜 연결해야 한다는 점이죠.


이제 Serial통신 수신부와 송신부 프로그램을 살펴보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//수신부 프로그램
void setup(){
  Serial.begin(9600);                 //통신속도 9600
  pinMode(13, OUTPUT);                 //아두이노 내부LED를 켜기위한 디지털 13번 포트 OUTPUT으로 설정
}
 
void loop(){
  if(Serial.available()){             //데이터가 들어오면 if문으로 들어갑니다.
   char Data = (char)Serial.read();         //들어온 데이터를 char Data에 저장
    if(Data == '1') {                  //Data가 1이면 
      digitalWrite(13, HIGH);          //L13 LED ON
    } else {                           //Data가 1이 아니면 
      digitalWrite(13, LOW);           //L13 LED OFF
    }
  }  
}
cs



1
2
3
4
5
6
7
8
9
10
11
//송신부 프로그램
void setup(){
  Serial.begin(9600);   //통신속도 9600
}
 
void loop(){
  Serial.print("1");   // Serial통신으로 1을 송신
  delay(1000);
  Serial.print("0");   // Serial통신으로 0을 송신
  delay(1000);
}
cs

프로그램의 전체적인 흐름은 주석을 참고해 주세요.


!! 프로그램 업로드시에는 보드를 서로 연결한 상태로 하시면 업로드 오류가 발생합니다. !!

서로 분리한 상태에서 따로 업로드를 진행해 주세요.

송신부수신부 모두 정상적으로 업로드 후 결과가 수신부의 내장LED가 1초마다 깜박이면 완료입니다.







2. I2C 통신으로 아두이노끼리 통신하기.


I2C통신은 1 : 다수의 연결을 지원하고 주(Master),종(Slave) 모드를 지원합니다.

아두이노에서 SDA(data)SCL(clock)을 사용하며 소프트웨어로 주소값을 컨트롤하기 때문에 

통신의 충돌을 방지하며 ISP와는 다르게 소프트웨어로 주소값을 컨트롤 하기때문에

장치가 추가되어도 연결선이 추가될 필요가 없습니다. 또한 Wire라이브러리에서는

Master모드 뿐만아니라 Slave모드까지 지원합니다.

다만, 다른통신에 비해 속도가 제한되며 저속입니다.


아두이노끼리 I2C통신 회로 ▼

아두이노끼리 I2C 통신 회로

/= Master =/             /= Slave =/

GND                       GND

SDA(A4)                    SDA(A4)

SCL(A5)                    SCL(A5)


두개의 보드에 USB를 모두 연결 하지 못한다면 

마스터쪽만 연결하고 5V를 서로 연결해 주세요.


이제 마스터와 슬레이브의 프로그램을 살펴보겠습니다.▼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Master

#include <Wire.h>                       //라이브러리 추가
#define SLAVE 4                         // 슬레이브 주소
void setup() {
  Wire.begin();                         // Wire 라이브러리 초기화
  Serial.begin(9600);                  // 직렬 통신 초기화
  Serial.println("I2C");               // 시리얼모니터 I2C 라는 문구 출력
}
void loop() {
  i2c_communication();                  // 슬레이브로 데이터 요구 및 수신 데이터 처리
  delay(1000);
}
void i2c_communication() {
  Wire.requestFrom(SLAVE, 1);           // 1 바이트 크기의 데이터 요청
  char c = Wire.read();                 // 수신 데이터 읽기
  Serial.println(c);                   // 수신 데이터 출력
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Slave

#include <Wire.h>                       //라이브러리 추가
#define SLAVE 4
byte count = 'A';                       // 카운터
void setup() {
  Wire.begin(SLAVE);                    // Wire 라이브러리 초기화 ,슬레이브로 참여하기 위해서는 주소를 지정해야 한다.
  Wire.onRequest(sendToMaster);         // 마스터의 데이터 전송 요구가 있을 때 처리할 함수 등록
}
 
void loop () {
}
 
void sendToMaster() {
  Wire.write(++count);                     // 카운터 값을 증가시키고 마스터로 전송
  
  if(count >= 'z'){ // 대문자'A'부터 소문자 'z'까지 하나씩 증가시키며 전송
    count = 'A';
  }
}

cs

프로그램의 전체적인 흐름은 주석을 참고해주세요.

DATA전송부만 잠깐 보면

Master에서 Slave에게 데이터를 요청하면 Slave에서 

대문자 'A'부터 소문자 'z'까지 하나씩 증가시키면서 전송합니다.

대문자 'A'는 10진수로는 65 16진수로는 0x41입니다.

소문자 'z'는  10진수로는 122 16진수로는 0x7A입니다.

하나씩 증하한다는 것은 이 수를 증가하면서 문자를 바꾸는 것입니다.



아스키 코드표 알아보기


프로그램을 업로드 해서 시리얼 모니터로 결과를 확인해볼까요?▼

순차적으로 데이터가 출력되는 것이 보이시나요?





3. ISP 통신으로 아두이노끼리 통신하기.


ISP통신은 1 : 다수의 연결을 지원하고 주(Master),종(Slave) 모드를 지원합니다. 

아두이노에서 MISO, MOSI, SCK, SS를 사용하면서 각각의 하드웨어적으로 주소값(SS)을 컨드롤하기 때문에 

통신이 충돌하지 않는 장점이 있습니다. 다만, 장치수가 늘어날 수록 연결선은 늘어나며

라이브러리에서는 마스터모드만 지원합니다.


아두이노끼리 ISP통신 회로도▼

아두이노끼리 ISP통신 회로


바로 마스터와 슬레이브의 프로그램을 살펴보도록 하겠습니다. ▼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Master
 
#include <SPI.h>
void setup (void)
{
  SPI.begin ();                           // SPI 통신 초기화
  digitalWrite(SS, HIGH);                 // 슬레이브가 선택되지 않은 상태로 유지
                                          // 안정적인 전송을 위해 분주비를 높여 전송 속도를 낮춤
  SPI.setClockDivider(SPI_CLOCK_DIV16);        //16Mhz/16 >> 1Mhz
  Serial.begin(9600);
}
void loop (void)
{
  if(Serial.available()){
    char data = Serial.read();            // 데이터 입력 확인
    if(data == 'K'){
      digitalWrite(SS, LOW);               // 슬레이브를 선택한다.
                                          // 1바이트 데이터 수신을 위해 의미 없는 1바이트 데이터를 전송한다.
      char received = SPI.transfer(0);
      digitalWrite(SS, HIGH);             // 슬레이브 선택을 해제한다.
      Serial.println(received);
    }
  }
}
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//Slave
 
#include <SPI.h>                        //라이브러리추가
byte count;
 
void setup (void)
{
  pinMode(MISO, OUTPUT);                  //디지털 12번 핀을 OUTPUT으로 설정합니다.
  pinMode(MOSI, INPUT);                   //디지털 11번 핀을 INPUT으로 설정합니다.
  pinMode(SCK, INPUT);                    //디지털 13번 핀을 INPUT으로 설정합니다.
  pinMode(SS, INPUT);                     //디지털 10번 핀을 INPUT으로 설정합니다.
                                          
  SPI.setClockDivider(SPI_CLOCK_DIV16);   // 마스터의 전송 속도에 맞추어 통신 속도를 설정한다.
                                          // SPI 통신을 위한 레지스터를 설정
  SPCR |= _BV(SPE);                       // SPI 활성화
  SPCR &= ~_BV(MSTR);                     // Slave 모드 선택
  SPCR |= _BV(SPIE);                      // 인터럽트 허용
  count = '0';                            // 카운터 초기화
}
                                          // SPI 통신으로 데이터가 수신될 때 발생하는 인터럽트 처리 루틴
ISR (SPI_STC_vect)
{
  SPDR = count;                           // 카운터 값을 ASCII 값으로 전달
}
void loop (void)
{
  count = (count + 1) ;                   // 카운터 값 증가
 
  delay(1000);
}
cs

프로그램의 전체적인 흐름은 주석을 확인해 주세요.


SPI.setClockDivider(SPI_CLOCK_DIV16);
이 함수는에 대해서 설명을 드리면

시스템 클록을 기준으로 SPI 클럭 디플레이터를 설정합니다. 

AVR 기반 보드에서 사용 가능한 분할기는 2, 4, 8, 16, 32, 64 또는 128입니다. 

기본 설정은 SPI_CLOCK_DIV4로, SPI 클럭을 시스템 클럭의 

주파수의 1/4로 설정합니다(16 MHz의 경우 4 Mhz).

( 아두이노 우노의 경우 16Mhz의 크리스탈을 쓰죠. )


그 밖에 ISP관련 라이브러리에 대해 좀더 알고 싶으시면 

아두이노 ISP라이브러리 알아보기


마스터쪽에서 시리얼 모니터를 실행시켜서 대문자 K를 보내면 

슬레이브에 데이터를 요청하고 슬레이브는 카운터를 1초마다 한번씩 증가시키고 

있다가 데이터 요청이 오는 시점의 카운터에 해당하는 문자를 반환합니다.


결과를 확인해 볼까요? ▼


마스터쪽에 대문자 K를 빠르게 보내면 마스터는 슬레이브로 계속 데이터 요청을하지만

슬레이브는 1초에 한번씩 카운터가 증가하며 문자가 바뀌기때문에 

위의 데이타 처럼 반복되는 문자가 반환됩니다.


차분히 기다렸다 대문자 K를 보내시면 다른 문자들이 반환 되는 것을 확인 할 수 있습니다.


지금까지 아두이노(Arduino) 중급 아두이노 끼리 통신(시리얼, I2C, ISP)에 대한 포스팅이였습니다.

계속해서 도움되는 포스팅으로 찾아 뵙겠습니다.

by 애드라이프




참고자료 :     https://cafe.naver.com/arduinostory/ >> 클러버님의 아두이노-아두이노 ISP연결

 https://kocoafab.cc/ >> 아두이노 간 통신하기 - UART, I2C, SPI

 http://www.hardcopyworld.com/ngine/aduino/ >> 아두이노끼리 연결, 2개 연결방법(Serial,I2C,SPI)

https://shaeod.tistory.com/ >> ASCII Table - 아스키 코드표