관리 메뉴

거북이처럼 천천히

LCD Display (HD44780U) - (1, 8bit mode) 본문

Embedded Programming (AVR)/Atmega 128A (실습)

LCD Display (HD44780U) - (1, 8bit mode)

유로 청년 2024. 9. 11. 08:04

1. 8bit mode를 통해 LCD 디스플레이 모듈인 HD44780U와 직접 연결하여 통신하기

 

Verilog RTL 설계(8월 22일 - 1, I2C 통신을 통한 LCD 컨트롤 - (1))

1. I2C Master 모듈을 통한 LCD 디스플레이 모듈 컨트롤이번에는 I2C 통신을 통해 LCD 디스플레이 모듈과 Basys3 과 통신해보도록 하겠다.구현에 앞서 Slave 모듈인 LCD 디스플레이 모듈에 대해서 공부해보

jbhdeve.tistory.com

 

 

 

 

2. Header File of HD44780U, LCD Display Module

  • Header File에 필요한 Parameter 선언 및 라이브러리, 함수 원형 선언하였다.
#ifndef LCD_H_
#define LCD_H_

// ATmega 128 System Clock 설정
#define F_CPU 16000000UL

// Define Header File
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>

// Define Parameter
#define LCD_DATA_PORT	PORTF
#define LCD_DATA_DDR	DDRF
#define LCD_DATA_PIN	PINF

#define LCD_RS_PORT		PORTE
#define LCD_RW_PORT		PORTE
#define LCD_E_PORT		PORTE

#define LCD_RS_DDR		DDRE
#define LCD_RW_DDR		DDRE
#define LCD_E_DDR		DDRE

// Define PIN of Control
#define LCD_RS_PIN		5		
#define LCD_RW_PIN		6
#define LCD_E_PIN		7

// Define Function Prototype
void LCD_INIT();
void LCD_SET_RW_READ();
void LCD_SET_RW_WRITE();
void LCD_SEND_DATA(uint8_t data);
void LCD_SEND_COMMAND (uint8_t command);
void LCD_ENABLE_PIN(); // Send data from MCU to LCD
void LCD_gotoXY(uint8_t row, uint8_t col);     // Change to specific x, y
void LCD_INPUT_PORT(uint8_t data);

// Send data
void LCD_SEND_CHARACTER (uint8_t character);
void LCD_SEND_STRING(char* string);

// Declare 8bit mode
#define COMMAND_8BIT_MODE 0x38

#endif /* LCD_H_ */
  • 이번 구현은 ATmega128A와 HD44780U LCD 디스플레이 모듈을 이용하여 구현하였다.
  • 8bit  데이터를 송수신하기 위해 PORT F를 사용하였으며, RS, RW, Enable,과 같은 제어 신호는 PORT E에 5핀, 6핀, 7핀에 각각 연결하였다.

 

 

 

3.  8bit-mode 로 LCD 디스플레이 모듈과 통신

< Source, Parameter로 전달 받은 8bit 데이터를 Port로 전달하여 출력 >

// Data Port 에 8bit data 입력 
void LCD_INPUT_PORT(uint8_t data) {
	LCD_DATA_PORT = data;
}

 

 

< Source, Register Select의 DDR을 1으로 설정하여 Write로 변경 >

// LCD_RW_PIN 핀 Write 설정 (LCD_RW_PIN = 1)
void LCD_SET_RW_WRITE() {
	// LCD_RW_PIN = 1
	LCD_RW_DDR |= (1<<LCD_RW_PIN);
}
  • 해당 함수는 LCD 디스플레이에 데이터를 Write하기 위해 RW 핀의 DDR 값을 1로 만들어 준다.

 

 

< Source, Enable 신호값을 Low → High → Low으로 변환 >

