관리 메뉴

거북이처럼 천천히

LCD Display (HD44780U) - (2, 4bit mode) 본문

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

LCD Display (HD44780U) - (2, 4bit mode)

유로 청년 2024. 9. 11. 13:35

1. 4bit mode를 이용하여 HD44780U LCD 모듈과 통신하기

  • 지난 게시글에서는 8bit mode를 이용하여 HD44780U LCD 모듈과 통신을 하였다.
  • HD44780U LCD 디스플레이 모듈은 8bit mode 외에도 4bit mode를 지원한다.
  • 4bit mode는 8bt mode와 달리 4개의 데이터 버스를 이용하여 MCU와 LCD 디스플레이 모듈간에 데이터를 주고 받는다. 따라서 8bit 모드과 비교하였을 때, 4개의 와이어를 통해 데이터를 주고 받을 수 있어 자원을 효율적으로 줄일 수 있지만, 데이터 송수신 시간이 8bit 모드 대비 상대적으로 많이 소요된다.
  • 4bit 모드를 통해 LCD 디스플레이 모듈과 통신 이론은 아래 게시글을 참고하길 바란다.
    Verilog RTL 설계(8월 22일 - 2, I2C 통신을 통한 LCD 컨트롤 - (2)) (tistory.com)
 

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

1.  서론이전 게시글까지 Basys3에서 I2C 프로토콜 생성 (i2c_master)에 대해서 살펴 보았으며, I2C 통신이 왜 필요하며, I2C 통신의 장점 및 특징에 대해서 살펴보았다.이를 통해 LCD 디스플레이 모듈와 I

jbhdeve.tistory.com

 

 

 

 

2.  4bit mode를 이용하여 HD44780U LCD 모듈과 통신하는 함수 구현

< Source, Header file >

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

// Define System Clock
#define F_CPU 16000000UL

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

// Define PORT, DDR, PIN
#define LCD_DATA_PORT PORTF
#define LCD_DATA_DDR  DDRF
#define LCD_DATA_PIN  PINF

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

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

// Define Pin
#define LCD_RS_PIN		5
#define LCD_RW_PIN		6
#define LCD_E_PIN		7

// Function prototype
void LCD_INPUT_DATA(uint8_t data);
void LCD_SET_RW_WRITE();
void LCD_SEND_DATA(uint8_t data);
void LCD_SEND_COMMAND(uint8_t commnad);
void LCD_ENABLE();
void LCD_INIT();
void LCD_gotoXY(uint8_t row, uint8_t col);
void LCD_SEND_STRING();

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

 

 

< Source, Parameter로 전달 받은 8bit 데이터를 4bit 데이터로 쪼개어 4bit씩 데이터를 PORT에 전달한다. >

// Parameter로 전달 받은 data값을 PORT로 전달
void LCD_INPUT_DATA(uint8_t data) {
	LCD_DATA_PORT = (LCD_DATA_PORT & 0x0f) | (data & 0xf0);
	LCD_ENABLE();
	LCD_DATA_PORT = (LCD_DATA_PORT & 0x0f) | ((data & 0x0f)<<4);
	LCD_ENABLE();
}
  • Parameter로 전달 받은 8bit 데이터를 4bit씩 쪼개어 두 번에 걸쳐서 데이터를 보내게 된다.
  • 4bit씩 쪼개진 데이터를 PORT에 전달 한 뒤, Enable 신호 값을 Low → High → Low으로 변화시키기 위해 LCD_ENALBE 함수를 4bit 데이터를 전송한 뒤, 작성하였다.

    ★★★★★★
  • Q) 왜 데이터를 PORT에 바로 넣지 않고, (LCD_DATA_PORT & 0x0f)와 OR 연산을 한 뒤, PORT에 대입하는가?
  • A) (LCD_DATA_PORT & 0x0f)의 의미는 "PORT의 상위 4bit를 0으로 초기화하는 과정을 의미한다. PORT의 상위 4bit에 데이터를 넣기 전, 0으로 초기화하는 이유는 PORT에 남아 있는 상태에서 데이터를 넣게 되면 잘못된 데이터가 PORT에 있을 수 있기 때문에 PORT에 데이터를 넣기 전에 초기화 작업을 수행하게 된다.

 

 

 

< Source, Read/Write Pin 값을 Write(1)로 설정하기 >

// RW Pin의 DDR 값을 1로 설정
void LCD_SET_RW_WRITE() {
	LCD_RW_PORT &= ~(1<<LCD_RW_PIN);
}

 

 

 

 

< Source, Enable 신호 값을 Low → High → Low 으로 변화시켜 LCD 모듈에 데이터를 전송한다. >

void LCD_ENABLE() {
	// 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);
}

 

 

 

 

< Source, 8bit 명령어 및 8bit 데이터를 전송하기 >

void LCD_SEND_DATA(uint8_t data) {
	LCD_SET_RW_WRITE();
	LCD_RS_PORT |= (1<<LCD_RS_PIN);
	LCD_INPUT_DATA(data);
}

void LCD_SEND_COMMAND(uint8_t command) {
	LCD_SET_RW_WRITE();
	LCD_RS_PORT &= ~(1<<LCD_RS_PIN);
	LCD_INPUT_DATA(command);
}
  • Parameter로 전달 받은 8bit data와 command를 MCU에서 LCD 디스플레이 모듈로 전달한다.

 

 

 

< Source, 특정 x와 y값을 Parameter로 받은 뒤, 해당 좌표 지점으로 이동한다. >

void LCD_gotoXY(uint8_t row, uint8_t col) {
	row %= 2;
	col %= 16;
	
	uint8_t address = 0x40*row + col;
	uint8_t specific_address_command = 0x80 + address;
	
	LCD_SEND_COMMAND(specific_address_command); 
}

 

 

 

 

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

void LCD_INIT() {
	// Init of port
	LCD_DATA_DDR = 0xff;
	LCD_RS_DDR |= (1<<LCD_RS_PIN);
	LCD_RW_DDR |= (1<<LCD_RW_PIN);
	LCD_E_DDR |= (1<<LCD_E_PIN);
	
	// Init of LCD
	_delay_ms(30);
	LCD_SEND_COMMAND(0x33);
	LCD_SEND_COMMAND(0x32);
	LCD_SEND_COMMAND(0x2a);
	LCD_SEND_COMMAND(0x0c);
	LCD_SEND_COMMAND(0x01);
	LCD_SEND_COMMAND(0x06);
}

 

 

 

 

 

< Source, 문자열을 Parameter로 전달 받아 순차적으로 문자열을 출력한다. >

void LCD_SEND_STRING(char* string) {
	int str_lenght = strlen(string);
	
	for(uint8_t i=0; i<str_lenght; i++)
		LCD_SEND_DATA(string[i]);
}

 

 

 

 

 

< Source, Main method >

#include "lcd.h"

int main(void)
{
	LCD_INIT();
	
	LCD_gotoXY(0, 0);
	LCD_SEND_STRING("Hello! World?");
	LCD_gotoXY(1, 0);
	LCD_SEND_STRING("I AM 4BIT MODE!");
	
    while (1) 
    {
    }
}

 

 

 

 

3. 구현