본문 바로가기

메이커 Maker

GC9A01 원형 LCD 모듈 아두이노

반응형

 

드론봇 워크숍에서는 액정 디스플레이(LCD)를 여러 번 사용해 왔지만, 오늘 작업할 LCD는 조금 특이한 형태입니다. 바로 원형이죠! 전자 게이지나 특수 효과를 만드는 데 안성맞춤입니다.

 

목차

1 서론

2 GC9A01 IPS 디스플레이

2.1 SPI 인터페이스

2.2 유사한 GC9A01 모듈

3 GC9A01과 Arduino Uno

3.1 아두이노 연결

3.2 Waveshare 샘플 코드 실행

3.3 Adafruit_GC9A01A 라이브러리 사용

ESP32가 탑재된 4 GC9A01

4.1 ESP32 연결

4.2 TFT_eSPI 라이브러리 설정

4.3 데모 코드 실행

4.4 전위차계 값 표시

5 GC9A01 애니메이션 눈

5.1 애니메이션 눈 연결하기

5.2 애니메이션 눈 구성

6 결론

6.1 부품 목록

6.2 리소스 

 

 

 

소개

 

LCD(액정 디스플레이)는 다양한 용도에 적합한 선택입니다. 전력 소모가 크지 않고, 흑백 또는 풀컬러 모델로 제공되며, 다양한 모양과 크기로 제공됩니다.

 

모양과 크기에 관해 말하자면, 오늘 우리가 작업대에 올려놓은 LCD 모듈은 원형입니다.

 

오늘은 이 디스플레이를 아두이노와 ESP32에 연결하는 방법을 알아보겠습니다. 그리고 두 개를 사용해서 으스스한 눈알 애니메이션도 만들어 보겠습니다!

 

 

 

 

GC9A01 IPS 디스플레이

 

오늘날 우리가 사용하고 있는 디스플레이는 Waveshare에서 제조한 것이고 , 다른 제조업체에서도 유사한 디스플레이를 제조하고 있습니다.

 

Waveshare에는 실제로 여러 개의 원형 LCD 모듈이 있는데, 저는 아마존에서 쉽게 구할 수 있는 1.28인치 모델을 선택했습니다. 다른 모듈을 사용하여 동일한 실험을 수행할 수도 있겠지만, 다른 드라이버가 필요할 수도 있습니다.

 

제가 사용한 모듈의 사양은 다음과 같습니다.

 

  • 작동 전압: 3.3V/5V
  • 인터페이스: SPI
  • LCD 유형: IPS
  • 컨트롤러: GC9A01
  • 해상도: 240(H)RGB x 240(V)
  • 디스플레이 크기: Φ32.4mm
  • 픽셀 크기: 0.135(H)x0.135(V)mm
  • 치수 : 40.4×37.5(mm) Φ37.5(mm)

 

꽤 저렴한 모듈이라 몇 개 사서 "놀아보기"로 했습니다!

 

SPI 인터페이스

 

우리는 이전에도 SPI 인터페이스를 여러 번 사용한 적이 있습니다. 이는 디스플레이와 메모리 카드 모두에 공통적인 인터페이스입니다.

 

이 장치는 다음 4개의 전선으로 구성된 일반적인 구성인 4선 SPI 버스 구성을 사용합니다.

 

  • CS – 이 라인은 SPI 장치를 선택합니다. 여러 장치에 대해 여러 개의 CS 라인이 있을 수 있습니다.
  • SCK – SPI 장치에 타이밍을 제공하는 클럭 라인입니다.
  • MOSI – 제어 장치의 출력.
  • MISO – 제어 장치에 대한 입력.

 

실제로 디스플레이는 이러한 와이어를 세 개만 사용하고, 디스플레이가 순전히 출력 장치이기 때문에 MISO는 사용되지 않습니다.

 

