Hardware | SSD1331 96x64 full color OLED 를 사용해보자

|

1. Full Color OLED


Arduino 에 연결하여 표현해 주는 OLED 가 있습니다.

센서값을 보여주는 모니터링용으로는 괜찮아 보입니다.


Monochrome 제품은 이미 테스트 해봤습니다.


http://chocoball.tistory.com/entry/Hardware-SSD1306-128x64-monochrome-OLED


0.95 크기를 가지는 OLED 는 대략 세가지가 있는것 같습니다.


하나는 위의 Monochrome 이고,

두번째는 윗쪽이 노란색이고 밑에가 파란색인 제품.




마지막은 full color 제품 입니다.



AliExpress 에서 찾아보니 6.84 USD 로 판매되고 있습니다.


https://ko.aliexpress.com/item/0-95-Inch-SPI-Full-Color-OLED-Display-DIY-Module-96x64-LCD-For-Arduino-SSD1306-Driver/32790785282.html



재미있는 것은, 제품이 SSD1306 드라이버라고 사이트에 올라와 있는데,

SSD1306 은 Monochrome 제품용이고, full color 는 SSD1331 드라이버 입니다.

결국 사이트에 잘못 올린거지요.


SSD1331 용 full color OLED 는 10 USD 정도 인데, SSD1306 으로 검색되는 full color OLED 는 7 USD 정도 이니,

검색은 SSD1306 으로 되는 full color OLED 를 구매하면 이득입니다.


이번 글에서도 "SSD1331" 드라이버에 맞는 sketch 를 이용했습니다.




2. 도착


도착샷은 다음과 같습니다.



창이 달린 모니터 있다 보니, 뽁뽁이로 잘 쌓여서 왔습니다.



오호이. 상태는 좋아 보입니다.



제품의 줌샷 입니다.



뒷면입니다.


SSD1331 datasheet 는 다음과 같습니다.


SSD1331_1.2.pdf


아래 link 를 많이 참조 했습니다.


http://educ8s.tv/arduino-color-oled-display-tutorial/




3. Pinout


Arduino 와 pin 연결 정보 입니다.


    SSD1331  | Arduino Nano
----------------------------
     GND     |     GND
     VCC     |     3.3V
     SCL     |     D13
     SDA     |     D11
     RES     |     D9
     DC      |     D8
     CS      |     D10
----------------------------


Layout 은 다음과 같습니다.



참조 Youtube 동영상에서 캡춰한 내용이 가장 잘 맞는것 같네요.






3. Library


아래 GitHub 에서 SSD1331 라이브러리를 다운로드 받습니다.


https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino


"/Arduino/Library/" 폴더에 다운로드 받은 파일을 넣어도 좋고,

아래처럼 Arduino IDE 에서 검색해서 install 할 수도 있습니다.


"Sketch > Include Library > Manage Libraries..." 에서 "gfx" 와 "SSD1331" 을 검색하면 install 되어 있으면 OK.

없으면 install 하면 됩니다.



"gfx" 를 검색하니, Adafruit GFX 가 이미 깔려 있네요.



"SSD1331" 을 검색하니, Adafruit SSD1331 OLED Driver Library for Arduino 도 이미 깔려 있습니다.





4. Sketch


"File > Examples > Adafruit SSD1331 OLED Driver Library for Arduino > test" 의 소스 입니다.


