Hardware | LCD2004 를 arduino 로 컨트롤 해보기 - 2

|

이 글은, 먼저 LCD 20x4 를 처음 사용해 본 글의 후편입니다.


* Hardware | LCD2004 를 arduino 로 컨트롤 해보기 - 1

https://chocoball.tistory.com/entry/Hardware-LCD2004-arduino-control-1




1. 이론적 배경


LCD2004 및 HD44780 을 사용하는 LCD 에 대해서는 아래 웹사이트에서 거의 완벽하게 설명하고 있습니다.


* Arduino with HD44780 based Character LCDs

http://www.martyncurrey.com/arduino-with-hd44780-based-lcds/


위의 글은 전반적인 이야기 이고, 아래에 보이는 글 두 개는, 커스텀 글짜에 대한 좀 더 자세한 이야기 입니다.


* How to generate and display self made Custom characters on 16×2 lcd

https://www.engineersgarage.com/knowledge_share/making-custom-characters-on-16x2-lcd/


An internal ​CG-RAM(character generated ram) in which we can generate or place our custom character. CG-RAM size is 64 bytes. We can generate/place 8 characters of size 5×8 at a time in CG-RAM.


* Making and displaying Custom characters on lcd with Arduino Uno and 16×2 lcd

https://www.engineersgarage.com/arduino/making-custom-characters-on-lcd-using-arduino/


CG-RAM is the main component in making custom characters. CG stands for custom generated and RAM you all know random access memory. This CG-RAM stores our custom characters once we declare them in our code. I will come on it later. As you know once we write any type of code we need a memory to store it and a controller to run it. In the 16×2 lcd custom character case its same. We write code(arrays) of character’s which we want to display on lcd. Then we store them in a memory on lcd. In our case this memory is named as CG-RAM(Character generated RAM). 


CG-RAM size is 64 Bytes. You can create 8 characters at a time and load them in cg-ram. Each character occupies 8-bytes. Eight characters each of eight byte (8-characters * 8-Bytes) is equal to 8×8=64 Bytes. CG-RAM address in lcd memory starts from 0x40(Hexadecimal) or 64 in decimal.


위의 글들을 요약하자면 다음과 같습니다.


- HD44780 을 사용하는 LCD 에서는 커스텀 글자를 만들 수 있다.

- 64 Bytes 메모리 한계로, 커스컴 글자는 8개까지만 가능.

- 어드레스는, 0x00~0x07 로 접근 가능.




2. 한땀 한땀 만들어 보기


Custom Character 제작 시, 어떤 형식으로 메모리에 올리는지를 자동으로 소스까지 생성해 주는 페이지 입니다.

이 페이지에서, 8x5 형상에 원하는 모양을 마우스로 클릭해 보면, 대충 감을 잡을 수 있습니다.


* LCD Custom Character Generator

http://maxpromer.github.io/LCD-Character-Creator/


위의 페이지를 따라해 보면, Parallel 연결 + Binary 조합으로 소스 작성은 다음과 같이 됩니다.

대문자 B 로 시작하여, 각 cell 값에 따라 도식처럼 보여줍니다.


이 블로그의 마스코트인 초코볼을 본따 봤습니다. (도트의 한계로 거의 뭐...)



Hexadecimal 로 표현할 때에는, 5자리 2진수를 Hex 코드로 만들어 줍니다. 예를 들면 아래처럼요...


B10111 = 0x17


내 머리로 계산하지 않더라도 Hexadecimal 인 "0x..." 로 표현할 수 있습니다.

코드적으로 보면, 아무래도 Hex 를 사용하는 것이 코드상 더 간결하게 됩니다.



Arduino 연결을 I2C 로 바꾸어 주면,

include 구문과 LiquidCrystal_I2C 를 I2C 접근 주소와 함께 선언할 수 있도록 소스가 추가됩니다.



소스까지 생성해 주니, 이해하기 쉽습니다.

