재료

  • 아두이노 우노 2개
  • USB 케이블 1개
  • 점프 와이어 6개

 이번 프로젝트에서는 디지털 통신에 대한 이해를 높이기 위해서 앞의 프로젝트와 같은 내용을 다른 통신을 사용해서 진행해보려고 합니다. 이번 프로젝트에서 사용될 통신 규약은 SPI 통신이에요. SPI 통신은 I2C 통신에 비하여 새로운 장치를 추가할 때 복잡하나 데이터 송수신 선이 2개여서 동시에 송수신이 가능하고 그래서 더 빠르다는 장점이 있다고 소개했었죠? 이번 프로젝트에서는 이런 SPI 통신을 이용해서 아두이노 간 통신이 가능하도록 만들어봅시다.




STEP1. 준비물

아두이노 보드 2개, USB 케이블, 점프 와이어 6개



STEP2. 회로도




STEP3. 코드

이것은 master code입니다.

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


이것은 slave code입니다.

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
31
32
33
#include <SPI.h>
 
byte num;
 
void setup (void)
{
  // SPI 통신을 위한 핀들의 입출력 설정
  pinMode(MISO, OUTPUT);
  pinMode(MOSI, INPUT);
  pinMode(SCK, INPUT);
  pinMode(SS, INPUT);
  
  // 마스터의 전송 속도에 맞추어 통신 속도를 설정한다.
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  
  // SPI 통신을 위한 레지스터를 설정
  SPCR |= _BV(SPE); // SPI 활성화
  SPCR &= ~_BV(MSTR); // Slave 모드 선택
  SPCR |= _BV(SPIE); // 인터럽트 허용
  num = 'A'// 카운터 초기화
}
// SPI 통신으로 데이터가 수신될 때 발생하는 인터럽트 처리 루틴
ISR (SPI_STC_vect)
{
  SPDR = num;  // 카운터 값을 ASCII 값으로 전달
}
void loop (void)
{
  num = (num + 1) ; // 카운터 값 증가
  if(num>'Z')
    num='A';
  delay(1000);
}


SPI 통신은 I2C 통신과는 다르게 slave로부터 1 byte의 정보를 받아오기 위해서는 master가 slave로 1byte의 정보를 보내야 합니다. 이 코드에서는 master가 slave로부터 num값을 받기 위해서 '0'이라는 문자를 계속 보내줘야하는 상황이고, 그렇게 보내면 slave는 'A'부터 차례대로 num값을 증가시켜가며 보내줍니다.


STEP4. 결과 확인

아래의 사진은 코드의 결과입니다. 먼저 여러분이 시리얼 모니터에 0이라는 문자를 계속 입력해주셔야 합니다. 위에서도 설명했듯이 SPI 통신에서는 master가 slave로부터 정보를 받아오기위해서는 정보를 보내주어야 합니다. 0이라는 문자를 입력받으면 slave는 'A'에서부터 계속 증가된 값을 보내줍니다. 이 값은 slave코드에서 설정해준대로 1초에 한번씩 올라갑니다.(delay(1000)) 그렇기 때문에 1초 간격으로 0을 입력하면 A부터 Z까지 차례대로 출력할 수 있겠지만 그것보다 빠르거나 그것보다 느리게 되면 같은 문자가 반복되어서 출력되거나 몇 개의 문자를 뛰어넘어서 출력될 수 있습니다.




STEP5. 응용

 마찬가지로 이제는 SPI 통신을 이용하여 slave로부터 입력받은 값을 master에서 읽어와 LCD를 통해서 출력해보도록 하겠습니다. 먼저 아래와 같이 회로를 구성해주세요.



출력은 master에서 해주는 것이므로 LCD는 master가 될 아두이노 보드에 연결해주셔야 합니다.

그런 후에 master 코드를 업로드하시고,

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
31
32
33
#include <SPI.h>
#include <LiquidCrystal.h>
 
LiquidCrystal lcd(9, 8, 5, 4, 3, 2);
 
void setup (void)
{
  SPI.begin (); // SPI 통신 초기화
  digitalWrite(SS, HIGH); // 슬레이브가 선택되지 않은 상태로 유지
  // 안정적인 전송을 위해 분주비를 높여 전송 속도를 낮춤
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  Serial.begin(9600);
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("Hello, SPI!");
}
 
void loop (void)
{
  if(Serial.available()){
    char data = Serial.read(); // 데이터 입력 확인
    if(data == '0'){
      digitalWrite(SS, LOW); // 슬레이브를 선택한다.
      // 1바이트 데이터 수신을 위해 의미 없는 1바이트 데이터를 전송한다.
      char received = SPI.transfer(0);
      digitalWrite(SS, HIGH); // 슬레이브 선택을 해제한다.
      lcd.setCursor(0,1);
      lcd.print("Output : ");
      lcd.print(received);
    }
  }
}
 

                                                    < Master 코드 >

                            

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
31
32
33
34
#include <SPI.h>
 
byte num;
 
void setup (void)
{
  // SPI 통신을 위한 핀들의 입출력 설정
  pinMode(MISO, OUTPUT);
  pinMode(MOSI, INPUT);
  pinMode(SCK, INPUT);
  pinMode(SS, INPUT);
  
  // 마스터의 전송 속도에 맞추어 통신 속도를 설정한다.
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  
  // SPI 통신을 위한 레지스터를 설정
  SPCR |= _BV(SPE); // SPI 활성화
  SPCR &= ~_BV(MSTR); // Slave 모드 선택
  SPCR |= _BV(SPIE); // 인터럽트 허용
  num = 'A'// 카운터 초기화
}
// SPI 통신으로 데이터가 수신될 때 발생하는 인터럽트 처리 루틴
ISR (SPI_STC_vect)
{
  SPDR = num;  // 카운터 값을 ASCII 값으로 전달
}
void loop (void)
{
  num = (num + 1) ; // 카운터 값 증가
  if(num>'Z')
    num='A';
  delay(1000);
}
 


                                                < Slave 코드 >


slave 코드를 업로드하시면 아래와 같은 결과를 확인하실 수 있습니다.

I2C 통신에 비하여 LCD를 추가할 때 몇개의 연결선이 더 들지만 똑같은 결과를 나타낼 수 있습니다.

동영상을 보시면 불규칙한 속도로 출력되는 것을 확인하실 수 있는데, 이것은 제가 0을 입력할 때마다 출력되는 것이기 때문에 0이 입력되지 않을 때에는 아무런 변화가 없다가 0을 입력하면 그에 맞는 num값을 ASCII 문자로 출력해주게 됩니다. 이 num 값은 1초에 한번씩 바뀌기 때문에 그 속도에 맞춰서 0을 입력하지 않으면 순서가 맞지 않게 출력됩니다.




댓글 0

손에 잡히는 아두이노

SPI 통신을 이용하여 아두이노 간 통신하기

by 김민정

MADE BY

김민정

사물인터넷, 아두이노