아두이노 강좌 #16 I2C 통신 소개와 구현 방법
Lucy Archive
Lucy 2023
2020. 7. 28. 02:21

Arduino Uno 에서 I2C 통신 구현 코드 소개

I2C 통신은 아두이노에서 사용 가능한 시리얼 통신 중의 하나로 비교적 빠른 속도를 요구하지 않는 간단한 주변 장치와 통신이 가능합니다. 아두이노에서는 주로 LCD, OLED 등으로 화면을 출력하고, 각종 센서로부터 데이터 수집, 다른 보드와의 통신등의 사용이 가능합니다. 폰 포스트에서는

I2C 통신에 대해 간단히 알아보고, Arduino 에서 I2C 구현하는 방법

에 대해 소개합니다.

I2C 통신

[각주:1]I2C는 UART와 유사한 직렬 통신 프로토콜 이지만, PC 장치 통신에는 사용되지 않고 모듈 및 센서와 함께 사용됩니다. 아두이노에서 사용되는 UART, I2C, SPI 는 차후 포스트에서 자세히 차이점에서 다룰 예정이고, 본 포스트에서는 I2C에 대해 간략한 소개만 작성하였습니다. 


I2C의 특징

  • 동기식 통신 방식
  • 다중 연결이 가능 : 최대 128개의 장치
  • 장치마다 고유한 주소를 사용하여 동일한 버스에 여러 장치 연결이 가능
  • 사용처 : 마이크로컨트롤러, EEPROM, A/D 컨버터, D/A 컨버터, I/O 확장 인터페이스 등 저속 장치

I2C 작동 방식

I2C는 SCK(직렬클럭라인)과 SDA(직렬 데이터 라인)의 두개 라인이 있습니다. SCK는 전송 동기화를 위한 클럭라인, SDA는 데이터 비트가 전송되거나 수신되는 데이터 라인입니다. 슬레이브 장치는 각자 고유 주소가 지정되어 있습니다. Master가 Slave 에게 데이터를 전송 또는 요청 하기 위해 지정된 주소를 호출하고 데이터를 송신 또는 수신합니다.

I2C는 Master 와 Slave 가 고정되어 있지 않고, 누구나 Master 가 될 수 있고, Slave 가 될 수 있습니다. 통신에 사용할 클럭(SCK)은 Master가 생성합니다.

I2C 버스 라인은 풀업 저항으로 전원과 연결 되어야 합니다. 통신이 유후 상태일 때는 두 라인 모두 높은 전원 수준입니다.

I2C InterfaceI2C Interface


I2C 데이터 프레임

Master는 Slave에게 7비트(또는 10비트) 주소와 읽기/쓰기 비트를 전달합니다. Slave 는 수신한 주소와 자신의 주소를 비교하여 주소가 일치하면 SDA 라인을 1비트 동안 LOW로 유지하여 ACK 비트를 반환 합니다. 주소가 일치하기 않을 경우 슬레이브는 SDA 라인을 HIGH 로 유지 합니다. 그 다음에 Master 가 데이터 프레임 8비트를 보내거나 받습니다. 각 데이터 프레임이 전송되면 수신 장치는 다른 ACK 비트를 송신하여 데이터 송신이 정상적으로 전송됨을 알려줍니다. 데이터 정송을 중지하기 위해 마스터는 SCL 을 HIGH 로 전환 후 SDA를 HIGH 로 전환하여 슬레이브에 중지 신호를 전송합니다.

I2C Data FrameI2C Data Frame


장점 및 단점

  • 장점
    • 많은 장치 연결시 사용되는 포트 수가 적음
    • 다중 마스터, 다중 슬레이브 통신을 지원
  • 단점
    • 풀업 저항기가 필요해 속도가 느림
    • 풀업 저항으로 PCB 공간을 차지
    • 반이중 방식의 통신으로 기기 수가 증가하면 구현이 복잡

Arduino Uno I2C Hardware

I2C Pinout

Arduino Uno 에서는 A4, A5번 핀이 I2C 포트로 사용이 가능합니다. Arduino Uno rev.3 이후 버전부터는 우측 핀 최상단 2핀이 A4, A5번 핀과 동일한 핀으로 할당되어 있습니다. 

Arduino Uno I2C PinoutArduino Uno I2C Pinout


