AT89C51 LCD Interfacing and Programming

 Here it is shown how to connect 16x2 LCD (Liquid Crystal Display) with AT89051 microcontroller. LCD are output devices which are essential in most of electronics projects to display sensor data, message to users and build an interactive electronic system. AT89C51 is one of the popular early microcontrollers which is still being used. It is cheap and very effective which lowers the system design cost while providing high efficiency. Another output device is seven segment display (SSD) which is explained in the tutorial Working with Seven-Segment Displays and AT89C51.

Circuit Diagram and Hardware

The following circuit diagram shows how to interface AT89C51 microcontroller with 16x2 LCD.

at89051 LCD circuit diagram

Component used

  • AT89C51 microcontroller
  • 16x2 LCD (Liquid Crystal Display)
  • 11.052MHz quartz crystal
  • 30pF x 2 capacitor
  • 10uF capacitor
  • 10KOhm resistor
  • Push button
  • LM7805 IC
  • 10KOhm Potentiometer (POT)
Note that the power supply part where LM7805 IC is shown here as +5V. The circuit diagram for power supply is shown in Power Supply for AT89C51 microcontroller & LED BlinkHere is the breakdown of how the schematic connects the AT89C51 microcontroller to the 16x2 Character LCD in 4-bit data mode.

1. The Data Bus (4-Bit Mode)

To save microcontroller pins, the LCD is configured in 4-bit mode instead of 8-bit mode. This means it only uses the upper four data pins (D4 to D7) on the LCD to receive information in two split packages (nibbles).

On the schematic layout, the pins are cross-connected to the lower pins of Port 2 in a bit-reversed order:

  • D7 (Pin 14) $\rightarrow$ Connected to P2.0 (Pin 21) (Most Significant Data Bit)

  • D6 (Pin 13) $\rightarrow$ Connected to P2.1 (Pin 22)

  • D5 (Pin 12) $\rightarrow$ Connected to P2.2 (Pin 23)

  • D4 (Pin 11) $\rightarrow$ Connected to P2.3 (Pin 24) (Least Significant Data Bit)

💡 Note on Data Handling: Pins D0, D1, D2, and D3 on the LCD are left completely disconnected since 4-bit communication ignores them entirely.

2. The Control Bus

The control lines tell the LCD what type of information is traveling across the data lines and exactly when to read it. They are wired to the upper pins of Port 2:

  • RS / Register Select (Pin 4) $\rightarrow$ Connected to P2.6 (Pin 27)

    • When RS = 0, the microcontroller sends layout instructions or commands (like clearing the screen or moving the cursor).

    • When RS = 1, the microcontroller sends actual ASCII character data to be printed (like 'e' or 'e').

  • R/W / Read-Write (Pin 5) $\rightarrow$ Connected to P2.5 (Pin 26)

    • Toggling this low (0) sets the display to Write Mode so the AT89C51 can stream characters onto it.

  • E / Enable (Pin 6) $\rightarrow$ Connected to P2.4 (Pin 25)

    • This acts as the latch trigger. When this pin scales from High to Low (falling edge), it clocks whatever information is sitting on the data bus directly into the LCD's processing registers.

3. Power and Contrast Setup

The first three pins on the LCD module handle the unit's basic power rails and visual visibility configuration:

  • VSS (Pin 1) $\rightarrow$ Tied directly to Ground (GND).

  • VDD (Pin 2) $\rightarrow$ Tied directly to the system +5V Power Supply.

  • VEE / Contrast (Pin 3) $\rightarrow$ Usually connected to the center wiper pin of a variable potentiometer sitting between +5V and Ground. Adjusting this modifies the driving voltage for the liquid crystals to make the pixels sharper or dimmer on screen.

Programming and Coding

The following is the program code to display scrolling text using AT89C51 with 16x2 LCD:


#include <reg51.h>

sbit RS = P2^6;
sbit RW = P2^5;
sbit EN = P2^4;

void delay(unsigned int ms);
void lcd_send_nibble(unsigned char nibble);
void lcd_cmd(unsigned char cmd);
void lcd_data(unsigned char data_char);
void lcd_init(void);
void lcd_string(char *str);

// The text to scroll on the second line (padded with spaces for clean entry/exit)
char code scroll_text[] = "                electronics engineering tutorial                ";

void main() {
    unsigned char i, j;
    
    lcd_init(); 
    
    // WRITE ONCE: Print static text on line 1 before entering the infinite loop
    lcd_cmd(0x80); 
    lcd_string("   ee-diary.net");
    
    while(1) {
        // Loop through the text array to shift the window (48 iterations total)
        for(i = 0; i < 48; i++) {
            
            // Move cursor to Line 2, Position 1
            lcd_cmd(0xC0); 
            
            // Send exactly 16 characters for the current window frame
            for(j = 0; j < 16; j++) {
                lcd_data(scroll_text[i + j]);
            }
            
            delay(1); // Set this between 100-200 for a smooth, natural speed
        }
    }
}

// Helper function to reverse the lower 4 bits to match your schematic layout
unsigned char reverse_nibble(unsigned char n) {
    unsigned char rev = 0;
    if (n & 0x01) rev |= 0x08; 
    if (n & 0x02) rev |= 0x04; 
    if (n & 0x04) rev |= 0x02; 
    if (n & 0x08) rev |= 0x01; 
    return rev;
}

void lcd_send_nibble(unsigned char nibble) {
    unsigned char temp;
    nibble = reverse_nibble(nibble & 0x0F);
    
    temp = P2 & 0xF0;        
    temp |= nibble;          
    P2 = temp;               
    
    EN = 1;              
    delay(1);
    EN = 0;
    delay(1);
}

void lcd_cmd(unsigned char cmd) {
    RS = 0; RW = 0;
    lcd_send_nibble(cmd >> 4);   
    lcd_send_nibble(cmd & 0x0F); 
}

void lcd_data(unsigned char data_char) {
    RS = 1; RW = 0;
    lcd_send_nibble(data_char >> 4);   
    lcd_send_nibble(data_char & 0x0F); 
}

void lcd_init() {
    delay(50); 
    
    RS = 0; RW = 0;
    lcd_send_nibble(0x03);
    delay(5);
    lcd_send_nibble(0x03);
    delay(1);
    lcd_send_nibble(0x03);
    
    lcd_send_nibble(0x02); 
    
    lcd_cmd(0x28); // 4-bit mode, 2 lines, 5x7 font
    lcd_cmd(0x0C); // Display ON, Cursor OFF
    lcd_cmd(0x06); // Entry mode: increment cursor
    lcd_cmd(0x01); // Clear display RAM
    delay(5);
}

void lcd_string(char *str) {
    int i;
    for(i=0; str[i]!='\0'; i++) {
        lcd_data(str[i]);
    }
}

void delay(unsigned int ms) {
    unsigned int x, y;
    for(x = 0; x < ms; x++) {
        for(y = 0; y < 1275; y++);
    }
}


Video Demonstration



Post a Comment

Previous Post Next Post