/*************************************************** 
  This is a example sketch demonstrating the graphics
  capabilities of the SSD1331 library  for the 0.96" 
  16-bit Color OLED with SSD1331 driver chip

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/684

  These displays use SPI to communicate, 4 or 5 pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/


// You can use any (4 or) 5 pins 
#define sclk 13
#define mosi 11
#define cs   10
#define rst  9
#define dc   8


// Color definitions
#define	BLACK           0x0000
#define	BLUE            0x001F
#define	RED             0xF800
#define	GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

#include "Adafruit_GFX.h"
#include "Adafruit_SSD1331.h"
#include "SPI.h"

// Option 1: use any pins but a little slower
Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, mosi, sclk, rst);  

// Option 2: must use the hardware SPI pins 
// (for UNO thats sclk = 13 and sid = 11) and pin 10 must be 
// an output. This is much faster - also required if you want
// to use the microSD card (see the image drawing example)
//Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);

float p = 3.1415926;

void setup(void) {
  Serial.begin(9600);
  Serial.print("hello!");
  display.begin();

  Serial.println("init");
  uint16_t time = millis();
  display.fillScreen(BLACK);
  time = millis() - time;
  
  Serial.println(time, DEC);
  delay(500);
   
  lcdTestPattern();
  delay(1000);
  
  display.fillScreen(BLACK);
  display.setCursor(0,0);
  display.print("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa");
  delay(1000);

  // tft print function!
  tftPrintTest();
  delay(2000);
  
  //a single pixel
  display.drawPixel(display.width()/2, display.height()/2, GREEN);
  delay(500);
  
  // line draw test
  testlines(YELLOW);
  delay(500);    
  
  // optimized lines
  testfastlines(RED, BLUE);
  delay(500);    
 
  testdrawrects(GREEN);
  delay(1000);

  testfillrects(YELLOW, MAGENTA);
  delay(1000);

  display.fillScreen(BLACK);
  testfillcircles(10, BLUE);
  testdrawcircles(10, WHITE);
  delay(1000);

  testroundrects();
  delay(500);
  
  testtriangles();
  delay(500);
  
  Serial.println("done");
  delay(1000);
}

void loop() {
}

void testlines(uint16_t color) {
   display.fillScreen(BLACK);
   for (int16_t x=0; x < display.width()-1; x+=6) {
     display.drawLine(0, 0, x, display.height()-1, color);
   }
   for (int16_t y=0; y < display.height()-1; y+=6) {
     display.drawLine(0, 0, display.width()-1, y, color);
   }
   
   display.fillScreen(BLACK);
   for (int16_t x=0; x < display.width()-1; x+=6) {
     display.drawLine(display.width()-1, 0, x, display.height()-1, color);
   }
   for (int16_t y=0; y < display.height()-1; y+=6) {
     display.drawLine(display.width()-1, 0, 0, y, color);
   }
   
   display.fillScreen(BLACK);
   for (int16_t x=0; x < display.width()-1; x+=6) {
     display.drawLine(0, display.height()-1, x, 0, color);
   }
   for (int16_t y=0; y < display.height()-1; y+=6) {
     display.drawLine(0, display.height()-1, display.width()-1, y, color);
   }

   display.fillScreen(BLACK);
   for (int16_t x=0; x < display.width()-1; x+=6) {
     display.drawLine(display.width()-1, display.height()-1, x, 0, color);
   }
   for (int16_t y=0; y < display.height()-1; y+=6) {
     display.drawLine(display.width()-1, display.height()-1, 0, y, color);
   }
   
}

void testdrawtext(char *text, uint16_t color) {
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);

  for (uint8_t i=0; i < 168; i++) {
    if (i == '\n') continue;
    display.write(i);
    if ((i > 0) && (i % 21 == 0))
      display.println();
  }    
}

void testfastlines(uint16_t color1, uint16_t color2) {
   display.fillScreen(BLACK);
   for (int16_t y=0; y < display.height()-1; y+=5) {
     display.drawFastHLine(0, y, display.width()-1, color1);
   }
   for (int16_t x=0; x < display.width()-1; x+=5) {
     display.drawFastVLine(x, 0, display.height()-1, color2);
   }
}

void testdrawrects(uint16_t color) {
 display.fillScreen(BLACK);
 for (int16_t x=0; x < display.height()-1; x+=6) {
   display.drawRect((display.width()-1)/2 -x/2, (display.height()-1)/2 -x/2 , x, x, color);
 }
}

void testfillrects(uint16_t color1, uint16_t color2) {
 display.fillScreen(BLACK);
 for (int16_t x=display.height()-1; x > 6; x-=6) {
   display.fillRect((display.width()-1)/2 -x/2, (display.height()-1)/2 -x/2 , x, x, color1);
   display.drawRect((display.width()-1)/2 -x/2, (display.height()-1)/2 -x/2 , x, x, color2);
 }
}

void testfillcircles(uint8_t radius, uint16_t color) {
  for (uint8_t x=radius; x < display.width()-1; x+=radius*2) {
    for (uint8_t y=radius; y < display.height()-1; y+=radius*2) {
      display.fillCircle(x, y, radius, color);
    }
  }  
}

void testdrawcircles(uint8_t radius, uint16_t color) {
  for (int16_t x=0; x < display.width()-1+radius; x+=radius*2) {
    for (int16_t y=0; y < display.height()-1+radius; y+=radius*2) {
      display.drawCircle(x, y, radius, color);
    }
  }  
}

void testtriangles() {
  display.fillScreen(BLACK);
  int color = 0xF800;
  int t;
  int w = display.width()/2;
  int x = display.height();
  int y = 0;
  int z = display.width();
  for(t = 0 ; t <= 15; t+=1) {
    display.drawTriangle(w, y, y, x, z, x, color);
    x-=4;
    y+=4;
    z-=4;
    color+=100;
  }
}

void testroundrects() {
  display.fillScreen(BLACK);
  int color = 100;
  int i;
  int t;
  for(t = 0 ; t <= 4; t+=1) {
  int x = 0;
  int y = 0;
  int w = display.width();
  int h = display.height();
    for(i = 0 ; i <= 24; i+=1) {
    display.drawRoundRect(x, y, w, h, 5, color);
    x+=2;
    y+=3;
    w-=4;
    h-=6;
    color+=1100;
  }
  color+=100;
  }
}

void tftPrintTest() {
  display.fillScreen(BLACK);
  display.setCursor(0, 5);
  display.setTextColor(RED);  
  display.setTextSize(1);
  display.println("Hello World!");
  display.setTextColor(YELLOW, GREEN);
  display.setTextSize(2);
  display.print("Hello Wo");
  display.setTextColor(BLUE);
  display.setTextSize(3);
  display.print(1234.567);
  delay(1500);
  display.setCursor(0, 5);
  display.fillScreen(BLACK);
  display.setTextColor(WHITE);
  display.setTextSize(0);
  display.println("Hello World!");
  display.setTextSize(1);
  display.setTextColor(GREEN);
  display.print(p, 5);
  display.println(" Want pi?");
  display.print(8675309, HEX); // print 8,675,309 out in HEX!
  display.print(" Print HEX");
  display.setTextColor(WHITE);
  display.println("Sketch has been");
  display.println("running for: ");
  display.setTextColor(MAGENTA);
  display.print(millis() / 1000);
  display.setTextColor(WHITE);
  display.print(" seconds.");
}

void mediabuttons() {
 // play
  display.fillScreen(BLACK);
  display.fillRoundRect(25, 10, 78, 60, 8, WHITE);
  display.fillTriangle(42, 20, 42, 60, 90, 40, RED);
  delay(500);
  // pause
  display.fillRoundRect(25, 90, 78, 60, 8, WHITE);
  display.fillRoundRect(39, 98, 20, 45, 5, GREEN);
  display.fillRoundRect(69, 98, 20, 45, 5, GREEN);
  delay(500);
  // play color
  display.fillTriangle(42, 20, 42, 60, 90, 40, BLUE);
  delay(50);
  // pause color
  display.fillRoundRect(39, 98, 20, 45, 5, RED);
  display.fillRoundRect(69, 98, 20, 45, 5, RED);
  // play color
  display.fillTriangle(42, 20, 42, 60, 90, 40, GREEN);
}

/**************************************************************************/
/*! 
    @brief  Renders a simple test pattern on the LCD
*/
/**************************************************************************/
void lcdTestPattern(void)
{
  uint32_t i,j;
  display.goTo(0, 0);
  
  for(i=0;i<64;i++)
  {
    for(j=0;j<96;j++)
    {
      if(i>55){display.writeData(WHITE>>8);display.writeData(WHITE);}
      else if(i>47){display.writeData(BLUE>>8);display.writeData(BLUE);}
      else if(i>39){display.writeData(GREEN>>8);display.writeData(GREEN);}
      else if(i>31){display.writeData(CYAN>>8);display.writeData(CYAN);}
      else if(i>23){display.writeData(RED>>8);display.writeData(RED);}
      else if(i>15){display.writeData(MAGENTA>>8);display.writeData(MAGENTA);}
      else if(i>7){display.writeData(YELLOW>>8);display.writeData(YELLOW);}
      else {display.writeData(BLACK>>8);display.writeData(BLACK);}
    }
  }
}




5. 동작


위의 sketch 를 업로드 하고 pin 을 잘 연결하면, 아래와 같은 동작을 보여줍니다.



글씨, 배경색, 크기 등 여러가지를 확인해 볼 수 있습니다.



그림들도 잘 표현이 됩니다. 물론 컬러로.



SPI 프로토콜이라서 그런지, Monochorme 의 I2C 인터페이스보다는 확실히 빠른 성늘을 보여주네요.

다음은 동영상 입니다.





FIN


화면의 상하단의 색이 다른 OLED 는 SSD1306 을 사용한지라,

부분 컬러이긴 하지만, 더이상 OLED 는 구매하지 않아도 될 듯 해요.

And