Sei sulla pagina 1di 20

Liquid Crystal Display(LCD) By Sayantan Mukherjee

An LCD display is specifically manufactured to be used with microcontrollers, which means that it cannot
be activated by standard IC circuits. It is used for displaying different messages on a miniature liquid
crystal display.



The model described here is for its low price and great capabilities most frequently used in practice. It is
based on the HD44780 controller (Hitachi) and can display messages in two lines with 16 characters
each. It displays all the letters of alphabet, Greek letters, punctuation marks, mathematical symbols etc.
In addition, it is possible to display symbols made up by the user. Other useful features include
automatic message shift (left and right), cursor appearance, LED backlight etc.

LCD Pins


There are pins along one side of a small printed board. These are used for connecting to the
microcontroller. There are in total of 14 pins marked with numbers (16 if it has backlight). Their function
is described in the table above.

LCD screen




An LCD screen consists of two lines each containing 16 characters. Each character consists of 5x8 or 5x11
dot matrix. This book covers the most commonly used display, i.e. the 5x8 character display. Display
contrast depends on the power supply voltage and whether messages are displayed in one or two lines.
For this reason, varying voltage 0-VCC is applied on the pin marked as VEE. Trimmer potentiometer is
usually used for that purpose. Some LCD displays have built-in backlight (blue or green LEDs). When
used during operation, a current limiting resistor should be serially connected to one of the pins for
backlight power supply (similar to LEDs).


If there are no characters displayed or if all of them are dimmed when the display is on, the first thing
that should be done is to check the potentiometer for contrast regulation. Is it properly adjusted? The
same applies if the mode of operation has been changed (writing in one or two lines).


LCD Memory

The LCD display contains three memory blocks:
DDRAM Display Data RAM.
CGRAM Character Generator RAM.
CGROM Character Generator ROM.

DDRAM Memory :

DDRAM memory is used for storing characters to be displayed. The size of this memory is sufficient for
storing 80 characters. Some memory locations are directly connected to the characters on display.

It works quite simply: it is sufficient to configure the display so as to increment addresses automatically
(shift right) and set the starting address for the message that should be displayed (for example 00 hex).

Since this is a sort of RAM memory, data can be written to and read from it, but its contents is
irretrievably lost when the power goes off.

CGROM Memory :

CGROM memory contains the default character map with all characters that can be displayed on the
screen. Each character is assigned to one memory location.

The addresses of CGROM memory locations match the characters of ASCII. If the program being
currently executed encounters a command send character P to port, then the binary value 0101 0000
appears on the port. This value is the ASCII equivalent to the character P. It is then written to LCD, which
results in displaying the symbol from 0101 0000 location of CGROM. In other words, the character P
is displayed. This applies to all letters of alphabet (capitals and small), but not to numbers.

CGRAM memory :

Apart from standard characters, the LCD display can also display symbols defined by the user itself. It
can be any symbol in the size of 5x8 pixels. RAM memory called CGRAM in the size of 64 bytes enables
it.
Memory registers are 8 bits wide, but only 5 lower bits are used. Logic one (1) in every register
represents a dimmed dot, while 8 locations grouped together represent one character.

Symbols are usually defined at the beginning of the program by simply writing zeros and ones to
registers of CGRAM memory so that they form desired shapes. In order to display them it is sufficient to
specify their address. Pay attention to the first column in the CGROM map of characters. It doesn't
contain RAM memory addresses, but symbols being discussed here. In this example, display 0 means
display , display 1 means - display etc.

LCD Basic Commands

All data transferred to LCD through the outputs D0-D7 will be interpreted as a command or a data,
which depends on the pin RS logic state:
RS = 1 - Bits D0-D7 are addresses of the characters to be displayed. LCD processor addresses one
character from the character map and displays it. The DDRAM address specifies the location on which
the character is to be displayed. This address is defined before the character is transferred or the
address of previously transferred character is automatically incremented.

RS = 0 - Bits D0 - D7 are commands which determine the display mode.




Although looking at the table you can make your own commands and test them. Below is a brief list of
useful commands which are used frequently while working on the LCD.

LCD Connection