// 데이터를 MCU에서 LCD 디스플레이 모듈로 전송하기 위한 Enable 신호 변화
void LCD_ENABLE_PIN() {
	// Enable : Low -> High -> Low
	LCD_E_PORT &= ~(1<<LCD_E_PIN);
	LCD_E_PORT |= (1<<LCD_E_PIN);
	LCD_E_PORT &= ~(1<<LCD_E_PIN);
	_delay_us(1600);
}
  • Enable 신호는 MCU와 HD44780 LCD 모듈과의 통신 타이밍을 정확하게 제어할 수 있게 만들어 준다.
  • Enable 신호가 Low → High 로 변화하게 되면 LCD 디스플레이 모듈에게 "LCD 디스플레이야! 너가 읽어야 할 데이터가 있으니, 데이터 읽을 준비 해!" 라는 신호를 보내게 되며, High → Low 로 변화하게 되면 LCD 디스플레이는 실제로 MCU로 부터 데이터를 가져오게 된다.
  • 따라서 LCD 디스플레이 모듈은 Enable 신호 값이 Low → High로 변화할 때, 데이터를 가져오는 것이 아니라 High → Low로 변화할 때, 데이터를 가져오게 된다.

    ★★★★★★★★★★★★
  • Q) Enable 신호값을 Low → High → Low로 변화시킨 뒤, 1600us delay time을 가지는가?
  • Enable 신호값을 변화시킨 뒤,  1600us delay time을 갖는 이유는 Enable 신호의 안정화 시간을 갖기 위해서 대기 시간을 갖는 것이다. LCD HD44780U의 DataSheet에 따르면 Enable 신호값을 변화시킨 뒤, 1600us delay time을 가질 것을 권장하고 있다.

 

 

< Source, Parameter로 전달받은 8bit 데이터를 MCU에서 LCD 모듈로 전송하는 전체적인 과정 >

// Send data 
void LCD_SEND_DATA(uint8_t data) {
	// Data Port Write 설정
	LCD_SET_RW_WRITE();
	
	// Register Select : 1로 설정
	LCD_RS_PORT |= (1<<LCD_RS_PIN);
	
	// Data Port에 데이터 전송
	LCD_INPUT_PORT(data);
	
	// 데이터를 LCD로 전송하기 위해 Enable 신호값 변화
	LCD_ENABLE_PIN();
}
  • 위 코드에서 각각의 줄은 다음과 같은 의미를 갖습니다.
    ▶ LCD_SET_RW_WRITE() : LCD 디스플레이에 데이터를 Write하기 위해 RW핀의 DDR 값을 1로 설정한다.
    ▶ LCD_RS_PORT |= (1<<LCD_RS_PIN) : 8bit 데이터를 전송할 것이기 때문에 RS = 1로 설정한다.
    ▶ LCD_INPUT_PORT(data) : Data Port에 parameter로 전달받은 데이터를 내보낸다>
    ▶ LCD_ENABLE_PIN() : Data Port에 데이터를 전달한 뒤, LCD 디스플레이에 데이터를 전송하기 위해 Enable 신호 값을 Low → High → Low 로 변화시킨다.

 

 

 

 

< Source, Parameter로 전달 받은 8bit 명령어를 MCU에서 LCD 모듈로 전송하는 전체적인 과정 >

// Send Command
void LCD_SEND_COMMAND (uint8_t command) {
	// Register Select : 0
	LCD_RS_PORT &= ~(1<<LCD_RS_PIN);
	
	// Data Port Write로 설정
	LCD_SET_RW_WRITE();
	
	// 명령어 전송
	LCD_INPUT_PORT(command);
	
	// 데이터를 LCD로 전송하기 위해 Enable 신호값 변화
	LCD_ENABLE_PIN();
}
  • 위 코드에서 각각의 줄은 다음과 같은 의미를 갖습니다.
    ▶ LCD_SET_RW_WRITE() : LCD 디스플레이에 데이터를 Write하기 위해 RW핀의 DDR 값을 1로 설정한다.
    ▶ LCD_RS_PORT &=  ~(1<<LCD_RS_PIN) : 8bit 명령어를 전송할 것이기 때문에 RS = 0로 설정한다.
    ▶ LCD_INPUT_PORT(command) : Data Port에 parameter로 전달받은 명령어를 내보낸다.
    ▶ LCD_ENABLE_PIN() : Data Port에 명령어를 전달한 뒤, LCD 디스플레이에 명령어를 전송하기 위해 Enable 신호 값을 Low → High → Low 로 변화시킨다.

 

 

 

< Source, LCD 디스플레이 모듈의 초기화 작업 >

