ESP32 개발 보드에서 OLED 디스플레이 사용하기

ESP32 개발 보드에서 OLED 디스플레이 사용하기

1. OLED 디스플레이

앞선 글에서 ESP32 보드에 1602라는 액정을 사용하여 정보를 표시하는 것을 소개하였었다.

이번 글에서는 ESP32 보드에서 LCD 대신 소형 OLED 디스플레이를 이용하여 출력하는 방법을 소개한다.

아두이노나 ESP 보드 등에서 사용하는 OLED 디스플레이는 대략 0.9~1.3인치 정도의 크기가 보편적이며, 시중에서 수천 원 정도에 구입이 가능하다.

이들 OLED 디스플레이의 통신방식은 다음 사진들과 같이 I2C여서, 전원 선을 포함하여 총 4개의 선으로 개발 보드와 연결되게 된다.

또한 OLED 제품은 사용하는 드라이버칩에 여러 가지가 있는데, 내가 선택한 0.91인치의 경우 SSD1306을 사용하는 것으로 알려져, OLED 자체를 SSD1306 OLED라고 부르기도 한다. (참고로 좀 더 큰 사이즈인 1.3인치의 경우 SH1106을 사용하는 경우도 있었다.) OELD는 이렇게 사용하는 드라이버 칩셋이 호환성을 결정하므로, 제품을 구입 시 반드시 사용된 드라이버 칩셋의 종류를 확인해야 한다.

이들 제품은 해상도에 따라 다음과 같이 128 x 64의 해상도를 가지는 제품과, ​화면 세로폭이 절반인 128×32의 해상도를 가지는 제품으로 나뉜다.

두 가지 제품 모두 사용된 드라이버 칩셋만 동일하다면, 128×32의 경우라도 사용 시 화면 해상도 설정만 변경하면 128×64와 동일한 방식으로 사용이 가능하다.

2. OLED 사용을 위한 Library

OLED 디스플레이를 ESP32 개발 보드에서 사용하려면, 전용의 라이브러리(SSD1306.py)를 미리 보드에 저장해 두어야 한다. 이 라이브러리는 여러 버전이 있기는 하지만, 가장 기본적인 버전은 다음 링크를 이용하여 Github에서 다운로드할 수 있다.

https://github.com/adafruit/micropython-adafruit-ssd1306/blob/master/ssd1306.py

이 링크를 열면 다음과 같은 화면이 나오는데, 여기서 다음 파일을 다운로드한 후, 그대로 ESP32개발 보드에 SSD1306.py라는 이름으로 저장해 주면 된다. (이 파일을 열고 Code를 복사한 후, ThonnyIDE에 붙여 넣은 후, ESP32보드에 저장하는 방법으로 하면 된다.)

3. ESP32 개발 보드 연결

이 OLED는 I2C 방식 통신을 이용한다. I2C에 대한 기본적 사항에 대해서는 앞선 글을 참조하기 바란다.

https://kongyine.com/223188515992

배선에는 총 4선이 필요한데, 다음과 같이 배선했다.

OLED의 전원선 Vcc와 GND를 개발 보드의 해당 핀에 연결하고, SDA 핀을 GP21번 핀에, SCL을 GP22번 핀에 연결했다.

배선이 연결된 전체 모습은 다음과 같다.

4. 마이크로 파이썬 코딩

OLED에 출력하려면 먼저 미리 저장해둔 OLED 라이브러리의 사용을 선언해 주어야 한다.

다른 필수 라이브러리도 함께 사용을 선언해 준다.

from machine import Pin, I2C

from ssd1306 import SSD1306_I2C

import utime

그 다음으로 I2C 통신 사용을 선언해 준다. 미리 핀을 연결한 대로 다음과 같이 선언한다.

sda=machine.Pin(21)

scl=machine.Pin(22)

i2c=machine.I2C(0,sda=sda, scl=scl, freq=400000)

그 다음은 OLED의 사용과 해상도를 선언해 준다.

WIDTH =128

HEIGHT= 64 (128×32 모듈은 32로 표기)

oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)

그런데, OLED의 경우에는 사용 선언 시 I2C 주소를 지정하지 않는다. 이는 ssd1306.py 라이브러리 내에서 OLED 모듈의 I2C 주소를 다음과 같이 Ox3C로 고정해 두었기 때문이다.

그 다음은 실제 출력 명령들을 이용하여 출력하면 된다.

문장이나 변수를 출력할 때는 oled.text(변수, 수평 위치, 수직 위치) 방식으로 표시하면 된다. 화면상 위치번호는 왼쪽 최상단이, 0,0에 해당되고, 오른쪽 가장 아래가 127.63에 해당된다.

그런데, 한 가지 기억할 것은, OLED의 경우, 출력 명령 그 자체로 화면에 표시되는 게 아니라, 표시한 것이 화면에 나타나도록 하려면 show() 명령을 바로 붙여서 사용해야 한다는 점이다.

