|
|
# LCD
|
|
|
|
|
|
LCD란 Liquid Crystal Display로 액정 표시장치 입니다.
|
|
|
LCD의 경우 후면에 백라이트를 두고, 전면에 액정을 두어 액정이 전기 신호에 따라 빛을 차단하거나 통과시키는 방식으로 빛을 냅니다.
|
|
|
소비전력이 낮아 휴대용 기기에 사용하기 좋습니다.
|
|
|
|
|
|
단점은 선명한 표시를 위해서 백 라이트가 필요하고 한글이나 특수문자른 잘 표현이 되지 않습니다.
|
|
|
|
|
|
![http://study.zumst.com/upload/00-T33-00-42-06/%EC%BD%98%ED%85%90%EC%B8%A0%20%EC%88%98%EC%A0%95%20%EC%97%94%ED%8A%B8%EB%A6%AC%20224.jpg](http://study.zumst.com/upload/00-T33-00-42-06/%EC%BD%98%ED%85%90%EC%B8%A0%20%EC%88%98%EC%A0%95%20%EC%97%94%ED%8A%B8%EB%A6%AC%20224.jpg)
|
|
|
|
|
|
## 1602 I2C LCD
|
|
|
|
|
|
1602 LCD란 세로 16칸, 가로 2칸으로 구성된 액정 표시 장치입니다.
|
|
|
1602 LCD는 연결을 위해서 16개의 핀으로 구성되어 있습니다.
|
|
|
|
|
|
![https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/88ed28145541c79075a89e6416e55b25.jpg](https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/88ed28145541c79075a89e6416e55b25.jpg)
|
|
|
|
|
|
![https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/fd70dde2c6060f61bb4789bd32b2b7c7.jpg](https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/fd70dde2c6060f61bb4789bd32b2b7c7.jpg)
|
|
|
|
|
|
## I2C 인터페이스 (Inter-Integrated Circuit Interface)
|
|
|
|
|
|
아두이노 우노에는 14개의 디지털 입출력 핀이 14개, 아날로그 입력 핀이 6개로 총 20개의 핀이 있습니다.
|
|
|
우노 보드에 1602 LCD와 함께 다른 부품을 사용하고자 하면, 핀의 연결 수가 많아져 연결 포트가 충분하지 않을 수 있습니다.
|
|
|
이러한 문제를 해결하기 위해서 사용하는 것이 I2C 인터페이스 모듈입니다.
|
|
|
|
|
|
I2C는 풀업 저항이 연결된 SCL(Serial Clock)핀과 SDA(Serial Data)핀을 사용하여 한 방향으로 1:N = 마스터(아두이노):다수 슬레이브(센서 모듈)를 연결할 수 있는 근거리 통신 인터페이스 입니다.
|
|
|
|
|
|
![https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/1b794f484d0b0264743aae35e21ffc1c.jpg](https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/1b794f484d0b0264743aae35e21ffc1c.jpg)
|
|
|
|
|
|
![https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/d0a8ebd261096a3b47dc99446cd0cecf.jpg](https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/d0a8ebd261096a3b47dc99446cd0cecf.jpg)
|
|
|
|
|
|
아두이노는 I2C통신 핀으로 SDA, SCL핀을 사용하거나 아날로그 A4, A5 핀을 SDA,SCL 각각의 기능으로 사용할 수 있습니다.
|
|
|
|
|
|
단,아두이노 우노 보드에서는 I2C 통신 인터페이스와 A4,A5 핀을 동시에 사용할 수 없습니다.
|
|
|
|
|
|
## 관련 라이브러리
|
|
|
|
|
|
I2C 통신을 하기위해서는 Wire 라이브러리를 사용해야합니다.
|
|
|
Wire Library에 대한 참고 글들은 이러 합니다.
|
|
|
1. [https://m.blog.naver.com/PostView.nhn?blogId=yuyyulee&logNo=220325361752&proxyReferer=https%3A%2F%2Fwww.google.com%2F](https://m.blog.naver.com/PostView.nhn?blogId=yuyyulee&logNo=220325361752&proxyReferer=https%3A%2F%2Fwww.google.com%2F)
|
|
|
2. [https://www.arduino.cc/en/Reference/Wire](https://www.arduino.cc/en/Reference/Wire)
|
|
|
|
|
|
LCD를 조작하기 위해서 사용하는 라이브러리에는 LiquidCrystal과 LiquidCrystal_I2C 두가지가 일반적으로 많이 사용됩니다.
|
|
|
이 둘의 차이점은 LiquidCrystal은 LCD의 조작을 위해 8개의 핀을 모두 사용하지만, LiquidCrystal의 경우 I2C 모듈에 연결된 핀 2가지를 활용하는데 있습니다.
|
|
|
LiquidCrystal_I2C 라이브러리는 LiquidCrystal 라이브러리에서 할 수 있는 것들을 모두 사용할 수 있습니다.
|
|
|
각각의 라이브러리에 대한 자세한 설명은 다음 글들을 참고하시기 바랍니다.
|
|
|
|
|
|
1. LquidCrystal : [https://www.arduino.cc/en/Reference/LiquidCrystal](https://www.arduino.cc/en/Reference/LiquidCrystal)
|
|
|
2. LiquidCrystal_I2C : [https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/LiquidCrystal_I2C.h](https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/LiquidCrystal_I2C.h)
|
|
|
3. 차이점 : [https://forum.arduino.cc/index.php?topic=309933.0](https://forum.arduino.cc/index.php?topic=309933.0)
|
|
|
|
|
|
진행하는 예제에서는 I2C 모듈을 사용하기에 LiquidCrystal_I2C 라이브러리를 활용하겠습니다.
|
|
|
|
|
|
![https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/773c05d62b4859f4c94ab19d8c2c1a66.jpg](https://storage.googleapis.com/cr-resource/forum/482c743ad6ddf00ee50331306178d311/773c05d62b4859f4c94ab19d8c2c1a66.jpg)
|
|
|
|
|
|
다음 코드는 LCD 사용에 관한 예시 코드 입니다.
|
|
|
|
|
|
>1.LCD 주소 스캐닝
|
|
|
>
|
|
|
> I2C LCD 기본 주소는 0x27(16진수 값) 이지만, 간혹 모듈 사용 시 오류가 생길 경우 주소를 확인해야합니다.
|
|
|
> 사용하고자 하는 I2C LCD 인터페이스 모듈의 주소를 알아내기 위해서 주소 스캐닝을 먼저 하는 것이 좋습니다.
|
|
|
|
|
|
```c++
|
|
|
#include <Wire.h> // Wire 라이브러리는 I2C(혹은 TWI) 기기와 통신 할 수 있게 하는 라이브러리입니다.
|
|
|
|
|
|
void setup() {
|
|
|
Wire.begin(); // Master와 Slave와 같이 Wire Library와 I2C bus를 연결합니다.
|
|
|
// beign(address)에서 address 지정을 하지 않았으므로 Master 모드로 설정됩니다.
|
|
|
// Slave 모드 일경우 자신의 주소 값(address)을 지정합니다.
|
|
|
Serial.begin(9600); // Serial 통신을 속도 9600으로 시작합니다.
|
|
|
while(!Serial); // Serial 모니터를 기다립니다.
|
|
|
Serial.println("I2C Address Scanner\n");
|
|
|
}
|
|
|
|
|
|
void loop() {
|
|
|
byte error,address; // 데이터를 전송할 Slave의 주소 address 변수, error의 종류를 나타내 줄 error 변수
|
|
|
int nDevices; // 연결된 장치의 수를 저장할 변수
|
|
|
|
|
|
Serial.println("Scanning...");
|
|
|
nDevices = 0;
|
|
|
|
|
|
for(address = 1; address<127; address++){ // 주소는 7비트의 데이터로, 127을 넘을 수 없습니다.
|
|
|
Wire.beginTransmission(address); // 마스터에서 전송을 시작하기 위해서 슬레이브의 주소 값을 지정합니다.
|
|
|
error = Wire.endTransmission(); // 데이터 버퍼에 저장된 데이터를 전송합니다. 마스터 모드에서만 사용합니다.
|
|
|
// 전송이 완료된 후 전송의 성공 여부를 byte형의 값으로 반환 합니다.
|
|
|
|
|
|
if (error == 0){ // 전송이 성공한 경우 입니다.
|
|
|
Serial.print("I2C device found at 0x");
|
|
|
if(address < 16){
|
|
|
Serial.print("0"); // 주소 값을 16진수로 표현하기에, 16보다 낮은 수가 오면 앞자리에 0을 붙입니다.
|
|
|
}
|
|
|
Serial.print(address,HEX);
|
|
|
Serial.println(" !");
|
|
|
|
|
|
nDevices++; // 연결된 장치의 수를 증가 시킵니다.
|
|
|
|
|
|
}else if(error == 4){ // 알 수 없는 오류가 발생하는 경우입니다.
|
|
|
Serial.print("Unknown error at address 0x");
|
|
|
if(address < 16){
|
|
|
Serial.print("0");
|
|
|
}
|
|
|
Serial.println(address,HEX);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(nDevices == 0){ // nDevices 가 0이면, 연결된 장치가 없는 것이고 0이 아니면 연결되어 있음을 나타냅니다.
|
|
|
Serial.println("No I2C devices found\n");
|
|
|
}else{
|
|
|
Serial.println("done\n");
|
|
|
}
|
|
|
|
|
|
delay(5000); // 다음 스캔까지 5초간 지연 시간을 갖습니다.
|
|
|
}
|
|
|
```
|
|
|
>2.Display Scroll
|
|
|
>
|
|
|
> LCD화면에 문자를 출력하고, 자동 스크롤 기능과, 사용자 지정 스크롤 기능에 대한 코드입니다.
|
|
|
|
|
|
```c++
|
|
|
#include<Wire.h>
|
|
|
#include<LiquidCrystal_I2C.h>
|
|
|
|
|
|
LiquidCrystal_I2C lcd(0x27,16,2); // I2C 모듈에 연결된 LCD에 대해서 초기 설정을 합니다.
|
|
|
// I2C 모듈의 주소는 0x27이며, 한줄에 16칸이고 2줄인 LCD를 사용합니다.
|
|
|
|
|
|
void setup() {
|
|
|
lcd.init(); // LCD를 초기화 해줍니다. 해당 코드 미입력시, LCD가 동작하지 않습니다.
|
|
|
lcd.backlight(); // Backlight를 켜줍니다.
|
|
|
|
|
|
}
|
|
|
|
|
|
void loop() {
|
|
|
lcd.setCursor(0,0); // LCD의 첫번째 줄, 첫번째 칸에 입력지점을 설정합니다.
|
|
|
|
|
|
// LCD의 첫번째 줄에 0~9까지 출력합니다.
|
|
|
for(int num = 0; num < 10; num++){
|
|
|
lcd.print(num); // LCD에 num을 출력합니다. print(data)는 data를 문자 그대로 출력합니다.
|
|
|
delay(500);
|
|
|
}
|
|
|
|
|
|
lcd.setCursor(16,1); // LCD의 두번째 줄, 마지막 칸에 입력지점을 설정합니다.
|
|
|
|
|
|
lcd.autoscroll(); // LCD의 자동 스크롤 기능을 킵니다.
|
|
|
// 이는 이전에 출력된 문자들을 모두 한칸씩 밀어냅니다. 방향은 현재의 text direction을 따릅니다.
|
|
|
// 기본설정은 왼쪽에서 오른쪽으로 텍스트가 써지기에 scroll방향은 왼쪽이됩니다.
|
|
|
// 만약 text direction이 오른쪽에서 왼쪽이면, scroll 방향은 오른쪽이 됩니다.
|
|
|
//LCD의 두번째 줄의 마지막에서 0~4까지 출력합니다.
|
|
|
for(int num = 0; num < 5; num++){
|
|
|
lcd.print(num);
|
|
|
delay(500);
|
|
|
}
|
|
|
|
|
|
lcd.noAutoscroll(); // LCD의 자동 스크롤 기능을 끕니다.
|
|
|
|
|
|
//출력된 문자를 한칸씩 오른쪽으로 움직입니다.
|
|
|
for(int positionCounter = 0; positionCounter < 4 ; positionCounter++){
|
|
|
lcd.scrollDisplayRight(); // 화면의 텍스트들을 모두 오른쪽으로 한칸 이동합니다.
|
|
|
delay(500); // 지연시간을 0.5초 갖습니다.
|
|
|
}
|
|
|
|
|
|
//출력된 문자를 한칸씩 왼쪽으로 6번 움직입니다.
|
|
|
for(int positionCounter = 0; positionCounter < 6 ; positionCounter++){
|
|
|
lcd.scrollDisplayLeft(); // 화면의 텍스트들을 모두 왼쪽으로 한칸 이동합니다.
|
|
|
delay(500); // 지연시간을 0.5초 갖습니다.
|
|
|
}
|
|
|
|
|
|
for(int positionCounter = 0; positionCounter < 4 ; positionCounter++){
|
|
|
lcd.scrollDisplayRight(); // 화면의 텍스트들을 모두 오른쪽으로 한칸 이동합니다.
|
|
|
delay(500); // 지연시간을 0.5초 갖습니다.
|
|
|
}
|
|
|
|
|
|
for(int counter = 0 ; counter < 2; counter++){
|
|
|
lcd.noDisplay(); // LCD 화면을 끕니다. 단, 현재 보이는 문자들의 손실은 없습니다.
|
|
|
delay(1000);
|
|
|
lcd.display(); // noDisplay()를 통해 저장한 문자들의 정보를 가지고 LCD 화면을 킵니다.
|
|
|
delay(1000);
|
|
|
}
|
|
|
|
|
|
lcd.clear(); // LCD의 화면에 보이는 것을 없애고, cussor를 왼쪽 상단에 위치시킵니다.
|
|
|
}
|
|
|
```
|
|
|
|
|
|
>scroll을 통해 텍스트가 이동하는 걸 볼 수 있었습니다.
|
|
|
>scroll을 한 방향으로 계속 진행(기본 방향인 왼쪽으로 진행)시키면 어떨까 싶어 48번을 한방향으로 움직였을 때, 문자열이 처음의 모습으로 돌아온 뒤 추가로 왼쪽으로 몇칸 더 움직인 것을 확인 할 수 있었습니다.
|
|
|
>그래서 몇번을 더 움직이면 처음 상태로 돌아올 수 있는지 확인 해보았습니다.
|
|
|
>그 결과 40번을 움직이면 처음 상태로 돌아오는 것을 확인 했습니다.
|
|
|
>
|
|
|
>결론적으로 1602 LCD 기준, LCD가 출력하는 2줄 16칸 이외에도 LCD의 내부적 확장 화면은 총 2줄 40칸의 순환임을 알 수 있었습니다.
|
|
|
|
|
|
>3.Text Direction Change
|
|
|
>
|
|
|
> LCD에 문자를 출력할 때 중간 중간 출력 방향을 바꿔 주었습니다.
|
|
|
|
|
|
```C++
|
|
|
#include<Wire.h>
|
|
|
#include<LiquidCrystal_I2C.h>
|
|
|
|
|
|
LiquidCrystal_I2C lcd(0x27,16,2); // I2C모듈의 주소인 0x27을 이용해 LCD의 초기 설정을 합니다.
|
|
|
|
|
|
char thisChar = 'a'; // LCD에 현재 출력할 문자에 대한 변수를 생성합니다.
|
|
|
|
|
|
void setup() {
|
|
|
lcd.init(); // LCD를 초기화 해줍니다.
|
|
|
lcd.backlight(); // LCD의 BackLight를 킵니다.
|
|
|
}
|
|
|
|
|
|
void loop() {
|
|
|
if(thisChar == 'f'){ // 현재 출력할 알파벳이 'e'이면, Text Direction을 (오른쪽→왼쪽)으로 바꿉니다.
|
|
|
lcd.rightToLeft();
|
|
|
}
|
|
|
if(thisChar == 'j'){ // 현재 출력할 알파벳이 'j'dlaus, LCD의 출력 위치를 두번 째줄 마지막칸으로 바꿉니다.
|
|
|
lcd.setCursor(15,1);
|
|
|
}
|
|
|
if(thisChar == 's'){ // 현재 출력할 알파벳이 's'이면, Text Direction을 (왼쪽→오른쪽)으로 바꿉니다.
|
|
|
lcd.leftToRight();
|
|
|
}
|
|
|
if(thisChar > 'z'){ // 현재 출력할 알파벳이 'z'를 넘어가면, Cursor를 home(왼쪽 최상단)으로 옮기고, thisChar를 a로 바꿉니다.
|
|
|
lcd.home();
|
|
|
thisChar = 'a';
|
|
|
}
|
|
|
|
|
|
lcd.write(thisChar); // lcd에 알파벳을 출력합니다. Write(data)는 data를 ASCII Code에 해당하는 문자로 바꾸어 출력합니다.
|
|
|
|
|
|
|
|
|
delay(1000); // 1초의 지연시간을 갖고 출력합니다.
|
|
|
|
|
|
thisChar++; // 현재 출력할 알파벳을 하나 증가시킵니다.
|
|
|
}
|
|
|
```
|
|
|
|
|
|
>4.Custom Character & Serial Display
|
|
|
>
|
|
|
> Serial 통신으로 입력한 문자와 Custom문자를 합쳐서 출력하는 코드입니다.
|
|
|
|
|
|
```C++
|
|
|
#include<Wire.h>
|
|
|
#include<LiquidCrystal_I2C.h>
|
|
|
|
|
|
LiquidCrystal_I2C lcd(0x27,16,2); //I2C모듈의 주소인 0x27을 통해 LCD 초기 설정
|
|
|
|
|
|
// Custom 문자 정의
|
|
|
byte smiley[8] ={
|
|
|
0b00000,
|
|
|
0b00000,
|
|
|
0b01010,
|
|
|
0b00000,
|
|
|
0b00000,
|
|
|
0b10001,
|
|
|
0b01110,
|
|
|
0b00000
|
|
|
};
|
|
|
|
|
|
byte sady[8] ={
|
|
|
0b00000,
|
|
|
0b00000,
|
|
|
0b01010,
|
|
|
0b00000,
|
|
|
0b00000,
|
|
|
0b01110,
|
|
|
0b10001,
|
|
|
0b00000
|
|
|
};
|
|
|
|
|
|
String lastString = "LCD ON"; // 최근에 입력 받은 메세지
|
|
|
String nowString = "Just Do It"; // 현재 입력된 메세지
|
|
|
|
|
|
void setup() {
|
|
|
lcd.init(); // LCD 초기화
|
|
|
lcd.backlight(); // LCD의 Backlight를 킵니다.
|
|
|
|
|
|
lcd.createChar(0,smiley); // 바이트 숫자 0에 새로운 문자 smiley를 저장합니다.
|
|
|
lcd.createChar(1,sady); // 바이트 숫자 1에 새로운 문자 sady를 저장합니다.
|
|
|
// createChar(num,data)num에는 byte숫자 0~7까지 총 8개의 문자를 정의할 수 있고, data는 byte 배열의 이름입니다.
|
|
|
Serial.begin(9600); // 시리얼 속도 9600으로 통신을 시작합니다.
|
|
|
|
|
|
lcd.setCursor(0,0); // (0,0)위치로 출력 위치 설정
|
|
|
lcd.print(lastString); // 이전 메세지를 출력
|
|
|
lcd.write(byte(1)); // 이전 메세지 뒤에 sady를 출력, byte숫자 1에 저장된 문자 출력
|
|
|
|
|
|
lcd.setCursor(0,1); // (0,1)위치로 출력위치 설정
|
|
|
lcd.print(nowString); // 현재 입력 받은 메세지 출력
|
|
|
lcd.write((byte)0); // 현재 메세지 뒤에 smiley출력, byte숫자 0에 저장된 문자 출력
|
|
|
}
|
|
|
|
|
|
void loop() {
|
|
|
if(Serial.available()){ // Serial Communication이 도착하면 실행
|
|
|
// Serial.available은 Serial Receive Buffer에 저장된 수신 데이터들의 바이트 수를 반환 합니다.
|
|
|
delay(100); // 전체 메세지가 도착할 때까지 지연
|
|
|
|
|
|
lastString = nowString; // 이전의 현재 메세지를 이전 메세지로 저장
|
|
|
nowString = Serial.readString(); // Serial에 입력한 메세지를 현재 메세지로 저장
|
|
|
Serial.println(nowString); // Serial Monitor에 입력한 메세지를 출력합니다.
|
|
|
|
|
|
lcd.clear(); // lcd화면 지우기
|
|
|
|
|
|
lcd.setCursor(0,0); // (0,0)위치로 출력 위치 설정
|
|
|
lcd.print(lastString); // 이전 메세지를 출력
|
|
|
lcd.write(byte(1)); // 이전 메세지 뒤에 sady를 출력, byte숫자 1에 저장된 문자 출력
|
|
|
|
|
|
lcd.setCursor(0,1); // (0,1)위치로 출력위치 설정
|
|
|
lcd.print(nowString); // 현재 입력 받은 메세지 출력
|
|
|
lcd.write((byte)0); // 현재 메세지 뒤에 smiley출력, byte숫자 0에 저장된 문자 출력
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|