하나의 아두이노로 많은 작업을 수행할 수 있지만, 일부 프로젝트에서는 여러 기능을 처리하기 위해 두 개 이상의 보드를 사용해야 할 수도 있습니다. 따라서 두 마이크로컨트롤러 간에 데이터를 전송할 수 있도록 하려면 CAN, SPI, I2C 또는 UART와 같은 통신 프로토콜을 설정해야 합니다.

이 가이드에서는 두 개의 아두이노 보드를 I2C 마스터 및 슬레이브 장치로 설정하는 데 필요한 I2C 작동 방식, 하드웨어 연결 및 소프트웨어 구현에 대한 기본 사항을 다룹니다.

I2C란 무엇인가요?

I2C(집적 회로)는 임베디드 시스템 및 마이크로 컨트롤러에서 널리 사용되는 통신 프로토콜로, 전자 장치 간에 데이터를 전송할 수 있도록 합니다. SPI(직렬 주변 장치 인터페이스)와 달리 I2C를 사용하면 하나 이상의 마스터 장치를 하나 또는 여러 개의 슬레이브 장치와 함께 버스에 연결할 수 있습니다. 필립스에서 처음 사용되었으며 TWI(2선 인터페이스) 통신 프로토콜이라고도 합니다.

I2C 통신은 어떻게 작동하나요?

I2C는 두 개의 양방향 라인을 사용합니다: 직렬 데이터(SDA)와 직렬 클록(SCL)을 사용하여 데이터를 전송하고 장치 간 통신을 동기화합니다. I2C 버스에 연결된 각 장치에는 통신 중에 장치를 식별하는 고유 주소가 있습니다. I2C 프로토콜을 사용하면 여러 장치가 동일한 버스를 공유할 수 있으며 각 장치는 마스터 또는 슬레이브로 작동할 수 있습니다.

통신은 마스터 장치에 의해 시작되며, 슬레이브 장치의 주소가 잘못 지정되면 전송 오류가 발생할 수 있습니다. UART, SPI 및 I2C 직렬 통신의 작동 방식에 대한 심층 가이드를 확인하여 자세한 내용을 알아보세요.

주목할 만한 I2C 통신의 주요 장점은 전원 관리와 관련하여 유연성을 제공한다는 점입니다. 서로 다른 전압 레벨에서 작동하는 디바이스도 전압 시프터를 사용하면 효과적으로 통신할 수 있습니다. 즉, 3.3V에서 작동하는 디바이스가 5V I2C 버스에 연결하려면 전압 시프터가 필요합니다.

와이어 라이브러리

와이어 라이브러리는 I2C를 통해 통신하는 기능을 제공하는 내장형 아두이노 라이브러리입니다. I2C 통신을 위해 아두이노 보드의 두 핀(SDA 및 SCL)을 사용합니다.

아두이노 우노의 I2C 핀:

아두이노 나노의 I2C 핀:

라이브러리를 사용하려면 아두이노 스케치 시작 부분에 Wire.h 헤더 파일을 포함해야 합니다.

 #include <Wire.h> 

Wire 라이브러리는 I2C 장치와의 통신을 시작하고, 데이터를 전송하고, 데이터를 수신하는 기능을 제공합니다. 알아야 할 몇 가지 중요한 기능은 다음과 같습니다:

이 글도 확인해 보세요:  MQTT와 함께 ESP-01 사용: IoT 디바이스 연결 및 제어 방법

⭐ Wire.begin(): I2C 버스에 가입하고 통신을 시작하는 데 사용됩니다.

⭐ Wire.beginTransmission(): 슬레이브 주소를 지정하고 전송을 시작하는 데 사용됩니다.

⭐ Wire.write(): I2C 장치로 데이터를 전송하는 데 사용됩니다.

⭐ Wire.endTransmission(): 전송을 종료하고 오류를 확인하는 데 사용됩니다.

⭐ Wire.requestFrom(): I2C 장치에서 데이터를 요청하는 데 사용됩니다.

