u8glib 라이브러리 사용하기
`U8glib` 라이브러리를 사용하는 기본적인 방법은 다음과 같습니다. 이 예시는 아두이노에서 U8glib를 사용하여 OLED 디스플레이에 그래픽과 텍스트를 표시하는 간단한 과정을 보여줍니다.
### 1. 라이브러리 설치
- 아두이노 IDE에서 "도구" > "라이브러리 관리"로 가서 `U8glib`를 검색하고 설치합니다.
### 2. 라이브러리 포함
- 아두이노 스케치의 시작 부분에 `U8glib` 라이브러리를 포함시킵니다.
```cpp
#include <U8glib.h>
```
### 3. 디스플레이 객체 생성
- 사용 중인 OLED 디스플레이에 맞는 객체를 생성합니다. 객체 생성 시 사용하는 생성자는 디스플레이 및 사용 중인 통신 프로토콜(I2C 또는 SPI)에 따라 달라집니다.
```cpp
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // 예시로 SH1106 128x64 디스플레이 사용
```
### 4. 기본 스케치 코드
- `setup()` 함수와 `loop()` 함수 안에 코드를 작성합니다.
```cpp
void setup() {
// 초기화, 필요한 경우 여기에 코드 추가
}
void loop() {
// 디스플레이 버퍼 지우기
u8g.firstPage();
do {
draw(); // 그리기 함수 호출
} while (u8g.nextPage());
// 필요한 경우 여기에 추가 코드 추가
delay(1000); // 1초 대기
}
void draw() {
// 여기에 디스플레이에 그릴 내용을 작성
u8g.setFont(u8g_font_unifont); // 폰트 설정
u8g.drawStr(0, 22, "Hello World!"); // 텍스트 그리기
}
```
### 주의 사항
- 디스플레이 모델과 사양에 따라 생성자를 올바르게 선택해야 합니다.
- `draw()` 함수 내에서 텍스트, 그래픽 등을 그립니다. U8glib는 페이지 버퍼 방식을 사용하므로 `u8g.firstPage()`와 `u8g.nextPage()`를 사용하여 전체 화면을 갱신합니다.
- U8glib는 다양한 그래픽 함수를 제공합니다. 예를 들어, 선, 원, 사각형을 그릴 수 있고, 다양한 폰트를 사용할 수 있습니다.
`U8glib` 라이브러리 몇 가지 주요 함수:
### 1. 초기화 및 설정 관련 함수
- `U8GLIB`: 디스플레이 객체를 생성하는 생성자 함수.
- `setFont`: 사용할 폰트를 설정합니다.
- `setColorIndex`: 그리기에 사용할 색상의 인덱스를 설정합니다.
### 2. 텍스트 관련 함수
- `drawStr`: 지정된 위치에 문자열을 그립니다.
- `setPrintPos`: 텍스트를 출력할 위치를 설정합니다.
### 3. 그래픽 관련 함수
- `drawBox`: 지정된 위치에 박스(사각형)을 그립니다.
- `drawFrame`: 지정된 위치에 빈 사각형(테두리만 있는)을 그립니다.
- `drawCircle`: 지정된 위치에 원을 그립니다.
- `drawDisc`: 지정된 위치에 채워진 원을 그립니다.
- `drawEllipse`: 타원을 그립니다.
- `drawLine`: 두 점을 잇는 선을 그립니다.
- `drawPixel`: 지정된 위치에 픽셀(점)을 그립니다.
- `drawTriangle`: 세 점을 연결하는 삼각형을 그립니다.
### 4. 이미지 관련 함수
- `drawBitmap`: 비트맵 이미지를 그립니다.
- `drawXBM`: XBM 형식의 비트맵 이미지를 그립니다.
### 5. 페이지 버퍼 관련 함수
- `firstPage`: 디스플레이의 첫 페이지를 준비합니다.
- `nextPage`: 다음 페이지를 준비하고, 모든 페이지가 렌더링될 때까지 반복합니다.
### 예시 코드
```cpp
void draw() {
u8g.setFont(u8g_font_unifont); // 폰트 설정
u8g.drawStr(0, 20, "Hello World!"); // 텍스트 출력
u8g.drawBox(10, 30, 20, 10); // 박스 그리기
u8g.drawFrame(40, 30, 20, 10); // 빈 사각형 그리기
u8g.drawCircle(30, 50, 10); // 원 그리기
u8g.drawLine(0, 0, 40, 40); // 선 그리기
}
```
`U8glib`가 페이지 버퍼 방식을 사용한다는 것은 이 라이브러리가 디스플레이의 내용을 업데이트할 때 전체 화면을 한 번에 그리지 않고, 화면을 여러 "페이지"로 나누어 각 페이지를 차례대로 그린다는 의미입니다. 이 방식의 주요 특징과 이점은 다음과 같습니다:
### 페이지 버퍼 방식의 특징
- **부분적 업데이트**: 화면은 여러 페이지로 나뉘며, 각 페이지는 화면의 일부 영역에 해당합니다. 이러한 방식은 디스플레이의 전체 화면을 한 번에 메모리에 저장할 필요가 없게 해줍니다.
- **메모리 절약**: 페이지 버퍼 방식은 전체 프레임 버퍼 방식에 비해 적은 양의 RAM을 사용합니다. 이는 특히 메모리가 제한적인 마이크로컨트롤러 환경에서 유리합니다.
### 작동 방식
- `firstPage()` 함수를 호출하여 첫 번째 페이지의 그리기를 시작합니다.
- `draw()` 함수 내에서 디스플레이에 그릴 내용을 정의합니다.
- `nextPage()` 함수를 호출하여 다음 페이지로 이동하고, 화면의 다음 부분을 그립니다.
- 이 과정을 화면의 모든 부분이 그려질 때까지 반복합니다.
### 예시
```cpp
void loop() {
u8g.firstPage();
do {
draw(); // 디스플레이에 그릴 내용을 정의하는 함수
} while ( u8g.nextPage() ); // 모든 페이지를 그릴 때까지 반복
}
```
### 이점
- **메모리 효율성**: 마이크로컨트롤러의 제한된 RAM에서도 대형 디스플레이를 사용할 수 있습니다.
- **유연성**: 화면의 일부만 업데이트할 수 있어서, 전체 화면을 갱신하는 것보다 더 빠를 수 있습니다.
단, 페이지 버퍼 방식은 전체 화면을 한 번에 업데이트하는 방식보다 구현이 조금 더 복잡할 수 있으며, 화면 전체를 갱신하는 데 시간이 조금 더 걸릴 수 있습니다. 그러나 메모리 사용 측면에서의 이점이 크기 때문에, 특히 아두이노와 같은 메모리 제한이 있는 환경에서 매우 유용합니다.
`U8glib`에서 "다음 페이지"가 어떻게 저장되는지 이해하기 위해서는 먼저 라이브러리가 어떻게 페이지 버퍼를 관리하는지 알아야 합니다. `U8glib`는 디스플레이의 내용을 RAM에 임시로 저장하는데, 이 때 전체 화면을 한 번에 저장하지 않고, 화면을 여러 '페이지'로 나누어 각 페이지를 순차적으로 처리합니다. 이 방식의 주요 특징은 다음과 같습니다:
### 페이지 버퍼의 관리
- **분할된 저장 공간**: 전체 화면을 한 번에 RAM에 저장하는 대신, `U8glib`는 화면을 여러 '페이지'로 나누어 각 페이지를 별도로 저장합니다. 이는 디스플레이의 일부분만을 한 번에 메모리에 저장하는 방식으로, 메모리 사용을 최소화합니다.
- **순차적 처리**: `U8glib`는 설정된 페이지 버퍼 크기에 따라 디스플레이의 일부분(한 페이지)을 메모리에 저장하고, 그 페이지를 디스플레이에 그린 후, 다음 페이지로 넘어갑니다.
### `nextPage()` 함수의 역할
- `nextPage()` 함수는 현재 페이지의 그리기 작업이 완료되면 다음 페이지로 넘어가는 역할을 합니다.
- 이 함수는 내부적으로 '현재 페이지'의 정보를 관리하며, 다음 페이지로 넘어갈 때 마다 이 정보를 업데이트합니다.
- 또한, 현재 처리 중인 페이지의 정보를 바탕으로 RAM에 저장된 페이지 데이터를 디스플레이 하드웨어로 전송합니다.
### 메모리 저장 방식
- **임시 저장**: 각 페이지의 데이터는 임시로 RAM에 저장됩니다. 이 데이터는 그 페이지에 그릴 내용(텍스트, 그래픽 등)을 나타냅니다.
- **하드웨어 전송**: 각 페이지가 RAM에 저장된 후, 그 데이터는 디스플레이 하드웨어로 전송되어 화면에 표시됩니다.
### 작업 흐름
1. `firstPage()`를 호출하여 첫 페이지로 시작합니다.
2. `draw()` 함수에서 해당 페이지를 그립니다.
3. `nextPage()`가 호출되면, 현재 페이지의 내용을 디스플레이에 전송하고, 다음 페이지로 넘어갑니다.
4. 이 과정이 모든 페이지에 대해 반복되며, 전체 화면이 그려집니다.
`U8glib`의 이런 방식은 특히 메모리가 제한된 시스템에서 전체 화면을 효과적으로 관리할 수 있게 해주며, 디스플레이의 전체 내용을 갱신하는데 필요한 메모리 요구량을 최소화합니다.
`U8glib`에서 "다음 페이지가 있다"는 것은 페이지 버퍼 방식을 사용하여 디스플레이의 내용을 업데이트할 때, 전체 화면을 여러 부분(페이지)으로 나누어 순차적으로 처리해야 한다는 의미입니다. 각 "페이지"는 디스플레이의 일부 영역을 나타내며, 이러한 페이지들을 차례대로 처리함으로써 전체 화면이 구성됩니다. "다음 페이지가 있다"는 말은 아직 그려야 할 페이지가 더 남아있다는 것을 의미합니다.
### 페이지 버퍼 방식의 작동 원리
- **화면 분할**: 디스플레이 화면은 여러 개의 수평 또는 수직 "페이지"로 나뉩니다. 각 페이지는 화면의 한 부분을 차지합니다.
- **순차적 업데이트**: 프로그램은 첫 번째 페이지부터 시작하여 각 페이지를 순차적으로 그립니다. 각 페이지가 그려진 후에는 다음 페이지로 넘어갑니다.
### `nextPage()` 함수의 역할
- **페이지 전환**: `nextPage()` 함수는 현재 페이지가 완전히 그려진 후 다음 페이지로 넘어가도록 합니다. 이 함수는 더 이상 그려야 할 페이지가 있으면 `true`를 반환하고, 모든 페이지가 그려졌다면 `false`를 반환합니다.
- **루프 제어**: 이 함수는 `do-while` 루프 내에서 사용되어, 더 이상 그려야 할 페이지가 없을 때까지 루프를 계속합니다.
### 예시
```cpp
do {
draw(); // 현재 페이지 그리기
} while ( u8g.nextPage() ); // 다음 페이지로 넘어가기
```
- 위 코드에서 `draw()` 함수는 현재 페이지에 그릴 내용을 정의합니다.
- `nextPage()`는 다음 페이지로 넘어갈 준비를 하고, 더 이상 페이지가 없으면 루프를 종료합니다.
이 방식은 특히 메모리가 제한된 마이크로컨트롤러 환경에서 유용하며, 전체 화면을 메모리에 한 번에 저장하지 않고도 디스플레이 내용을 효과적으로 업데이트할 수 있게 해줍니다.
`U8glib`를 사용하는 경우 `draw()` 함수로 한 번에 전체 화면을 그리지 않습니다. 대신, 이 라이브러리는 페이지 버퍼 방식을 사용하여 화면을 여러 개의 "페이지"로 나누고, 각 페이지를 차례대로 그립니다. 이는 디스플레이의 각 부분(페이지)을 순차적으로 처리하여 전체 화면을 구성하는 방식입니다.
### 페이지 버퍼 방식의 작동 원리
- **분할된 화면**: 디스플레이는 여러 페이지로 나뉘어 있으며, 각 페이지는 화면의 일부분을 차지합니다.
- **순차적 그리기**: `draw()` 함수는 현재 활성화된 페이지에 내용을 그립니다. 이 함수는 `u8g.firstPage()`를 호출한 후 `u8g.nextPage()`가 `false`를 반환할 때까지, 즉 모든 페이지가 그려질 때까지 반복적으로 호출됩니다.
### 예시
```cpp
void loop() {
u8g.firstPage();
do {
draw(); // 현재 페이지를 그림
} while ( u8g.nextPage() ); // 다음 페이지가 있으면 계속 반복
}
```
- 여기서 `draw()` 함수는 각 페이지에 대해 한 번씩 호출됩니다.
- 각 호출에서 `draw()`는 현재 페이지의 일부분만 그립니다.
- `nextPage()`는 다음 페이지로 넘어가는데, 이는 다음 `draw()` 호출이 다음 페이지의 일부분을 그리게 합니다.
- 이렇게 모든 페이지가 그려질 때까지 반복됩니다.
### 그리기 방식의 장점
- **메모리 효율**: 전체 화면을 메모리에 저장할 필요가 없어, 메모리 사용량이 줄어듭니다. 이는 특히 메모리가 제한된 마이크로컨트롤러에서 중요합니다.
- **유연성**: 페이지 단위로 화면을 업데이트할 수 있어, 복잡한 그래픽이나 텍스트를 메모리 제한 내에서 효과적으로 표현할 수 있습니다.
따라서 `U8glib`의 `draw()` 함수는 전체 화면을 한 번에 그리지 않고, 페이지 단위로 화면을 나누어 순차적으로 그리는 방식을 사용합니다. 이는 더 적은 메모리로 더 큰 디스플레이를 관리할 수 있게 해줍니다.
`U8glib` 라이브러리에서 `draw()` 함수 내에서 그래픽이나 텍스트를 그릴 때, 사용자는 버퍼 설정과 같은 저수준의 세부 사항을 신경 쓰지 않아도 됩니다. 이는 `U8glib`의 내부 구현 덕분에 가능한데, 라이브러리가 자동으로 페이지 버퍼를 관리하고, 사용자가 `draw()` 함수에 작성한 그래픽 명령들을 이 버퍼에 적절하게 배치합니다.
### `U8glib`의 내부 작동 방식
1. **자동 버퍼 관리**: `U8glib`는 현재 활성화된 페이지에 대한 버퍼를 내부적으로 관리합니다. 이 버퍼는 디스플레이의 해당 페이지 부분에 해당하는 메모리 영역을 나타냅니다.
2. **그래픽 명령의 처리**: `draw()` 함수에서 사용자가 그래픽 명령(예: 텍스트 그리기, 도형 그리기)을 호출할 때, 이 명령들은 현재 활성화된 페이지의 버퍼에 적용됩니다.
3. **페이지 순회**: `do-while` 루프와 `nextPage()` 함수를 사용함으로써, `U8glib`는 각 페이지를 차례대로 활성화하고, 각 페이지에 대해 `draw()` 함수를 호출하여 그래픽 명령들을 해당 페이지 버퍼에 적용합니다.
4. **디스플레이 업데이트**: 각 페이지의 그래픽 명령이 버퍼에 적용된 후, `U8glib`는 이 버퍼의 내용을 디스플레이 하드웨어로 전송합니다. 이 과정은 모든 페이지에 대해 반복됩니다.
### 사용자 경험
- 사용자는 `draw()` 함수 내에서 그리고자 하는 내용을 정의하기만 하면 됩니다. 예를 들어, 텍스트를 출력하거나 도형을 그리는 명령을 포함시킵니다.
- `U8glib`의 내부 로직이 페이지 버퍼를 관리하고, 사용자의 그래픽 명령을 적절한 페이지에 배치하며, 이를 디스플레이에 순차적으로 표시합니다.
이런 방식으로 `U8glib`는 사용자에게 간결하고 직관적인 프로그래밍 인터페이스를 제공하면서도, 메모리 효율적인 디스플레이 업데이트를 구현합니다. 사용자는 복잡한 버퍼 관리나 페이지 관리에 대해 걱정할 필요 없이, 원하는 그래픽 출력을 쉽게 구현할 수 있습니다.
---
페이지 버퍼 방식으로 업데이트 되므로
무조건
u8g.firstPage();
do {
//그리는 함수
} while ( u8g.nextPage() );
이런 형태가 필요하다.
화면은 여러 페이지로 쪼개서 램에 순차적으로 올려서 순차적으로 그리는 건데
do while 동안 다음페이지 있나 보고 그리는 거다
Adafruit_SSD1306은 회전 기능 지원했는데
u8glib 여긴 없...는줄 알았는데 있다. 챗지피티가 잘못알려줬네
위키는 이쪽
https://github.com/olikraus/u8glib/wiki/userreference
색깔 바꾸기
setDefaultBackgroundColor
setDefaultForegroundColor
u8g.setColorIndex(0);
drawBitmap
drawBitmapP
progmem 저장이면 drawBitmapP이거 써야한다
drawBitmap 쓰면 쓰레기값 출력한거처럼 나옴.
u8g.drawBitmapP((display_width - 64) / 2, (display_height - 96+2) , 8, 96, character_bitmap);
세번째 변수가 바이트로 적어야해서(비트/8) 좀 독특하다.
x, y, 너비(바이트=비트수/8), 높이(그냥 바이트로), 비트맵
순으로 적어야해서 이상하다.
페이지 버퍼 방식때문에 너무 느린 것이 문제가 된다
화면 넘어가는 부분이 그냥 보인다..
화면이 순차적으로 그려지는게 그냥 보여서 아무래도 좀 별로였다
-> u8g2로 옮겨보기로 결정
댓글
댓글 쓰기