1602(16x2) 또는 2004(20x4) 크기의 CLCD(Character LCD)는 텍스트 LCD(Text LCD)라고로 부르는데요. 최소로 제어해야 하는 핀이 6개여서, CLCD를 제어하려면 MCU의 핀이 최소한 6개가 필요합니다. 그런데 SPI 방식이나 I2C 방식의 port extender IC를 사용하면 각각 4개, 2개의 MCU 핀으로도 제어할 수 있어서, 제어핀의 갯수가 줄어드는 이점이 있어요. 그래서 이전 글에서 PCF8574 port extender IC가 있는 확장보드를 CLCD에 납땜으로 연결한 뒤, STM32F746 MCU로 구동했습니다.

 

이전 글: PCF8574 I/O 확장보드를 사용한 CLCD(Text LCD) 구동 (STM32F746, I2C)

 

 

 

이 글에서는 I2C 방식의 CLCD를 아두이노 레오나르도로 제어하기 위해, STM32F746에 올렸던 코드를 아두이노용으로 살짝 바꿨습니다. 같은 확장보드가 연결된 CLCD를 제어해서, 제어논리를 똑같이 쓸 수 있어서 코드의 논리적인 부분은 바꿀 필요가 없었습니다. ST사의 HAL 함수를 아두이노의 해당 함수로 바꾸고, 8자리 I2C 주소를 7자리 I2C 주소로 바꾸고, 그리고 CLCD에 나타낼 문자열을 바꾸는 것이 거의 전부였어요. 한 MCU에서 완성시킨 코드를 다른 MCU에도 쉽게 변형해서 사용할 수 있었습니다. 여기서부터는 CLCD 대신 텍스트 LCD(text LCD)라고 부르겠습니다.

 

 

 

1. 동작 동영상

 

PCF8574 확장보드의 VCC, GND, SCL, SDA 핀은 각각 아두이노 레오나르도의 5V, GND, SCL, SDA 핀에 연결했습니다. 그래서 PCF8574는 아두이노로부터 I2C 신호를 SCL, SDA 버스를 통해 받고, 5V 전원도 공급받아 텍스트 LCD에 전원을 공급합니다. PCF8574와 아두이노 레오나르도의 USB 케이블은 스위치가 있는 USB 아답터에 연결했습니다. 동영상의 2초 정도에 스위치를 눌러 아두이노 레오나르도에 전원을 공급하면, 텍스트 LCD가 켜지고 조명이 깜박이는 것을 볼 수 있어요. STM32F746으로 텍스트 LCD를 구동했을 때와 똑같이 동작시켰습니다.

 

 

  •  

 

PCF8574 I2C 확장보드로 CLCD, Text(텍스트) LCD 구동 (아두이노)

재생 수542

 

 

 

 

 

 

 

 

  

화질 선택 옵션1080p

 

 

 

 







2. PCF8574 I/O 확장보드와 회로도

 

아래 사진은 같은 PCF8574 모듈이 부착된 텍스트 LCD를 제어했던 이전 글에서 가져왔습니다. 위 동영상의 텍스트 LCD도 PCF8574 모듈이 사진처럼 연결되어 있어요. 모듈의 IC는 PCF8574 의 여러 시리즈 중 PCF8574T 이고요. 제가 사용한 코드는 STM32F746 MCU로 동작시키면서 검증이 되어서, 프로브가 연결된 사진과 다르게 이 글에서는 로직 아날라이저로 신호를 측정하지 않았습니다.






PCF8574 보드의 회로도 역시 이전 글에서 가져왔습니다. PCF8574를 사용한 확장보드는 여러 종류가 있어서, PCF8574와 텍스트 LCD가 어떻게 연결되어 있는지 회로도를 잘 봐야해요. 저 아래에 나오는 코드의 함수는 텍스트 LCD의 D[7:4]핀이 PCF8574의 P[3:0]핀에 연결된 경우 그대로 사용할 수 있습니다. D[7:4]핀이 P[7:4]에 연결된 경우는 함수를 수정해야 CLCD를 구동할 수 있어요. 어떤 확장보드는 텍스트 LCD의 A핀이 VCC에 연결되어 백라이트가 항상 켜지는 경우도 있는데, 이 경우 LCD의 백라이트 on/off 제어는 안됩니다. A[2:0]핀의 납땜상태는 GND에 연결된 상태로 그대로 놔둬서, PCF8574의 I2C 주소는 이전글과 똑같이 0x20 입니다. I2C 버스로 PCF8574의 주소와 함께 write 비트를 전송하고 나면, 그 뒤에 8비트 값이 전송될때마다 PCF8574의 P[7:0]출력상태가 바뀝니다. 8비트 값이 그대로 P[7:0]핀의 출력상태가 되어, 텍스트 LCD를 I2C 신호로 제어할 수 있어요. 자세한 내용은 PCF8574의 데이터시트를 보면 알 수 있습니다.








3. HD44780의 명령어와 DDRAM 주소

 