위의 페이지를 통하여, custom character 는 어떻게 해서 생성되는 지를 감각적으로 배워볼 수 있네요.




3. 끝판 왕


한땀 한땀이 아니라, 8개 생성 가능한 메모리를 한번에 만들 수 있는 소개 자료 입니다.


* Alphanumeric LCD HD44780 - big font, big digits generator (excel sheet)

https://www.avrfreaks.net/forum/alphanumeric-lcd-hd44780-big-font-big-digits-generator-excel-sheet



EXCEL 을 이용하여, 마우스 클릭만으로 폰트를 제작할 수 있게 되어 있습니다.


* dblachut/LCD-font-generator

https://github.com/dblachut/LCD-font-generator

LCD-font-generator.xlsm


Custom Character 는 8개까지 가능하니,

all 흑백, all 흰색을 제외하면 7개를 만들고, 추가적으로 하나 더 만들 수 있는 여유가 있습니다.




4. 메모리 들여다 보기


아래 장표는 HD44780 에 기억되어 있는 코드들 입니다.

왼쪽이 아시아 버전 (일본어 가다가나가 미리 들어가 있슴) 과, 오른쪽이 유럽 버전 (뭔가 더 다채로움) 입니다.



그럼, 실제로 커스텀 글짜를 입력해 보고, 메모리에 어떤 문자가 기억되어 있는지 알아 볼 수 있는 소스가 있습니다.

해당 소스를 사용하려면 아래처럼, 관련 Library 를 인스톨 하면 됩니다.


Tools > Manage Libraries... > LiquidCrystal I2C by Frank de Brabander



위의 library 를 인스톨 하면, 예제코드를 받을 수 있습니다.


File > Examples > LiquidCrystal I2C > CustomChars



소스는 다음과 같습니다.


//YWROBOT
//Compatible with the Arduino IDE 1.0
//Library version:1.1
#include "Wire.h"
#include "LiquidCrystal_I2C.h"

#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args)  write(args);
#else
#define printByte(args)  print(args,BYTE);
#endif

