본문 바로가기
아두이노

I2C 멀티플렉서(multiplexer)를 활용하여 여러개의 OLED를 사용해보기

by 구루가 되고픈 2023. 1. 2.

OLED 디스플레이 같은 I2C 모듈을 사용할때의 문제점은 address가 같으면 안된다는 것입니다.

 

예전의 프로젝트에서 여러개의 OLED 디스플레이를 사용하는 경우가 많았는데, 이때 address가 같아서 여러개의 oled를 아두이노 하나에 연결하지 못해서 아두이노 1개당 하나씩의 oled를 연결하는 방식을 사용하였습니다.

 

2개 디스플레이 정도는 이 방식이 큰 부담이 없으나 여러개의 디스플레이는 사용하는 경우 매우 비효율적인 방식입니다.

과거 프로젝트에서 8개의 최대 oled를 사용하였는데, 이때 아두이노 8개를 사용하여 각각의 oled를 출력하였습니다.

 

이러한 문제를 해결하는 것이 I2C 멀티플렉서(multiplexer)라고 하는 모듈입니다.

동일한 address를 가진 디바이스를 멀티플렉서에 연결하면 0~7번까지의 채널번호로 각각의 디바이스에 연결하는 역할을 하는 것이 멀티플렉서의 역할입니다.

 

멀티플렉서는 보통 TCA9548A 모듈을 많이 사용하며, 최대 8개의 동일한 address를 가진 디바이스를 연결할 수 있습니다.

 

TCA9548A 멀티플렉서

 

제가 알리에서 구매한것은 PCA9548A라는 모듈명을 달고 있는 모듈로 칩셋번호도 다르긴 하나 동작은 동일하게 하는 것 같습니다.

 

PCA9548A 모듈

 

멀티플렉스에 대한 설명은 아래 2개 URL에서 매우 자세하고 설명하고 있어서 참고해 보시기 바랍니다.

 

https://randomnerdtutorials.com/tca9548a-i2c-multiplexer-esp32-esp8266-arduino/

 

TCA9548A I2C Multiplexer: ESP32, ESP8266, Arduino | Random Nerd Tutorials

Learn how to expand the I2C bus ports (ESP32, ESP8266 NodeMCU, Arduino) using TCA9458A 1-to-8 I2C Multiplexer. It controls multiple I2C devices with the same I2C address.

randomnerdtutorials.com

 

https://www.youtube.com/watch?v=XWQsqPQOW-U

 

이외에도 멀티플렉스에 대한 설명은 인터넷상에 많이 소개 되어 있으므로 더 찾아보시면 될것 같습니다.

 

테스트를 위해 아두이노 micro pro버전에 멀티플렉서를 연결하여 멀티플렉서에는 oled 디스플레이 3개를 연결하였습니다.

 

아두이노 - 멀티플렉서 - OLED디스플레이 연결

 

멀티플렉스 기본코드는 위에 소개해드린 두번째 YOUTUBE 영상에서 소개한 코드를 사용하여 구현하였습니다.

일단 영상에서 소개한 기본코드는 아래와 같습니다.

 

#include "Wire.h"
#include <U8glib.h>
#define MUX_Address 0x70 // TCA9548A Encoders address

char tmp_string[8];  // Temp string to convert numeric values to string before print to OLED display
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_FAST);  // Fast I2C / TWI

// Initialize I2C buses using TCA9548A I2C Multiplexer
void tcaselect(uint8_t i2c_bus) {
    if (i2c_bus > 7) return;
    Wire.beginTransmission(MUX_Address);
    Wire.write(1 << i2c_bus);
    Wire.endTransmission(); 
}

void setup(){
	  DisplayInit(); // Initialize the displays 
}

// Initialize the displays 
void DisplayInit(){
    for (int i = 0; i < 7; i++) {
      tcaselect(i);   // Loop through each connected displays on the I2C buses  
  		u8g.firstPage();
  		do {
  			u8g.begin();  // Initialize display
  		 } while( u8g.nextPage() );
    }
}