아래에 표로 설명된 명령어는 텍스트 LCD의 구동 IC인 HD44780의 데이터시트에 나옵니다. 텍스트 LCD의 E핀에 하강엣지가 입력될 때, 다른 핀의 상태에 따라 다른 명령어가 입력됩니다. 아두이노가 아래 코드를 통해 텍스트 LCD에 입력하는 명령어는 이 표를 보고 해석하면 돼요. 빨간 밑줄로 표시된 명령어는 DDRAM의 주소를 텍스트 LCD에 입력합니다.






1602(16x2) 크기의 텍스트 LCD의 위치에 따른 DDRAM의 주소는 아래와 같습니다. 입력되는 DB7(D7) 핀의 상태가 high여서 Set DDRAM address 명령어가 LCD에 입력될 때, 8비트 모드이면 표처럼 DB[6:0] 또는 D[6:0] 핀에 따라 주소가 결정돼요. 4비트 모드이면 주소가 D[7:4]핀으로 두번 전송됩니다. DDRAM 주소는 바로 다음에 문자를 출력할 위치를 가리키고, 문자가 한개씩 출력될때마다 1씩 증가해서 다음 위치를 가리킵니다. 그래서 LCD_String( ) 함수에 문자열을 입력하면, 문자열의 문자가 바로 옆 위치로 순서대로 출력됩니다. 다른 글에서 사용된 2004(20x4) 크기의 텍스트 LCD는 4줄로 구성되어 있는데요. 눈으로는 4줄이지만, 제어는 40x2 크기의 2줄 형태로 해야해요. HD44780으로 구동되는 텍스트 LCD는 1줄 또는 2줄 모드로 제어해야 하고, 4줄 모드의 제어방식은 없습니다.

 






4. 아두이노에 올린 코드

 

텍스트 LCD를 동작시키기 위해 아두이노에 올린 코드는 아래와 같습니다. I2C 방식으로 동작하는 PCF8574 IC를 통해 텍스트 LCD를 제어하기 때문에, I2C 라이브러리가 있는 Wire.h 파일을 include 했습니다. 제가 LCD 제어를 위해 직접 작성한 함수를 사용하기 위해, 많은 사람들이 사용하는 LiquidCrystal_I2C.h 파일은 include하지 않았습니다. Initialize_LCD( ) 함수는 텍스트 LCD를 초기화하기 위해 필요한데, HD44780 데이터시트에 나온 초기화 과정대로 함수의 코드를 작성했습니다. LCD_string( ) 함수의 주소를 입력하는 부분에 0x80을 더한 이유는, 위 표처럼 DDRAM의 주소를 설정하는 명령어가 0x80으로 시작하기 때문입니다. 아래 코드에 대한 더 자세한 설명은 주석에서 볼 수 있어요.

 

#include "Wire.h"  // I2C library

 

uint8_t I2C_addr_PCF8574 = 0x20 // I2C address of PCF8574

 

void I2C_LCD_command_8(unsigned char command); // 8-bit command to text LCD

void I2C_LCD_command(unsigned char command);   // 4-bit command to text LCD

void I2C_LCD_data(unsigned char data);         // Transfer 1 character to text LCD

void LCD_string(unsigned char command, char *string);  // Transfer string to text LCD

void Initialize_LCD(void);  // Initialize text LCD

 

 

 

void setup()

{

    char str0[] = "PCF8574 I2C CLCD";

    char str1[] = "Arduino Leonardo";

 

    Wire.begin(); // Initialize I2C bus

    delay(100);

    Initialize_LCD(); // Initialize Text LCD

 

    // 0x80: Set DDRAM address instruction

    LCD_string(0x80, str0); // 0x80: the 1st position in the 1st row

    LCD_string(0x80 + 0x40, str1); // 0x80 + 0x40: the 1st position in the 2nd row

}

 

 

 

void loop()

{

    uint8_t Backlight[] = {0x80, 0x00}; // off, on

    delay(500);

 

    // LCD backlight off

    Wire.beginTransmission(I2C_addr_PCF8574); ); // Send address to PCF8574

    Wire.write(Backlight[0]); // Transfer 0x80 signal (BJT off) to text LCD

    Wire.endTransmission();   // Transfer I2C stop signal to PCF8574

 

    delay(500);

 

    // LCD backlight on

    Wire.beginTransmission(I2C_addr_PCF8574); // Send address to PCF8574

    Wire.write(Backlight[1]); // Transfer 0x00 signal (BJT on) to text LCD

    Wire.endTransmission();   // Transfer I2C stop signal to PCF8574

}

 

 

 

void I2C_LCD_command_8(unsigned char command) // write a command(instruction) to text LCD

{

    //P0: D4  P1: D5  P2: D6  P3: D7

    //P4: E   P5: RW  P6: RS  P7: BJT base

 

    uint8_t T_buf[2]; // transmit buffer

 

    T_buf[0] = (command >> 4) | 0x10; // high 4 bit, E = 0, RS = 0, base = low (Backlight on)

    T_buf[1] = T_buf[0] & 0xEF;       // E = 0

 

    Wire.beginTransmission(I2C_addr_PCF8574); // Send address to PCF8574

    Wire.write(T_buf[0]);   // Transfer buffer to text LCD via PCF8574

    Wire.write(T_buf[1]);

    Wire.endTransmission(); // Transfer I2C stop signal to PCF8574

}

 

 

