SPI연결
(예: 아두이노 SD카드 연결)
SD 카드 | 아두이노 핀 |
GND | GND |
5V | 5V |
CS | 4 |
MOSI | 11 |
SCK | 13 |
MISO | 12 |
I2C 연결
(예: 아두이노 LCD 연결)
LCD | 아두이노핀 |
GND | GND |
5V | 5V |
SDA | A4 or SDA |
SCL | A5 or SCL |
https://ludenscode.com/2021/10/09/i2c-%EC%99%80-spi-%EB%B9%84%EA%B5%90/
요약 : UART, I2C, SPI 통신을 비교하고 어떤 방식을 사용할 것인지 결정하는데 도움을 준다. UART는 고전적인 방식으로 모든 하드웨어가 지원하고 있는 방식이고, I2C는 작은 선으로 여러 하드웨어를 연결하여 사용할 수 있게 한다. SPI 통신은 근거리에 있는 하드웨어에 고속을 신호를 전송하기 위해 사용된다.
아두이노를 포함, 대부분의 MCU 들은 자체적인 처리와 함께 신호를 외부로 보내거나 받는 과정이 많다.
이때 고전적인 방식은 시리얼과 패러럴통신이 사용된다. 지금도 시리얼통신은 여전히 많은 산업현장에서 표준으로 사용된다. 반면 패러럴 통신은 특별한 경우가 아니고서는 많은 전송선을 써야 한다는 현실적 제약때문에 새로운 MCU 혹은 새로운 디지털 기반의 센서들은 채택하지 않고 있다. 반면 새롭게 등장하고 범용적으로 많이 쓰이는 것으로 I2C 와 SPI가 있다.
최근 사용되는 대부분의 MCU 들에는 UART, SPI, I2C 를 내장하고 있다.
UART는 시리얼통신이라고 불리는 것으로 데이터를 직렬로 전송하는 방법을 말한다. 송신과 수신을 별도로 처리하기에 데이터의 양방향 통신이 가능하다. 이를 Full Duplex 라고 한다. 또한 송신측과 수신측의 속도를 사용자가 알아서 맞춰야만한다. 아두이노에서 시리얼통신의 속도 결정이 필요한 이유이다.
>> 아두이노 측 속도 설정 : 9600 bps
>> 아두이노와 통신하는 PC 측 속도 설정 9600 bps
위처럼 아두이노와 PC의 속도를 서로 같게 하지 않으면 통신이 불가능해진다. 이처럼 서로간의 신호를 자동적으로 동기화하지 않는 것을 Asynchronous, 비동기라고 한다.
UART 가 비동식인 반면 SPI 와 I2C는 동기식이다.
I2C : UART 가 데이터 전송과 수신용 선만을 가진 반면 I2C는 데이터 전송선(SDA)과 클럭신호선(SCL)을 가진다. 이때 I2C 는 데이터 전송선이 하나이므로 송신과 수신을 동시에 하지 못한다. 이를 반이중(Half Duplex)라고 한다. I2C 는 여러 하드웨어와 연결하여 사용할 수 있다. 1:N 혹은 N:N 통신도 가능하다.
SPI : SPI는 I2C 와 비슷하게 1:N 통신이 가능하다. 데이터 송신(MOSI), 데이터 수신(MISO) 두개를 가져 Full Duplex 방식이고, 여러 하드웨어 중 하나를 선택하기 위해 신호선 SS를 가진다.
UART 통신 | I2C 통신 | SPI 통신 | |
동기, 비동기 | Asynchronous | Synchronous | Synchronous |
x:x | 1:1 | N:N | 1:N |
선 수 | 2 (R,T) | 2 (SDA, SCL) | 4 (SCK, MISO, MOSI, SS) |
Half/Full Duplex | Full | Half | Full |
전송거리 | <5m | <2~3m, 10m | <2m, 단거리 |
전송속도 | 느림 | 중간 | 빠름 |
모든 통신에서 전송거리는 케이블을 상태와 주변 상태에 따라 달라지고, 전송 신호의 속도에 따라 달라진다. I2C는 SPI도 전송속도를 느리게 하면 보다 멀리 신호를 전송할 수 있다. 단, SPI 통신은 근거리장치간 고속통신을 위해 준비된 프로토콜이므로 멀리 떨어진 장치에 굳이 SPI를 고집할 이유는 없다.
UART 는 모든 산업용 장비에서 사용될 수 있는 예전부터 사용된 프로토콜이다.
I2C는 다수의 하드웨어에 신호를 전달할 때 2개의 선만으로 가능하기때문에 센서들을 연결해서 사용할 때 많이 사용된다. 느리게 읽어도 되는 센서 신호의 입력이나 제어용으로 많이 사용된다.
SPI는 고속으로 데이터를 전송하는 프로토콜로 고속전송이 필요한 근접 기기간 많이 사용된다.
https://mmirann.github.io/iot/arduino/2021/02/16/SPI_I2C.html
아두이노에서 고속의 주변 장치를 연결하기 위해 (1:N) 사용하는 통신방식은 SPI 통신과 I2C 통신이 있다. 두 통신 모두 동기식 통신 방식이고 비동기식 통신 방식(Clock X)으로는 UART 통신이 있는데 본 포스팅에선 동기식 통신 방식인 SPI 통신과 I2C 통신에 대해 알아본다.
SPI 통신
- SPI point to point 연결
- SPI Master-slave 연결
SPI(Serial Peripheral Interface) 통신은 MOSI(Master Out Slave In), MISO(Master In Slave Out) 선으로 데이터 송수신을 분리해 통신하기 때문에 I2C 통신 방식보다 통신 속도가 빠르고 전력 소모가 적다. 따라서 동시에 송수신 또한 가능하다. (속도: 10Mbs~20Mbs) 센서를 더 추가하는 경우 Slave 갯수 만큼 SS 라인이 더 필요하다. 또한 SPI Bus라인에 하나의 Master만 존재해야한다. 이더넷 연결이나 메모리카드와 같은 고속 통신이 필요한 경우 많이 쓰인다. 보드 별로 예약된 핀은 아래 표와 같다.
Arduino BoardMOSIMISOSCKSS (slave)SS (master)
Uno | 11 or ICSP-4 | 12 or ICSP-1 | 13 or ICSP-3 | 10 | - |
Mega | 51 or ICSP-4 | 50 or ICSP-1 | 52 or ICSP-3 | 53 | - |
Leonardo | ICSP-4 | ICSP-1 | ICSP-3 | - | - |
Due | ICSP-4 | ICSP-1 | ICSP-3 | - | 4, 10, 52 |
I2C 통신
I2C(Inter-intergrated Circuit) 통신 방식은 위의 사진에서 볼 수 잇듯이 SDA 하나의 선으로 양방향 데이터 송수신을 한다. 클럭 시그널을 전송하는 SCL(Serial Clock) 핀과 데이터 전송을 위한 SDA(Serial Data)핀을 사용한다. SPI 방식보다는 상대적으로 느리고, 한 번에 양쪽에서 데이터 송수신이 불가하다. 센서를 더 추가하는 경우 버스라인에 데이터 선만 연결하면 된다. 고속 연결이 필요하지 않은 일반적인 경우에 I2C 방식을 많이 사용한다. 아두이노 우노에는 SDA-A4번 핀, SCL-A5번 핀이 예약되어 있고 아두이노 메가에는 SDA-D20번 핀, SCL-D21번 핀이 예약되어 있다.
I2C VS SPI
SPII2C
핀 드라이브 | Push-pull | Open drain |
Signal lines | 4 | 2 |
최대 속도 | 10-100Mbps | 400 kbps in fast-mode(high-speed mode에선 3.4Mbps까지 가능) |
주변 기기 갯수 | Master의 SS라인에 사용할 수 있는 핀 수에 의해 제한 | 112(7-bit addressing) |
Multi Master | X | O |
Flow control | X | O |
Reference
https://kocoafab.cc/tutorial/view/451
아두이노 간 통신하기 - UART, I2C, SPI
2015-03-30 17:02:44
개요
이번 컨텐츠에서는 두 개의 오렌지 보드로 UART, I2C, SPI 통신 방법을 이용하여 한쪽에서 알파벳을 순서대로 보내면 다른쪽에서 그 알파벳을 받아서 시리얼 모니터에 출력해 보도록 하겠습니다.
부품 목록
NO | 부품명 | 수량 | 상세설명 |
1 | 오렌지 보드 | 2 | |
2 | 10kΩ저항 | 2 | I2C 통신에서만 사용됩니다. |
3 | 점퍼케이블 | 8 | 2개(UART) ~ 8개(I2C) |
부품명 | 오렌지 보드 | 10kΩ저항 | 점퍼케이블 |
파트 |
UART
UART는 병렬 및 직렬 방식으로 데이터를 전송하는 컴퓨터 하드웨어의 일종입니다. 마이크로컨트롤러에서 사용되는 대표적인 시리얼 통신 방법 중 하나로, 많은 장비들이 지원하고 연결이 간단하여 많이 사용되고 있습니다.
* UART 시리얼 통신은 1:1통신이라서 따로 마스터-슬레이브를 따로 정하지 않습니다. 이번 컨텐츠에서는 한쪽은 송신부 다른 한쪽은 수신부로 두고 사용하겠습니다.
* 밑의 연결방법에서도 수신부에서는 TX만, 송신부에서는 RX만 연결합니다.(TX-RX 교차 연결)
우선 UART 통신을 이용하여 2개의 오렌지보드 간의 데이터를 주고 받는 방법을 알아보겠습니다.
아두이노 연결
브레드보드 레이아웃
회로도
소프트웨어 Coding
송신부
char message = 'A';
void setup(){
Serial.begin(9600);
Serial.println("UART");
}
void loop(){
Serial.println(message);
message++;
if(message > 'z'){
message = 'A';
}
delay(1000);
}
수신부
* 수신부에 업로드시 꼭 RX(디지털 0번)핀에 연결되있는 케이블을 빼시고 업로드 해야 합니다. RX핀이 연결되어 있는 상태에서 컴퓨터에서 아두이노로 업로드를 할 경우 핀의 중복사용으로 인하여 업로드 오류가 발생합니다.
void setup(){
Serial.begin(9600);
}
void loop(){
while(Serial.available()){
char data = Serial.read();
Serial.print(data);
}
}
소프트웨어 설명
송신부에서 A부터 z 까지의 값을 하나씩 UART 통신을 이용하여 수신부로 보내고, 수신부에서는 송신부에서 날라오는 문자를 하나씩 받아서 시리얼 모니터에 출력하는 코드입니다. (밑에 다른 방법으로 진행할 경우도 기본 동작은 같습니다.)
// 수신부
Serial.println(message); // 데이터 전송
// 송신부
while(Serial.available()){ // 시리얼 통신으로 온 데이터가 있을 경우
char data = Serial.read(); // 데이터 1byte를 읽습니다.
Serial.print(data); // 읽은 데이터 출력
}
UART 통신으로 데이터를 전송할 경우는 시리얼 모니터에서 입출력 받을 때와 마찬가지로 Serial.println(), Serial.read()을 이용하여 전송하시면 됩니다.
SPI
(아두이노 스토리 - 클라이버 님의 아두이노-아두이노 SPI 연결을 참고 하였습니다.)
* SPI 통신은 1:N연결을 지원하고 Master-Slave 모드로 통신합니다.
* SPI 통신을 위해서는 MISO와 MOSI, SCK, SS를 사용합니다.(4-wire) SPI 통신은 SS를 이용하기 때문에 같은 주소 충돌이 발생하지 않지만, 연결하는 장치수가 늘어날 수록 연결선의 수가 늘어납니다.
* 아두이노에서 SPI통신을 위한 라이브러리를 제공하므로, 주변 장치와 SPI통신이 쉽게 가능합니다. 하지만 아두이노 SPI 라이브러리는 마스터 모드만 지원하므로 슬레이브를 설정하실 경우는 직접 레지스터를 통해 제어하셔야 합니다.
SPI 통신을 이용하여 2개의 오렌지보드 간의 데이터를 주고 받는 방법을 알아보겠습니다.
아두이노 연결
브레드보드 레이아웃
회로도
소프트웨어 Coding
Master
#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 == 'K'){
digitalWrite(SS, LOW); // 슬레이브를 선택한다.
// 1바이트 데이터 수신을 위해 의미 없는 1바이트 데이터를 전송한다.
char received = SPI.transfer(0);
digitalWrite(SS, HIGH); // 슬레이브 선택을 해제한다.
Serial.println(received);
}
}
}
// 출처 : 아두이노 스토리 - 클라이버님 SPI강좌
Slave
#include <SPI.h>
byte count;
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); // 인터럽트 허용
count = '0'; // 카운터 초기화
}
// SPI 통신으로 데이터가 수신될 때 발생하는 인터럽트 처리 루틴
ISR (SPI_STC_vect)
{
SPDR = count; // 카운터 값을 ASCII 값으로 전달
}
void loop (void)
{
count = (count + 1) ; // 카운터 값 증가
delay(1000);
}
// 출처 : 아두이노 스토리 - 클라이버님 SPI강좌
소프트웨어 설명
마스터 시리얼 모니터에서 K(대문자) 를 입력하시면 슬레이브에게 데이터를 요청하여 알파벳 A부터 하나씩 받아옵니다. (현재 해당하는 알파벳이 전송됩니다. ex : A를 받은후 3초뒤 다시 K입력 -> D 수신)
SPI 통신에서 마스터가 슬레이브로부터 데이터를 수신하기 위해서는 슬레이브로 데이터를 송신하여야 합니다. 1바이트 데이터를 얻기위해서는 1바이트의 데이터를 보내야만 합니다.
위 코드에서 슬레이브는 알파벳 A부터 1초마다 하나씩 증가하는 카운터입니다. 마스터에 'K'가 입력이 되면 마스터는 슬레이브에게 현재 카운트 값을 요청하고 슬레이브에서는 현재 카운트를 마스터로 보냅니다.
I2C
I2C는 필립스에서 개발한 직렬 컴퓨터 버스이며, 마더보드, 임베디드 시스템, 휴대전화 등에 저속의 주변기기를 연결하기 위해 사용됩니다.
* I2C 통신은 1:N연결을 지원하고 Master-Slave 모드로 통신합니다.
* I2C 통신은 SPI와 다르게 슬레이브 선택을 위해 소프트웨어적인 주소를 사용하므로 연결하는 장치가 늘어나도 사용하는 핀이 증가하지 않습니다.
* I2C 통신은 데이터 송수신을 위한 SDA와 동기화 클록을 위한 SCL 핀 2개만 사용합니다.(2-Wire)
* UART나 SPI와 비교할 때 속도의 한계가 있으므로 사용에는 제한됩니다. 그러나 아두이노에서는 SPI와 달리 Wire라이브러리에서 슬레이브 모드를 지원하고, UART와 달리 1:N통신이 지원되므로 비교적 간단하게 다양한 기능 구현이 가능합니다.
우선 I2C 통신을 이용하여 2개의 오렌지보드 간의 데이터를 주고 받는 방법을 알아보겠습니다.
아두이노 연결
브레드보드 레이아웃
회로도
소프트웨어 Coding
Master
#include <Wire.h>
#define SLAVE 4 // 슬레이브 주소
void setup() {
Wire.begin(); // Wire 라이브러리 초기화
Serial.begin(9600); // 직렬 통신 초기화
Serial.println("I2C");
}
void loop() {
i2c_communication(); // 슬레이브로 데이터 요구 및 수신 데이터 처리
delay(1000);
}
void i2c_communication() {
Wire.requestFrom(SLAVE, 1); // 1 바이트 크기의 데이터 요청
char c = Wire.read(); // 수신 데이터 읽기
Serial.println(c); // 수신 데이터 출력
}
// 출처 : 아두이노 스토리 - 클라이버님의 I2C 강좌
Slave
#include <Wire.h>
#define SLAVE 4
byte count = 'A'; // 카운터
void setup() {
// Wire 라이브러리 초기화
// 슬레이브로 참여하기 위해서는 주소를 지정해야 한다.
Wire.begin(SLAVE);
// 마스터의 데이터 전송 요구가 있을 때 처리할 함수 등록
Wire.onRequest(sendToMaster);
}
void loop () {
}
void sendToMaster() {
Wire.write(++count); // 카운터 값을 증가시키고 마스터로 전송
if(count >= 'z'){
count = 'A';
}
}
// 출처 : 아두이노 스토리 - 클라이버님의 I2C 강좌
소프트웨어 설명
마스터가 슬레이브에게 요청을 할 경우 슬레이브에서 1byte의 알파벳 'A'부터 1증가시킨 후 마스터로 전송합니다.
// Wire 라이브러리 초기화
// 슬레이브로 참여하기 위해서는 주소를 지정해야 한다.
Wire.begin(SLAVE);
// 마스터의 데이터 전송 요구가 있을 때 처리할 함수 등록
Wire.onRequest(sendToMaster);
슬레이브는 자신의 주소를 설정하고 마스터의 요청을 기다립니다. 마스터의 요청이 들어왔을 경우 sendToMaster 함수를 실행 합니다.
Wire.begin(); // Wire 라이브러리 초기화
마스터는 자신의 주소를 따로 설정할 필요 없이 Wire 라이브러리만 초기화 시켜주면 됩니다.
void loop() {
i2c_communication(); // 슬레이브로 데이터 요구 및 수신 데이터 처리
delay(1000);
}
void i2c_communication() {
Wire.requestFrom(SLAVE, 1); // 1 바이트 크기의 데이터 요청
char c = Wire.read(); // 수신 데이터 읽기
Serial.println(c); // 수신 데이터 출력
}
1초마다 지정된 슬레이브(여기서는 4번 슬레이브입니다.)에 데이터를 요청합니다. requestFrom() 함수를 통해 4번 슬레이브에게 1바이트의 데이터를 요청하고, Wire.read()를 통해 전송된 1바이트의 데이터를 c에 저장합니다.
이렇게 받은 c(전송받은 데이터)를 시리얼 모니터에 출력합니다.
'프로세싱+아두이노+안드로이드' 카테고리의 다른 글
MPU6050 상보(상호보완) 필터 (0) | 2022.07.21 |
---|---|
Robot Eyes 2 (0) | 2022.06.26 |
Moving Average Filter (Physical Computing) (0) | 2022.06.21 |
ESP-IDF Programming Guide (0) | 2022.06.05 |
아두이노 ESP32 - 환경 설정 - 윈도우 (0) | 2022.06.05 |
댓글