Hello Friends,
~Pratyush
In my previous post I cover the introduction part of HITACHI 16x2 character LCD. In this
post I will explain you its internal operation that how a character prints on
LCD screen. To understand its internal operation we have to know about these
terms-
IR:
Instruction register
DR: Data Register
AC:
Address Counter
DDRAM: Display Data RAM
CGROM: Character Generator ROM
CGRAM: Character Generator RAM
Let’s understand these terms one by one. As I told
you in the previous post that HD44780 has two 8-bit registers—
1. Instruction
Register : IR
2. Data
Register : DR
IR
stores instruction codes such as display clear, cursor position, font size etc.
HD44780 Datasheet provides a Command Sets for LCD to do these things. We
just put the command code in IR to perform the task which we want. In this post I will also explain you that how to use these command sets.
MCU send data to LCDs data pins. How LCD recognize that the data coming
from MCU is an ASCII character or
it’s a command?? Answer depends on
the status of RS pin.
If RS=”0” then data coming from MCU is stored in IR. LCD treats this data as an instruction or command.
If RS=”1” then data coming from MCU is stored in DR. LCD treats this data as a character.
DR
is used for storing data (ascii value of a character) which is
ready to be displayed on LCD. When ENABLE pin of LCD is set to “1” (HIGH), the
data coming from MCU is latched inside IR or DR depends on the status of RS
pin. If RS=”1” then data is latched into DR and moved automatically into DDRAM
or CGRAM by an internal operation and displayed on LCD screen. See the timing
diagram below for more clarification.
AC:
When we store data into instruction register then basically we are storing the
location (address) of that instruction/command. This address information is now
sent from IR to AC. After writing into DDRAM or CGRAM, the AC is automatically
incremented by one.
DDRAM:
Display
data RAM (DDRAM) stores display data represented in 8-bit character codes. Its
extended capacity is 80 X 8 bits, or 80 characters. The area in display data
RAM (DDRAM) that is not used for display can be used as general data RAM.
Basically
DDRAM provides the location (address) to the character where it will be
displayed on LCD screen. To print any character we have to set DDRAM address first
and then we have to send the ascii/Hex value of that character. Because our LCD
size is 16x2 hence only 16 characters in one line is visible, total of 32 characters
we can display at a time on the screen.
CGROM:
The bitmap images of all the characters are
previously stored in Character Generator ROM. DDRAM fetch bitmap image of the
character from this ROM. It generates 5x8 dot or 5x10 dot character patterns
from 8-bit character code (ascii code or Hex code).See Figure below :
CGRAM can generate 208, 5x8 dot character patterns
and 32, 5x10 dot character patterns. In the above figure green area shows CGRAM area.
CGRAM:
If we want to display some special characters then
CGRAM is used; it is located at 0x00 to 0x07(Highlighted
green in the figure). You can design your custom characters and displays on LCD. I
will post on ‘custom character designing’ separately in next post.
Block
Diagram from above discussion:
Writing
Data and Commands:
I am using LCD in 4-bit mode means its only 4 data pins
(MSB) is used to send data. Because our microcontroller deals with 8-bit
data, so we have to send data to LCD in two parts. First we have to send MSB and then LSB.
To do this we have to first mask MSB of the data and send to LCD then we have to
shift this data 4 times Left due to this LSB comes in place of MSB position and
then send it to LCD.
Send
Character to LCD: In order to print a character onto LCD
we have to select data register first means RS=”1”. And we know that data
is processed only when EN=”1” one more thing is to be remember that EN should
low before sending data or command. OK! These information is enough to print a
character.Follow this algorithm to do this :
Step:
1 Put MSB of the data on LCD data pins
Step:
2 EN
= 0; RS=1
Step:
3
EN=1 wait EN=0 (Clock to
latch MSB)
Step:
4
put LSB of the data
Step:
5
EN = 0; RS=1
Step:
6
EN=1 wait EN=0 (Clock to
latch LSB)
Step:
7 Wait
Function
to Send Character to LCD: I
write the program in ‘C’ for AVR microcontroller. Here I only show you the
function used to display a character. You will get complete code and macro definition
in my next post.
void Send_LCD_Char(uint8_t data)
{
LCD_PORT=(data & 0xF0); //MSB
SET_RS;
Clock();
LCD_PORT=((data & 0x0F) << 4);
//LSB
SET_RS;
Clock();
_delay_ms(5); //wait (LCD is busy)
}
Example : Send_LCD_Char(‘A’);
Send
Command to LCD: Only RS will change, other things remain
unchanged. For command mode RS=0.Algorithm:
Step:
1 Put MSB of the data
Step:
2 EN
= 0; RS=0
Step:
3
EN=1 wait EN=0 (Clock
to latch MSB)
Step:
4
put LSB of the data
Step:
5
EN = 0; RS=0
Step:
6
EN=1 wait EN=0 (Clock to
latch LSB)
Step:
7 Wait
Function
to Send Command to LCD:
void Send_LCD_Cmd(uint8_t data)
{
LCD_PORT=(data & 0xF0); //MSB
RESET_RS;
Clock();
LCD_PORT=((data & 0x0F) << 4);
//LSB
RESET_RS;
Clock();
_delay_ms(5); // Wait (LCD is busy)
}
Example : Send_LCD_Cmd(0x01);
Busy
Flag (BF): There is one more thing which I want to explain
shortly. You will notice that in both of the function at the end of function I
write some delay. This delay is needed for LCD to successfully process the
data.
We can set the accurate delay required by the LCD to process the data using Busy Flag reading function.To access the busy flag we have to use RW pin
because we have to read the status of busy flag from LCD. When BF=1, means LCD
is processing a command/data or we can say that LCD is busy till BF=1. When LCD
is busy it will not accepts any command/data. So we have to poll (Read) busy
Flag to ensure that BF=0. When BF=0 LCD is ready to process next data.
The only advantage to use BF is that it will give
exact amount of time which LCD needs to process the data. However, Busy Flag reading
may be ignored by simply using delay function so I write this delay in code and that’s
the region why I grounded RW pin.
LCD
Command Sets: HD44780 Datasheet provides a table for
LCD commands which is very useful during writing code for LCD.
Some
Useful Commands:
0x01 - LCD Clear
0x0C – Turn on LCD, No cursor
0x0E – Solid Cursor
0x0F – Blinking Cursor
0x80 - Moves cursor to first address on the left of
LINE 1
0xC0 - Moves cursor to first address on the left of
LINE 2
0x1C – Shift display right
0x18 – Shift display left
0x28 – 4-Bit mode, 2-line, 5x7 Font
0x06 – Automatic increment in cursor, no display
shift
LCD
Initialization:
LCD initialization is just a set of commands which
prepare the LCD according to our requirement. To use LCD we first have to initialize
it at the beginning of the main program.
We can Initialize LCD using two methods: 1. Using
Internal Reset 2.Using Software
I found in datasheet that internal initialization is
set for 8-bit mode, which is not useful because we are using 4-bit mode so we
have to write a function to initialize it with our requirements. HD44780 Datasheet
gives a flowchart for initialization.
Function
For LCD Initialization: According to this algorithm we can easily write code for LCD initialization.
void LCD_init()
{
_delay_ms(20);
LCD_DDR = 0xFF;
LCD_PORT = 0x00;
Send_LCD_Cmd(0x30);
_delay_ms(5);
Send_LCD_Cmd(0x30);
_delay_us(200);
Send_LCD_Cmd(0x30);
_delay_us(200);
Send_LCD_Cmd(0x28); //4-bit mode, 2-line - 5x7 Font
Send_LCD_Cmd(0x06); //Auto. Increment - NO disp. shift
Send_LCD_Cmd(0x01); //clear display
Send_LCD_Cmd(0x0C); //NO cursor - NO Blink
}
Ok!! Now all things done!! In the
next post I will show you How to work with LCD and its Interfacing with AVR Microcontroller
and doing some practical stuff.