⭐ Wire.available(): I2C 장치에서 데이터를 읽을 수 있는지 확인하는 데 사용됩니다.

⭐ Wire.read(): I2C 장치에서 데이터를 읽는 데 사용됩니다.

Wire.startTransmission() 함수를 사용하여 인자로 삽입되는 센서의 주소를 설정합니다. 예를 들어 센서의 주소가 0x68이면 다음을 사용합니다:

 Wire.beginTransmission(0x68); 

아두이노 I2C 하드웨어 설정

I2C를 사용하여 두 개의 아두이노 보드를 연결하려면 다음 하드웨어 구성품이 필요합니다:

⭐ 아두이노 보드 2개(마스터 및 슬레이브)

⭐ 브레드보드

⭐ 점퍼 와이어

⭐ 4.7kΩ 풀업 저항기 2개

두 아두이노 보드의 SDA 및 SCL 핀을 브레드보드에 연결합니다. 풀업 저항을 SDA 및 SCL 핀과 브레드 보드의 5V 전원 레일 사이에 연결합니다. 마지막으로 점퍼 와이어를 사용하여 두 브레드보드를 서로 연결합니다.

아두이노 우노 회로

아두이노 나노 회로

이미지 출처: 아두이노 I2C 문서

아두이노 보드를 I2C 마스터 및 슬레이브 장치로 설정

Wire.requestFrom() 함수를 사용하여 통신하려는 슬레이브 장치의 주소를 지정합니다. 그런 다음 Wire.read() 함수를 사용하여 슬레이브 장치에서 데이터를 가져옵니다.

마스터 장치 코드:

 #include <Wire.h>
void setup() {
Wire.begin(); // join i2c bus
Serial.begin(9600); // start serial for output
}
void receiveData() {
int address = 8;
int bytesToRead = 6;
Wire.requestFrom(address, bytesToRead);
while (Wire.available()) {
char data = Wire.read();
Serial.print(data);
}
delay(500);
}
void loop() {
receiveData();
}

Wire.onReceive() 함수는 슬레이브가 마스터 장치로부터 데이터를 수신할 때 수행할 작업을 지정하는 데 사용됩니다. 위 코드에서 Wire.available() 함수는 데이터를 사용할 수 있는지 확인하고, Wire.read() 함수는 마스터 장치에서 전송한 데이터를 읽습니다.

슬레이브 장치 코드:

 #include <Wire.h>
void setup() {
Wire.begin(8); // join the I2C bus with address 8
Wire.onReceive(receiveEvent); // call receiveEvent when data is received
}
void loop() {
delay(100);
}
void receiveEvent(int bytes) {
Wire.write("hello "); // respond with message of 6 bytes as expected by master
}

I2C를 이용한 데이터 송수신

이 예제에서는 슬레이브 아두이노와 인터페이스된 DHT11 온도 센서에서 온도를 읽고 마스터 아두이노의 직렬 모니터에 출력해 보겠습니다.

이 글도 확인해 보세요:  풀업 저항기란 무엇이며 어떻게 사용하나요?

온도 측정값을 포함하도록 앞서 작성한 코드를 수정하여 I2C 버스를 통해 마스터 보드에 전송해 보겠습니다. 그러면 마스터 보드는 우리가 보낸 값을 읽은 다음 직렬 모니터에 표시할 수 있습니다.

마스터 장치 코드:

 #include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Master Initialized!");
}
void loop() {
Wire.requestFrom(8, 1); // Request temperature data from slave
if (Wire.available()) {
byte temperature = Wire.read(); // Read temperature data from slave
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" &deg;C");
}
delay(2000); // Wait for 2 seconds before requesting temperature again
}

슬레이브 장치 코드:

 #include <Wire.h>
#include <DHT.h>

#define DHTPIN 4 // Pin connected to DHT sensor
#define DHTTYPE DHT11 // DHT sensor type
DHT dht(DHTPIN, DHTTYPE);
byte temperature;

