[아두이노] [강좌] 33. SPI 통신 (2) – SPI 함수 알아보기

이번 강좌에서는 SPI 통신을 사용하기 위해 아두이노에서 제공하는 함수들에 대해 알아보자.

 

사실 SPI 통신을 사용하는 센서나 모듈이 많음에도 불구하고 SPI 함수를 직접 다룰 일은 많지 않다. SPI 통신을 사용하는 모듈은 대부분 길이가 긴 데이터를 주고받고또 동작을 위한 단계가 복잡한 경우가 많기 때문에 보통은 해당 모듈의 제조사에서 라이브러리 소스를 제공하거나아두이노에서 제공하는 라이브러리를 사용한다.

 

예를 들어 이더넷 또는 Wifi 모듈의 경우 SPI를 사용하지만대부분의 모듈 제조사에서 자신들의 라이브러리를 제공하고 있으며, SD 쉴드의 경우 아두이노에서 “SD”라는 라이브러리를 제공하여 사용하도록 하고 있다. Wifi SD 쉴드를 직접 제어하기 위해 소스를 구현하고자 한다면일주일 밤낮을 새도 못할 것 같다물론 뚝딱 할 수 있는 고수들은 많겠지만. (그런 고수가 내 블로그 글 읽을 일 없을 테니까 ㅠㅠㅋㅋㅋㅋㅋㅋ)

 

아무튼그렇지만 간혹 SPI 통신을 직접 사용해야 하는 경우도 있고알아둬서 나쁠 일이 없으므로 배워보도록 하자.

 


brown_and_cony-50 (귀척?) 

 

 

지난 강좌에서 설명한대로, SPI 통신을 위해서는 MOSI, MISO, SCK, SS 핀이 필요하고각 핀은 아두이노 보드의 50~53번 핀에 할당되어 있다그 중 SS 핀은 변경이 가능한데만일 하나의 슬레이브만을 사용한다면 그대로 53번을 SS 핀으로 사용하면 되고(물론 변경해도 되고), 둘 이상의 슬레이브를 사용한다면 하나는 53번에, 나머지는 다른 핀에 연결해야 한다. 슬레이브 하나 당 SS 핀 하나. 

 

만일 SS 핀을 변경했다면 소스 상에서도 SS 핀을 변경해줘야 한다? SS 핀을 변경하는 방법은 맨 마지막에 “*참고에서 다시 자세히 설명.

 

 


일단 함수 설명 고고!


SPI 함수는 SPI.h 파일에 정의되어 있으므로 “#include <SPI.h>” 구문을 추가한 후 사용할 수 있다.

 



SPI.begin()

SPI.begin(ss) – Due Only

 

SPI 통신을 위해 통신 포트를 초기화한다듀에(Due) 외의 보드에서는 매개 변수가 없으며듀에의 경우에만 매개 변수로 SS 핀의 번호를 지정할 수 있다듀에탐난다ㅋㅋㅋㅋㅋ

 

 

 

 매개 변수

 

 (듀에 외의 보드에서는 매개 변수 없음)

 ss – 듀에에서만 사용하는 매개 변수. SS 핀 번호를 설정한다.

 



 

 

SPI.setBitOrder(order)

 

데이터 전송 시 최상위 비트를 먼저 전송할지최하위 비트를 먼저 전송할지를 설정한다. SPI 공통의 설정을 변경하는 것이므로슬레이브 간에 설정이 다를 경우에는 SPI.beginTransaction() 함수를 이용해서 설정해야 한다듀에의 경우 매개 변수로 SS 핀이 추가되지만따로 설명은 생략하도록 하겠다듀에는 공식 홈페이지를 참고하세용.

 

 

 

 매개 변수

 

 order – LSBFIRST 또는 MSBFIRST 중에 선택하여 사용한다.

 

 LSBFIRST – 최하위 비트부터 전송

 MSBFIRST – 최상위 비트부터 전송 (default)

 


 


SPI.setClockDivider(divider)

 

SPI 통신 속도 설정을 위해 클럭 나누기 값(-_-)을 설정한다몇 클럭에 한 비트를 보낼 건지 정한다고 생각하면 쉽다지정된 값들 중 하나를 선택하여 사용할 수 있다이 함수 역시 공통으로 사용하는 SPI의 속도를 변경하므로 슬레이브 간의 설정이 다를 경우SPI.beginTransaction() 함수를 사용하여 각각 설정해야 한다.

 

 

 

 매개 변수

 

 divider – 다음 값들 중 하나를 선택한다.

 