디스플레이에는 몇 가지 추가 연결 단자가 있습니다. 그중 하나인 DC는 디스플레이를 데이터 모드 또는 명령 모드로 설정합니다. 또 다른 BL은 디스플레이 백라이트를 제어합니다.

 

 

 

위 그림은 디스플레이 연결을 보여줍니다. Waveshare 디스플레이는 3.3V 또는 5V 로직과 함께 사용할 수 있으며, 전원 공급 전압은 로직 레벨과 일치해야 합니다(3.3V 로직과 함께 5V 전원을 사용할 수도 있습니다).

 

유사한 GC9A01 모듈

 

GC9A01을 중심으로 제작된 또 다른 일반적인 원형 디스플레이가 있는데, 이는 eBay나 다른 일반적인 공급원에서 찾을 수 있습니다.

 

이 GC9A01 모델의 한 가지 차이점은 온보드 전압 조절기가 없어 3.3V 로직으로만 작동한다는 점입니다.

 

 

 

또 다른 차이점은 디스플레이의 라벨링입니다. SDA와 SCL로 표시된 두 개의 핀이 있습니다. 언뜻 보기에는 I2C 장치라고 생각하실 수 있지만, Waveshare 장치처럼 SPI입니다.

 

SDA는 데이터 입력(Waveshare 디스플레이의 DIN)이고 SCL은 클록 입력(Waveshare 장치의 CLK)입니다.

 

이 디스플레이는 ESP32로 진행할 실험에 사용할 수 있습니다. ESP32는 3.3V 로직 마이크로컨트롤러이기 때문입니다. 아두이노 우노에서 이 디스플레이를 사용하려면 전압 레벨 변환기가 필요합니다.

 

아두이노 우노를 탑재한 GC9A01

 

아두이노 우노는 지구상에서 가장 널리 쓰이는 마이크로컨트롤러라고 할 수 있으며, 특히 실험용으로는 그렇습니다. 하지만 상당히 오래되었고, 최신 기기에 비해 16MHz 클럭 속도가 상당히 느립니다.

 

그럼에도 불구하고, 특히 애플리케이션에 디스플레이 새로 고침이 많이 필요하지 않은 경우 Arduino Uno에서 디스플레이를 사용하는 것이 가능합니다.

 

아두이노 연결

 

디스플레이를 Arduino Uno에 연결하는 것은 매우 간단하며, 그림은 다음과 같습니다.

 

 

 

5볼트 논리를 사용하므로 Arduino의 5볼트 전원 출력으로 디스플레이에 전원을 공급한다는 점에 유의하세요.

 

Waveshare 장치에는 디스플레이용 케이블이 포함되어 있습니다. 아쉽게도 암 단자만 있어서 라즈베리 파이(지원됨)에는 좋지만 아두이노 우노에는 적합하지 않습니다. 저는 짧은 브레드보드 점퍼선을 사용하여 아두이노에 적합한 수 단자로 변환했습니다.

 

Waveshare 샘플 코드 실행

 

모든 것을 연결했으면 디스플레이 코딩을 시작할 수 있습니다. 몇 가지 방법이 있는데, 그중 하나는 Waveshare 위키에서 제공하는 샘플 코드를 가져오는 것입니다 .

 

Waveshare Wiki는 디스플레이에 대한 정보와 몇 가지 일반적인 컨트롤러에 대한 샘플 코드를 제공합니다. 괜찮은 지원 페이지인데, 아쉽게도 Waveshare에서 제공하는 유일한 지원 페이지입니다. (더 많은 예제와 튜토리얼이 있었으면 좋았겠지만, Adafruit와 Sparkfun에 너무 익숙해져서 그런가 봐요. ㅎㅎ)

 

위키 페이지 하단에 코드 다운로드 링크가 있습니다. ZIP 파일이며, Raspberry Pi, Arduino, STM32용 샘플이 포함되어 있습니다.

 

파일을 다운로드한 후 압축을 풀어주세요. 압축을 풀면 지원되는 프로세서별로 폴더 세 개가 있습니다.

 

