반응형

예전 글(http://deneb21.tistory.com/508) 에서 노키아 5110 LCD를 아두이노로 컨트롤 하는 방법에 대해서 알아보았다. 이번에는 그래픽 라이브러리를 사용해서 간단한 그래픽을 나타내 보려고 한다. 라이브러리는 Adafruit 의 GFX 라이브러리와 PCD8544(5110 LCD 정식 품명) 라이브러리를 이용했으며 다운 받은 라이브러리에 포함된 예제를 핀배열과 백라이트 부분을 살짝 수정해서 그래픽을 표시해 보았다. 5110 LCD에 대한 기본적인 사항은 이 글의 첫 줄에 있는 예전 글을 참고하면 된다.

 

연결은 예전과 동일하다. 만약 라이브러리 파일의 예제 그대로 연결하고 싶다면 아래의 연결을 따르지 않아도 된다. 물론 아래의 소스도 수정이 되어야 할 것이다.

 

■ Nokia 5110 LCD 와 아두이노 우노의 연결

 

 

 

 Arduino UNO  Nokia 5110 LCD
 7  CE
 6  RST
 5  DC
 4  DIN
 3  CLK
 2  LIGHT
 3.3V  VCC
 GND  GND

 

 

 

 

■ 라이브러리 다운로드

 

Adafruit GFX 라이브러리 : https://github.com/adafruit/Adafruit-GFX-Library

 

Adafruit PCD8544 Nokia 5110 LCD library : https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library

 

위의 두 가지 라이브러리를 다운로드 받아서 압축을 풀고 아두이노 설치폴더 하위의 Libraries 폴더에 복사해 넣으면 된다. 참고로 GFX 라이브러리는 예전 OLED LCD 사용에 대한 글에서도 사용한 라이브러리이다.

 

Adafruit-GFX-Library-master.zip
다운로드
Adafruit-PCD8544-Nokia-5110-LCD-library-master.zip
다운로드

 

 

 

■ 소스

아래 소스는 라이브러리 설치 시 Example 로 제공되는 소스(pcdtest.ino)이며 핀 연결 부분을 나의 연결에 맞게 수정했으며 백라이트 제어 부분을 추가한 소스이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
/*********************************************************************
This is an example sketch for our Monochrome Nokia 5110 LCD Displays
 
  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/338
 
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, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/
 
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
 
#define PIN_BL    2   //백라이트 제어를 위한 핀연결
 
// Software SPI (slower updates, more flexible pin options):
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
//Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3); //원래 핀연결
Adafruit_PCD8544 display = Adafruit_PCD8544(34576);   //나의 연결에 맞게 수정한 핀연결
 
// Hardware SPI (faster, but must use certain hardware pins):
// SCK is LCD serial clock (SCLK) - this is pin 13 on Arduino Uno
// MOSI is LCD DIN - this is pin 11 on an Arduino Uno
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
// Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);
// Note with hardware SPI MISO and SS pins aren't used but will still be read
// and written to during SPI transfer.  Be careful sharing these pins!
 
#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2
 
 
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
 
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };
 
void setup()   {
  //백라이트를 ON 함
  pinMode(PIN_BL,OUTPUT); 
  digitalWrite(PIN_BL,LOW); //HIGH = Turn Backlight OFF, LOW = Turn Backlight ON
 
  Serial.begin(9600);
 
  display.begin();
  // init done
 
  // you can change the contrast around to adapt the display
  // for the best viewing!
  display.setContrast(50);
 
  display.display(); // show splashscreen
  delay(2000);
  display.clearDisplay();   // clears the screen and buffer
 
  // draw a single pixel
  display.drawPixel(1010, BLACK);
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw many lines
  testdrawline();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw rectangles
  testdrawrect();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw multiple rectangles
  testfillrect();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw mulitple circles
  testdrawcircle();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw a circle, 10 pixel radius
  display.fillCircle(display.width()/2, display.height()/210, BLACK);
  display.display();
  delay(2000);
  display.clearDisplay();
 
  testdrawroundrect();
  delay(2000);
  display.clearDisplay();
 
  testfillroundrect();
  delay(2000);
  display.clearDisplay();
 
  testdrawtriangle();
  delay(2000);
  display.clearDisplay();
   
  testfilltriangle();
  delay(2000);
  display.clearDisplay();
 
  // draw the first ~12 characters in the font
  testdrawchar();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // text display texts
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor(0,0);
  display.println("Hello, world!");
  display.setTextColor(WHITE, BLACK); // 'inverted' text
  display.println(3.141592);
  display.setTextSize(2);
  display.setTextColor(BLACK);
  display.print("0x"); display.println(0xDEADBEEF, HEX);
  display.display();
  delay(2000);
 
  // rotation example
  display.clearDisplay();
  display.setRotation(1);  // rotate 90 degrees counter clockwise, can also use values of 2 and 3 to go further.
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor(0,0);
  display.println("Rotation");
  display.setTextSize(2);
  display.println("Example!");
  display.display();
  delay(2000);
 
  // revert back to no rotation
  display.setRotation(0);
 
  // miniature bitmap display
  display.clearDisplay();
  display.drawBitmap(3016,  logo16_glcd_bmp, 16161);
  display.display();
 
  // invert the display
  display.invertDisplay(true);
  delay(1000); 
  display.invertDisplay(false);
  delay(1000); 
 
  // draw a bitmap icon and 'animate' movement
  testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_WIDTH, LOGO16_GLCD_HEIGHT);
}
 
 
void loop() {
  
}
 
 
void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  uint8_t icons[NUMFLAKES][3];
  randomSeed(666);     // whatever seed
 
  // initialize
  for (uint8_t f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS] = random(display.width());
    icons[f][YPOS] = 0;
    icons[f][DELTAY] = random(5+ 1;
    
    Serial.print("x: ");
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(" y: ");
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(" dy: ");
    Serial.println(icons[f][DELTAY], DEC);
  }
 
  while (1) {
    // draw each icon
    for (uint8_t f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK);
    }
    display.display();
    delay(200);
    
    // then erase it + move it
    for (uint8_t f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS],  logo16_glcd_bmp, w, h, WHITE);
      // move it
      icons[f][YPOS] += icons[f][DELTAY];
      // if its gone, reinit
      if (icons[f][YPOS] > display.height()) {
  icons[f][XPOS] = random(display.width());
  icons[f][YPOS] = 0;
  icons[f][DELTAY] = random(5+ 1;
      }
    }
   }
}
 
 
void testdrawchar(void) {
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor(0,0);
 
  for (uint8_t i=0; i < 168; i++) {
    if (i == '\n'continue;
    display.write(i);
    //if ((i > 0) && (i % 14 == 0))
      //display.println();
  }    
  display.display();
}
 
void testdrawcircle(void) {
  for (int16_t i=0; i<display.height(); i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, BLACK);
    display.display();
  }
}
 
void testfillrect(void) {
  uint8_t color = 1;
  for (int16_t i=0; i<display.height()/2; i+=3) {
    // alternate colors
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, color%2);
    display.display();
    color++;
  }
}
 
void testdrawtriangle(void) {
  for (int16_t i=0; i<min(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(display.width()/2, display.height()/2-i,
                     display.width()/2-i, display.height()/2+i,
                     display.width()/2+i, display.height()/2+i, BLACK);
    display.display();
  }
}
 
void testfilltriangle(void) {
  uint8_t color = BLACK;
  for (int16_t i=min(display.width(),display.height())/2; i>0; i-=5) {
    display.fillTriangle(display.width()/2, display.height()/2-i,
                     display.width()/2-i, display.height()/2+i,
                     display.width()/2+i, display.height()/2+i, color);
    if (color == WHITE) color = BLACK;
    else color = WHITE;
    display.display();
  }
}
 
void testdrawroundrect(void) {
  for (int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i, display.height()/4, BLACK);
    display.display();
  }
}
 
void testfillroundrect(void) {
  uint8_t color = BLACK;
  for (int16_t i=0; i<display.height()/2-2; i+=2) {
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i, display.height()/4, color);
    if (color == WHITE) color = BLACK;
    else color = WHITE;
    display.display();
  }
}
   
void testdrawrect(void) {
  for (int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, BLACK);
    display.display();
  }
}
 
void testdrawline() {  
  for (int16_t i=0; i<display.width(); i+=4) {
    display.drawLine(00, i, display.height()-1, BLACK);
    display.display();
  }
  for (int16_t i=0; i<display.height(); i+=4) {
    display.drawLine(00, display.width()-1, i, BLACK);
    display.display();
  }
  delay(250);
  
  display.clearDisplay();
  for (int16_t i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, BLACK);
    display.display();
  }
  for (int8_t i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, BLACK);
    display.display();
  }
  delay(250);
  
  display.clearDisplay();
  for (int16_t i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, BLACK);
    display.display();
  }
  for (int16_t i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-10, i, BLACK);
    display.display();
  }
  delay(250);
 
  display.clearDisplay();
  for (int16_t i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-100, i, BLACK);
    display.display();
  }
  for (int16_t i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-10, i, display.height()-1, BLACK); 
    display.display();
  }
  delay(250);
}
cs

 

소스는 setup() 에서 여러가지 도형 및 문자를 출력하는 function을 순차적으로 실행하고 있다. 각 function 들을 자세히 보면 어떻게 도형과 문자 그리고 애니메이션을 만드는지 알 수 있을 것이다. 복잡한 부분은 라이브러리와 되어 있어서 자세히 살펴보면 별로 어려운 부분은 없다. 대부분의 기능들이 예를 들어 display.clearDisplay(); 같이 간단하게 제어가 가능하게 되어있다.

 

 

https://youtu.be/mR0pEJtO5mg

 

 

■ 추가사항 (2017.04.20) : 위의 소스에서 텍스트 표시하는 부분만 잘라서 정리해 보았다. 아무래도 이 디스플레이를 가지고 그래픽 보다는 텍스트 표시 용도로 사용할 경우가 많을 것으로 보여서 정리해 보았다. 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#define PIN_BL 2   //백라이트 제어를 위한 핀연결
 
//SCLK, DIN, DC, CE, RST 핀연결
Adafruit_PCD8544 display = Adafruit_PCD8544(34576);
 
void setup()
{
  //백라이트를 ON 함, HIGH = Turn Backlight OFF, LOW = Turn Backlight ON
  pinMode(PIN_BL,OUTPUT); 
  digitalWrite(PIN_BL,LOW); 
 
  //디스플레이 초기화
  display.begin();
 
  //디스플레이 Contrast 조절 (값이 올라가면 진해짐)
  display.setContrast(60);
 
  //텍스트 디스플레이
  display.clearDisplay();             //디스플레이 지우기
  display.setTextSize(1);             //텍스트 사이즈 조절
  display.setTextColor(BLACK);        //텍스트 색
  display.setCursor(0,0);             //커서 좌표
  display.println("Hello, world!");   //표시 텍스트
  display.setTextColor(WHITE, BLACK); // 'inverted' text (배경 까맣게 글자 하얗게)
  display.println(3.141592);          //숫자 표시
  display.setTextSize(2);             //텍스트 사이즈 조절
  display.setTextColor(BLACK);        //텍스트 색
  display.print("0x");                //표시 텍스트
  display.println(0xDEADBEEF, HEX);   //HEX 쓰기
  display.display();                  //위의 설정내용 표시
}
 
void loop()
{
 
}
cs
 
주석을 나름대로 상세하게 달아 보았다.

 

실행결과

반응형
반응형

조금 전 포스팅한 OLED 디스플레이와 DHT11 센서를 이용한 온습도계를 개선해 보았다. 글자가 너무 작아서 잘 안보이길래 텍스트 크기를 크게 했으며 (벌써 노안인가? ㅠㅠ) 기상청에서 퍼온 불쾌지수 구하는 공식을 활용하여 온도, 습도, 불쾌지수가 표시되게 하였다. 불쾌지수는 온도와 습도로 구할 수 있다. 불쾌지수 (Discomfort Index) 가 80을 넘으면 대부분의 사람이 불쾌감을 느끼게 되며 실제로도 80이 넘으면 폭력, 살인 등 강력사건이 늘어난다고 한다. 


아두이노와 센서, OLED 디스플레이의 연결은 바로 전 포스팅과 같으며 소스만 수정이 되었다. 그러므로 소스 이외의 사항은 아래의 글을 참고하면 된다.




■ 소스


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//** http://deneb21.tistory.com/431
 
#include <DHT11.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
//DHT11 연결핀
#define DHT11_PIN   2
DHT11 dht11(DHT11_PIN);
 
//Software SPI 연결핀 설정
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
 
void setup() {
    display.begin();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
}
 
void loop() {
  int err;
  float temp, humi;
  if((err=dht11.read(humi, temp))==0//온도, 습도 읽어와서 표시
  {
    display.setCursor(0,0);
    display.print("T : ");
    display.println(temp,0);
    display.print("H : ");
    display.println(humi,0);
    display.print("D : ");
    display.println(discomfortIndex(temp,humi),0);
    display.display();
  }
  else                                //에러일 경우 처리
  {
    display.setCursor(0,0);
    display.print("Error :");
    display.print(err);
    display.display();
  }
  delay(5000);                        //5초마다 측정
  display.clearDisplay();
}
 
//불쾌지수 구하기 (공식출처: 기상청)
float discomfortIndex(float temp, float humi) {
    return (1.8f*temp)-(0.55*(1-humi/100.0f)*(1.8f*temp-26))+32;
}
cs



소스를 보면 display.setTextSize(1) 에서 display.setTextSize(2) 로 텍스트 크기를 1 증가 시켰으며 discomfortindex() 함수를 추가해서 불쾌지수를 표시해 주도록 하였다. 그리고 의미 없는 온도와 습도의 소수점 이하 자리를 잘라 버렸다.



 

개선 전



개선 후... 위로 부터 온도(T), 습도(H), 불쾌지수(D) 표시


훨씬 잘 보인다.

반응형
반응형

지난 글에서 0.96 인치 디스플레이 모듈에 텍스트를 표시하는 방법을 알아 보았다. 내친김에 DHT11 온습도 센서와 연결해서 온습도계를 만들어 보았다. 아두이노와 OLED 디스플레이의 연결은 기존 글에서와 같으며 거기에 DHT11 센서를 추가하고 아두이노 IDE의 시리얼 모니터에 출력하던 온도, 습도 데이터를 OLED 디스플레이에 출력하는 것으로 전환 하였다.






아두이노와 OLED 디스플레이와의 연결은 아래와 같이 하였다.

0.96" OLED Display Module 

Arduino Uno 

GND

GND

VDD

3.3V

SCK

D10

SDA

D9

RES

D13

DC

D11

CS

D12


아두이노와 DHT11 의 연결은 아래와 같이 하였다.

DHT11 

Arduino Uno 

GND

GND

VCC

5V

Signal

D2



■ 소스

아래의 소스를 실행하려면 OLED 관련 라이브러리 2개와 DHT11 라이브러리를 설치해야 한다.

Adafruit-GFX-Library-master.zip

Adafruit_SSD1306-master.zip

DHT11_library.zip

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//** http://deneb21.tistory.com/430
 
#include <DHT11.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
//DHT11 연결핀
#define DHT11_PIN   2
DHT11 dht11(DHT11_PIN);
 
//Software SPI 연결핀 설정
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
 
void setup() {
    display.begin();
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
}
 
void loop() {
  int err;
  float temp, humi;
  if((err=dht11.read(humi, temp))==0//온도, 습도 읽어와서 OLED 표시
  {
    display.setCursor(0,0);
    display.print("Temperature :");
    display.println(temp);
    display.print("Humidity :");
    display.println(humi);    
    display.display();
  }
  else                                //DHT11 에러일 경우 처리
  {
    display.setCursor(0,0);
    display.print("Error :");
    display.print(err);
    display.display();
  }
  delay(5000);                        //5초마다 측정
  display.clearDisplay();
}
cs


소스는 위와 같다. 어려운 부분은 없으며 DHT11 로 측정한 온도, 습도 값을 5초 마다 측정해서 OLED 디스플레이에 표시해 준다.

 

실행한 결과이다. 온도와 습도가 잘 표시되고 있으며 5초마다 디스플레이의 깜빡임도 거의 없이 온도와 습도가 갱신된다. 그나저나 33도라니 너무 덥다!



▶추가사항(2016.08.04) : "DHT11과 OLED 디스플레이를 이용한 온습도계 개선" 에 개선된 소스를 올려 놓았다.

반응형
반응형

예전 글 "[아두이노] 0.96인치 OLED LCD 모듈의 사용 (Adafruit SSD1306 호환)" 에서 이 디스플레이 모듈에 대해서 Adafruit 의 조금은 긴 예제를 실행해 보았다. 이 모듈은 간단한 애니메이션, 그림도 표현이 가능하나 나 같은 경우 딱히 그런 용도로 쓸 것 같지는 않다. 거의 텍스트 표시 용도로 사용될 것인데 예전 글에서 실행했던 예제는 너무 길고 좀 정신이 없었다. 그래서 그 예제 소스 중에서 텍스트 표시 하는 부분만 간추리고 소스에 주석을 달아서 사용법을 정리해 보려고 한다.

 

연결방법과 라이브러리 설치는 예전 글에서와 같다. 그래도 살짝 다시 정리를 해 보면...

 

모듈은 위와 같이 생겼다. 100원짜리 정도의 크기이며 모노크롬 화면으로서 128x64 의 해상도를 가진다. 7개의 핀을 아두이노와 연결해서 사용한다.

 

모듈 뒷면의 모습이다. 

 

더욱 자세한 정보는 아래의 링크를 참고하면 된다.

[아두이노] 0.96인치 OLED LCD 모듈의 사용 (Adafruit SSD1306 호환)

https://learn.adafruit.com/monochrome-oled-breakouts

 

아두이노와의 연결은 아래와 같이 하면 된다.

0.96" OLED Display Module  Arduino Uno 
GND GND
VDD 3.3V (5V에 연결해도 됩니다.)
SCK D10
SDA D9
RES D13
DC D11
CS D12

 

아두이노 우노와 OLED 모듈을 연결한 모습

 

 

■ 소스

 

아래 소스의 실행을 위해서는 아래 두 개의 라이브러리를 설치해야 한다.

Adafruit-GFX-Library-master.zip
다운로드
Adafruit_SSD1306-master.zip
다운로드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//** http://deneb21.tistory.com/429
 
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
// software SPI 통신핀 설정
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
 
void setup() {
  //adafruit 로고(기본로고) 보여줌 (디스플레이 ON)
  display.begin();
  display.display();      //디스플레이 표시함, 이것을 실행하지 않으면 표시 안됨.
  delay(2000);
  display.clearDisplay(); //지우기 (다음 텍스트를 표시해야 지워짐)
  
  //텍스트 표시 #1
  display.setTextSize(1);             //텍스트 크기 조절
  display.setTextColor(WHITE);        //텍스트 색상
  display.setCursor(0,0);             //텍스트 표시 좌표 (X,Y 픽셀단위)
  display.println("Hello, world!");   //표시 텍스트
  display.setTextColor(BLACK, WHITE); //텍스트 색상: 흰색배경, 검은 글씨
  display.println("Hello, world!");
  display.setTextSize(2);             //텍스트 사이즈 크게, 2 
  display.setTextColor(WHITE);
  display.println("Hello, world!");
  display.display();
  delay(5000);
  display.clearDisplay();
 
  //텍스트 표시 #2
  display.setCursor(25,30);  //텍스트를 디스플레이 중간에 표시
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.println("Hello, world!");
  display.display();
  delay(3000);
  display.clearDisplay();  
 
  //텍스트 표시 #3
  display.setCursor(0,0);  //텍스트를 디스플레이 중간에 표시
  display.println("Hello, korea!");
  display.println("Hello, all!");
  display.display();  
}
 
void loop() {
  // put your main code here, to run repeatedly:
 
}
cs

 

소스에 주석을 달았지만 다시 한 번 설명하자면 

  • display.begin() : 디스플레이 ON
  • display.setTextSize(사이즈) : 텍스트 크기 설정
  • display.setTextColor(텍스트컬러,배경컬러) : 텍스트 컬러 설정, 모노크롬 이기 때문에 BLACK, WHITE 밖에 없음, 배경컬러 생략가능
  • display.setCursor(X, Y) : 텍스트 표시 좌표설정 (픽셀 단위로서 X 는 0~128, Y는 0~64)
  • display.println("텍스트") : 표시할 텍스트 또는 숫자 지정, 이전 텍스트에 이어 쓰기를 원할 경우 display.print("텍스트") 도 사용가능
  • display.display() : 설정한 텍스트를 화면에 표시
  • display.clearDisplay() : 화면 지우기, 하지만 다른 텍스트 표시 전에는 이 명령을 사용해도 지워지지 않음

 

이 정도만 알면 OLED 디스플레이에 텍스트를 출력하는데 문제가 없는 듯 하다.

 

 

 

https://youtu.be/QoFWs9zAbXc

위의 소스를 실행하는 모습을 동영상으로 찍어 보았다. 크기에 비해 해상도가 높아서 예전의 16x2 LCD 보다는 쓰임새가 많은 모듈이다.

반응형
반응형

아두이노의 내용을 디스플레이 하는데는 예전에 알아보았던 16x2 LCD 모듈이나 7 세그먼트 LED를 이용하는 방법외에도 화소수가 훨씬 많은 OLED 모듈을 이용하는 방법도 있습니다. 제가 가진 모듈은 128x64 의 해상도를 가지고 있어서 텍스트는 물론 간단한 그래픽이나 애니메이션 등을 표현할 수 있습니다. 이번에 구입한 모듈은 SPI 통신을 지원하는 OLED 디스플레이 모듈로서 0.96 인치의 손목시계 크기 모듈입니다. 아두이노 프로 미니 등의 작은 아두이노와 결합하면 손목시계나 소형 온습도계, 조금 더 발전한다면 간단한 게임도 구현이 가능할 것 같습니다. 테스트겸 Adafruit 의 라이브러리와 예제소스를 이용하여 OLED 모듈을 돌려보았습니다.

 

OLED 모듈의 스펙

  • 0.96 인치 OLED 
  • 128 x 64 해상도
  • SPI 통신
  • 3V ~ 5V 동작전압

 

OLED 모듈의 PIN

  • GND (Ground)
  • VDD (3V ~ 5V)
  • SCK (Serial Clock Input, D0 으로 표시된 모듈도 있음)
  • SDA (Serial Data Input, D1 으로 표시된 모듈도 있음)
  • RES (Reset Signal Input, RST 로 표시된 모듈도 있음)
  • DC (Data / Command Control)
  • CS (Chip Select)

 

 

OLED 모듈의 모습입니다. 백원짜리 동전과 크기가 비슷합니다. 7개의 연결핀이 있습니다. 핀에는 각각의 용도가 쓰여 있습니다.

 

뒷면 입니다. 7개의 암핀을 꼽을 수 있도록 되어 있고 보드와 OLED 를 연결하는 갈색의 케이블이 보입니다.

 

 

위의 사진과 같이 아두이노와 연결했습니다. 연결은 다음과 같이 하였습니다.

 

0.96" OLED Display Module  아두이노 우노 
GND GND
VDD 3.3V (5V에 연결해도 됩니다.)
SCK D10
SDA D9
RES D13
DC D11
CS D12

 

 

소스

 

아래의 소스를 구동하기 위해서는 아래의 사이트에서 두 개의 Adafruit 라이브러리를 다운로드 받아서 설치해야 합니다.

 

■ SSD1306 oled driver library for 'monochrome' 128x64 and 128x32 OLEDs

https://github.com/adafruit/Adafruit_SSD1306

 

■ Adafruit GFX graphics core library

https://github.com/adafruit/Adafruit-GFX-Library

 

또는 아래의 파일을 다운로드 받아도 됩니다.

Adafruit-GFX-Library-master.zip
다운로드
Adafruit_SSD1306-master.zip
다운로드

 

라이브러리 설치는 압축을 풀고 아두이노 IDE 설치 폴더 하위의 libraries 폴더에 넣고 아두이노 IDE를 재실행하면 됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
/*********************************************************************
This is an example for our Monochrome OLEDs based on SSD1306 drivers
 
  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/category/63_98
 
This example is for a 128x64 size display using 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, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/
 
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
// If using software SPI (the default case):
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
 
/* Uncomment this block to use hardware SPI
#define OLED_DC     6
#define OLED_CS     7
#define OLED_RESET  8
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);
*/
 
#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2
 
#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };
 
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
 
void setup()   {                
  Serial.begin(9600);
 
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC);
  // init done
  
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(2000);
 
  // Clear the buffer.
  display.clearDisplay();
 
  // draw a single pixel
  display.drawPixel(1010, WHITE);
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw many lines
  testdrawline();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw rectangles
  testdrawrect();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw multiple rectangles
  testfillrect();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw mulitple circles
  testdrawcircle();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw a white circle, 10 pixel radius
  display.fillCircle(display.width()/2, display.height()/210, WHITE);
  display.display();
  delay(2000);
  display.clearDisplay();
 
  testdrawroundrect();
  delay(2000);
  display.clearDisplay();
 
  testfillroundrect();
  delay(2000);
  display.clearDisplay();
 
  testdrawtriangle();
  delay(2000);
  display.clearDisplay();
   
  testfilltriangle();
  delay(2000);
  display.clearDisplay();
 
  // draw the first ~12 characters in the font
  testdrawchar();
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // draw scrolling text
  testscrolltext();
  delay(2000);
  display.clearDisplay();
 
  // text display tests
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Hello, world!");
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.println(3.141592);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("0x"); display.println(0xDEADBEEF, HEX);
  display.display();
  delay(2000);
  display.clearDisplay();
 
  // miniature bitmap display
  display.drawBitmap(3016,  logo16_glcd_bmp, 16161);
  display.display();
 
  // invert the display
  display.invertDisplay(true);
  delay(1000); 
  display.invertDisplay(false);
  delay(1000); 
  display.clearDisplay();
 
  // draw a bitmap icon and 'animate' movement
  testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH);
}
 
 
void loop() {
  
}
 
 
void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  uint8_t icons[NUMFLAKES][3];
 
  // initialize
  for (uint8_t f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS] = random(display.width());
    icons[f][YPOS] = 0;
    icons[f][DELTAY] = random(5+ 1;
    
    Serial.print("x: ");
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(" y: ");
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(" dy: ");
    Serial.println(icons[f][DELTAY], DEC);
  }
 
  while (1) {
    // draw each icon
    for (uint8_t f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE);
    }
    display.display();
    delay(200);
    
    // then erase it + move it
    for (uint8_t f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, BLACK);
      // move it
      icons[f][YPOS] += icons[f][DELTAY];
      // if its gone, reinit
      if (icons[f][YPOS] > display.height()) {
        icons[f][XPOS] = random(display.width());
        icons[f][YPOS] = 0;
        icons[f][DELTAY] = random(5+ 1;
      }
    }
   }
}
 
 
void testdrawchar(void) {
  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();
  }    
  display.display();
}
 