void setup() {
Wire.begin(8); // Slave address is 8
Wire.onRequest(requestEvent);
dht.begin();
}

void loop() {
delay(2000); // Wait for 2 seconds for DHT to stabilize
temperature = dht.readTemperature(); // Read temperature from DHT sensor
}

void requestEvent() {
Wire.write(temperature); // Send temperature data to master
}

프로젝트에 있는 센서에 맞게 이 코드를 사용자 지정하거나 디스플레이 모듈에 센서 값을 표시하여 나만의 실내 온도계 및 습도계를 만들 수도 있습니다.

아두이노에서 I2C로 슬레이브 주소 지정하기

이러한 프로젝트에서 I2C 버스에 추가된 구성 요소의 값을 읽으려면 코딩할 때 올바른 슬레이브 주소를 포함하는 것이 중요합니다. 다행히도 Arduino는 슬레이브 주소를 식별하는 프로세스를 간소화하는 스캐너 라이브러리를 제공하므로 긴 센서 데이터 시트와 혼란스러운 온라인 설명서를 살펴볼 필요가 없습니다.

다음 코드를 사용하여 I2C 버스에 있는 슬레이브 장치의 주소를 식별합니다.

 #include <Wire.h> // Include the Wire library for I2C communication

void setup() {
Wire.begin(); // Initialize the I2C communication
Serial.begin(9600); // Initialize the serial communication with a baud rate of 9600
while (!Serial); // Wait for the serial connection to establish
Serial.println("\nI2C Scanner"); // Print a message indicating the start of I2C scanning
}

void loop() {
byte error, address; // Declare variables to store errors and device addresses
int nDevices; // Declare a variable to store the number of devices found

Serial.println("Scanning..."); // Print a message indicating the start of I2C scanning

nDevices = 0; // Set the number of devices found to 0
for (address = 1; address < 127; address++) { // Iterate over all possible I2C addresses
Wire.beginTransmission(address); // Start a transmission to the current address
error = Wire.endTransmission(); // End the transmission and store any errors

if (error == 0) { // If no errors were found
Serial.print("I2C device found at address 0x"); // Print a message indicating a device was found
if (address < 16) Serial.print("0"); // If the address is less than 16, add a leading 0 for formatting purposes
Serial.print(address, HEX); // Print the address in hexadecimal format
Serial.println(" !"); // Print a message indicating a device was found

nDevices++; // Increment the number of devices found
}
else if (error == 4) { // If an error was found
Serial.print("Unknown error at address 0x"); // Print a message indicating an error was found
if (address < 16) Serial.print("0"); // If the address is less than 16, add a leading 0 for formatting purposes
Serial.println(address, HEX); // Print the address in hexadecimal format
}
}
if (nDevices == 0) { // If no devices were found
Serial.println("No I2C devices found\n"); // Print a message indicating no devices were found
}
else { // If devices were found
Serial.println("done\n"); // Print a message indicating the end of I2C scanning
}
delay(5000); // Delay for 5 seconds before starting the next scan
}

지금 프로젝트를 확장하세요

I2C 통신 프로토콜을 사용하여 두 개의 아두이노 보드를 인터페이스하면 단일 보드에서 처리할 수 없는 복잡한 작업을 유연하고 효율적으로 수행할 수 있습니다. 와이어 라이브러리를 사용하면 I2C를 사용하여 두 보드 간의 통신이 쉬워져 프로젝트에 더 많은 구성 요소를 추가할 수 있습니다.

By 이지원

상상력이 풍부한 웹 디자이너이자 안드로이드 앱 마니아인 이지원님은 예술적 감각과 기술적 노하우가 독특하게 조화를 이루고 있습니다. 모바일 기술의 방대한 잠재력을 끊임없이 탐구하고, 최적화된 사용자 중심 경험을 제공하기 위해 최선을 다하고 있습니다. 창의적인 비전과 뛰어난 디자인 역량을 바탕으로 All Things N의 잠재 독자가 공감할 수 있는 매력적인 콘텐츠를 제작합니다.