Arduino 폴더를 엽니다. 폴더 안에는 Waveshare에서 지원하는 각 디스플레이 크기별로 여러 개의 폴더가 있습니다. 저는 1.28인치 모델을 사용하고 있으므로 LCD_1inch28 폴더를 선택했습니다.

 

선택한 폴더 전체를 Arduino 디렉토리나 폴더에 복사해야 합니다.

 

그러면 Arduino IDE를 열고 해당 폴더로 이동하세요. 폴더 안에 LCD_1inch28.ino 라는 스케치 파일이 있는데, 이 파일을 열어주세요.

 

스케치를 열면 Arduino IDE에 오류 메시지가 표시됩니다. 오류는 스케치에 포함된 두 파일에 인식할 수 없는 문자가 포함되어 있다는 것입니다. IDE는 도구 메뉴의 "인코더 수정 및 다시 로드" 기능을 사용하여 이 문제를 해결하도록 권장하지만, 작동하지 않습니다.

 

오류는 스케치 주석에 사용된 중국어 문자 몇 개에서 발생하는 것 같습니다. 이 오류는 무시해도 됩니다. 스케치는 정상적으로 컴파일됩니다.

 

코드는 매우 기본적인데, 여러 파일로 구성되어 있으므로 여기서 전체 내용을 반복하지는 않겠습니다. 하지만 여기 보이는 것처럼 메인 파일에서 상당한 양의 정보를 얻을 수 있습니다.

 

#include <SPI.h>
#include "LCD_Driver.h"
#include "GUI_Paint.h"
#include "image.h"

void setup()
{
  Config_Init();
  LCD_Init();
  LCD_SetBacklight(1000);
  Paint_NewImage(LCD_WIDTH, LCD_HEIGHT, 0, BLACK);
  Paint_Clear(BLACK);
  Paint_DrawCircle(120,120, 120, BLUE ,DOT_PIXEL_2X2,DRAW_FILL_EMPTY);
  Paint_DrawLine  (120, 0, 120, 12,GREEN ,DOT_PIXEL_4X4,LINE_STYLE_SOLID);
  Paint_DrawLine  (120, 228, 120, 240,GREEN ,DOT_PIXEL_4X4,LINE_STYLE_SOLID);
  Paint_DrawLine  (0, 120, 12, 120,GREEN ,DOT_PIXEL_4X4,LINE_STYLE_SOLID);
  Paint_DrawLine  (228, 120, 240, 120,GREEN ,DOT_PIXEL_4X4,LINE_STYLE_SOLID);
  Paint_DrawImage(gImage_70X70, 85, 25, 70, 70); 
  Paint_DrawString_CN(56,140, "微雪电子",   &Font24CN,BLACK,  WHITE);
  Paint_DrawString_EN(123, 123, "WAVESHARE",&Font16,  BLACK, GREEN);
  Paint_DrawLine  (120, 120, 70, 70,YELLOW ,DOT_PIXEL_3X3,LINE_STYLE_SOLID);
  Paint_DrawLine  (120, 120, 176, 64,BLUE ,DOT_PIXEL_3X3,LINE_STYLE_SOLID);
  Paint_DrawLine  (120, 120, 120, 210,RED ,DOT_PIXEL_2X2,LINE_STYLE_SOLID); 
}
void loop()
{
  
}



/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

 

코드에서 라이브러리를 로드한 후 디스플레이를 초기화하고, 백라이트 레벨을 설정하고(BL 핀의 PWM을 사용하여 레벨을 설정할 수 있습니다), 새 이미지를 그리는 것을 볼 수 있습니다. 그런 다음 디스플레이에 선과 문자열을 그립니다.

 

안타깝게도 Waveshare에서는 이에 대한 설명서를 제공하지 않지만 LCD_Driver.cpp 파일을 읽으면 함수에 대한 설명이 어느 정도 나와 있어 많은 정보를 얻을 수 있습니다 .

 

