MCU의 정보들을 보여주기 위한 방법들이 여러가지 있습니다. 그중 저렴한 OLED 제품들이 오픈마켓이나 알리등을 통해 저렴하게 구매할 수 있었습니다. 꽤 밝고 선명해서 사용하기 편리합니다.
일단 테스트를 위해 여러가지를 구매해서 사용해보는 중이고 이 글에서는 128x32 (0.91인치) 제품을 이용해봅니다. MCU는 DOIT ESP32 Devkit V1을 사용했습니다. ESP32 WROOM 계열 제품이면 비슷하게 작동될것으로 보입니다.
0.91인치 128x32 OLED Display
DOIT ESP32 Devkit V1
OLED에 신호를 보내는 방법은 여러가지가 있을 수 있으나 여기서는 I2C(Hardware)방식을 이용합니다.
핀배열을 위 그림과 같고 I2C 통신을 이용하려면 D21(I2C_SDA)을 OLED의 SDA와 연결하고 D22(I2C_SCL)을 OLED의 SCL(간혹 제품에 SCK로 표시된 경우도 있음)과 연결합니다. OLED의 전원은 3.3V~5V까지 지원되므로 VCC와 GND(Ground)에 적절한 전원을 연결해 줍니다.
OLED제품을 이용하려면 모듈이 필요한데 SSD1306을 다운로드 받아 main.py와 동일한 위치에 넣어놓고 함께 업로드 되어야 합니다.
ESP32를 PC와 연결 후 다음 코드(main.py)를 업로드 하고(물론 MicroPython을 사용하기 위한 펌웨어 업로드 등의 전 작업이 미리 되어 있어야 합니다) EN키를 누르며 Boot키를 눌러 MCU를 재기동 하면 OLED 상단에 Hello, World! 가 출력됩니다.
from machine import Pin, I2C
import ssd1306
i2c = I2C(sda=Pin(21), scl=Pin(22))
display = ssd1306.SSD1306_I2C(128, 32, i2c)
display.text('Hello, World!', 0, 0, 1)
display.show()
SSD1306 모듈에 다양한 기능이 있으니 레퍼런스를 참고하면 다양하게 제어할 수 있습니다. 아두이노를 사용할때는 u8g2라는 라이브러리로 사용했었습니다.
기본 폰트의 크기는 8x8로 화면 가득 채우면 16x4개의 문자를 사용할 수 있습니다.
이미지 출력
이 OLED는 단일색상이므로 이미지는 BW로 만들어야 합니다. 보통 이미지 파일을 만들어 함께 업로드 해 읽어 처리하거나 이미지를 List로 만들어 main.py내에 포함시켜 처리하게 됩니다.
간단하게 List를 이용해 봅니다. 아래 이미지는 구글 검색을 통해 나온것으로 핀터레스트에 있는 이미지 입니다.
이 이미지를 List로 만들어 보면 다음처럼 표현할 수 있습니다.
from machine import Pin, I2C
import ssd1306
i2c = I2C(sda=Pin(21), scl=Pin(22))
display = ssd1306.SSD1306_I2C(128, 32, i2c)
MARIO = [
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0],
[0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0],
[0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0],
[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0],
[1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0],
[1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0],
[1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1],
[0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1],
[0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0],
]
display.fill(0) # 화면지우기
for y, row in enumerate(MARIO):
for x, c in enumerate(row):
display.pixel(x, y, c)
display.show()
0인 부분은 건너뛰고 1인 부분에 픽셀을 찍어 OLED 화면 좌측 상단에 마리오 그림이 보여집니다. 물론 bit단위로 처리를 해야 효율적이겠지만 간단히 구조를 이해해보기 편한 방법으로 해봤습니다.