0
0
Power-electronicsHow-ToBeginner · 4 min read

How to Interface 16x2 LCD with Microcontroller in Embedded C

To interface a 16x2 LCD with a microcontroller in Embedded C, connect the LCD data pins and control pins (RS, RW, EN) to microcontroller ports, then send commands and data using specific functions. Initialize the LCD with commands for 4-bit or 8-bit mode, then write characters to display text.
📐

Syntax

The basic steps to interface a 16x2 LCD in Embedded C include initializing the LCD, sending commands, and sending data. You use functions like lcd_command() to send instructions and lcd_data() to send characters.

Typical pins used are:

  • RS: Register Select (command/data)
  • RW: Read/Write (usually grounded for write)
  • EN: Enable pin to latch data
  • D4-D7: Data pins for 4-bit mode

Example function calls:

lcd_command(0x38); // Function set: 8-bit, 2 lines, 5x7 dots
lcd_command(0x0C); // Display ON, Cursor OFF
lcd_command(0x01); // Clear display
lcd_data('A'); // Display character 'A'
c
void lcd_command(unsigned char cmd);
void lcd_data(unsigned char data);
void lcd_init(void);
💻

Example

This example shows how to initialize a 16x2 LCD in 4-bit mode and display "HELLO" on the first line.

c
#include <xc.h>
#define _XTAL_FREQ 4000000

// Define LCD control pins
#define RS LATBbits.LATB0
#define EN LATBbits.LATB1

// Define LCD data pins (D4-D7)
#define D4 LATDbits.LATD4
#define D5 LATDbits.LATD5
#define D6 LATDbits.LATD6
#define D7 LATDbits.LATD7

void pulse_enable() {
    EN = 1;
    __delay_ms(1);
    EN = 0;
    __delay_ms(1);
}

void lcd_command(unsigned char cmd) {
    RS = 0; // Command mode
    // Send higher nibble
    D4 = (cmd >> 4) & 1;
    D5 = (cmd >> 5) & 1;
    D6 = (cmd >> 6) & 1;
    D7 = (cmd >> 7) & 1;
    pulse_enable();
    // Send lower nibble
    D4 = cmd & 1;
    D5 = (cmd >> 1) & 1;
    D6 = (cmd >> 2) & 1;
    D7 = (cmd >> 3) & 1;
    pulse_enable();
    __delay_ms(2);
}

void lcd_data(unsigned char data) {
    RS = 1; // Data mode
    // Send higher nibble
    D4 = (data >> 4) & 1;
    D5 = (data >> 5) & 1;
    D6 = (data >> 6) & 1;
    D7 = (data >> 7) & 1;
    pulse_enable();
    // Send lower nibble
    D4 = data & 1;
    D5 = (data >> 1) & 1;
    D6 = (data >> 2) & 1;
    D7 = (data >> 3) & 1;
    pulse_enable();
    __delay_ms(2);
}

void lcd_init() {
    TRISBbits.TRISB0 = 0; // RS output
    TRISBbits.TRISB1 = 0; // EN output
    TRISD = 0x00;         // Data pins output
    __delay_ms(20);       // Wait for LCD to power up

    lcd_command(0x02); // Initialize LCD in 4-bit mode
    lcd_command(0x28); // 4-bit, 2 line, 5x7 font
    lcd_command(0x0C); // Display ON, Cursor OFF
    lcd_command(0x06); // Entry mode
    lcd_command(0x01); // Clear display
    __delay_ms(2);
}

void main() {
    lcd_init();
    char *msg = "HELLO";
    while(*msg) {
        lcd_data(*msg++);
    }
    while(1);
}
Output
HELLO displayed on the first line of the 16x2 LCD
⚠️

Common Pitfalls

  • Not initializing the LCD properly before sending data causes no display.
  • Incorrect wiring of RS, EN, or data pins leads to garbled output.
  • Forgetting to set RW pin to write mode (usually grounded) can block communication.
  • Sending commands/data without proper delays can cause LCD to miss instructions.
  • Mixing 4-bit and 8-bit mode commands without matching wiring causes errors.
c
/* Wrong: No delay after command */
lcd_command(0x01); // Clear display
lcd_data('A');    // May not show 'A' because LCD is busy

/* Right: Add delay to let LCD process */
lcd_command(0x01);
__delay_ms(2);
lcd_data('A');
📊

Quick Reference

CommandHex CodeDescription
Clear Display0x01Clears the LCD screen
Return Home0x02Cursor returns to first position
Entry Mode Set0x06Cursor moves right, no display shift
Display ON/OFF0x0CDisplay ON, cursor OFF
Function Set0x284-bit mode, 2 lines, 5x7 font
Set DDRAM Address0x80Set cursor position

Key Takeaways

Always initialize the LCD with correct commands before sending data.
Use proper delays after commands to ensure LCD processes instructions.
Connect RS, EN, and data pins correctly and set RW to write mode (usually grounded).
Choose 4-bit or 8-bit mode and match wiring and commands accordingly.
Send commands with RS=0 and data with RS=1 to control the LCD properly.