Depending on how many lines are used for connecting the LCD to the microcontroller, there are 8-bit
and 4-bit LCD modes. The appropriate mode is selected at the beginning of the operation. This process is
called initialization. 8-bit LCD mode uses outputs D0-D7 to transfer data in the way explained on the
previous page. The main purpose of 4-bit LED mode is to save valuable I/O pins of the microcontroller.
Only 4 higher bits (D4-D7) are used for communication while other may be left unconnected. Each data
is sent to the LCD in two steps: four higher bits are sent first (normally through the lines D4-D7), then
four lower bits. Initialization enables the LCD to link and interpret received bits correctly. Data is rarely
read from the LCD (it is mainly transferred from the microcontroller to LCD) so that it is often possible to
save an extra I/O pin by simple connecting R/W pin to ground. Such saving has its price. Messages will
be normally displayed, but it will not be possible to read the busy flag since it is not possible to read the
display either.
Fortunately, there is a simple solution. After sending a character or a command it is important to give
the LCD enough time to do its job. Owing to the fact that execution of the slowest command lasts for
approximately 1.64mS, it will be sufficient to wait approximately 2mS for LCD.



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 discuss both ways of initialization one by
one.
a) Initialization by internal Reset Circuit

An internal reset circuit automatically initializes the HD44780U when the power is turned on. The
following instructions are executed during the initialization. The busy flag (BF) is kept in the busy state
until the initialization ends (BF = 1). The busy state lasts for 10 ms after VCC rises to 4.5 V.
Display clear
Function set:
DL = 1; 8-bit interface data
N = 0; 1-line display
F = 0; 5 x 8 dot character font
Display on/off control:
D = 0; Display off
C = 0; Cursor off
B = 0; Blinking off
Entry mode set:
I/D = 1; Increment by 1
S = 0; No shift

What is the Busy flag?
Compared to the microcontroller, the LCD is an extremely slow component. Because of this, it was
necessary to provide a signal which will, upon command execution, indicate that the display is ready
to receive a new data. That signal, called the busy flag, can be read from line D7. When the BF bit is
cleared (BF=0), the display is ready to receive a new data.
To check the state of the busy flag and read the address counter
1. Set R/W Pin of the LCD HIGH(read from the LCD)
2. Select the instruction register by setting RS pin LOW
3. Enable the LCD by Setting the enable pin HIGH
4. The most significant bit of the LCD data bus is the state of the busy flag (1=Busy, 0=ready to
accept instructions/data).The other bits hold the current value of the address counter.


b) Initialization by instructions

Initializing LCD with instructions is really simple. We just need to follow some steps :

1. Send command 0x30 - Using 8-bit interface
2. Delay 20ms
3. Send command 0x30 - 8-bit interface
4. Delay 20ms
5. Send command 0x30 - 8-bit interface
6. Delay 20ms
7. Send Function set (See the frequently used commands chart)
8. Display Clear command

The first 3 commands are usually not required but are recommended when you are using 4-bit interface.
So you can program the LCD starting from step 7 when working with 8-bit interface. Function set
command depends on what kind of LCD you are using and what kind of interface you are using.

LCD Programs :

In our AW51V2 board R/W pin of LCD is grounded so we can only write to LCD and cant read LCD
(generally R/W is always grounded).

1)Write a 8051 C program to print character A in LCD.

Solution :

#include<reg51f.h>

sbit rs = P3^7; // RS connected to port 3.7 in AW51V2 board
sbit e = P3^6; //Enable connected to port 3.6 in AW51V2 board
void lcd_com(int ); //lcd command prototype
void lcd_init(); //lcd initialization prototype


void main()
{
char b='A'; //taking the character A
int i;
P3=0x00; //Enable and RS connected to port 3 are designated as output
P0=0x00; // data lines of LCD connected in port 0 are designated as output

lcd_init(); //calling LCD initialization function
while(1) //infinite loop
{
rs=1; //RS=1 .For passing data
e=1; //Enable= 1
P0=b; //passing contents of variable b i.e. A
e=0; //Enable =0

for(i=0;i<=1000;i++); //delay loop

}
}

void lcd_init() //LCD initialization function
{
int i;
lcd_com(0x38); //passing 0x38 command to lcd_com function
for(i=0;i<=1000;i++); //delay loop
lcd_com(0x0E); //passing 0x0E command to lcd_com function
for(i=0;i<=1000;i++); //delay loop
lcd_com(0x01); //passing 0x01 command to lcd_com function
for(i=0;i<=1000;i++); //delay loop
}

void lcd_com(int x) //LCD command function
{
int i;
rs=0; //RS=0.For passing commands
e=1; // Enable=1
P0=x; //passing commands through variable x
e=0; //Enable =0
for(i=0;i<=1000;i++); //delay loop
}

Simple enough, so lets do another program.