즉, “hello”라는 글자를 화면 왼쪽 최상단에 표시하려면 다음과 같이 두 개의 명령어를 사용해야 한다.

oled.text(“Hello!”, 0, 0)

oled.show()

5. 주요 명령어

사용이 가능한 주요 명령어들은 다음과 같다.

​​

화면 지우기 oled.fill( ) 명령어를 사용한다.

oled.fill(0)은 어두운 상태로 화면이 지워지며, oled.fill(1)은 반전 상태로 화면을 지운다.

화면 출력 oled.text(“Hello!”, 시작가로 위치, 시작 세로 위치)를 이용한다.

8X8의 해상도를 가지는 크기로 표기된다. (가로 16자 x 세로 8자 출력)

Contrast oled.contrast(1~9) 명령으로 조절 (3~5 정도가 읽기에 좋다)

화면 반전 oled.invert( ) 인자 값이 1이면 화면이 반전되며, 0 이면 반전이 취소된다.

화면끄기/켜기 oled.poweroff( )

oled.poweron( )

화면 표시 oled.show( ) 를 추가해 주어야 한다. (On/Off 제외)

선그리기 oled.hline(시작수평위치, 시작수직위치, 수평이동수,1)

oled.vline(시작수평위치, 시작수직위치, 수직이동수,1)

oled.line(시작수평위치, 시작수직위치, 수평이동수, 수직이동수,1)

사각형그리기 oled.rect(시작수평위치, 시작수직위치, 수평이동수, 수직이동수,1)

(명령속의 마지막 인자 1은 실선을 의미한다. 0으로 설정하면 선이 보이지 않는다.)

그런데 여기서 기억할 중요한 사항이 있다. 이렇게 선 그리기 명령에서는 명령이 시작되는 점의 위치는 절대 위치이지만, 그 뒤에 나오는 것은 절대 위치가 아니라 상대 위치라는 점이다. 또한 해상도 영역 밖의 위치에 해당되는 위치를 지정해서 그리기 명령을 지정하면, 해상도 영역 밖을 표시해 주지는 못하지만, 마치 해상도 영역 밖의 공간도 실제 하는 것처럼 그리기 동작이 이루어진다는 점이다.

다음 예제 사진들을 참고하면 OLED 모듈의 이러한 특성을 이해하는 데 도움이 될 듯하다.

5. 예제

위에 소개한 내용을 토대로, 다음과 같은 에제 Code를 만들어 동작시켜보았다.

from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import utime

WIDTH =128
HEIGHT= 64
i2c=I2C(0,scl=Pin(22),sda=Pin(21),freq=200000)
oled = SSD1306_I2C(WIDTH,HEIGHT,i2c)
oled.init_display()
while True:
    oled.fill(0)
    oled.text("Hello!", 0, 0)
    oled.show()
    utime.sleep(2)   
       
    oled.fill(0)
    oled.text("OLED Clearing", 0, 0)
    oled.show()
    utime.sleep(2)
for k in range(9):
        oled.fill(0)
        oled.text("< Normal mode >",0,0)
        oled.text("Contrast Setting",0,16)
        oled.text(str(k),0,32)
        oled.contrast(k)
        oled.show()
        utime.sleep(0.5)


    oled.invert(1)
for k in range(9):
        oled.fill(0)
        oled.text("< Invert mode >",0,0)
        oled.text("Contrast Setting",0,16)
        oled.text(str(k),0,32)
        oled.contrast(k)
        oled.show()
        utime.sleep(0.5)
    oled.invert(0)


    oled.fill(0)
    oled.text("OLED Turning off", 0, 0)
    oled.show()
    utime.sleep(2)
    oled.poweroff()
    utime.sleep(2)
    oled.poweron()
    oled.fill(0)
    oled.text("OLED Turned on", 0, 0)
    oled.show()
    utime.sleep(2)
           
    oled.fill(0)
    oled.text("123456789012345678",0,0)
    oled.text("012345678901234567",0,8)
    oled.text("901234567890123456",0,16)
    oled.text("890123456789012345",0,24)
    oled.text("789012345678901234",0,32)
    oled.text("678901234567890123",0,40)
    oled.text("567890123456789012",0,48)
    oled.text("456789012345678901",0,56)
    oled.text("345678909876543210",0,64)
    oled.show()
    utime.sleep(3)
for k in range(6):
        oled.fill(0)    
        oled.hline(0,k*10,126,1)
        oled.show()
        utime.sleep(0.2)
for k in range(12):
        oled.fill(0)    
        oled.vline(k*10,0, 64,1)
        oled.show()
        utime.sleep(0.2)


    oled.fill(0)    
    oled.line(10,10,120,64,1)
    oled.line(120,10,10,64,1)
    oled.show()
    utime.sleep(2)

    oled.fill(0)    
    oled.rect(0,0,128,64,1)
    oled.show()
    utime.sleep(2)

동작 모습은 다음과 같다.