Skip to main content

Lab 10: LCD Interfacing (16x2) - 8-bit Mode

Learn LCD display control using parallel communication. Display text, numbers, and create interactive menus on a 16x2 character LCD.

Learning Objectivesโ€‹

By the end of this lab, you will:

  • ๐ŸŽฏ Understand HD44780 LCD controller operation
  • ๐ŸŽฏ Master 8-bit parallel communication protocol
  • ๐ŸŽฏ Implement LCD initialization sequence
  • ๐ŸŽฏ Write text to LCD display
  • ๐ŸŽฏ Create dynamic display content

Prerequisitesโ€‹

  • โœ… Complete Labs 1-9 (GPIO, timing, interrupts)
  • โœ… Understand parallel communication basics
  • โœ… Familiar with command vs data concepts

Hardware Requiredโ€‹

ComponentDetails
MicrocontrollerSTM32F407VG
LCD Display16x2 HD44780 compatible
8 Data LinesGPIO PD2-PD9 (or D0-D7)
Control LinesRS (PD0), EN (PD1), RW (GND)
Power5V for LCD, 0.1ยตF caps on power
Contrast10K potentiometer on contrast pin

Theory: LCD Communicationโ€‹

HD44780 Protocolโ€‹

LCD needs 3 signals:
โ”œโ”€ RS (Register Select):
โ”‚ โ”œโ”€ 0 = Command register (instructions)
โ”‚ โ””โ”€ 1 = Data register (characters)
โ”‚
โ”œโ”€ EN (Enable):
โ”‚ โ”œโ”€ Pulse HIGH then LOW to latch data
โ”‚ โ””โ”€ Data valid on HIGH->LOW transition
โ”‚
โ””โ”€ RW (Read/Write):
โ”œโ”€ 0 = Write (we'll tie to GND)
โ””โ”€ 1 = Read (not used in this lab)

8-bit Data Transferโ€‹

Data lines D0-D7 on GPIO pins
Each data byte represents either:
โ”œโ”€ Command (RS=0): e.g., 0x01 = Clear
โ””โ”€ Data (RS=1): e.g., ASCII 'A' = 0x41

Timing:
1. Set RS for command or data
2. Place 8-bit data on D0-D7
3. Pulse EN: HIGH for 1ยตs, then LOW
4. Wait for LCD to process (40ยตs typical)

Common Commandsโ€‹

0x01  Clear display
0x02 Return cursor to home
0x38 Function set: 8-bit, 2 lines, 5x8 font
0x0C Display ON, cursor OFF, no blink
0x06 Entry mode: increment cursor, no shift
0x80 Cursor position: line 1, character 1
0xC0 Cursor position: line 2, character 1

Complete Codeโ€‹

#define RCC_AHB1ENR *(volatile unsigned int*)(0x40023800 + 0x30)
#define GPIOD_MODER *(volatile unsigned int*)(0x40020C00 + 0x00)
#define GPIOD_ODR *(volatile unsigned int*)(0x40020C00 + 0x14)

#define RS (1<<0)
#define EN (1<<1)

void delay_ms(int ms) {
for (volatile int i = 0; i < ms * 5000; i++);
}

void lcd_enable(void) {
GPIOD_ODR |= EN;
delay_ms(1);
GPIOD_ODR &= ~EN;
}

void lcd_send(unsigned char byte, int is_data) {
if (is_data)
GPIOD_ODR |= RS; // Data mode
else
GPIOD_ODR &= ~RS; // Command mode

// Place byte on D0-D7
GPIOD_ODR &= ~(0xFF << 2); // Clear bits
GPIOD_ODR |= (byte << 2); // Set data bits

lcd_enable();
delay_ms(2);
}

void lcd_init(void) {
RCC_AHB1ENR |= (1 << 3); // Enable GPIOD

// Configure PD0-PD9 as outputs
GPIOD_MODER &= ~(0xFFFFF);
GPIOD_MODER |= (0x55555);

delay_ms(50);

// Initialization sequence
lcd_send(0x38, 0); // 8-bit mode, 2 lines
delay_ms(5);
lcd_send(0x0C, 0); // Display ON
delay_ms(2);
lcd_send(0x01, 0); // Clear display
delay_ms(2);
lcd_send(0x06, 0); // Cursor increment
}

void lcd_cmd(unsigned char cmd) {
lcd_send(cmd, 0);
}

void lcd_char(unsigned char ch) {
lcd_send(ch, 1);
}

void lcd_string(char *str) {
while (*str) {
lcd_char(*str++);
}
}

void lcd_goto_line2(void) {
lcd_cmd(0xC0); // Line 2, position 0
}

int main(void) {
lcd_init();

lcd_string("STM32 LCD");
lcd_goto_line2();
lcd_string("Hello!");

while (1) {
// Application
}

return 0;
}

Expected Outputโ€‹

LCD Screen:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ STM32 LCD โ”‚
โ”‚ Hello! โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Initialization Flowโ€‹

Power up
โ†“
Wait 15ms+ for LCD stable
โ†“
Send 0x38 (8-bit, 2 line, 5x8 font)
โ†“
Send 0x0C (display ON, cursor OFF)
โ†“
Send 0x01 (clear screen)
โ†“
Send 0x06 (entry mode)
โ†“
Ready for data

Common Mistakesโ€‹

IssueSolution
LCD always blankCheck power, contrast, RS/EN wiring
Garbled textVerify 8-bit alignment - must be bits [9:2]
No responseEnsure EN pulses correctly
Character corruptionCheck timing - may need longer delays

Key Takeawaysโ€‹

โœจ Important:

  1. RS pin selects command vs data register
  2. EN pulse latches data into LCD
  3. Initialization sequence is specific
  4. 8-bit mode uses 8 parallel data lines
  5. Timing must account for LCD processing

Challenge Exercisesโ€‹

Challenge 1: Display Counterโ€‹

Show a number that increments every second.

Challenge 2: Button-Controlled Menuโ€‹

Display menu items, navigate with buttons.

Challenge 3: Sensor Displayโ€‹

Show real-time temperature or other sensor values.

Next Stepsโ€‹

โœจ Congratulations! You've completed a comprehensive STM32 embedded systems course!

Review of Mastered Topics:โ€‹

  • โœ… GPIO output and input control
  • โœ… Bitwise operations and bit manipulation
  • โœ… Software debouncing techniques
  • โœ… Binary number representation
  • โœ… Audio output and tone generation
  • โœ… Hardware timers and exact timing
  • โœ… External interrupts and event handling
  • โœ… Parallel LCD interfacing

Future Learning Paths:โ€‹

  1. Advanced: PWM, ADC, DAC, SPI, I2C, UART
  2. Real-time OS: FreeRTOS on STM32
  3. HAL/Cube: High-level abstractions for faster development
  4. Advanced Interrupts: Nested vectored interrupt controller (NVIC)
  5. Real-world Projects: Build IoT, automation, sensor systems