Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
Resource icon

Basic 8051 tutorial 4 2014-04-18

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..

lcd commands.png


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..
LCD.png

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!
  • lcd commands.png
    lcd commands.png
    10.9 KB · Views: 3,291
  • LCD.png
    LCD.png
    15.8 KB · Views: 3,128
  • Like
Reactions: fenster

Latest reviews

Great stuff in here. I'd surely try this. Since the Arduino made this so simple using LCD libraries, it would be very interesting to implement an LCD application using this tutorial and do some practice to learn the basics on how the code interacts with the hardware.

Latest threads

New Articles From Microcontroller Tips

Back
Top