The tutorial for the LCD screen will use the basic 1602 type from Hitachi!! This has been cloned to death... Everyone has a copy of this chip set down to mimicking its every function..
I use “Displaytech” and “Fordata” mainly because of the cost... I'm certainly not advertising them.. Use whatever you have... But they have served me well over the past few years...
To use these devices you have to set them up before you can use them.... The chip set can use a variety of sizes, the main ones being 16 character by 2 line, 20 character by 2 line, 16 character by 4 line and 20 character by 4 line.
The basic commands for the display set up are shown here..
This is the start of the digital communication age... devices talking to other devices we can control various devices by addressing, commands and data... As we move on through the next few tutorials we will see more and more “control” over the way we read and write to sensors and displays..
I have connected an LCD to our circuit.. The data lines D0~D7 are connected to P1 of our micro and the three control lines RS, RW and E are connected to P3 of our micro..
The display has 16 pins D0~D7, RS, RW, E , Vo, Vcc and Vee, we also have the Cathode and Anode for the back light.. The screen I use uses an LED back light that needs 20mA at 4.2 volts..
This needs a current limiting resistor of 0.8v /20mA ( Ohms law ) = 40 ohm resistor... This will give optimal lighting, however! I try to give the LED its best life so I decrease the current to 10mA to prolong its life... As the daylight reflection isn't too bad and the display is still readable in the dark and the light, so I use an 80 ohm resistor to limit the back light current.. ( nearest value = 82R )
The display also needs a contrast!! The contrast varies from manufacturer to manufacturer... The small 5mm digit sized displays run with a contrast of 5 volts... Bigger displays need more contrast voltage... This can be up to 17 volts. This voltage is almost always referenced from the Vcc rail down... So the display I use has a maximum of -5 volts.... I use a small negative voltage generator... Namely the ICL7660, a small 8 pin IC that can produce the negative of the voltage that is supplied.. In our case +5 volts will produce -5 volts to generate the negative voltage the LCD contrast needs.
For your convenience just use the single rail type... then the contrast will fall between 5 volts and ground...
I have written the ASM and C code to write to the LCD screen and display messages and user input information..
Code 13
From the code above you will see that all the commands are made by manipulating the data and control lines ( buses ). By writing several low level “device drivers” then several High level routines, we have proper control over the device connected to port 1
LcdPrint can be called to print an entire NULL terminated string to the display.. Almost automating the process.
The C code version starts to show the big differences when programming.... We can use strings as simply as typing them out.. If you examine the differences in the code, you start to understand the ease without the mundane programming.... I do not want to discourage ASM coding as its the nuts and bolts that all compilers are built on....
I program comfortably in both environments so I can get to grips with both... I have written oodles of line of code in ASM and in C.. You can include ASM into C code to make the timing aspect of ASM possible in C...
Here's my representation of the code in C.... Representation because the code WILL start to differ greatly..
Code 14
I am hopefully going to upload the serial communication tutorial next. Simple micro ~ PC stuff....
Enjoy!
I use “Displaytech” and “Fordata” mainly because of the cost... I'm certainly not advertising them.. Use whatever you have... But they have served me well over the past few years...
To use these devices you have to set them up before you can use them.... The chip set can use a variety of sizes, the main ones being 16 character by 2 line, 20 character by 2 line, 16 character by 4 line and 20 character by 4 line.
The basic commands for the display set up are shown here..
This is the start of the digital communication age... devices talking to other devices we can control various devices by addressing, commands and data... As we move on through the next few tutorials we will see more and more “control” over the way we read and write to sensors and displays..
I have connected an LCD to our circuit.. The data lines D0~D7 are connected to P1 of our micro and the three control lines RS, RW and E are connected to P3 of our micro..
The display has 16 pins D0~D7, RS, RW, E , Vo, Vcc and Vee, we also have the Cathode and Anode for the back light.. The screen I use uses an LED back light that needs 20mA at 4.2 volts..
This needs a current limiting resistor of 0.8v /20mA ( Ohms law ) = 40 ohm resistor... This will give optimal lighting, however! I try to give the LED its best life so I decrease the current to 10mA to prolong its life... As the daylight reflection isn't too bad and the display is still readable in the dark and the light, so I use an 80 ohm resistor to limit the back light current.. ( nearest value = 82R )
The display also needs a contrast!! The contrast varies from manufacturer to manufacturer... The small 5mm digit sized displays run with a contrast of 5 volts... Bigger displays need more contrast voltage... This can be up to 17 volts. This voltage is almost always referenced from the Vcc rail down... So the display I use has a maximum of -5 volts.... I use a small negative voltage generator... Namely the ICL7660, a small 8 pin IC that can produce the negative of the voltage that is supplied.. In our case +5 volts will produce -5 volts to generate the negative voltage the LCD contrast needs.
For your convenience just use the single rail type... then the contrast will fall between 5 volts and ground...
I have written the ASM and C code to write to the LCD screen and display messages and user input information..
Code 13
Code:
org 0 ; Reset vector
sjmp Start
org 30H ; Code starts here
Start:
acall LcdInit ; Initialise screen
While:
acall LcdGotoline1
mov DPTR,#mess1 ; Get message 1
acall LcdPrint
acall LcdGotoline2
mov DPTR,#mess2 ; Get message 2
acall LcdPrint
mov A,#0CDH ; Line 2 position 13
acall LcdCmd
jb P0.0, SW2 ; Is switch one pressed
mov A,#31H ; print a '1'
acall LcdData
SW2:
jb P0.1,NS ; Is switch two pressed
mov A,#32H ; print a '2'
acall LcdData
NS:
sjmp While ; Back to loop
; Screen Init..
;---------------
LcdInit:
clr P3.6
clr P3.7
acall Delay15 ; Settle time
mov P1,#33H ; Init 1
setb P3.5
nop
clr P3.5 ; Init 2
acall Delay5
setb P3.5
nop
clr P3.5
acall Delay1
mov A,#38H ; Function set 38
acall LcdCmd
mov A,#0CH ; Display on
acall LcdCmd
mov A,#06H ; cursor off
acall LcdCmd
mov A,#01H ; Clear and home..
acall LcdCmd
ret
; Screen goto
;---------------
LcdGotoline1:
mov A,#080H ; Home 0,0
acall LcdCmd
ret
LcdGotoline2:
mov A,#0C0H ; Home 0,1
acall LcdCmd
ret
; Screen Print
;---------------
LcdPrint:
clr A
Lp:
push Acc ; save index
movc A,@A+DPTR ; Get character
jz Fin ; NULL terminator
acall LcdData ; place on screen
pop Acc
inc A ; Increase index
sjmp Lp ; Next character
Fin:
pop Acc
ret ; Done
; Screen Busy
;---------------
LcdBusy:
mov P1,#0FFH ; Port as input
clr P3.7 ; RS = 1
setb P3.6 ; RW = 0
setb P3.5 ; E on
nop
mov A,P1 ; Busy flag
clr P3.5 ; E off
clr P3.6 ; RW = off
ret
; Screen data
;---------------
LcdData:
push Acc ; save data
Dbusy:
acall LcdBusy ; See if screen is ready
jb Acc.7,DBusy ; Loop until it is
pop Acc ; get data
setb P3.7 ; RS = 1
clr P3.6 ; RW = 0
mov P1,A ; Data to screen
setb P3.5 ; E on
nop
clr P3.5 ; E off
clr P3.7 ; RS = off
ret
; Screen command
;---------------
LcdCmd:
push Acc ; save data
Cbusy:
acall LcdBusy ; See if screen is ready
jb Acc.7,CBusy ; Loop until it is
pop Acc ; get data
clr P3.7 ; RS = 0
clr P3.6 ; RW = 0
mov P1,A ; Command to screen
setb P3.5 ; E on
nop
clr P3.5 ; E off
ret
delay15:
mov R2,#1BH ; Aproximately 15mS
sjmp delay
Delay5:
mov R2,#0AH ; aproximately 5mS
sjmp delay
Delay1:
mov R2,#2H ; Aproximately 1mS
delay:
mov R1,#0 ; 2 clock cycles (loading) = 2
d1:
djnz R1,d1 ; 2 * 256 clock cycles *180 = 92160
djnz R2,d1 ; 2 * 180 clock cycles = 380
ret ; 2 clock cycles (return) = 2
; * 1.0815 (11.0952 osc) = 100.07ms
Mess1: db " PRESS A KEY ",0
Mess2: db "YOU PRESSED: ",0
END
From the code above you will see that all the commands are made by manipulating the data and control lines ( buses ). By writing several low level “device drivers” then several High level routines, we have proper control over the device connected to port 1
LcdPrint can be called to print an entire NULL terminated string to the display.. Almost automating the process.
The C code version starts to show the big differences when programming.... We can use strings as simply as typing them out.. If you examine the differences in the code, you start to understand the ease without the mundane programming.... I do not want to discourage ASM coding as its the nuts and bolts that all compilers are built on....
I program comfortably in both environments so I can get to grips with both... I have written oodles of line of code in ASM and in C.. You can include ASM into C code to make the timing aspect of ASM possible in C...
Here's my representation of the code in C.... Representation because the code WILL start to differ greatly..
Code 14
C:
#include<8051.h> // definition file
#define LCDPORT P1
__sbit __at (0xB7) RS; // Register select pin
__sbit __at (0xB6) RW; // Read write pin
__sbit __at (0xB5) E; // Enable pin
void delayUs(int x)
{ // As I don't need uS delays:----
x/=19; // Explanation: This takes 380uS
while(x--); // This takes 11uS 1000 / 19 = 52.
} // 52 * 11uS + 380uS + 4uS = 963uS
void delayMs(int x)
{
while(x--)
delayUs(1000); // 13uS + 963uS = 976uS (close enough )
}
unsigned char LcdBusy(void)
{
char ERR = 0;
LCDPORT = 0xFF; // Port as input
RS = 0; // Set for command
RW = 1; // Set to read
E = 1; // Clock on
ERR = LCDPORT & 0x80; // Bit 7 is busy flag
E = 0; // Clock off
RW = 0; // Set to write
if(ERR)return 1; // Return 1 or 0
return 0;
}
void LcdCmd( unsigned char C)
{
while(LcdBusy()); // Wait until not busy
RS = 0; // Set to command
RW = 0; // Set to write
LCDPORT = C; // Write command
E = 1; // Clock
E = 0;
}
void LcdData( unsigned char C)
{
while(LcdBusy()); // Wait until not busy
RS = 1; // Set to Data
RW = 0; // Set to write
LCDPORT = C; // Write Data
E = 1; // Clock
E = 0;
}
void LcdInit(void)
{
delayMs(50); // Setting time
RS = 0; // Command
RW = 0; // Write
LCDPORT = 0x33; // Init value
E = 1; // Clock
E = 0;
delayMs(15); // Twice
E = 1; // Clock
E = 0;
delayMs(5); // Ready to start
LcdCmd(0x38); // Function set
LcdCmd(0x0C); // Display command
LcdCmd(0x06); // Cursor conmmand
LcdCmd(0x01); // Clear and Home command
}
void LcdClear(void)
{
LcdCmd(1); // Clear and Home
}
void LcdPrintRam(unsigned char* str)
{
while(*str != 0)
LcdData(*str++); // Print until NULL
}
void LcdPrintConst( const char * str)
{
LcdPrintRam((unsigned char *) str); //Convert to ram and print
}
void LcdGoto(unsigned char x, unsigned char y)
{
x += 0x80; // Line 1
if(y==1) x+=0x40; // Line 2
LcdCmd(x); // Line Command
} // For 4 line use 0xD4 and 0x94 as well..
void main(void) // Main entry point
{
LcdInit(); // Get screen ready
while(1) // Forever loop
{
LcdGoto(0,0);
LcdPrintConst(" PRESS A KEY ");
LcdGoto(0,1);
LcdPrintConst("YOU PRESSED: ");
LcdGoto(13,1);
if(!P0_0) LcdData(0x31);
if(!P0_1) LcdData(0x32);
}
}
I am hopefully going to upload the serial communication tutorial next. Simple micro ~ PC stuff....
Enjoy!