void loop(){
    for (int i = 0; i < 7; i++) {
      tcaselect(i);

  	  u8g.firstPage();
  	  do {
    		/******** Display Something *********/
    		u8g.setFont(u8g_font_ncenB10);
        u8g.drawStr(0, 13, "Connected to:");

        itoa(i, tmp_string, 10);  
        u8g.setFont(u8g_font_ncenB18);
        u8g.drawStr(25, 50, tmp_string);
        /************************************/
  	  } while( u8g.nextPage() );
  	  delay(50);
    }
	  delay(500);
}

 

그래픽 라이브러리로 u8glib를 사용하고 있고 7개 디스플레이를 연결하는 코드입니다.

이 코드로 기본 구조나 구현하는 부분은 이해할 수 있어서 이 코드를 기반으로 3개 디스플레이는 연결하는 코드로 수정해서 테스트 해 보았습니다.

 

#include "Wire.h"
#include <U8glib.h>
#define MUX_Address 0x70 // TCA9548A Encoders address

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST);

char tmp_string[8];  // Temp string to convert numeric values to string before print to OLED display
uint16_t cnt;
uint8_t dispcnt = 3; // 디스플레이 개수 (최대 7개)

// Initialize I2C buses using TCA9548A I2C Multiplexer
void tcaselect(uint8_t i2c_bus)
{
  if (i2c_bus > dispcnt) return;           // 디스플레이 숫자 개수로 설정
  Wire.beginTransmission(MUX_Address);
  Wire.write(1 << i2c_bus);
  Wire.endTransmission(); 
}

void setup()
{
  DisplayInit(); // Initialize the displays 
}

// Initialize the displays 
void DisplayInit()
{
  for (int i = 0; i < dispcnt; i++) {  // 디스플레이 숫자 개수로 설정
    tcaselect(i);   // Loop through each connected displays on the I2C buses  
		u8g.firstPage();
		do {
			u8g.begin();  // Initialize display
		 } while( u8g.nextPage() );
  }
}


void loop()
{
  for (int i = 0; i < dispcnt; i++) {  // 디스플레이 숫자 개수로 설정
    tcaselect(i);

  u8g.firstPage();
  do {

    /******** Display Something *********/
    if (i == 0)
    {
  		u8g.setFont(u8g_font_ncenB10);
      u8g.drawStr(0, 13, "Disp1");
  
      itoa(cnt, tmp_string, 10);  
      u8g.setFont(u8g_font_ncenB18);
      u8g.drawStr(25, 50, tmp_string);
    }
    else if (i == 1)
    {
      u8g.setFont(u8g_font_ncenB10);
      u8g.drawStr(0, 13, "Disp2");
  
      itoa(cnt, tmp_string, 10);  
      u8g.setFont(u8g_font_ncenB18);
      u8g.drawStr(25, 50, tmp_string);       
    }
    else if (i == 2)
    {
      u8g.setFont(u8g_font_ncenB10);
      u8g.drawStr(0, 13, "Disp3");
  
      itoa(cnt, tmp_string, 10);  
      u8g.setFont(u8g_font_ncenB18);
      u8g.drawStr(25, 50, tmp_string);        
    }
    else
    {}
    
  } while( u8g.nextPage() );

  cnt++;
  }
  delay(500);
}

 

0.5초 단위로 디스플레이에 각각 증감값을 출력하는 코드로 수정하였습니다.

화면에 표시되는 것은 loop의 if문으로 구성된 코드블럭이 각각의 디스플레이에 표시됩니다.

 

실행영상을 참고하시기 바랍니다.

 

 

 

멀티플렉스를 사용하면 어렵지 않게 아두이노 하나로 여러개의 OLED 디스플레이를 사용할 수 있는 장점이 있고, 역으로 동일한 센서 모듈을 사용할 수 있는 장점이 있습니다.