1)Write a 8051 C program to print character A in LCD.

Solution :

#include<reg51f.h>
sbit rs = P3^7;
sbit e = P3^6;
void lcd_com(int );
void lcd_init();

char a[12]="CORE FUTURE";

void main()
{
unsigned int i;
int j=0;
P3=0x00;
P0=0x00;
lcd_init();

while(1)
{
lcd_com(0x80);
while(a[j]!='\0')
{
rs=1;
e=1;
P0=a[j];
e=0;
for(i=0;i<=1000;i++);
j++;
}

for(i=0;i<=35000;i++);
}
}
void lcd_init()
{
int i;
lcd_com(0x38);
for(i=0;i<=1000;i++);
lcd_com(0x0C);
for(i=0;i<=1000;i++);
lcd_com(0x01);
for(i=0;i<=1000;i++);
lcd_com(0x87);
for(i=0;i<=1000;i++);
}


void lcd_com(int x)
{
int i;
rs=0;
e=1;
P0=x;
e=0;
for(i=0;i<=1000;i++);
}

Creating Custom Character in LCD

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 address 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 address 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 5x8 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 5x10 dots, you can define 4 user defined patterns.

All we have to do is make a pixel-map of 7x5 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 explanation in a better way I am going to take an example. Lets make a "Kite"
pattern as shown below.



Here :

ROWS DECIMAL VALUE HEX VALUE
Row1 4 0x04
Row2 10 0x0A
Row3 17 0x11
Row4 10 0x0A
Row5 4 0x04
Row6 0 0x00
Row7 0 0x00
Row8 0 0x00

So the program will be :

#include<reg51f.h>

sbit rs = P3^7;
sbit e = P3^6;
void lcd_com(int );
void lcd_init();
void custom_character(); //prototype for creating KITE character
void lcd_data(char);

void main()
{
P3=0x00;
P0=0x00;

lcd_init();
custom_character();
while(1);
}

void lcd_init()
{
int i;
lcd_com(0x38);
for(i=0;i<=1000;i++);
lcd_com(0x0E);
for(i=0;i<=1000;i++);
lcd_com(0x01);
for(i=0;i<=1000;i++);
}

void lcd_com(int x)
{
int i;
rs=0;
e=1;
P0=x;
e=0;
for(i=0;i<=1000;i++);
}

void lcd_data(char c)
{
int i;
rs=1;
e=1;
P0=c;
e=0;
for(i=0;i<=1000;i++);
}

void custom_character() //function for creating custom character
{

lcd_com(0x40); //CGRAM address starting from 0x40

lcd_data(4); //Passing the decimal values
lcd_data(10);
lcd_data(17);
lcd_data(10);
lcd_data(4);
lcd_data(0);
lcd_data(0);
lcd_com(0x80); //Custom character will be displayed at 1
st
line of 1
st
row
lcd_data(0);
}
KEYPAD INTERFACING


Keyboards are the most widely used input devices of the 8051, and a basic understanding of them is
essential. In this section, we first discuss keyboard fundamentals, along with key press and key detection
mechanisms. Then we show how a keyboard is interfaced to an 8051.

Interfacing the keyboard to the 8051
At the lowest level, keyboards are organized in a matrix of rows and columns. The CPU accesses both
rows and columns through ports; therefore, with two 8-bit ports, an 8 x 8 matrix of keys can be
connected to a microprocessor. When a key is pressed, a row and a column make a contact; otherwise,
there is no connection between rows and columns. In IBM PC keyboards, a single microcontroller
(consisting of a microprocessor, RAM and EPROM, and several ports all on a single chip) takes care of
hardware and software interfacing of the keyboard. In such systems, it is the function of programs
stored in the EPROM of the microcontroller to scan the keys continuously, identify which one has been
activated, and present it to the motherboard. In this section we look at the mechanism by which the
8051 scans and identifies the key.

Switch De-bounce
Before we go into the depths of matrix keypad we must know how a switch works. When a switch is
operated by a human like a push button, or is operated by a machine like limit switches, spikes of low
and high voltages will always occur across that switch resulting into a series of High and Low signals that
can by interpreted by a digital circuit as more that one pulse instead of one clean pulse or transition
from a logic state to another.
Figure below shows a basic switch configuration with a pull up resistors, which will output 0V when
pressed and 5V through the resistor when released.
This switch configuration can be reversed to output 5V when pressed and 0V when released back, but
we will study this configuration as it is a standard for all inputs of 8051 microcontrollers and any active
low input.
The problem with this configuration, as described briefly before is that, due to the mechanical nature of
any switch that may contains spring return action of some kind, there wont be a clean transition from a
state to another, but instead there will be a series of high and low states spikes.
This series of spikes can be interpreted by a microcontroller (or any digital circuit) as if the button was
pressed many times. It may even have happened to you before when you connected a switch to a
counter of any kind, and notice that on press on the button is sometimes counted as more than one
push.