- SPI_CLOCK_DIV2

- SPI_CLOCK_DIV4

- SPI_CLOCK_DIV8

- SPI_CLOCK_DIV16

- SPI_CLOCK_DIV32

- SPI_CLOCK_DIV64

- SPI_CLOCK_DIV128



 

예를 들어 ‘SPI_CLOCK_DIV8’을 선택할 경우 클럭 당 한 비트씩 전송하게 되므로, 16MHz의 메인 클럭을 가지는 메가(Mega 2560/ADK) 또는 우노(Uno)의 경우 2MHz(=16MHz/8)의 속도로 통신을 하게 된다. 2,000,000bps의 속도를 가지게 된다는 뜻. (1M = 1,000,000)

 

 

 

SPI.setDataMode(mode)

 

데이터 전송 시 사용할 모드를 선택한다모드는 4가지가 있으며클럭 신호를 HIGHLOW(Falling)부터 시작할지, LOWHIGH(Rising)부터 시작할지클럭이 HIGHLOW(Falling)가 될 때 데이터를 쓸 건지, LOWHIGH(Rising)가 될 때 데이터를 쓸 건지를 정하는 함수이다.

 

?? 뭐라규??

 

다음 표를 보자.

 

 

 

클럭 시작

클럭 종료

모드

신호

데이터

신호

데이터

0

Rising

읽기 (Sample)

Falling

쓰기 (Setup)

1

Rising

쓰기

Falling

읽기

2

Falling

읽기

Rising

쓰기

3

Falling

쓰기

Rising

읽기

 

 

그렇군.

 

brown_and_cony-58 

 

 

다음은 메가의 칩인 ATmega2560의 데이터 시트 중 모드에 관한 부분이다타이밍도를 보면 이해하기 쉬울 듯.

5f998e34b5eadf67672c4e8710f301fc.png
 

  

하하하.

 

 

암튼 매개 변수.

 


 

 매개 변수

 

 mode – 다음 중 하나를 선택하여 설정한다.

 

- SPI_MODE0 (default)

- SPI_MODE1

- SPI_MODE2

- SPI_MODE3


 

 

 

SPI.end()

 

SPI 통신을 종료하고사용하던 핀을 일반 디지털 핀으로 전환한다.

 

 

 

 매개 변수

 

 없음



 

 

 

SPI.beginTransaction(SPISettings)

 

연결된 슬레이브가 두 개 이상일 경우 슬레이브마다 SPI 통신 설정이 다를 수 있는데이럴 경우 각각의 통신마다 설정 값을 변경하기 위해 사용한다.

 

설정을 위해서는 ‘SPISettings’라는 클래스가 사용되는데, SPISettings 클래스를 선언할 때 생성자에 설정 값을 설정하여 객체를 생성한 후SPI.beginTransaction() 함수에 매개 변수로 전달한다.

 

SPISettings 클래스의 생성자는 다음과 같다.

 

 

SPISetting(speed, order, mode)

 

SPI.setOrder() 함수에 사용된 매개 변수와 SPI.setDataMode()에 사용된 매개 변수가 각각 order mode에 들어가며, speed 값은 실제 통신 속도 값을 넣는다. 2MHz를 사용하고 싶으면 2000000, 1MHz를 사용하고 싶다면 1000000을 사용한다각각SPI.setClockDivider() 함수에 매개 변수로 CLOCK_DIV8, CLOCK_DIV16을 사용한 것과 같은 역할을 한다.

 

 

 

 매개 변수

 

 speed – 통신 속도 값

 order – LSBFIRST 또는 MSBFIRST

 mode – SPI_MODE0~3



 

SPI.endTransaction() 함수까지 알아본 후 사용 예제를 살펴보도록 하자.

 

 

 

SPI.endTransaction()

 

다른 슬레이브 기기를 설정하기 위해 이 전의 설정을 종료한다매개 변수는 없다.

 