코드를 업로드하면 화면에 가짜 "시계"가 표시됩니다. 고정된 화면이지만, Waveshare 코드와 함께 사용하는 방법을 보여줍니다.

 

Adafruit_GC9A01A 라이브러리 사용

 

Waveshare 샘플 코드는 괜찮지만, 이 디스플레이에 더 적합하고 더 잘 문서화된 다른 라이브러리가 있습니다.

 

이러한 라이브러리 중 하나는 GitHub에서 얻을 수 있는 Adafruit_GC9A01A 라이브러리 입니다 .

 

이 라이브러리는 Adafruit GFX 라이브러리의 확장 기능으로, Adafruit GFX 라이브러리는 가장 널리 사용되는 디스플레이 라이브러리 중 하나입니다. 따라서 Adafruit에서는 이 라이브러리에 대한 자세한 설명서를 제공합니다. 따라서 이 라이브러리는 직접 애플리케이션을 개발하려는 사용자에게 매우 유용한 선택입니다.

 

GitHub에서 ZIP 형식으로 라이브러리를 다운로드한 후, 영상에서 보여준 대로 Arduino IDE를 사용하여 설치하세요.

 

라이브러리에서 "graphicstest"라는 하나의 예시 스케치가 있는데, 여기에 나와 있습니다.

 

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"

#define TFT_DC 9
#define TFT_CS 10

// Hardware SPI on Feather or other boards
Adafruit_GC9A01A tft(TFT_CS, TFT_DC);

void setup() {
  Serial.begin(9600);
  Serial.println("GC9A01A Test!");

  tft.begin();

  Serial.println(F("Benchmark                Time (microseconds)"));
  delay(10);
  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(500);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(3000);

  Serial.print(F("Lines                    "));
  Serial.println(testLines(GC9A01A_CYAN));
  delay(500);

  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(GC9A01A_RED, GC9A01A_BLUE));
  delay(500);

  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(GC9A01A_GREEN));
  delay(500);

  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(GC9A01A_YELLOW, GC9A01A_MAGENTA));
  delay(500);

  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, GC9A01A_MAGENTA));

  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, GC9A01A_WHITE));
  delay(500);

  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(500);

  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(500);

  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(500);

  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(500);

  Serial.println(F("Done!"));
}

