Aim:
The main aim of this project is display the custom character on LCD.
The main aim of this project is display the custom character on LCD.
Description:
The most commonly used Character based LCDs are based on Hitachi’s
HD44780 controller or other which are compatible with HD44580. In this
tutorial, we will discuss about character based LCDs, their interfacing
with various microcontrollers, various interfaces (8-bit/4-bit),
programming, special stuff and tricks you can do with these simple
looking LCDs which can give a new look to your application.
We are already know about how LCD works and 8051 micro-controller.
Here 8051 has 3 PORTS. In the programming first you have to set the
direction of PORT. The bellow steps are LCD programming using 8051
microcontroller.
Instruction Register (IR) and Data Register (DR)
There are two 8-bit registers in HD44780 controller Instruction and Data
register. Instruction register corresponds to the register where you
send commands to LCD e.g LCD shift command, LCD clear, LCD address etc.
and Data register is used for storing data which is to be displayed on
LCD. when send the enable signal of the LCD is
asserted, the data on the pins is latched in to the data register and
data is then moved automatically to the DDRAM and hence is displayed on
the LCD. Data Register is not only used for sending data to DDRAM but
also for CGRAM, the address where you want to send the data, is decided
by the instruction you send to LCD.We will discuss more on LCD
instuction set further in this tutorial.
Commands and Instruction set
Only the instruction register (IR) and the data register (DR) of the LCD
can be controlled by the MCU. Before starting the internal operation of
the LCD, control information is temporarily stored into these registers
to allow interfacing with various MCUs, which operate at different
speeds, or various peripheral control devices. The internal operation
of the LCD is determined by signals sent from the MCU. These signals,
which include register selection signal (RS), read/write signal (R/W),
and the data bus (DB0 to DB7), make up the LCD instructions (Table 3).
There are four categories of instructions that:
- Designate LCD functions, such as display format, data length, etc.
- Set internal RAM addresses
- Perform data transfer with internal RAM
- Perform miscellaneous functions
LCD Initialization
Before using the LCD for display purpose, LCD has to be initialized
either by the internal reset circuit or sending set of commands to
initialize the LCD. It is the user who has to decide whether an LCD has
to be initialized by instructions or by internal reset circuit. we will
dicuss both ways of initialization one by one.
Sending Commands to LCD
To send commands we simply need to select the command register.
Everything is same as we have done in the initialization routine. But we
will summarize the common steps and put them in a single subroutine.
Following are the steps:
- Move data to LCD port
- select command register
- select write operation
- send enable signal
- wait for LCD to process the command
Sending Data to LCD
To send data we simply need to select the data register. Everything is same asthe command routine. Following are the steps:
- Move data to LCD port
- select data register
- select write operation
- send enable signal
- wait for LCD to process the data
CGRAM and Character Building
As already explained, all character based LCD of type HD44780 has CGRAM
area to create user defined patterns. For making custom patterns we need
to write values to the CGRAM area defining which pixel to glow. These
values are to be written in the CGRAM adress starting from 0x40. If you
are wondering why it starts from 0x40? Then
the answer is given below.
Bit 7 is 0 and Bit 6 is 1, due to which the CGRAM adress command starts
from 0x40, where the address of CGRAM (Acg) starts from 0x00. CGRAM has a
total of 64 Bytes. When you are using LCD as 5×8 dots in function set
then you can define a total of 8 user defined patterns (1 Byte for each
row and 8 rows for each pattern), where as when LCD is working in 5×10
dots, you can define 4 user defined patterns.
Lets take an of bulding a custom pattern. All we have to do is make a
pixel-map of 7×5 and get the hex or decimal value or hex value for each
row, bit value is 1 if pixel is glowing and bit value is 0 if pixel is
off. The final 7 values are loaded to the CGRAM one by one. As i said
there are 8 rows for each pattern, so last row is usually left blank
(0x00)
for the cursor. If you are not using cursor then you can make use of that 8th row also. so you get a bigger pattern.
To explain the above explaination in a better way. I am going to take an example. Lets make a “Bell” pattern as shown below.
Now we get the values for each row as shown.
Bit: 4 3 2 1 0 – Hex
Row1: 0 0 1 0 0 – 0x04
Row2: 0 1 1 1 0 – 0x0E
Row3: 0 1 1 1 0 – 0x0E
Row4: 0 1 1 1 0 – 0x0E
Row5: 1 1 1 1 1 – 0x1F
Row6: 0 0 0 0 0 – 0x00
Row7: 0 0 1 0 0 – 0x04
Row8: 0 0 0 0 0 – 0x00
We are not using row 8 as in our pattern it is not required. if you are
using cursor then it is recommended not to use the 8th row. Now as we
have got the values. We just need to put these values in the CGRAM. You
can decided which place you want to store in. Following is the memory
map for custom patterns in CGRAM.
Memory Map
Pattern No. CGRAM Address (Acg)
1 0x00 – 0x07
2 0x08 – 0x0F
3 0x10 – 0x17
4 0x18 – 0x1F
5 0x20 – 0x27
6 0x28 – 0x2F
7 0x30 – 0x37
8 0x38 – 0x3F
We can point the cursor to CGRAM address by sending command, which is
0x40 + CGRAM address (For more information please see Table 4 in
commands section). Lets say we want to write the Bell pattern at second
pattern location. So we send the command as 0x48 (0x40 + 0x08), and then
we send the pattern data. Below is a small programming example to do
this.
The most commonly used Character based LCDs are based on Hitachi’s
HD44780 controller or other which are compatible with HD44580. In this
tutorial, we will discuss about character based LCDs, their interfacing
with various microcontrollers, various interfaces (8-bit/4-bit),
programming, special stuff and tricks you can do with these simple
looking LCDs which can give a new look to your application.
We are already know about how LCD works and 8051 micro-controller.
Here 8051 has 3 PORTS. In the programming first you have to set the
direction of PORT. The bellow steps are LCD programming using 8051
microcontroller.
Instruction Register (IR) and Data Register (DR)
There are two 8-bit registers in HD44780 controller Instruction and Data register. Instruction register corresponds to the register where you send commands to LCD e.g LCD shift command, LCD clear, LCD address etc. and Data register is used for storing data which is to be displayed on LCD. when send the enable signal of the LCD is
asserted, the data on the pins is latched in to the data register and data is then moved automatically to the DDRAM and hence is displayed on the LCD. Data Register is not only used for sending data to DDRAM but also for CGRAM, the address where you want to send the data, is decided by the instruction you send to LCD.We will discuss more on LCD instuction set further in this tutorial.
There are two 8-bit registers in HD44780 controller Instruction and Data register. Instruction register corresponds to the register where you send commands to LCD e.g LCD shift command, LCD clear, LCD address etc. and Data register is used for storing data which is to be displayed on LCD. when send the enable signal of the LCD is
asserted, the data on the pins is latched in to the data register and data is then moved automatically to the DDRAM and hence is displayed on the LCD. Data Register is not only used for sending data to DDRAM but also for CGRAM, the address where you want to send the data, is decided by the instruction you send to LCD.We will discuss more on LCD instuction set further in this tutorial.
Commands and Instruction set
Only the instruction register (IR) and the data register (DR) of the LCD can be controlled by the MCU. Before starting the internal operation of the LCD, control information is temporarily stored into these registers to allow interfacing with various MCUs, which operate at different speeds, or various peripheral control devices. The internal operation
of the LCD is determined by signals sent from the MCU. These signals, which include register selection signal (RS), read/write signal (R/W), and the data bus (DB0 to DB7), make up the LCD instructions (Table 3). There are four categories of instructions that:
Only the instruction register (IR) and the data register (DR) of the LCD can be controlled by the MCU. Before starting the internal operation of the LCD, control information is temporarily stored into these registers to allow interfacing with various MCUs, which operate at different speeds, or various peripheral control devices. The internal operation
of the LCD is determined by signals sent from the MCU. These signals, which include register selection signal (RS), read/write signal (R/W), and the data bus (DB0 to DB7), make up the LCD instructions (Table 3). There are four categories of instructions that:
- Designate LCD functions, such as display format, data length, etc.
- Set internal RAM addresses
- Perform data transfer with internal RAM
- Perform miscellaneous functions
LCD Initialization
Before using the LCD for display purpose, LCD has to be initialized either by the internal reset circuit or sending set of commands to initialize the LCD. It is the user who has to decide whether an LCD has to be initialized by instructions or by internal reset circuit. we will dicuss both ways of initialization one by one.
Before using the LCD for display purpose, LCD has to be initialized either by the internal reset circuit or sending set of commands to initialize the LCD. It is the user who has to decide whether an LCD has to be initialized by instructions or by internal reset circuit. we will dicuss both ways of initialization one by one.
Sending Commands to LCD
To send commands we simply need to select the command register. Everything is same as we have done in the initialization routine. But we will summarize the common steps and put them in a single subroutine. Following are the steps:
To send commands we simply need to select the command register. Everything is same as we have done in the initialization routine. But we will summarize the common steps and put them in a single subroutine. Following are the steps:
- Move data to LCD port
- select command register
- select write operation
- send enable signal
- wait for LCD to process the command
Sending Data to LCD
To send data we simply need to select the data register. Everything is same asthe command routine. Following are the steps:
To send data we simply need to select the data register. Everything is same asthe command routine. Following are the steps:
- Move data to LCD port
- select data register
- select write operation
- send enable signal
- wait for LCD to process the data
CGRAM and Character Building
As already explained, all character based LCD of type HD44780 has CGRAM area to create user defined patterns. For making custom patterns we need to write values to the CGRAM area defining which pixel to glow. These values are to be written in the CGRAM adress starting from 0x40. If you are wondering why it starts from 0x40? Then
the answer is given below.
As already explained, all character based LCD of type HD44780 has CGRAM area to create user defined patterns. For making custom patterns we need to write values to the CGRAM area defining which pixel to glow. These values are to be written in the CGRAM adress starting from 0x40. If you are wondering why it starts from 0x40? Then
the answer is given below.
Bit 7 is 0 and Bit 6 is 1, due to which the CGRAM adress command starts
from 0x40, where the address of CGRAM (Acg) starts from 0x00. CGRAM has a
total of 64 Bytes. When you are using LCD as 5×8 dots in function set
then you can define a total of 8 user defined patterns (1 Byte for each
row and 8 rows for each pattern), where as when LCD is working in 5×10
dots, you can define 4 user defined patterns.
Lets take an of bulding a custom pattern. All we have to do is make a pixel-map of 7×5 and get the hex or decimal value or hex value for each row, bit value is 1 if pixel is glowing and bit value is 0 if pixel is off. The final 7 values are loaded to the CGRAM one by one. As i said there are 8 rows for each pattern, so last row is usually left blank (0x00)
for the cursor. If you are not using cursor then you can make use of that 8th row also. so you get a bigger pattern.
To explain the above explaination in a better way. I am going to take an example. Lets make a “Bell” pattern as shown below.
Lets take an of bulding a custom pattern. All we have to do is make a pixel-map of 7×5 and get the hex or decimal value or hex value for each row, bit value is 1 if pixel is glowing and bit value is 0 if pixel is off. The final 7 values are loaded to the CGRAM one by one. As i said there are 8 rows for each pattern, so last row is usually left blank (0x00)
for the cursor. If you are not using cursor then you can make use of that 8th row also. so you get a bigger pattern.
To explain the above explaination in a better way. I am going to take an example. Lets make a “Bell” pattern as shown below.
Now we get the values for each row as shown.
Bit: 4 3 2 1 0 – Hex
Row1: 0 0 1 0 0 – 0x04
Row2: 0 1 1 1 0 – 0x0E
Row3: 0 1 1 1 0 – 0x0E
Row4: 0 1 1 1 0 – 0x0E
Row5: 1 1 1 1 1 – 0x1F
Row6: 0 0 0 0 0 – 0x00
Row7: 0 0 1 0 0 – 0x04
Row8: 0 0 0 0 0 – 0x00
We are not using row 8 as in our pattern it is not required. if you are using cursor then it is recommended not to use the 8th row. Now as we have got the values. We just need to put these values in the CGRAM. You can decided which place you want to store in. Following is the memory map for custom patterns in CGRAM.
Bit: 4 3 2 1 0 – Hex
Row1: 0 0 1 0 0 – 0x04
Row2: 0 1 1 1 0 – 0x0E
Row3: 0 1 1 1 0 – 0x0E
Row4: 0 1 1 1 0 – 0x0E
Row5: 1 1 1 1 1 – 0x1F
Row6: 0 0 0 0 0 – 0x00
Row7: 0 0 1 0 0 – 0x04
Row8: 0 0 0 0 0 – 0x00
We are not using row 8 as in our pattern it is not required. if you are using cursor then it is recommended not to use the 8th row. Now as we have got the values. We just need to put these values in the CGRAM. You can decided which place you want to store in. Following is the memory map for custom patterns in CGRAM.
Memory Map
Pattern No. CGRAM Address (Acg)
1 0x00 – 0x07
2 0x08 – 0x0F
3 0x10 – 0x17
4 0x18 – 0x1F
5 0x20 – 0x27
6 0x28 – 0x2F
7 0x30 – 0x37
8 0x38 – 0x3F
We can point the cursor to CGRAM address by sending command, which is 0x40 + CGRAM address (For more information please see Table 4 in commands section). Lets say we want to write the Bell pattern at second pattern location. So we send the command as 0x48 (0x40 + 0x08), and then we send the pattern data. Below is a small programming example to do this.
Pattern No. CGRAM Address (Acg)
1 0x00 – 0x07
2 0x08 – 0x0F
3 0x10 – 0x17
4 0x18 – 0x1F
5 0x20 – 0x27
6 0x28 – 0x2F
7 0x30 – 0x37
8 0x38 – 0x3F
We can point the cursor to CGRAM address by sending command, which is 0x40 + CGRAM address (For more information please see Table 4 in commands section). Lets say we want to write the Bell pattern at second pattern location. So we send the command as 0x48 (0x40 + 0x08), and then we send the pattern data. Below is a small programming example to do this.
Block Diagram
Schematic
Code
// *******************************************************
// Project: Display custom character in LCD using 8051
// Author: Code Bloges
// Module description: Operate single LCD
// *******************************************************
#include <reg51.h>
#include <string.h>
/* Function declarations */
void cct_init(void);
void delay(int);
void lcdinit(void);
void writecmd(int);
void writedata(char);
void writeline(char[]);
void ReturnHome(void);
void LCDBuildChar(unsigned char, unsigned char*);
// ----------------------- Define Custom Characters ----------------------- //
unsigned char Character1[8] = { 0x1c,0x16,0x1d,0x01,0x1d,0x16,0x1c,0x00 }; // Phone Up 1
unsigned char Character2[8] = { 0x07,0x0d,0x17,0x10,0x17,0x0d,0x07,0x00 }; // Phone Up 2
unsigned char Character3[8] = { 0x1f,0x1f,0x12,0x04,0x09,0x10,0x1f,0x00 }; // Phone Down 1
unsigned char Character4[8] = { 0x1f,0x1f,0x09,0x04,0x12,0x01,0x1f,0x00 }; // Phone Down 2
unsigned char Character5[8] = { 0x04,0x04,0x04,0x04,0x15,0x0e,0x04,0x00 }; // Downward Arrow
unsigned char Character6[8] = { 0x04,0x0e,0x15,0x04,0x04,0x04,0x04,0x00 }; // Upward Arrow
unsigned char Character7[8] = { 0x01,0x02,0x04,0x08,0x10,0x11,0x1f,0x00 }; // Curvy Object
unsigned char Character8[8] = { 0x00,0x1f,0x11,0x11,0x11,0x1f,0x00,0x00 }; // Square Box
/*---------------------------------------------------*/
/* Main program */
int main(void)
{
cct_init(); /* Make all ports zero */
lcdinit(); /* Initilize LCD */
writedata(0x00); /* Write Custom Character 1 */
writedata(0x01); /* Write Custom Character 2 */
writedata(' '); // Space
writedata(0x02); /* Write Custom Character 3 */
writedata(0x03); /* Write Custom Character 4 */
writedata(' '); // Space
writedata(0x04); /* Write Custom Character 5 */
writedata(0x05); /* Write Custom Character 6 */
writedata(' '); // Space
writedata(0x06); /* Write Custom Character 7 */
writedata(0x07); /* Write Custom Character 8 */
while(1)
{;}
}
void cct_init(void)
{
P0 = 0x00; /* not used */
P1 = 0x00; /* not used */
P2 = 0x00; /* used as data port */
P3 = 0x00; /* used for generating E and RS */
}
void delay(int a)
{
int i;
for(i=0;i<a;i++); /* null statement */
}
void writedata(char t)
{
P3 |= 0x01; /* => RS = 1 */
P2 = t; /* Data transfer */
P3 |= 0x02; /* => E = 1 */
delay(150);
P3 &= 0xfd; /* => E = 0 */
delay(150);
}
void writecmd(int z)
{
P3 &= 0xfe; /* => RS = 1 */
P2 = z; /* Data transfer */
P3 |= 0x02; /* => E = 1 */
delay(150);
P3 &= 0xfd; /* => E = 0 */
delay(150);
}
void lcdinit(void)
{
/* ------------ Reset process from datasheet ----------- */
delay(15000);
writecmd(0x30);
delay(4500);
writecmd(0x30);
delay(300);
writecmd(0x30);
delay(650);
/* ----------------------------------------------------- */
writecmd(0x38); /* function set */
writecmd(0x0c); /* display on,cursor off,blink off */
writecmd(0x01); /* clear display */
writecmd(0x06); /* entry mode, set increment */
/* ---------- Build Custom Characters -----------------*/
LCDBuildChar(0, Character1); /* Build Character1 at position 0 */
LCDBuildChar(1, Character2); /* Build Character2 at position 1 */
LCDBuildChar(2, Character3); /* Build Character3 at position 2 */
LCDBuildChar(3, Character4); /* Build Character4 at position 3 */
LCDBuildChar(4, Character5); /* Build Character5 at position 4 */
LCDBuildChar(5, Character6); /* Build Character6 at position 5 */
LCDBuildChar(6, Character7); /* Build Character6 at position 6 */
LCDBuildChar(7, Character8); /* Build Character6 at position 7 */
}
void ReturnHome(void) /* Return to 0 cursor location */
{
writecmd(0x02);
delay(1500);
}
void writeline(char Line[])
{
int i;
for(i=0;i<strlen(Line);i++)
{
writedata(Line[i]); /* Write Character */
}
ReturnHome(); /* Return to 0 cursor position */
}
/**********************************************************
Function Name: LCDBuildChar
Input:
loc: location where you want to store 0,1,2,....7
p: Pointer to pattern data
Usage:
LCDBuildChar(1,pattern);
********************************************************* */
void LCDBuildChar(unsigned char loc, unsigned char *p)
{
unsigned char i;
if(loc<8) //If valid address
{
writecmd(0x40+(loc*8)); //Write to CGRAM
for(i=0;i<8;i++)
writedata(p[i]); //Write the character pattern to CGRAM
}
writecmd(0x80); //shift back to DDRAM location 0
}
// *******************************************************
// Project: Display custom character in LCD using 8051
// Author: Code Bloges
// Module description: Operate single LCD
// *******************************************************
#include <reg51.h>
#include <string.h>
/* Function declarations */
void cct_init(void);
void delay(int);
void lcdinit(void);
void writecmd(int);
void writedata(char);
void writeline(char[]);
void ReturnHome(void);
void LCDBuildChar(unsigned char, unsigned char*);
// ----------------------- Define Custom Characters ----------------------- //
unsigned char Character1[8] = { 0x1c,0x16,0x1d,0x01,0x1d,0x16,0x1c,0x00 }; // Phone Up 1
unsigned char Character2[8] = { 0x07,0x0d,0x17,0x10,0x17,0x0d,0x07,0x00 }; // Phone Up 2
unsigned char Character3[8] = { 0x1f,0x1f,0x12,0x04,0x09,0x10,0x1f,0x00 }; // Phone Down 1
unsigned char Character4[8] = { 0x1f,0x1f,0x09,0x04,0x12,0x01,0x1f,0x00 }; // Phone Down 2
unsigned char Character5[8] = { 0x04,0x04,0x04,0x04,0x15,0x0e,0x04,0x00 }; // Downward Arrow
unsigned char Character6[8] = { 0x04,0x0e,0x15,0x04,0x04,0x04,0x04,0x00 }; // Upward Arrow
unsigned char Character7[8] = { 0x01,0x02,0x04,0x08,0x10,0x11,0x1f,0x00 }; // Curvy Object
unsigned char Character8[8] = { 0x00,0x1f,0x11,0x11,0x11,0x1f,0x00,0x00 }; // Square Box
/*---------------------------------------------------*/
/* Main program */
int main(void)
{
cct_init(); /* Make all ports zero */
lcdinit(); /* Initilize LCD */
writedata(0x00); /* Write Custom Character 1 */
writedata(0x01); /* Write Custom Character 2 */
writedata(' '); // Space
writedata(0x02); /* Write Custom Character 3 */
writedata(0x03); /* Write Custom Character 4 */
writedata(' '); // Space
writedata(0x04); /* Write Custom Character 5 */
writedata(0x05); /* Write Custom Character 6 */
writedata(' '); // Space
writedata(0x06); /* Write Custom Character 7 */
writedata(0x07); /* Write Custom Character 8 */
while(1)
{;}
}
void cct_init(void)
{
P0 = 0x00; /* not used */
P1 = 0x00; /* not used */
P2 = 0x00; /* used as data port */
P3 = 0x00; /* used for generating E and RS */
}
void delay(int a)
{
int i;
for(i=0;i<a;i++); /* null statement */
}
void writedata(char t)
{
P3 |= 0x01; /* => RS = 1 */
P2 = t; /* Data transfer */
P3 |= 0x02; /* => E = 1 */
delay(150);
P3 &= 0xfd; /* => E = 0 */
delay(150);
}
void writecmd(int z)
{
P3 &= 0xfe; /* => RS = 1 */
P2 = z; /* Data transfer */
P3 |= 0x02; /* => E = 1 */
delay(150);
P3 &= 0xfd; /* => E = 0 */
delay(150);
}
void lcdinit(void)
{
/* ------------ Reset process from datasheet ----------- */
delay(15000);
writecmd(0x30);
delay(4500);
writecmd(0x30);
delay(300);
writecmd(0x30);
delay(650);
/* ----------------------------------------------------- */
writecmd(0x38); /* function set */
writecmd(0x0c); /* display on,cursor off,blink off */
writecmd(0x01); /* clear display */
writecmd(0x06); /* entry mode, set increment */
/* ---------- Build Custom Characters -----------------*/
LCDBuildChar(0, Character1); /* Build Character1 at position 0 */
LCDBuildChar(1, Character2); /* Build Character2 at position 1 */
LCDBuildChar(2, Character3); /* Build Character3 at position 2 */
LCDBuildChar(3, Character4); /* Build Character4 at position 3 */
LCDBuildChar(4, Character5); /* Build Character5 at position 4 */
LCDBuildChar(5, Character6); /* Build Character6 at position 5 */
LCDBuildChar(6, Character7); /* Build Character6 at position 6 */
LCDBuildChar(7, Character8); /* Build Character6 at position 7 */
}
void ReturnHome(void) /* Return to 0 cursor location */
{
writecmd(0x02);
delay(1500);
}
void writeline(char Line[])
{
int i;
for(i=0;i<strlen(Line);i++)
{
writedata(Line[i]); /* Write Character */
}
ReturnHome(); /* Return to 0 cursor position */
}
/**********************************************************
Function Name: LCDBuildChar
Input:
loc: location where you want to store 0,1,2,....7
p: Pointer to pattern data
Usage:
LCDBuildChar(1,pattern);
********************************************************* */
void LCDBuildChar(unsigned char loc, unsigned char *p)
{
unsigned char i;
if(loc<8) //If valid address
{
writecmd(0x40+(loc*8)); //Write to CGRAM
for(i=0;i<8;i++)
writedata(p[i]); //Write the character pattern to CGRAM
}
writecmd(0x80); //shift back to DDRAM location 0
}
No comments:
Post a Comment