다음 예제는 두 개의 슬레이브를 각각 다른 설정으로 통신하는 예제 소스이다출처는 아두이노 공식 홈페이지.

 

 

 SPISettingsTest.ino

 

 #include <SPI.h>

  

 int ssA = 20;    // 슬레이브 A SS 

 int ssB = 21;    // 슬레이브 B SS 

 

 SPISettings settingA(2000000, MSBFIRST, SPI_MODE1);

 SPISettings settingB(16000000, LSBFIRST, SPI_MODE3);

 

 byte val1, val2, val3;

 

 void setup() {

   pinMode(ssA, OUTPUT);

   pinMode(ssB, OUTPUT);

 

   SPI.begin();

 }

 

 void loop() {

   SPI.beginTransaction(settingA);   // 슬레이브 A와 통신 시작 – settingA로 설정

 

   digitalWrite(ssA, LOW);          // 슬레이브 A 선택 신호(LOW) 출력

   val1 = SPI.transfer(0);            // 데이터 전송/수신

   val2 = SPI.transfer(100);          // 데이터 전송/수신

   digitalWrite(ssA, HIGH);          // 슬레이브 A 선택 해제 신호(HIGH) 출력


   SPI.endTransaction();             // 슬레이브 A와 통신 종료 – 설정 해제

 

   SPI.beginTransaction(settingB);    // 슬레이브 B와 통신 시작 – settingB로 설정


   digitalWrite(ssB, LOW);           // 슬레이브 B 선택 신호(LOW) 출력

   val3 = SPI.transfer(val1+val2);     // 데이터 전송/수신

   digitalWrite(ssB, HIGH);           // 슬레이브 B 선택 해제 신호(HIGH) 출력


   SPI.endTransaction();             // 슬레이브 B와 통신 종료 – 설정 해제

 

   if(val3) {

      // ...

   }

 }




어렵지 않다그럼 데이터를 전송하고 수신하는 함수를 알아보자.

 

 

 

byte SPI.transfer(data)

 

SPI 통신은 전송과 수신이 동시에 이뤄지기 때문에 전송 함수수신 함수가 따로 있지 않다전송하면 수신되는거수신된 데이터가 반환 값으로 반환된다.

 

 

 

 매개 변수

 

 data – 전송할 데이터 (byte )

  

 반환 값

 

 byte – 수신된 데이터 (byte )



 

 

실제 SPI 통신에 사용되는 함수는 SPI.transfer() 함수 뿐이고나머지는 다 설정 함수네유의해야 할 점은 SPI.transfer() 함수가 사용되기 전 데이터를 전송할 슬레이브의 SS 핀을 LOW로 출력하고전송이 완료되면 HIGH로 변경해야 한다는 것.

 

 

 

함수 몇 개 안되는데왜 이렇게 내용이 길지

 

 

다음 강좌에서는 직접 SPI 통신 함수를 사용해야 하는 몇 안 되는 센서들 중 하나인 기압 센서를 가지고 실습을 해보도록 하겠다그럼 안녕!

  

0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

임베디드 보드

번호 제목 글쓴이 날짜 조회수
118 아두이노 ESP32 Analog Inputs (ADC) +4 icon 양재동메이커 02-12 16,137
117 아두이노 TIP : Serial의 Port가 Open 시점 확인 icon 양재동메이커 01-21 12,990
116 아두이노 ESP32 Boot Mode icon 양재동메이커 12-28 12,835
115 아두이노 아두이노 에러 리스트(Arduino Error list) icon 양재동메이커 11-24 17,818
114 아두이노 ESP32 main.cpp +1 icon 양재동메이커 11-19 13,181
113 아두이노 ESP32 EEPROM 와 IR Remote icon 양재동메이커 08-06 13,074
112 아두이노 Learn ESP32 icon 양재동메이커 06-25 12,655
111 라즈베리 파이 라즈베리 파이 (Raspberry Pi) 기초 icon 양재동메이커 06-19 14,150
110 라즈베리 파이 (동영상 강의) 라즈베리 파이 강좌 Link icon 양재동메이커 06-17 13,248
109 STM32 / MBED [MED] Switch debouncing icon HellMaker 12-30 15,226
108 기타 [타이젠] 아두이노의 16x2 LCD Display라이브러리 LiquidCrystal_I2C의 타이젠 포팅 icon 양재동메이커 09-15 14,803
107 기타 [타이젠] GPIO의 디지탈 출력과 입력 인터럽트의 C++ Class 제작 icon 양재동메이커 09-12 14,280
106 마이크로비트 서보 모터 icon HellMaker 09-03 14,098
105 마이크로비트 아날로그 온도센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 14,605
104 마이크로비트 터치센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 13,719
103 마이크로비트 디지털 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,900
102 마이크로비트 리니어 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,455
101 마이크로비트 불꽃 감지 센서 (마이크로 비트 센서 활용) icon HellMaker 08-26 12,794
100 마이크로비트 로터리 엔코더 (마이크로 비트 센서 활용) icon HellMaker 08-25 12,899
99 마이크로비트 2컬러 LED(3mm) (센서 활용) icon HellMaker 08-22 12,901