void loop(void) {
  for(uint8_t rotation=0; rotation<4; rotation++) {
    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}

unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(GC9A01A_BLACK);
  yield();
  tft.fillScreen(GC9A01A_RED);
  yield();
  tft.fillScreen(GC9A01A_GREEN);
  yield();
  tft.fillScreen(GC9A01A_BLUE);
  yield();
  tft.fillScreen(GC9A01A_BLACK);
  yield();
  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(GC9A01A_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(GC9A01A_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(GC9A01A_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(GC9A01A_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(GC9A01A_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(GC9A01A_BLACK);
  yield();

  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  yield();
  tft.fillScreen(GC9A01A_BLACK);
  yield();

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  yield();
  tft.fillScreen(GC9A01A_BLACK);
  yield();

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  yield();
  tft.fillScreen(GC9A01A_BLACK);
  yield();

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

  yield();
  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(GC9A01A_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(GC9A01A_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(GC9A01A_BLACK);
  n = min(tft.width(), tft.height());
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
    yield();
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(GC9A01A_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(GC9A01A_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(i, i, i));
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(GC9A01A_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i*10, i*10));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i*10, i*10, 0));
    yield();
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(GC9A01A_BLACK);
  w     = min(tft.width(), tft.height());
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(GC9A01A_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()); i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
    yield();
  }

  return micros() - start;
}

 

 

DC를 9에서 7로 변경하려면 5번째 줄의 스케치를 편집해야 합니다. 이는 Arduino를 디스플레이에 연결하는 방식을 반영합니다.

 

Waveshare 샘플과 마찬가지로 이 파일은 도형과 텍스트만 디스플레이에 출력합니다. 특히 Adafruit 설명서를 참고하면 이해하기 매우 쉬운 스케치입니다.

 

스케치는 화면에 기괴한 텍스트를 출력하며 마무리됩니다. 이 텍스트는 더글러스 애덤스의 『은하수를 여행하는 히치하이커를 위한 안내서』에서 발췌한 것으로, 은하계에서 세 번째로 최악으로 꼽히는 보곤족 시의 샘플입니다!

 

ESP32가 탑재된 GC9A01

 

ESP32는 Arduino Uno보다 훨씬 빠른 마이크로컨트롤러이며, 원형 LCD 모듈과 함께 사용하기에 이상적입니다.

 

이 실험에서는 ESP32 WROVER 모듈을 사용했지만, 다른 대부분 ESP32 모듈도 마찬가지로 작동합니다.

 

ESP32 연결

 

ESP32와 GC9A01 디스플레이의 연결은 다음과 같습니다. 대부분의 ESP32 연결 다이어그램과 마찬가지로, 실제 핀 대신 올바른 GPIO 번호를 사용하는 것이 중요합니다. 이 다이어그램은 WROVER를 보여 주므로, 다른 모듈을 사용하는 경우 해당 모듈의 설명서를 참조하여 올바르게 연결되었는지 확인해야 합니다.

 

 

 

또한 GPIO 핀 14에 전위차계가 연결되어 있는 것을 볼 수 있습니다. 이것을 실험 중 하나에 사용할 것입니다.

 

TFT_eSPI 라이브러리 설정

 

모든 것을 연결한 후에는 적합한 라이브러리를 구해야 합니다.

 

TFT_eSPI 라이브러리는 이 디스플레이를 비롯한 여러 디스플레이에 적합합니다. Arduino IDE 라이브러리 관리자를 통해 설치할 수 있습니다. "TFT_eSPI"를 검색하세요.

 

이 라이브러리는 여러 유형의 디스플레이와 프로세서를 위해 만들어졌기 때문에 라이브러리를 작동시키려면 몇 가지 수정이 필요합니다.

 

당신이 해야 할 일은 다음과 같습니다.

 

  • 파일 관리자(Mac에서는 Finder)를 사용하여 Arduino 폴더 내부에 있는 Arduino Libraries 폴더로 이동합니다.
  • TFT_eSPI 폴더를 찾으세요. 찾으면 열어주세요.
  • 폴더 안에는 여러 파일이 있습니다. 그중 User_Setup.h 파일을 찾아보세요 .
  • 텍스트 편집기로 User_Setup.h 파일을 엽니다 .

 

User_Setup.h 파일을 열면 다음과 같이 편집해야 합니다.

 

  • 44번째 줄에서 ILI9341 드라이버를 정의하는 줄을 주석으로 처리합니다(즉, 텍스트 앞에 "//"를 추가합니다).
  • 64번째 줄에서 GC9A01 드라이버를 정의하는 줄의 주석 처리를 제거합니다(즉, "//"를 제거합니다).
  • 204~209번째 줄에서 ILI9341에 대한 모든 SPI 정의를 주석으로 처리합니다.
  • 215번째 줄에서 MOSI를 23으로 설정합니다.
  • 216번째 줄에서 SCLK를 18로 설정합니다.
  • 217번째 줄에서 CS를 22로 설정합니다.
  • 218번째 줄에서 DC를 16으로 설정합니다.
  • 219번째 줄에서 RST를 4로 설정합니다.

 

이제 파일을 저장하고 GC9A01 디스플레이와 함께 라이브러리를 사용할 준비가 되었습니다.

 

데모 코드 실행

 

라이브러리에는 많은 데모 코드가 포함되어 있습니다. 일부는 다른 디스플레이 크기에 맞춰 제작되었지만, 원형 디스플레이에도 사용할 수 있는 코드도 몇 가지 있습니다.

 

디스플레이를 테스트하려면 라이브러리 샘플의 테스트 및 진단 메뉴 항목에 있는 Colour_Test 스케치를 사용할 수 있습니다. 이 스케치는 이 디스플레이용으로 제작된 것은 아니지만, 모든 것이 제대로 연결되고 구성되었는지 확인하는 좋은 방법입니다.

 

훌륭한 데모 코드 샘플은 스프라이트 메뉴 항목 에 있는 Animated_dial 스케치입니다 . 이 데모 코드는 화면에 "다이얼" 표시기와 함께 시뮬레이션된 "데이터"(실제로는 난수 생성기)를 생성합니다.

 

이 스케치를 실행하려면 다른 라이브러리를 설치해야 합니다. 라이브러리 관리자에서 Tjpeg_Decoder 라이브러리를 설치하세요. 설치가 완료되면 스케치가 컴파일되어 ESP32에 업로드할 수 있습니다.

 

원형 디스플레이에 놓으면 정말 멋지게 보이네요!

 

 

 

 

전위차계 값 표시

 

Animated_dial 스케치를 수정하여 난수 대신 전위차계 입력을 사용할 수 있습니다. 다음과 같이 변경하세요.

 

  • 전위차계 핀에 대한 정의 추가 - #define POT_PIN 14
  • 100번째 줄에서 "degrees"라는 텍스트를 원하는 대로 변경할 수 있습니다(이 단계는 선택 사항입니다).
  • Loop의 첫 번째 줄인 119번째 줄을 주석 처리하거나 제거하세요. 이 줄은 난수 생성기에 연결되는 줄입니다.
  • Loop의 시작 부분에 다음 줄을 추가합니다.

 

Uint16_t 각도 = map(analogRead(POT_PIN),0,4095,0,240)

 

이렇게 하면 전위차계의 값이 0~240 범위에 매핑되고, 이를 각도 변수에 할당합니다.

 

스케치를 새 이름으로 저장하고 ESP32에 업로드하세요. 이제 전위차계를 사용해 보세요. 미터가 값을 추적하고 표시할 것입니다.

 

이 기술은 다른 측정에도 사용할 수 있습니다.

 

GC9A01 애니메이션 눈

 

제가 가장 좋아하는 스케치 중 하나는 움직이는 눈알 한 쌍을 아주 사실적으로 표현한 "Animated Eyes" 스케치입니다. 하나의 디스플레이로도 작동하지만, 두 개를 사용하면 더 효과적입니다.

 

애니메이션 눈 연결하기

 

가장 먼저 해야 할 일은 두 번째 디스플레이를 연결하는 것입니다. 이를 위해 CS(칩 선택) 선을 제외한 모든 선을 첫 번째 디스플레이와 병렬로 연결합니다.

 

 

 

첫 번째 디스플레이에서는 CS를 GPIO 22에 둡니다. 두 번째 디스플레이에서는 GPIO 21을 사용합니다.

 

두 개의 "눈알"을 수동으로 제어하기 위해 몇 가지 옵션 부품을 연결할 수도 있습니다. 아날로그 조이스틱과 순간 접촉식, 상시 개방형 푸시 버튼 스위치 몇 개가 필요합니다.

 

 

 

모두 연결하고 나면, 이제 코드를 살펴보고 무시무시한 눈알을 만들어 볼까요!

 

애니메이션 눈 구성

 

Animated Eyes 스케치는 TFT_eSPI 라이브러리 샘플 파일의 "generic" 폴더에 있습니다. 두 번째 GC9A01 디스플레이를 연결했다면 Animated_Eyes_2 스케치를 사용하면 됩니다.

 

이건 정말 큰 스케치예요. 제가 지금까지 본 스케치 중에서는 가장 큰 것 중 하나예요.

 

개발자는 작업을 편리하게 하기 위해 구성 파일을 포함시켰습니다. 조이스틱과 푸시 버튼을 추가한 경우 이 파일을 편집해야 합니다.

 

변경 사항 은 config.h 파일 에서 처리합니다.

 

// Pin selections here are based on the original Adafruit Learning System
// guide for the Teensy 3.x project.  Some of these pin numbers don't even
// exist on the smaller SAMD M0 & M4 boards, so you may need to make other
// selections:

// GRAPHICS SETTINGS (appearance of eye) -----------------------------------

// If using a SINGLE EYE, you might want this next line enabled, which
// uses a simpler "football-shaped" eye that's left/right symmetrical.
// Default shape includes the caruncle, creating distinct left/right eyes.

//#define SYMMETRICAL_EYELID

// Enable ONE of these #includes -- HUGE graphics tables for various eyes:
#include "data/defaultEye.h"      // Standard human-ish hazel eye -OR-
//#include "data/dragonEye.h"     // Slit pupil fiery dragon/demon eye -OR-
//#include "data/noScleraEye.h"   // Large iris, no sclera -OR-
//#include "data/goatEye.h"       // Horizontal pupil goat/Krampus eye -OR-
//#include "data/newtEye.h"       // Eye of newt -OR-
//#include "data/terminatorEye.h" // Git to da choppah!
//#include "data/catEye.h"        // Cartoonish cat (flat "2D" colors)
//#include "data/owlEye.h"        // Minerva the owl (DISABLE TRACKING)
//#include "data/naugaEye.h"      // Nauga googly eye (DISABLE TRACKING)
//#include "data/doeEye.h"        // Cartoon deer eye (DISABLE TRACKING)

// DISPLAY HARDWARE SETTINGS (screen type & connections) -------------------
#define TFT_COUNT 2        // Number of screens (1 or 2)
#define TFT1_CS 22         // TFT 1 chip select pin (set to -1 to use TFT_eSPI setup)
#define TFT2_CS 21         // TFT 2 chip select pin (set to -1 to use TFT_eSPI setup)
#define TFT_1_ROT 1        // TFT 1 rotation
#define TFT_2_ROT 3        // TFT 2 rotation
#define EYE_1_XPOSITION  50 // x shift for eye 1 image on display
#define EYE_2_XPOSITION  50 // x shift for eye 2 image on display

#define DISPLAY_BACKLIGHT  -1 // Pin for backlight control (-1 for none)
#define BACKLIGHT_MAX    255

// EYE LIST ----------------------------------------------------------------
#define NUM_EYES 2 // Number of eyes to display (1 or 2)

#define BLINK_PIN   27 // Pin for manual blink button (BOTH eyes)
#define LH_WINK_PIN 26 // Left wink pin (set to -1 for no pin)
#define RH_WINK_PIN 14 // Right wink pin (set to -1 for no pin)

// This table contains ONE LINE PER EYE.  The table MUST be present with
// this name and contain ONE OR MORE lines.  Each line contains THREE items:
// a pin number for the corresponding TFT/OLED display's SELECT line, a pin
// pin number for that eye's "wink" button (or -1 if not used), a screen
// rotation value (0-3) and x position offset for that eye.

#if (NUM_EYES == 2)
  eyeInfo_t eyeInfo[] = {
    { TFT1_CS, LH_WINK_PIN, TFT_1_ROT, EYE_1_XPOSITION }, // LEFT EYE chip select and wink pins, rotation and offset
    { TFT2_CS, RH_WINK_PIN, TFT_2_ROT, EYE_2_XPOSITION }, // RIGHT EYE chip select and wink pins, rotation and offset
  };
#else
  eyeInfo_t eyeInfo[] = {
    { TFT1_CS, LH_WINK_PIN, TFT_1_ROT, EYE_1_XPOSITION }, // EYE chip select and wink pins, rotation and offset
  };
#endif

// INPUT SETTINGS (for controlling eye motion) -----------------------------

// JOYSTICK_X_PIN and JOYSTICK_Y_PIN specify analog input pins for manually
// controlling the eye with an analog joystick.  If set to -1 or if not
// defined, the eye will move on its own.
// IRIS_PIN speficies an analog input pin for a photocell to make pupils
// react to light (or potentiometer for manual control).  If set to -1 or
// if not defined, the pupils will change on their own.
// BLINK_PIN specifies an input pin for a button (to ground) that will
// make any/all eyes blink.  If set to -1 or if not defined, the eyes will
// only blink if AUTOBLINK is defined, or if the eyeInfo[] table above
// includes wink button settings for each eye.

#define JOYSTICK_X_PIN 33 // Analog pin for eye horiz pos (else auto)
#define JOYSTICK_Y_PIN 32 // Analog pin for eye vert position (")
#define JOYSTICK_X_FLIP   // If defined, reverse stick X axis
#define JOYSTICK_Y_FLIP   // If defined, reverse stick Y axis
#define TRACKING            // If defined, eyelid tracks pupil
#define AUTOBLINK           // If defined, eyes also blink autonomously

//  #define LIGHT_PIN      -1 // Light sensor pin
  #define LIGHT_CURVE  0.33 // Light sensor adjustment curve
  #define LIGHT_MIN       0 // Minimum useful reading from light sensor
  #define LIGHT_MAX    1023 // Maximum useful reading from sensor

#define IRIS_SMOOTH         // If enabled, filter input from IRIS_PIN
#if !defined(IRIS_MIN)      // Each eye might have its own MIN/MAX
  #define IRIS_MIN       90 // Iris size (0-1023) in brightest light
#endif
#if !defined(IRIS_MAX)
  #define IRIS_MAX      130 // Iris size (0-1023) in darkest light
#endif

 

41번째 줄에서 BLINK_PIN을 27로 정의합니다.

42번째 줄에서 LH_WINK_PIN을 26으로 정의합니다.

43번째 줄에서 RH_WINK_PIN을 14로 정의합니다.

75번째 줄에서 JOYSTICK_X_PIN을 33으로 정의합니다.

76번째 줄에서 JOYSTICK_Y_PIN을 32로 정의합니다.

 

이 파일은 매우 잘 문서화되어 있으며, 필요에 따라 추가 편집이 가능합니다. 파일을 편집한 후 ESP32에 업로드하세요.

 

조이스틱과 스위치로 조종할 수 있는 무서운 눈알 한 쌍이 여러분을 맞이할 것입니다!

 

결론

 

GC9A01 디스플레이는 다음 프로젝트를 위한 훌륭한 지표 또는 측정기가 될 것입니다. IPS 디스플레이라 광각에서도 매우 읽기 쉽습니다.

 

이 중 몇 개를 구입하는 게 좋을 것 같아요. 가지고 놀면 정말 재밌을 거예요!

 

부품 목록

 

이 글의 실험을 완료하는 데 필요할 수 있는 몇 가지 구성 요소를 소개합니다. 일부 링크는 제휴 링크일 수 있으며, DroneBot Workshop은 구매 시 수수료를 받을 수 있습니다. 이는 귀하의 비용 증가가 아니며, 광고 없는 웹사이트를 지원하기 위한 조치입니다.

 

곧 출시!

 

자원

 

Waveshare Wiki – GC9A01 원형 디스플레이에 대한 Waveshare Wiki입니다.

Adafruit GC9A01A 라이브러리 – 이 디스플레이를 위한 Adafruit GFX 라이브러리입니다.

Adafruit GFX 라이브러리 – Adafruit GFX 라이브러리를 사용한 프로그래밍에 대한 문서입니다.

Adafruit Animated Eyes – Animated Eyes 스케치에 대한 전체 문서입니다.

 

 

튜토리얼의 원문을 보시려면 이 링크를 따라가세요. 

 

고생하셨습니다. 즐거운 메이커 생활 되세요.

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^