void testdrawcircle(void) {
  for (int16_t i=0; i<display.height(); i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, WHITE);
    display.display();
  }
}
 
void testfillrect(void) {
  uint8_t color = 1;
  for (int16_t i=0; i<display.height()/2; i+=3) {
    // alternate colors
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, color%2);
    display.display();
    color++;
  }
}
 
void testdrawtriangle(void) {
  for (int16_t i=0; i<min(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(display.width()/2, display.height()/2-i,
                     display.width()/2-i, display.height()/2+i,
                     display.width()/2+i, display.height()/2+i, WHITE);
    display.display();
  }
}
 
void testfilltriangle(void) {
  uint8_t color = WHITE;
  for (int16_t i=min(display.width(),display.height())/2; i>0; i-=5) {
    display.fillTriangle(display.width()/2, display.height()/2-i,
                     display.width()/2-i, display.height()/2+i,
                     display.width()/2+i, display.height()/2+i, WHITE);
    if (color == WHITE) color = BLACK;
    else color = WHITE;
    display.display();
  }
}
 
void testdrawroundrect(void) {
  for (int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i, display.height()/4, WHITE);
    display.display();
  }
}
 
void testfillroundrect(void) {
  uint8_t color = WHITE;
  for (int16_t i=0; i<display.height()/2-2; i+=2) {
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i, display.height()/4, color);
    if (color == WHITE) color = BLACK;
    else color = WHITE;
    display.display();
  }
}
   
