아두이노 강좌 #17 I2C 통신으로 아두이노 우노와 ESP32 통신 하기
Lucy Archive
Lucy 2023
2020. 7. 29. 01:34

Arduino Uno ESP32 I2CArduino Uno ESP32 I2C

Arduino Uno and nodeMCU ESP-32s

지난 포스트에서 I2C 통신에 대한 설명과 아두이노에서 I2C 통신 구현을 위한 기본적인 함수들을 알아보았습니다. 본 포스트에서는

아두이노 보드끼리 I2C 통신하여 내장 LED를 켜고 끄는 예제를 소개하면서 I2C 통신에 대해 학습

할 예정입니다. 
관련포스트

I2C 통신 소개 및 아두이노에서 I2C 통신 구현 방법

2020/07/28 - [Arduino/Basic] - 아두이노 강좌 #16 I2C 통신 소개와 구현 방법


예제 소개

아두이노에서 I2C 통신 사용법을 익히기 위해 아래의 3가지 예제를 준비하였습니다.

  • 예제1
    • I2C 버스에 존재하는 I2C 장치의 주소 검색
  • 예제2
    • Master Write / Slave receiver 예제
    • Slave 에서 1을 수신하면 내장 LED 를 ON, 0을 수신하면 내장 LED 를 OFF
  • 예제3
    • Master Read / Slave Write 예제
    • Master 에서 1을 수신하면 내장 LED 를 ON, 0을 수신하면 내장 LED 를 OFF

✔ I2C 통신방식은 크게 아래의 두 가지 방식으로 나누어질 수 있습니다.

  • Master Write/Slave Receiver : Master 가 Slave 에 데이터를 쓰기
  • Master Read/Slave Write : Master 가 Slave 에게 데이터를 요청

📌 참고로 I2C 장치에 따라 통신 방식이 차이가 있어, 장치의 통신 방식에 맞게 구현이 필요합니다. 그러기 위해서 I2C 기본적인 통신 방식에 대한 이해가 필요합니다.

Hardware

준비물

본 예제의 구성품은 아래와 같습니다.

  • Arduino Uno x 1 EA
  • nodeMCU ESP32s x 1 EA
  • Bread Board x 1 EA
  • Jumper Wires

📌 정식 아두이노 보드간 I2C 통신을 구현하려 했으나, 제가 Arduino Uno 이외의 아두이노 보드가 없어 Arduino IDE (아두이노 언어)로 프로그래밍이 가능한 nodeMCU ESP32s 보드를 사용하여 예제를 구현하였습니다.

회로도 및 연결

Arduino Uno 와 ESP32 I2C 통신Arduino Uno 와 ESP32 I2C 통신

본 예제의 회로 구성은 아래와 같습니다. 

  • Arduino Uno
    • I2C Slave 장치로 사용 - Address : 0x13
  • nodeMCU ESP-32s
    • I2C Master 장치로 사용

📌 회로도 그림의 Arduino Uno 에서 아두이노 포트를 왼쪽 하단의 A4, A5 포트로 사용해도 동일 합니다.

📌 다른 보드를 사용해서 이 예제를 테스트 해보는 경우 I2C 포트에 풀업 처리가 필요할 수 있습니다.

예제1 : I2C 장치 스캔

두 가지 아두이노 보드에 I2C 초기화를 하고 Master에서 I2C 버스에서 장치가 있는지 스캔하는 예제입니다. 

(Master) nodeMCU-32s 코드

I2C 초기화를 하고, I2C 장치를 검색 합니다.

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
35
36
37
38
39
40
#include <HardwareSerial.h>
#include <Wire.h>
 
void setup() {
    Wire.begin();
    Serial.begin(115200);
    while(!Serial){
    ;
    }
    delay(3000);
    Serial.println("Program start...");  
    delay(3000);
}
 
void loop() {
    int statusTransmission;
    int flag = 1
    Serial.println("I2C Device Scanning....");
    
    delay(100);
    for(int i=0 ; i<127 ; i++)
    {
        Wire.beginTransmission(i);
        /* Slave 로 부터 정상적으로 ACK 가 도착하면 Wire.endTransmission() 이 '0'를 반환*/
        statusTransmission = Wire.endTransmission();
        if(statusTransmission == 0)
        {
            Serial.print("Connected I2C Device Address : 0x");
            if(i < 16)
                Serial.print("0");
            Serial.println(i,HEX);
            flag = 0;
        }
    }
    if(flag == 1){
        Serial.println("No I2C devices found");
    }
    Serial.println("Program End...");
    while(1);
}
cs
  • 21 Line - for문 : I2C 장치 주소 1 ~ 127 까지 검색을 수행하는 반복문
  • 23 Line - Wire.beginTransmission(i) : i 주소 7비트와 Write Bit를 함께 I2C 송신 대기열에 추가
  • 25 Line - Wire.endTransmission() : I2C 통신을 시작합니다.
    • Wire.endTransmission() 은 정상적으로 통신이 완료되면 숫자 0 을 반환합니다.
    • 0 이 반환 되었다는 것은 해당 i 주소의 장치 존재하여가 ACK 신호를 보낸 것을 의미합니다. 