uint8_t bell[8]  = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4};
uint8_t note[8]  = {0x2,0x3,0x2,0xe,0x1e,0xc,0x0};
uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0};
uint8_t heart[8] = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0};
uint8_t duck[8]  = {0x0,0xc,0x1d,0xf,0xf,0x6,0x0};
uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0};
uint8_t retarrow[8] = {	0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
  
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

void setup() {
	lcd.init(); // initialize the lcd
	lcd.backlight();
	
	lcd.createChar(0, bell);
	lcd.createChar(1, note);
	lcd.createChar(2, clock);
	lcd.createChar(3, heart);
	lcd.createChar(4, duck);
	lcd.createChar(5, check);
	lcd.createChar(6, cross);
	lcd.createChar(7, retarrow);
	lcd.home();
	
	lcd.print("Hello world...");
	lcd.setCursor(0, 1);
	lcd.print(" i ");
	lcd.printByte(3);
	lcd.print(" arduinos!");
	delay(5000);
	displayKeyCodes();
}

// display all keycodes
void displayKeyCodes(void) {
	uint8_t i = 0;
	
	while (1) {
		lcd.clear();
		lcd.print("Codes 0x"); lcd.print(i, HEX);
		lcd.print("-0x"); lcd.print(i+16, HEX);
		lcd.setCursor(0, 1);
		for (int j=0; j<16; j++) {
			lcd.printByte(i+j);
		}
		
		i+=16;
		
		delay(4000);
	}
}

void loop() {

}


위의 소스를 arduino 에 올리고, LCD 20x4 와 I2C 연결해서 얻은 결과 입니다.



Custom Character 가 잘 올라가서 표현되었습니다.

0x00 부터 0xff 까지, 내부 글짜를 모두 훑는 결과는 다음과 같습니다.



확실히 아시아 버전임을 알 수 있네요.

버전이 다르지만, 구동은 같은 HD44780 칩 이므로, 해킹을 통하여 비어있는 address 에도 쓰기가 가능할 것 같은데,

복잡할 듯 하여 그만 두기로 합니다.




5. 큰 폰트


여기까지 해 보면, 큰 폰트 사용하여 시계 등을 표현하는 방법을 대강 생각해 낼 수 있습니다.

이 글의 원래 목적이었던, 아래 그림처럼 표현해 보고자 함이었으니, 이제 커스텀 폰트를 만들어 봅니다.



위의 숫자 들을 잘 살펴 보면, 몇 가지 모양을 조합하여 큰 폰트를 만들어 낸 것을 알 수 있습니다.



유니크한 영역을 살펴 보면, 아무것도 적혀있지 않은 모양까지 포함하면, 모두 8개가 됩니다.

이렇게 딱 맞게 만들다니...


열씸히 만들어 보려고 여러가지 검색하던 중, 좋은 소스를 발견합니다.


* 4-Line LCD Big Numbers

http://woodsgood.ca/projects/2015/02/27/4-line-lcd-big-numbers/



Software RTC 를 이용하여, 시간 데이터를 가져오고, custom / big font 로 시계를 표현해 주는 소스 입니다.


//************************************************************
//             BIG FONT (4-line) LCD CHARACTERS 
//                Adrian Jones, February 2015
//************************************************************

// Build 1
//   r1 150214 - initial build with glyphs and big font character table in program memory
//   r2 150227 - added RTC support
//************************************************************
#define build 1
#define revision 2
//************************************************************

#include "avr/pgmspace.h" // for memory storage in program space

#include "Wire.h" 
#include "LiquidCrystal_I2C.h" // library for I@C interface

LiquidCrystal_I2C lcd(0x27, 20, 4);

const char custom[][8] PROGMEM = {
	{0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0f, 0x1f}, // char 1: top left triangle
	{0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f}, // char 2: upper block
	{0x00, 0x00, 0x00, 0x00, 0x10, 0x1c, 0x1e, 0x1f}, // char 3: top right triangle
	{0x1f, 0x0f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00}, // char 4: bottom left triangle
	{0x1f, 0x1e, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00}, // char 5: bottom right triangle
	{0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00}, // char 6: bottom block
	{0x1f, 0x1f, 0x1e, 0x1c, 0x18, 0x18, 0x10, 0x10}  // char 7: full top right triangle
	                                                  // room for another one!
};

const char bn[][30] PROGMEM = { // organized by row
//         0               1               2               3               4              5               6                7               8               9
    {0x01,0x02,0x03, 0x01,0x02,0xFE, 0x01,0x02,0x03, 0x01,0x02,0x03, 0x02,0xFE,0x02, 0x02,0x02,0x02, 0x01,0x02,0x03, 0x02,0x02,0x02, 0x01,0x02,0x03, 0x01,0x02,0x03},
    {0xff,0xfe,0xff, 0xFE,0xFF,0xFE, 0x01,0x02,0xFF, 0xFE,0x02,0xFF, 0xFF,0x02,0xFF, 0xFF,0x02,0x02, 0xFF,0x02,0x03, 0xFE,0x01,0x07, 0xFF,0x02,0xFF, 0xFF,0xFE,0xFF},
    {0xff,0xfe,0xff, 0xFE,0xFF,0xFE, 0xFF,0xFE,0xFE, 0xFE,0xFE,0xFF, 0xFE,0xFE,0xFF, 0xFE,0xFE,0xFF, 0xFF,0xFE,0xFF, 0xFE,0xFF,0xFE, 0xFF,0xFE,0xFF, 0x04,0x06,0xFF},
    {0x04,0x06,0x05, 0xFE,0x06,0xFE, 0x06,0x06,0x06, 0x04,0x06,0x05, 0xFE,0xFE,0x06, 0x04,0x06,0x05, 0x04,0x06,0x05, 0xFE,0x06,0xFE, 0x04,0x06,0x05, 0xFE,0xFE,0x06}
};

byte col, row, nb=0, bc=0; // general
byte bb[8]; // byte buffer for reading from PROGMEM

#include "RTClib.h"
RTC_Millis RTC;
byte hr, mn, se, osec;

//*********************** INITIAL SETUP ***********************
void setup() {
	randomSeed(analogRead(0));
	RTC.begin(DateTime(__DATE__, __TIME__));
	
	lcd.init(); // initialize the LCD
	lcd.backlight();
	lcd.begin(20, 4);
	
	for (nb=0; nb<7; nb++ ) { // create 8 custom characters
		for (bc=0; bc<8; bc++) bb[bc]= pgm_read_byte( &custom[nb][bc] );
		lcd.createChar( nb+1, bb );
	}
	
	lcd.clear();
	lcd.setCursor(4, 0);
	lcd.print(F("4-Line LARGE"));
	lcd.setCursor(4, 1);
	lcd.print(F("TIME DISPLAY"));
	lcd.setCursor(5, 3);
	lcd.print(F("V"));
	lcd.print(build);
	lcd.print(F("."));
	lcd.print(revision);
	lcd.print(F(" "));
	lcd.print(freeRam());
	lcd.print(F("B"));
	printNum(random(0,10),0);
	printNum(random(0,10),17);
	delay(5000);
	lcd.clear();
}

//************************* MAIN LOOP ************************
void loop() {
	DateTime now = RTC.now();
	hr = now.hour();
	mn = now.minute();
	se = now.second();
	
	if(se != osec) {
		printNum(hr/10,0);
		printNum(hr%10,3);
		printColon(6);
		printNum(mn/10,7);
		printNum(mn%10,10);
		printColon(13);
		printNum(se/10,14);
		printNum(se%10,17);
		osec = se;
	}
	delay(50); // not strictly necessary
}

...


소스가 좀 길어서, SyntaxHighLighter 가 커버하지 못합니다. 따로 소스파일을 올립니다.


4line_LCD_clock.txt


참고로, 사이트에 올라와 있는 소스 그대로 사용할 수가 없습니다.

제작된지 시간도 좀 흘렀고, 사용한 library 가 조금 다른 것이 원인일 듯 하네요.

그래서 소스에서 몇가지 살짝 수정하였습니다.


	lcd.init(); // initialize the LCD
	lcd.backlight();
	lcd.begin(20, 4);


debug 시, 특히 가장 시간을 많이 잡아 먹은 부분은, 위의 LCD 초기화 부분이었습니다.

원 소스에는 위의 부분이 없거나, 실행 위치가 달라 그대로 사용하면 이상한 폰트들을 마구 뿌립니다.

특히, "lcd.init()" 는 custom character 를 메모리에 입히는 전단계에서 실행되어야 합니다.


추가로, Software RTC 라이브러리가 필요합니다.


Tools > Manage Libraries... > RTClib by Adafruit




모든 준비가 완료되면 arduino 에 업로드 합니다.



역시 삽질 끝에 맛보는 행복. 동영상도 올려봅니다.



참고로, 다른 custom character 들은 숫자들 끼리 공유가 되지만, 7 숫자의 중간 꺾이는 부분에 할당된 character 는 7에서만 사용됩니다.

위의 동영상에서 7 나오는 부분을 잘 보시면 됩니다.



7에서만 사용되는 문자 형상은 위와 같습니다. 공유되기 애매한 모양이죠?

메모리 한개가 여유 있으니, 소스 원작자가 여유를 부린 듯 합니다 :-)



사무실 책상 위에, laptop 옆에 위치 시켰더니, 가독성도 좋고 시간 보는 재미가 있습니다.

사진에는 잘 표현되지 못했지만, 검은색 글씨라 눈도 편안합니다.


모두 Happy Arduino~!


And