void testdrawrect(void) {
  for (int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, WHITE);
    display.display();
  }
}
 
void testdrawline() {  
  for (int16_t i=0; i<display.width(); i+=4) {
    display.drawLine(00, i, display.height()-1, WHITE);
    display.display();
  }
  for (int16_t i=0; i<display.height(); i+=4) {
    display.drawLine(00, display.width()-1, i, WHITE);
    display.display();
  }
  delay(250);
  
  display.clearDisplay();
  for (int16_t i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, WHITE);
    display.display();
  }
  for (int16_t i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, WHITE);
    display.display();
  }
  delay(250);
  
  display.clearDisplay();
  for (int16_t i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE);
    display.display();
  }
  for (int16_t i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-10, i, WHITE);
    display.display();
  }
  delay(250);
 
  display.clearDisplay();
  for (int16_t i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-100, i, WHITE);
    display.display();
  }
  for (int16_t i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-10, i, display.height()-1, WHITE); 
    display.display();
  }
  delay(250);
}
 
void testscrolltext(void) {
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(10,0);
  display.clearDisplay();
  display.println("scroll");
  display.display();
 
  display.startscrollright(0x000x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x000x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);    
  display.startscrolldiagright(0x000x07);
  delay(2000);
  display.startscrolldiagleft(0x000x07);
  delay(2000);
  display.stopscroll();
}
cs
 