// Initialization of LCD
void LCD_INIT() {
	// PORT 초기화
	LCD_DATA_DDR = 0xff;
	LCD_RW_DDR |= (1<<LCD_RW_PIN);
	LCD_E_DDR |= (1<<LCD_E_PIN);
	LCD_RS_DDR |= (1<<LCD_RS_PIN); 

	// LCD 초기화	
	_delay_ms(30);
	LCD_SEND_COMMAND(COMMAND_8BIT_MODE);
	_delay_ms(5);
	LCD_SEND_COMMAND(COMMAND_8BIT_MODE);
	_delay_ms(100);
	LCD_SEND_COMMAND(COMMAND_8BIT_MODE);
	
	LCD_SEND_COMMAND(0x3c);  // 2-line, 5x10 dots
	LCD_SEND_COMMAND(0x0c);  // Display: on, cursor : off
	LCD_SEND_COMMAND(0x01);  // Clear Display
	LCD_SEND_COMMAND(0x06);  // Increase, Display Shift : off
}
  • 해당 함수는 HD 44780U LCD 디스플레이 모듈을 사용하기 위해 수행하는 초기화 작업이다.
  • 먼저, 8bit Data, RW(Read/Write). Enable, RS(Register Select)의 DDR(Data Direction Register)을 초기화시켜 준다.
  • HD 44780U LCD 디스플레이 모듈의 Data Sheet에 따라 8bit mode, initialization of LCD 작업 수행시켜 주었다.

 

 

 

 

< Source, LCD 디스플레이 화면에서 특정 X, Y 좌표로 이동하는 명령어 전송 >

void LCD_gotoXY(uint8_t row, uint8_t col) {
	// row, col 값을 LCD 화면으로 제한
	row %= 2;
	col %= 16;
	
	// 특정 좌표의 주소값을 계산
	// 1행 : 0x00 ~ 0x0f
	// 2행 : 0x40 ~ 0x4f;
	uint8_t address = (0x40*row) + col;
	
	// 특정 좌표로 전송하는 명령어와 계산한 주소값과 더한다.
	uint8_t command_move_address = 0x80 + address;
	
	// Send command
	LCD_SEND_COMMAND(command_move_address);
}
  • LCD_gotoXY 함수는 parameter로 전달 받은 row, col 값으로 커서를 이동시키는 명령어를 전송하는 함수이다.
  • LCD_gotoXY 함수의 각 명령어 소스 코드들은 다음과 같은 의미를 갖는다.
    row %= 2; col %= 16;  :  row값과 col값을 2 x 16 LCD 화면안으로 제한하도록 설계
    uint8_t command_move_address = (0x40*row) + col; : 특정 x, y 좌표의 주소값을 계산
    ▶ uint8_t command_move_address = 0x80 + address; : 커서 이동 명령어와 계산된 주소를 연산
    ▶ LCD_SEND_COMMAND(command_move_address); : 연산된 명령어를 LCD 모듈에 전송

 

 

 

 

< Source, parameter로 전달 받은 character와 string 변수를 LCD 모듈로 전송한다. >

// Send character
void LCD_SEND_CHARACTER (uint8_t character) {
	LCD_SEND_DATA(character);
}

// Send String
void LCD_SEND_STRING(char* string) {
	int str_length = strlen(string);
	
	for(uint8_t i=0; i<str_length; i++)
		LCD_SEND_DATA(string[i]);
}
  • Parameter로 전달 받은 character와 string을 LCD_SEND_DATA 함수를 통해 MCU에서 LCD 디스플레이 모듈로 데이터를 전송한다

 

 

 

 

< Source, Main 함수 >

#include "lcd.h"

int main(void)
{
    // Init of LCD
	LCD_INIT();
	
	// SEND_DATA
	LCD_gotoXY(0, 0);
	LCD_SEND_STRING("Hello World!");
	LCD_gotoXY(1,0);
	LCD_SEND_STRING("I am 8bit mode!");
	
	return 0;
}
  • LCD 디스플레이를 데이터 시트에 따라 8bit mode로 LCD 초기화 작업을 수행한다.
  • 초기화 작업이 끝나면 1행에는 "Hello World!", 2행에는 "I am 8bit mode!" 문자열을 출력하도록 하였다.

 

 

 

4. 구현