Graph above also shows approximately the ranges of voltages where a signal is considered as a HIGH
signal (Logic 1) or LOW one (Logic 0).
The unknown range can be recognized by some a digital circuit as 1 or 0, but in a completely random
manner.
There are two common solutions to this problem. Analog solution, and digital micro-controller based
solution. Both are commonly used, and sometimes, both are used at the same time to provide a very
stable design.

The analog de-bouncing circuit
The analog solution relies principally on a capacitor, which plays the role of resisting the voltage changes
on the output. In other words, this will prevent the the output to change too fast which will prevent
High and Low pulses to appear on the output. A de-bouncing circuit can be tuned exactly to your
requirements, it can be adjusted to choose which pulse is rejected and which one is accepted.

Figure above shows how to assemble a switch de-bouncing circuit. The values of the resistor R
1
and the
capacitor C
1
will determine the response speed of the switch. The more you increase R
1
and/or C
1
, the
more your circuit become immune to errors, but the more time it takes to react and give adequate
output. Its up to you to chose the values of R
1
and C
1
, using trial and error (or calculations) until you get
the suitable response for you application. Good starting values for a general purpose de-bouncing circuit
would be R
1
= 10 K and C
1
= 100 nF ceramic capacitor.
It is clear on second graph, that the addition of a capacitor made the voltages rise smooth and clean as
compared to the spikes in previous graph. But even though the addition of a capacitor, you can notice
that, while rising from 0 to 5 v, the voltage passes through a range where the output is unknown
(shaded in yellow in the figure), which will again cause some error pulses to appear on the output.
This last minor problem can be fixed by adding a schmitt trigger. Shortly, a schmitt trigger will keep its
outputs unchanged during the passage through the unknown zone, until the inputs have safely reached
above or below some threshold values, which define the High and Low logic states. In other words, a
schmitt trigger hocked to the output will eliminate the error pulses generated when the button was
released and will give straight output, clean of any errors.



The software/microcontroller based de-bouncing
The approach for a software based de-bouncing circuit is totally different than what was discussed
before. The idea here is not to prevent voltage spikes to occur, but rather to record them and analyze
them in real-time using simple software routines.

The timing T
1
, T
2
and T
3
corresponds to the low (logic =0) pulses being sent to the microcontroller from
the switch. T
1
and T
2
are the length of the reading we want to get rid off, or more scientifically, that we
want to filter. T
3
is a valid reading that we want to take in account. It is clear that the difference between
those three periods is their length, and that is how the micro-controller will be able to differentiate
between valid and un-valid pulses.
There are many ways to implement digital de-bouncing or filtering using a microcontroller, one simple
method is to make a counter count up as long as the signal is Low, and reset this counter when the
signal is High. If the counter reach a certain fixed value, which should be 1 or 2 times bigger than T
1
or T
2

(noise pulses), this means that the current pulse is a valid pulse.

The program below demonstrates technique to read input switch press and also method to control LED
output. This program also takes care of switch de-bouncing problem. The program checks the switch
release action and waits too. This avoids false triggering of output devices.

Connections:
1. Connect Switch to P2.0
2. Connect LED to P2.1.

#include <reg51f.h>
#include <stdio.h> /* prototype declarations for I/O functions */

sbit SW = P2^0; //Connect switch to P2.0
sbit LED = P2^1; //Connect LED to p2.1

void main (void) {

while(1)
{
while(SW==1); //Loop till switch is not pressed

LED = ~ LED; //Toggle LED Status

while(SW==0); //Loop till switch is not released
}
}


