아두이노용이라고 딱 정해진 것은 아니지만 아두이노에 많이 쓰이는 디스플레이 출력장치에는 7 Segment LED 부터 LCD, OLED 등 꽤 많은 부품들이 쓰이고 있다. 이 중에서 과거 노키아 피처폰에 사용되었던 LCD 인 Nokia 5110 LCD 라는 디스플레이를 아두이노에 연결해보고 출력하는 방법을 알아보겠다. 노키아는 망했지만 과거의 영광을 간직한 LCD는 아직도 남아서 아두이노의 부품으로 쓰일 수 있다는 점이... 생각할수록 기분이 참 묘하다.
위의 핸드폰이 노키아 5110 핸드폰이다. 이 핸드폰에 쓰인 LCD만 사용해서 문자를 표시하거나 간단한 그래픽을 표시할 수 있는 것이다.
아두이노용으로 팔고 있는 Nokia 5110 LCD 이다. 아래 위에 8개의 단자가 있으며 2개의 8핀 커넥터가 제공된다. 아래나 위나 단자의 역할은 같다. 양 쪽 중에서 원하는 곳에 아두이노와 연결하면 된다.
LCD 모듈의 뒷면이다. 1번 부터 RST(RESET), CE(Chip Enable), DC(Data/Command Selection), DIN(Serial Input), SCLK(Clock Input), VCC(3.3V), LIGHT(Back Light), GND 가 있다.
나는 그냥 양 쪽 모두 납땜해 버렸다.
■ 노키아 5110 LCD 데이터시트
LCD 모듈은 모노크롬이며 48 x 84 픽셀의 해상도를 가진다. 문자나 간단한 그래픽을 나타내기에 적당한 해상도이다. LCD의 컨트롤러로는 PCD8544 라는 컨트롤러를 사용한다. 자세한 내용은 위의 데이터시트에 나와 있다. 개발 시 참고하면 되겠다. 작동은 3.3V 권장인데 5V 에서도 작동하긴 한다. 하지만 LCD 화면이 너무 진하게 나오거나 약간의 조정이 필요했다. 화면의 크기는 직접 자로 재보니 가로 3.6 x 세로 2.6 cm 였다.
■ 아두이노와의 연결
Nokia_5110_LCD.fzz다운로드
Arduino UNO Nokia 5110 LCD 7 CE 6 RST 5 DC 4 DIN 3 CLK 2 LIGHT 3.3V VCC GND GND
■ 소스
Nokia 5110 LCD 의 경우 라이브러리가 많이 개발되어 있다. 아래의 소스는 라이브러리를 사용하지 않은 소스이다. 기존의 라이브러리를 사용한다면 좀 더 간결하게 표현할 수 있을 것이다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 #define PIN_SCE 7#define PIN_RESET 6#define PIN_DC 5#define PIN_SDIN 4#define PIN_SCLK 3#define PIN_BL 2 //BackLight#define LCD_C LOW#define LCD_D HIGH#define LCD_X 84#define LCD_Y 48#define LCD_CMD 0int a = 0;static const byte ASCII[][5] ={{0x00, 0x00, 0x00, 0x00, 0x00} // 20,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 ",{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 ',{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 ),{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,,{0x08, 0x08, 0x08, 0x08, 0x08} // 2d -,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .,{0x20, 0x10, 0x08, 0x04, 0x02} // 2f /,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 30 0,{0x00, 0x42, 0x7f, 0x40, 0x00} // 31 1,{0x42, 0x61, 0x51, 0x49, 0x46} // 32 2,{0x21, 0x41, 0x45, 0x4b, 0x31} // 33 3,{0x18, 0x14, 0x12, 0x7f, 0x10} // 34 4,{0x27, 0x45, 0x45, 0x45, 0x39} // 35 5,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 36 6,{0x01, 0x71, 0x09, 0x05, 0x03} // 37 7,{0x36, 0x49, 0x49, 0x49, 0x36} // 38 8,{0x06, 0x49, 0x49, 0x29, 0x1e} // 39 9,{0x00, 0x36, 0x36, 0x00, 0x00} // 3a :,{0x00, 0x56, 0x36, 0x00, 0x00} // 3b ;,{0x08, 0x14, 0x22, 0x41, 0x00} // 3c <,{0x14, 0x14, 0x14, 0x14, 0x14} // 3d =,{0x00, 0x41, 0x22, 0x14, 0x08} // 3e >,{0x02, 0x01, 0x51, 0x09, 0x06} // 3f ?,{0x32, 0x49, 0x79, 0x41, 0x3e} // 40 @,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A,{0x7f, 0x49, 0x49, 0x49, 0x36} // 42 B,{0x3e, 0x41, 0x41, 0x41, 0x22} // 43 C,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 44 D,{0x7f, 0x49, 0x49, 0x49, 0x41} // 45 E,{0x7f, 0x09, 0x09, 0x09, 0x01} // 46 F,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 47 G,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H,{0x00, 0x41, 0x7f, 0x41, 0x00} // 49 I,{0x20, 0x40, 0x41, 0x3f, 0x01} // 4a J,{0x7f, 0x08, 0x14, 0x22, 0x41} // 4b K,{0x7f, 0x40, 0x40, 0x40, 0x40} // 4c L,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 4d M,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 4e N,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 4f O,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 51 Q,{0x7f, 0x09, 0x19, 0x29, 0x46} // 52 R,{0x46, 0x49, 0x49, 0x49, 0x31} // 53 S,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 55 U,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 56 V,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 57 W,{0x63, 0x14, 0x08, 0x14, 0x63} // 58 X,{0x07, 0x08, 0x70, 0x08, 0x07} // 59 Y,{0x61, 0x51, 0x49, 0x45, 0x43} // 5a Z,{0x00, 0x7f, 0x41, 0x41, 0x00} // 5b [,{0x02, 0x04, 0x08, 0x10, 0x20} // 5c ¥,{0x00, 0x41, 0x41, 0x7f, 0x00} // 5d ],{0x04, 0x02, 0x01, 0x02, 0x04} // 5e ^,{0x40, 0x40, 0x40, 0x40, 0x40} // 5f _,{0x00, 0x01, 0x02, 0x04, 0x00} // 60 `,{0x20, 0x54, 0x54, 0x54, 0x78} // 61 a,{0x7f, 0x48, 0x44, 0x44, 0x38} // 62 b,{0x38, 0x44, 0x44, 0x44, 0x20} // 63 c,{0x38, 0x44, 0x44, 0x48, 0x7f} // 64 d,{0x38, 0x54, 0x54, 0x54, 0x18} // 65 e,{0x08, 0x7e, 0x09, 0x01, 0x02} // 66 f,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 67 g,{0x7f, 0x08, 0x04, 0x04, 0x78} // 68 h,{0x00, 0x44, 0x7d, 0x40, 0x00} // 69 i,{0x20, 0x40, 0x44, 0x3d, 0x00} // 6a j,{0x7f, 0x10, 0x28, 0x44, 0x00} // 6b k,{0x00, 0x41, 0x7f, 0x40, 0x00} // 6c l,{0x7c, 0x04, 0x18, 0x04, 0x78} // 6d m,{0x7c, 0x08, 0x04, 0x04, 0x78} // 6e n,{0x38, 0x44, 0x44, 0x44, 0x38} // 6f o,{0x7c, 0x14, 0x14, 0x14, 0x08} // 70 p,{0x08, 0x14, 0x14, 0x18, 0x7c} // 71 q,{0x7c, 0x08, 0x04, 0x04, 0x08} // 72 r,{0x48, 0x54, 0x54, 0x54, 0x20} // 73 s,{0x04, 0x3f, 0x44, 0x40, 0x20} // 74 t,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 75 u,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 76 v,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 77 w,{0x44, 0x28, 0x10, 0x28, 0x44} // 78 x,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 79 y,{0x44, 0x64, 0x54, 0x4c, 0x44} // 7a z,{0x00, 0x08, 0x36, 0x41, 0x00} // 7b {,{0x00, 0x00, 0x7f, 0x00, 0x00} // 7c |,{0x00, 0x41, 0x36, 0x08, 0x00} // 7d },{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ←,{0x00, 0x06, 0x09, 0x09, 0x06} // 7f →};void LcdCharacter(char character){LcdWrite(LCD_D, 0x00);for (int index = 0; index < 5; index++){LcdWrite(LCD_D, ASCII[character - 0x20][index]);}LcdWrite(LCD_D, 0x00);}void LcdClear(void){for (int index = 0; index < LCD_X * LCD_Y / 8; index++){LcdWrite(LCD_D, 0x00);}}void LcdInitialise(void){pinMode(PIN_SCE, OUTPUT);pinMode(PIN_RESET, OUTPUT);pinMode(PIN_DC, OUTPUT);pinMode(PIN_SDIN, OUTPUT);pinMode(PIN_SCLK, OUTPUT);digitalWrite(PIN_RESET, LOW);delay(1);digitalWrite(PIN_RESET, HIGH);LcdWrite( LCD_CMD, 0x21 ); // LCD Extended Commands.LcdWrite( LCD_CMD, 0xB9 ); // Set LCD Vop (Contrast). //B0~B9LcdWrite( LCD_CMD, 0x04 ); // Set Temp coefficent. //0x04LcdWrite( LCD_CMD, 0x14 ); // LCD bias mode 1:48. //0x13LcdWrite( LCD_CMD, 0x0C ); // LCD in normal mode. 0x0d for inverseLcdWrite(LCD_C, 0x20);LcdWrite(LCD_C, 0x0C);}void LcdString(const char *characters){while (*characters){LcdCharacter(*characters++);}}void LcdWrite(byte dc, byte data){digitalWrite(PIN_DC, dc);digitalWrite(PIN_SCE, LOW);shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);digitalWrite(PIN_SCE, HIGH);}// gotoXY routine to position cursor// x - range: 0 to 84// y - range: 0 to 5void gotoXY(int x, int y){LcdWrite( 0, 0x80 | x); // Column.LcdWrite( 0, 0x40 | y); // Row.}void drawLine(void){unsigned char j;for(j=0; j<84; j++) // top{gotoXY (j,0);LcdWrite (1,0x01);}for(j=0; j<84; j++) //Bottom{gotoXY (j,5);LcdWrite (1,0x80);}for(j=0; j<6; j++) // Right{gotoXY (83,j);LcdWrite (1,0xff);}for(j=0; j<6; j++) // Left{gotoXY (0,j);LcdWrite (1,0xff);}}void setup(void){LcdInitialise();LcdClear();pinMode(PIN_BL,OUTPUT);digitalWrite(PIN_BL,HIGH); //HIGH = Turn Backlight OFF, LOW = Turn Backlight ON}void loop(void){int a,b;char Str[15];// Draw a Boxfor(b=1000; b>0; b--){drawLine();for(a=0; a<=5 ; a++){gotoXY(4,1);// Put text in BoxdigitalWrite(PIN_BL,LOW);LcdString ("TestDisplay");gotoXY(24,3);LcdCharacter('H');LcdCharacter('E');LcdCharacter('L');LcdCharacter('L');LcdCharacter('O');LcdCharacter(' ');LcdCharacter('=');// Draw + at this positiongotoXY(10,3);LcdCharacter('=');delay(2000);gotoXY(24,3);LcdCharacter('W');LcdCharacter('O');LcdCharacter('R');LcdCharacter('L');LcdCharacter('D');LcdCharacter(' ');LcdCharacter('-');// Draw - at this positiongotoXY(10,3);LcdCharacter('-');delay(2000);digitalWrite(PIN_BL,HIGH);gotoXY(24,3);LcdCharacter('D');LcdCharacter('I');LcdCharacter('Y');LcdCharacter('!');LcdCharacter('@');LcdCharacter('$');LcdCharacter('&');// Draw - at this positiongotoXY(10,3);LcdCharacter('#');delay(2000);}}}cs
만약 LCD의 콘트라스트가 잘 맞지 않는다면 151행의 값을 적절하게 조절하면 된다. 나의 경우 처음 테스트 시 LCD의 문자가 잘 보이지 않다가 (초기값 0xB0) 값을 0xB9 로 조절하니 진하게 잘 표현이 되었다.
LCD의 백라이트의 경우 LIGHT 단자를 GND에 연결해 버리면 코드에서 제어할 필요 없이 상시 백라이트가 ON 상태로 유지된다. 백라이트 컨트롤을 원하면 위와 같이 아두이노 디지털 핀에 연결하고 digitalWrite 를 HIGH 하면 OFF, LOW 하면 ON 된다.
이 LCD는 OLED LCD보다 저렴하고 크기도 커서 잘 사용하면 저렴하고 좋은 아두이노의 출력장치로 사용할 수 있을 것 같다.
'아두이노' 카테고리의 다른 글
| 아두이노를 좋아하는 사람들의 모임 소개 (0) | 2017.07.20 |
|---|---|
| [아두이노] 노키아 5110 LCD (Nokia 5110 LCD) - 그래픽 라이브러리 (4) | 2017.04.20 |
| [아두이노] SSR (Solid State Relay) 의 사용 (6) | 2017.01.24 |
| [아두이노] MQ-3 알코올센서 모듈의 이용 (3) | 2017.01.06 |
| [아두이노] 3색 RGB LED를 이용한 무드등 만들기 (7) | 2016.12.28 |