아두이노 I2C 코딩

I2C 라이브러리

아두이노에서 I2C 통신을 사용하기 위해서 wire.h 라이브러리를 사용합니다. wire.h는 아두이노에 기본으로 내장되어 있는 라이브러리로, 별도의 라이브러리 설치 없이 코드 선언부에 #include <wire.h> 만 선언하면 됩니다. 

[각주:2]아두이노 코딩을 하기 전에 내가 사용하는 아두이노 보드가 Master 인지 Slave 인지 구분을 하고, Master -> Slave 데이터 쓰기으로 사용하는지 Master -> Slave 데이터 호출 인지 4가지로 구분하여 정리하면 좀 더 쉽게 I2C 코딩에 대해 감을 잡을 수 있습니다. 


1. I2C Initialize

아래는 I2C 초기화 함수이며, 일반적으로 void setup() 함수내에서 작성 됩니다.
  • Wire.begin() : I2C Master 로 초기화
  • Wire.begin(address) : I2C 주소를 부여하여 초기화, Master/Slave 모두 사용 가능

Syntax

  • Wire.begin()
  • Wire.begin(address)

Parameters

  • address : (Optional) 7 비트 slave address 값입니다. 생략할 경우 마스터로 인식 합니다.
    • (optional) 7 비트 Slave Address 값 입니다.
    • 생략할 경우 마스터로 인식 합니다.

Returns : None

Example

  • Wire.begin() : I2C를 초기화 하고, Master 로만 사용합니다.
  • Wire.begin(13) : I2C Address 를 13 로 초기화 하고, Master/Slave 모두 사용 가능합니다.


2. Master -> Slave 데이터 쓰기

Master 측 코드 : Master 데이터 송신

  • Wire.beginTransmission(address) : Master -> Slave(address) 데이터 쓰기 모드를 시작 코드
  • Wire.write(data) : 데이터 송신 코드
  • Wire.endTransmission() : 데이터 송신 종료 -> 해당 함수 실행되는 타이밍에 I2C 통신이 시작 됩니다.

Master Wrie 모드에서 Master 코드Master Wrie 모드에서 Master 코드


Slave 측 코드 : Slave 데이터 수신
  • void setup() 안에서
    • Wire.onReceive(handler) : Slave 에서 데이터가 수신 될 때 호출할 함수를 지정
  • void loop() 에서 또는 void handler() 안에서
    • Wire.available() : I2C 수신 버퍼에 저장된 데이터 수를 반환
    • Wire.read() : I2C 수신 버퍼의 데이터를 읽고, 읽은 데이터 수신 버퍼에서 비우기

Master Wrie 모드에서 Slave 코드Master Wrie 모드에서 Slave 코드

3. Master -> Slave 데이터 호출

Master 측 코드 : Master 데이터 호출

  • Wire.requestFrom(address, dataSize) : 지정된 주소의 Slave 에게 dataSize 크기의 데이터를 호출
  • Wire.available() : I2C 수신 버퍼에 저장된 데이터 수를 반환
  • Wire.read() : I2C 수신 버퍼에 데이터를 읽고, 읽은 데이터를 수신 버퍼에서 비우기

Master Read 모드에서 Master 코드Master Read 모드에서 Master 코드

Slave 측 코드 : Slave 데이터 송신

  • void setup() 안에서
  • Wire.onRequest(handler) : Slave 로 부터 데이터 요청이 있을 때 호출할 함수(hanlder)를 지정
  • void loop() 에서 또는 void handler() 안에서
  • Wire.write(value) : I2C 데이터 송신

Master Read 모드에서 Slave 코드Master Read 모드에서 Slave 코드


마무리

본 포스트에서

I2C의 모드 종류에 따라 사용되는 아두이노 코드

에 대해 알아보았습니다. 다음 포스트는 이번 포스트에서 소개한 함수들을 사용하여 Arduino Uno 와 nodeMCU ESP32s 보드를 I2C 통신하는 예제에 대해 작성할 예정입니다. 참고해주세요. 끝까지 읽어주셔서 감사합니다.^^
관련포스트

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

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


  1. I2C bus specification : https://www.nxp.com/docs/en/user-guide/UM10204.pdf [본문으로]
  2. Arduino Reference wire.h : https://www.arduino.cc/en/Reference/Wire [본문으로]