Scanning and identifying the key
Now lets return to matrix keypad, Figure below shows a 4 x 4 matrix connected to two ports. The rows
are connected to an output port and the columns are connected to an input port. If no key has been
pressed, reading the input port will yield 1 s for all columns since they are all connected to high (Vcc). If
all the rows are grounded and a key is pressed, one of the columns will have 0 since the key pressed
provides the path to ground. It is the function of the microcontroller to scan the keyboard continuously
to detect and identify the key pressed. How it is done is explained next.
To detect a pressed key, the microcontroller grounds all rows by providing 0 to the output latch, then it
reads the columns. If the data read from the columns is D3 DO = 1111, no key has been pressed and
the process continues until a key press is detected. However, if one of the column bits has a zero, this
means that a key press has occurred. For example, if D3 DO = 1101, this means that a key in the Dl
column has been pressed. After a key press is detected, the microcontroller will go through the process
of identifying the key. Starting with the top row, the microcontroller grounds it by providing a low to
row DO only; then it reads the columns. If the data read is all Is, no key in that row is activated and the
process is moved to the next row. It grounds the next row, reads the columns, and checks for any zero.
This process continues until the row is identified. After identification of the row in which the key has
been pressed, the next task is to find out which column the pressed key belongs to. This should be easy
since the microcontroller knows at any time which row and column are being accessed.


Example
From Figure above, identify the row and column of the pressed key for each of the following.
1. D3 DO = 1110 for the row, D3 DO = 1011 for the column
2. D3 DO = 1101 for the row, D3 DO = 0111 for the column
Solution:
From Figure above the row and column can be used to identify the key.
1. The row belongs to DO and the column belongs to D2; therefore, key number 2 was
pressed.
2. The row belongs to Dl and the column belongs to D3; therefore, key number 7 was
pressed.
So the basic steps for reading keys in matrix keypad are :
1. To make sure that the preceding key has been released, 0s are output to all rows at once, and
the columns are read and checked repeatedly until all the columns are high. When all columns
are found to be high, the program waits for a short amount of time before it goes to the next
stage of waiting for a key to be pressed.

2. To see if any key is pressed, the columns are scanned over and over in an infinite loop until one
of them has a 0 on it. Remember that the output latches connected to rows still have their initial
zeros (provided in stage 1), making them grounded. After the key press detection, the
microcontroller waits 20 ms for the bounce and then scans the columns again. This serves two
functions: (a) it ensures that the first key press detection was not an erroneous one due to a
spike noise, and (b) the 20-ms delay prevents the same key press from being interpreted as a
multiple key press. If after the 20Tins delay the key is still pressed, it goes to the next stage to
detect which row it belongs to; otherwise, it goes back into the loop to detect a real key press.

3. To detect which row the key press belongs to, the microcontroller grounds one row at a time,
reading the columns each time. If it finds that all columns are high, this means that the key press
cannot belong to that row; therefore, it grounds the next row and continues until it finds the
row the key press belongs to. Upon finding the row that the key press belongs to, it sets up the
starting address for the look-up table holding the scan codes (or the ASCII value) for that row
and goes to the next stage to identify the key.

4. To identify the key press, the microcontroller rotates the column bits, one bit at a time, into the
carry flag and checks to see if it is low. Upon finding the zero, it pulls out the ASCII code for that
key from the look-up table; otherwise, it increments the pointer to point to the next element of
the look-up table.

Now lets do a program in AW51V2 board to print 0 to 9 in seven segment display using matrix key pad.
In AW51V2 board 4 rows of matrix keypad are connected in port 2.0, port2.1, port2.2, port2.3.They all
are connected to +5V (VCC) through a pull up resistance network and columns are connected in port 2.4,
port 2.5, port 2.6.


#include<reg51f.h>

sbit a=P2^6; //columns matrix keypad
sbit b=P2^5; // columns matrix keypad
sbit c=P2^4; // columns matrix keypad
sbit u=P1^3; //display 2 control pin

void main()
{
int i;
P0=0x00; // port 0(seven segment data pins) as output
P1=0x00; // port 1(seven segment control pins) as output
P2=0x70; //designating columns as input and rows as output
u=1;
while(1)
{
for(i=0;i<=3;i++) //loop for reading columns
{
switch(i)
{
case 0:P2=0x77;
if(c==0)
{
P0=0x06;
}
if(b==0)
{
P0=0x5B;
}
if(a==0)
{
P0=0x4F;
}
break;

case 1:
P2=0x7B;
if(c==0)
{
P0=0x66;
}
if(b==0)
{
P0=0x6D;
}
if(a==0)
{
P0=0x7D;
}
break;

case 2:
P2=0x7D;
if(c==0)
{
P0=0x07;
}
if(b==0)
{
P0=0x7F;
}
if(a==0)
{
P0=0x6F;
}
break;

case 3:
P2=0x7E;

if(b==0)
{
P0=0x3F;
}
break;
}
}
}
}

Potrebbero piacerti anche