void I2C_LCD_command(unsigned char command) // write a command(instruction) to text LCD

{

    //P0: D4  P1: D5  P2: D6  P3: D7

    //P4: E   P5: RW  P6: RS  P7: BJT base

 

    uint8_t T_buf[4]; // transmit buffer

 

    T_buf[0] = (command >> 4) | 0x10; // high 4 bit, E = 1, RS = 0, base = low (Backlight on)

    T_buf[1] = T_buf[0] & 0xEF;       // E = 0

 

    T_buf[2] = (command & 0x0F) | 0x10; // low 4 bit, E = 1

    T_buf[3] = T_buf[2] & 0xEF;         // E = 0

 

    Wire.beginTransmission(I2C_addr_PCF8574); // Send address to PCF8574

    Wire.write(T_buf[0]);   // Transfer buffer to text LCD via PCF8574

    Wire.write(T_buf[1]);

    Wire.write(T_buf[2]);

    Wire.write(T_buf[3]);

    Wire.endTransmission(); // Transfer I2C stop signal to PCF8574

}

 

 

void I2C_LCD_data(unsigned char data) // display a character on text LCD

{

    //P0: D4  P1: D5  P2: D6  P3: D7

    //P4: E   P5: RW  P6: RS  P7: BJT base

 

    uint8_t T_buf[4]; // transmit buffer

 

    T_buf[0] = (data >> 4) | 0x50;   // high 4 bit, E = 1, RS = 1

    T_buf[1] = T_buf[0] & 0xEF;      // E = 0

 

    T_buf[2] = (data & 0x0F) | 0x50; // low 4 bit, E = 1, RS = 1

    T_buf[3] = T_buf[2] & 0xEF;      // E = 0

 

    Wire.beginTransmission(I2C_addr_PCF8574); // Send address to PCF8574

    Wire.write(T_buf[0]);   // Transfer buffer to text LCD via PCF8574

    Wire.write(T_buf[1]);

    Wire.write(T_buf[2]);

    Wire.write(T_buf[3]);

    Wire.endTransmission(); // Transfer I2C stop signal to PCF8574

}

 

 

void LCD_string(unsigned char command, char *string) // display a string on LCD

{

    I2C_LCD_command(command); // start position of string

    while (*string != '\0')   // display string

    {

        I2C_LCD_data(*string);

        string++;

    }

}

 

 

void Initialize_LCD(void) // initialize text LCD module

{

    // 8-bit mode

    I2C_LCD_command_8(0x30);

    delay(10);

    I2C_LCD_command_8(0x30);

    delay(6);

    I2C_LCD_command_8(0x30);

    I2C_LCD_command_8(0x20); // changes to 4-bit mode

 

    // 4-bit mode

    I2C_LCD_command(0x28); // function set(4-bit, 2 line, 5x7 dot)

    I2C_LCD_command(0x0C); // display control(display ON, cursor OFF)

    I2C_LCD_command(0x06); // entry mode set(increment, not shift)

    I2C_LCD_command(0x01); // clear display

    delay(3);

}

 

 

 

I2C 방식의 PCF8574 확장보드가 연결된 텍스트 LCD는 아두이노로 이렇게 구동할 수 있습니다. 제가 텍스트 LCD를 다른 MCU로 구동하는 코드를 이미 작성해서 가지고 있어서, LiquidCrystal_I2C.h 헤더파일을 사용하는 대신 기존의 코드를 조금만 수정해서 손쉽게 텍스트 LCD를 동작시켰습니다. 제가 직접 작성한 코드를 사용해서 신뢰감이 더 느껴지는군요. 텍스트 LCD를 STM32F746 MCU로 구동한 이전 글의 코드와 비교하면, 이 글의 코드는 거의 복사 + 붙여넣기 수준입니다^^

 

이 글에서는 I2C 핀과 텍스트 LCD의 각 핀의 신호를 로직 아날라이저로 측정하지 않았는데요. 각 핀으로 전달되는 신호를 보고 싶으시면, 같은 방식으로 텍스트 LCD를 구동했던 이전 글의 로직 아날라이저 화면을 보세요. 이 글과 이전 글은 확장보드와 I2C 클럭 주파수가 같고 코드도 유사해서, 신호도 거의 같습니다.

 

이전 글: PCF8574 I/O 확장보드를 사용한 CLCD(Text LCD) 구동 (STM32F746, I2C)

'홍익인간 프로젝트 > Arduino C' 카테고리의 다른 글

What's means F() function ?  (0) 2021.01.14
u8g2setupcpp  (0) 2020.12.25
LiquidCrystal I2C - 3 Arguments Type  (0) 2020.12.25
Software Serial Example  (0) 2020.12.16
Arduino Uno TM1637 Display  (0) 2020.12.16

+ Recent posts