(Slave) Arduino Uno 코드

I2C Address (0x13)을 부여하고, I2C 초기화를 진행합니다.

1
2
3
4
5
6
7
8
9
#include <Wire.h>
 
void setup(){
    Wire.begin(0x13);
}
 
void loop(){
    
}
cs
  • 4번 줄 Wire.begin(0x13) : I2C 주소를 0x13 으로 할당하고, I2C 포트를 초기화 합니다.


실행 결과

아래 영상은 nodeMCU 가 Reset 되면서 I2C 버스의 장치를 검색하는 영상입니다. 시리얼 포트로 0x13번 주소의 장치가 정상적으로 검색 되는 것을 확인 할 수 있습니다.

아래 왼쪽 그림은 0x00번 주소를 호출, 오른쪽 그림은 0x13번 주소를 호출한 파형입니다. I2C 버스에 0x13 주소의 장치만 존재하기 때문에 좌측 파형에는 ACK 신호가 없고, 우측 파형에만 ACK 신호가 있습니다. 우측 그림과 같이 정상적으로 ACK 신호가 수신되는 경우, Wire.endTransmission() 함수에서 0을 반환합니다.

I2C 파형(좌) 0x00 주소 송신시, (우) 0x13 주소 송신시


예제2 : ESP32 -> Arduino Uno 데이터 송신

Master Write 모드의 I2C 통신 방식으로, Master 에서 Slave 에게 1을 전송시 Slave 의 내장 LED를 켜고, 0을 전송시 Slave 의 LED를 끄는 예제입니다. 


(Master) nodeMCU-32s 코드

0.5초 간격으로 0x13 Slave 장치에 숫자 데이터 1와 0을 순차적으로 전송합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <Wire.h>
 
byte x = 0;
 
void setup() {
    Wire.begin(); 
}
void loop() {
    Wire.beginTransmission(0x13);
    Wire.write(x);
    Wire.endTransmission();
 
    if(x==0){
        x = 1;
    }
    else{
        x = 0;
    }
    delay(500);
}
cs


(Slave) Arduino Uno 코드

Master 장치로 부터 '1'이 수신 되면 LED 를 ON, '0'이 수신 되면 LED 를 OFF합니다.

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
#include <Wire.h>
 
#define ledPin 13
 
void setup()
{
    pinMode(ledPin, OUTPUT);
  Wire.begin(0x13);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
}
 
void loop()
{
  delay(500);
}
 
void receiveEvent(int howMany)
{
    byte value;
    while(0 < Wire.available())
    {
        value = Wire.read();
    }
 
    if(value == 1){
        digitalWrite(ledPin, HIGH);
    }
    else{
        digitalWrite(ledPin, LOW);
    }
}
cs

실행결과

(Master) nodeMCU ESP32s 보드가 1과 0을 순차적으로 전송하여 (Slave) Arduino Uno의 내장 LED를 깜빡이게 합니다.


예제3 : ESP32 -> Arduino Uno 데이터 호출

Master Read 통신 방식으로 Master 장치가 Slave 장치에게 Data를 요청 후 1이 수신 되면 Master 보드의 내장 LED 를 ON, 0이 수신되면 내장 LED를 OFF 하는 예제입니다.


(Master) nodeMCU-32s 코드

0.5초 간격으로 Slave 장치에게 1Byte 데이터를 호출 합니다. Slave 장치로 부터 '1'이 수신 되는 경우 내장 LED 를 ON, '0'이 수신되는 경우 LED를 OFF합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define ledPin 2
 
void setup() {
    pinMode(ledPin, OUTPUT);
    Wire.begin(); 
}
void loop() {
    byte value;
    Wire.requestFrom(0x131);
 
    while(Wire.available()){
        value = Wire.read();
    }
 
    if(value == 1){
        digitalWrite(ledPin, HIGH);
    }
    else{
        digitalWrite(ledPin, LOW);
    }
    delay(500);
}
cs

(Slave) Arduino Uno 코드

Master 장치로부터 데이터 송신 요청이 있는 경우 value 의 값을 송신 합니다. value 의 값은 0.5초 간격으로 '1' 또는 '0'으로 변경됩니다.

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 <Wire.h>
 
byte value = 0;
 
void setup()
{
  Wire.begin(0x13);                // join i2c bus with address #4
  Wire.onRequest(requestEvent);
}
 
void loop()
{
    if(value == 1){
        value = 0;
    }
    else{
        value = 1;
    }
  delay(500);
}
 
void requestEvent(){
    Wire.write(value);
}
cs

실행 결과

(Master)nodeMCU ESP32s 장치가 (Slave)Arduino Uno 로 부터 데이터를 수신하여 0.5 간격으로 내장 LED 를 깜빡입니다.


마무리

본 포스트에서는

I2C 장치 스캔, Master Write, Master Read 모드의 I2C 통신 예제

를 소개하였습니다. 이후 포스트에서는 Arduino Uno 와 다른 장치와 I2C 통신을 하는 예제에 대해 작성할 예정입니다.

끝까지 읽어주셔서 감사합니다. 😊

관련포스트

👉 아두이노 I2C 통신 관련글 목록 보기

👉 아두이노 관련글 전체 목록 보기