OLED에 한글출력

출처: http://andy-power.blogspot.com/2018/08/oled.html

1. 늘 고생이다.

 Display 장치에 한글을 표현하기 위해서 고생한 경우가 한두번이 아니다. DOS 시절부터 프로그래밍을 했고, 게임도 만들었던 세대라 한글이 늘 문제였다. 꽤 오래전에 마지막으로 한글 출력 때문에 고생한 것은 Sony의 PSP 때문이었다. PSP용 Home Brew가 시작 되던 시기에 그당시 좋은 Display를 가지고 있는 게임기 였지만, 한글로된  txt 파일을 볼 수 있는 방법은 없었다. 게임을 주로 하는 게임기였지만, 가끔 소설을 보고 싶을 때가 있어서 결국 한글 출력을 만들게 되었다. 그때 당시 HanView라는 이름으로 릴리즈하기 시작했고, 꽤 많은 인기가 있었다. 마지막 부분에 전체 소스를 공개하였고, 그 뒤로 내가 만든 라이브러리는 PSP의 동영상 플레이어의 제작자가 자막 표시용으로 사용한다는 이야기를 얼핏 들은것 같다.

 PSP 시절에도 이게 문제였다. 처음에는 조합형으로 시작했다가 결국 완성형으로 다시 만들어 버린 기억이 있다. (물론 이유는 txt파일이라도 한자나, 일본글자 등이 많기 때문에 unicode에 포함된 약 6만5천자를 표현하기 위하여 완성형으로 돌아 서게 되었다)

2. 조합형이냐 완성형이냐 이것이 문제로다.

ESP2866 이라도 그렇게 여유롭지 못한 메모리 및 스케치 영역 때문에 처음 기획은 조합형 이었다.  조합형 폰트의 경우 초성 8벌, 중성 4벌, 종성 4벌로 구성되기 때문에 360개 정도의 폰트 정보만 있으면, 평소에 사용되는 모든 글자를 표현할 수 있다.  하여간 아주 오래전 시절을 떠올리며 조합형 글자 표현이 가능한 한글 라이브러리를 만들었다. 하지만 최근 10년을 넘게 완성형 글자만을 보아와서 그런지,  완성형 폰트의 미려함을 포기할 수가 없었다. (지금 조합형 글자들을 보면 먼가 어설퍼 보인다… 예전에는 그런 생각을 가지지 않았지만…)
결국 완성형 폰트로 다시 시작 하게 되었다.

3. 얼마 만큼의 문자수를 지원할까 그것도 문제로다.

 최신 버전의 Arduino IDE는 한글은 UTF8로 저장된다.  UTF8은  Unicode와 일맥상통하고, 결국 6만자 이상의 폰트 정보가 필요한 상황이지만, 결국 활용 빈도가 높은 EUC-KR에 포함된 한글의 2350글자(0xb0a1 ~ ) 만을 표시 하기로 결정했다. 2350글자라는 것은 이 블로그에 글을 적을때 사용하는 모든 종류의 한글 글자수 이다. 이것 이상의 글자를 블로그에서 사용하지 않는다.

4. 폰트정보를 어디에 적재할 것인가 이것 역시 문제로다.

 이론상 16px X 16px 한글 1글자의 폰트 정보는 32바이트가 필요하고, 영숫자는 16바이트의 정보가 필요하다.  대충 76KB의 공간이 필요하다.  ESP8266의 경우 스케치 공간에 올릴수는 있다. 하지만 이건 16px 크기의 폰트 1종류에 필요한 공간이며, 폰트 크기가 3종류만 되어도 여러가지 불편한 진실이 되어 버린다. 그래서 SPIFSS 공간에 올리기로 결정하였다.

 이전 포스트를 통하여 SPIFSS공간에 데이터를 올리는 방법을 소개한 적이 있다.
https://andy-power.blogspot.com/2018/07/esp8266-esp32-spifss.html

5. 폰트 정보를 만들다.

그나마 편리한 언어를 이용하여 폰트 저장 하는 프로그램을 만들었다. 폰트 크기는 12px, 14px, 16px의 3개 크기로 만들었다. 폰트 크기가 12px이하가 되면 한글은 가독성이 아주 떨어져서 특별히 만들지 않았다.  폰트가 12px 크기인 경우 hfont12.dat라는 이름으로 저장되고, 파일은 앞부분에 128 * 12bytes로 구성된 ascii 폰트와 그 뒤로 EUC-KR의 한글 코드 0xb0a1 부터 유효한 한글 글자의 폰트가  2350 * 12 * 2bytes 형태로 기록되어 있다. (즉 폰트 크기에 따라서 데이터 파일 크기가 다르다는 이야기 이다.)

한글이 시작되는 위치에는 아래와 같이 ‘가’ 라고 기록되어 있다.  (1행 = 2bytes)
0000000000010000
0111111000010000
0000000100010000
0000000100010000
0000000100010000
0000000100011100
0000000100010000
0000001000010000
0000001000010000
0000010000010000
0001100000010000
0110000000010000
0000000000010000
0000000000000000
0000000000000000
0000000000000000

특별히  ascii 코드 쪽에 몇글자는 사용의 편리를 위하여 몇개 번외로 기록하였다.
(첫부분에 소개한 이미지에 포함된다. )
아래 첨자 4개

0x0b 0x0c  0x0d  0x0e
₁    ₂     ₃    ₄

윗 첨자 4개

0x15 0x16  0x17  0x18
¹    ²     ³     ⁴

특수 문자 5개

0x0f 0x10  0x11  0x12   0x13
℉    ℃    ‰      μ      °

이렇게 매핑 시켰더니 특수문자는 영숫자보다 더 넓은 글자폭이 필요하여, 결국 2350글자 뒷부분에 폰트 정보를 넣어 버렸다.

6. Unicode -> EUC-KR 정보를 만들다.

UTF8의 한글은 각 글자당 3바이트 이고,  Unicode로는 아래의 코드로 변환 가능하다.

unicode = (byte1 & 0b00001111) << 12 | (byte2 & 0b00111111) << 6 | (byte3 & 0b00111111);

하지만 Unicode를 EUC-KR로 변환하는 공식은 없다. (처음에 이부분을 고려 못했다.) 1대1 매핑으로만 가능하다. 어쩔수 없이 Unicode의 11172 글자에 해당하는  EUC-KR 매핑표를 따로 파일로 만들었다.

7. 소스 코드를 기록하다.

여러 고민을 하고 준비하고 해서 최종적으로 HanDrawClass를 만들게 되었다.

1. HanDrawClass.h

2. HanDrawClass.cpp

8. 사용법을 기록하다.

 대단한 예제는 아니지만 아래의 내용으로 컴파일 해서 실행하면 맨 처음에 소개한 사진2장에 포함된 내용이 화면에 표시된다.

9. 끝으로

ESP8266의 CPU Frequency를 160MHz로 변경하고 테스트해보니, IIC 통신으로도 이 작은 디스플레이는 53fps(아마도 최대 60fps일듯)가 가능했다.

답글 남기기