위의 소스는 라이브러리 설치 후 파일 -> 예제 -> Adafruit SSD1306 -> SSD1306_128x64_spi 를 불러 와도 됩니다. 만약 128x32 의 해상도의 모듈을 가지고 있다면 SSD1306_128x32_spi 예제를 불러오면 됩니다. 
 
그런데 위의 소스를 컴파일하니 에러가 납니다. 소스의 62행을 보면 
 
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
 
이 부분에서 컴파일 에러가 나고 업로드가 되지 않습니다. 라이브러리가 128x32 해상도로 설정되어 있어서 그렇습니다. 해결방법은...
 
1. 위에서 설치한 SSD1306 oled driver library 폴더에 들어갑니다.
2. Adafruit_SSD1306.h 파일을 편집기로 엽니다.
3. #define SSD1306_128_32 부분을 주석처리하고 #define SSD1306_128_64 의 주석을 해제 하고 저장합니다. (물론 128x32 해상도의 모듈을 사용한다면 수정하지 않아도 됩니다.)
4. 아두이노 IDE를 닫았다가 다시 실행하고 소스를 다시 업로드 하면 컴파일이 될 것 입니다.
 
소스를 보면 영어이긴 하지만 자세하게 설명이 달려 있습니다. 텍스트를 표시하는건 display.println("Hello, world!"); 이런 식으로 아주 간단하게 표시가 가능하고 부가적으로 텍스트 크기, 컬러, 표시 위치 등의 설정 등이 가능합니다. 스크롤도 간단하게 가능하네요. 소스와 주석을 참고하면 거의 모든 것을 그릴 수 있을 것 같습니다.

 

 

https://youtu.be/kCqMqHkPudw

128x64 해상도의 모듈에 128x32 소스를 적용한 모습... 실행은 되지만 해상도가 맞지 않아서 일부모습만 보인다거나 화면이 깨지는 모습을 보여줍니다.

 

 

https://youtu.be/A9r0tpoS5to

128x64 해상도의 제대로된 소스를 적용해 보았습니다. 모든 화면이 잘 표시되고 삼각형이나 원도 제대로 표시 됩니다. 텍스트도 깨지지 않고 표시 됩니다.

 

 

다양한 표시가 가능해서 각종 센서류와 연결하여 휴대용 장치를 만들기에 아주 적당한 디스플레이 모듈 같습니다. 앞으로 많이 활용을 해 봐야겠습니다.

 

 

▶추가사항(2016.08.03) : http://deneb21.tistory.com/429 글에서 위의 모듈에 텍스트를 출력하는 방법을 정리해 보았다.

반응형

+ Recent posts