※ I2C 주소가 같은 ssd1306 5개를 esp32-c3 mini 에 연결해서 구동하려고 한다. 어떻게 연결해야 하나?
1. I2C 주소 문제 (0x3C, 0x3D)
일반적인 SSD1306 모듈은 뒷면의 저항(Jumper) 위치를 옮겨서 주소를 0x3C 또는 0x3D 중 하나로 설정할 수 있습니다.
- 결론: 동일한 I2C 버스 하나에는 최대 2개까지만 직접 연결할 수 있습니다.
- 우리는 5개를 연결해야 하므로, 단순히 병렬로 연결하는 것만으로는 불가능합니다.
2. 해결 방법: I2C Multiplexer (TCA9548A) 사용
가장 깔끔하고 권장되는 방법은 TCA9548A 같은 I2C 확장 모듈을 사용하는 것입니다.
- 원리: 이 칩은 1개의 I2C 입력을 받아 8개의 독립된 I2C 채널(선택 가능)로 분리해 줍니다.
- 연결 방식: ESP32-C3의 I2C 핀을 TCA9548A에 연결하고, 각 OLED를 TCA9548A의
SD0/SC0부터SD4/SC4까지 하나씩 연결합니다. - 장점: 코드가 매우 단순해지며 전압 관리도 수월합니다.
3. 멀티플렉서 없이 연결하는 방법 (S/W I2C 또는 Multi-Bus)
부품을 추가하고 싶지 않다면 두 가지 대안이 있습니다.
A. 소프트웨어 I2C (Bit-banging)
ESP32-C3는 핀 매핑이 자유롭습니다. 5개의 디스플레이를 위해 각각 다른 GPIO 쌍을 사용하는 방식입니다.
- 핀 소모: SDA 5개 + SCL 1개(공통) = 총 6개의 핀 필요.
- 단점: CPU 부하가 늘어나고 화면 업데이트 속도가 느려질 수 있습니다.
B. 공통 SCL + 개별 SDA 방식
SSD1306 라이브러리(u8g2 등)에서 SDA 핀을 각각 다르게 설정하여 5개의 인스턴스를 생성합니다.
- ESP32-C3 GPIO 예시:
- SCL: GPIO 8 (공통)
- SDA1: GPIO 0, SDA2: GPIO 1, SDA3: GPIO 2, SDA4: GPIO 3, SDA5: GPIO 4
4. 회로 연결 가이드 (TCA9548A 기준 권장)
| ESP32-C3 Mini | TCA9548A | SSD1306 (5개) |
| 3.3V | VIN | VCC (모두 연결) |
| GND | GND | GND (모두 연결) |
| GPIO 8 (SCL) | SCL | – |
| GPIO 10 (SDA) | SDA | – |
| – | SD0~SD4 | 각 OLED의 SDA에 하나씩 연결 |
| – | SC0~SC4 | 각 OLED의 SCL에 하나씩 연결 |
⚠️ 주의사항
- 전류 소모: OLED 5개를 동시에 켜면 전류 소모가 상당합니다. ESP32-C3 Mini의 3.3V 출력 핀만으로는 부족할 수 있으니, 외부 3.3V 전원을 사용하는 것이 안정적입니다.
- 메모리(RAM): ESP32-C3는 RAM이 넉넉한 편이지만, 128×32 해상도 버퍼 5개를 동시에 유지하면 메모리 압박이 올 수 있습니다.
u8g2라이브러리의_F_(Full Buffer) 모드 대신_1_또는_2_(Page Buffer) 모드 사용을 권장합니다.

Pythone PCA9548A.py
from machine import Pin, SoftI2C
import ssd1306
import time
import math
# 1. I2C 및 PCA9548A 설정
i2c = SoftI2C(scl=Pin(1), sda=Pin(0), freq=400000)
PCA_ADDR = 0x70
# 요청하신 새로운 채널 구성: 2, 3, 4, 6
CHANNELS = [2, 3, 4, 6]
WIDTH, HEIGHT = 128, 32
def select_channel(ch):
i2c.writeto(PCA_ADDR, bytearray([1 << ch]))
# 2. 각 화면 객체 초기화
displays = []
for i, ch in enumerate(CHANNELS):
select_channel(ch)
oled = ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)
oled.contrast(50)
displays.append(oled)
print(f"Device {i+1} on Channel {ch} 초기화 완료")
# --- 애니메이션 변수 ---
offset = 0
ball_x, ball_y = 64, 16
dx, dy = 3, 2
print("데모 쇼를 시작합니다 (채널 2, 3, 4, 6)")
try:
while True:
# --- [화면 1: 슬라이딩 텍스트 (Ch 2)] ---
select_channel(CHANNELS[0])
d1 = displays[0]
d1.fill(0)
d1.text("SYSTEM ONLINE", int(math.cos(offset/5)*10) + 10, 10)
d1.show()
# --- [화면 2: 다이내믹 바 그래프 (Ch 3)] ---
select_channel(CHANNELS[1])
d2 = displays[1]
d2.fill(0)
for b in range(6):
h = int((math.sin(offset/4 + b) + 1) * 12) + 2
d2.fill_rect(5 + (b*20), 32-h, 12, h, 1)
d2.show()
# --- [화면 3: 바운싱 볼 (Ch 4)] ---
select_channel(CHANNELS[2])
d3 = displays[2]
d3.fill(0)
d3.fill_rect(ball_x, ball_y, 4, 4, 1)
ball_x += dx
ball_y += dy
if ball_x <= 0 or ball_x >= 124: dx *= -1
if ball_y <= 0 or ball_y >= 28: dy *= -1
d3.show()
# --- [화면 4: 스캐닝 라인 (Ch 6)] ---
select_channel(CHANNELS[3])
d4 = displays[3]
d4.fill(0)
scan_x = (offset * 4) % 128
d4.vline(scan_x, 0, 32, 1)
d4.text("SCANNING...", 35, 12)
d4.show()
offset += 1
time.sleep_ms(5) # 전환 속도를 더 높였습니다.
except KeyboardInterrupt:
print("데모 종료")




답글 남기기