📡 Level 3 – Advanced Communication

Project 3.3: "1602 LCD Display"

 

🚀 Project 3.3 – 1602 LCD Display

🎯 What you’ll learn

  • ✅ Goal 1: Initialize a 1602 LCD over I2C and show text
  • ✅ Goal 2: Move messages across the LCD and format data
  • ✅ Goal 3: Build a tiny multi‑screen interface with clear status messages

Key ideas

  • Short definition: An LCD shows characters in rows and columns using I2C.
  • Real‑world link: Robots use LCDs to show status like battery, mode, and sensor data.

🧱 Blocks glossary (used in this project)

  • I2C setup: Connect two pins (SCL, SDA) to talk to displays and sensors.
  • LCD setup: Create an LCD object to control text.
  • LCD show: Print text at column/row (0–15 columns, 0–1 rows on 1602).
  • Delay: Wait a short time to make changes readable.
  • Variable: Store data to print (like numbers or words).
  • Serial print: Log actions to your computer for debugging.

🧰 What you need

PartHow many?Pin connection
D1 R321USB cable (30 cm)
LCD 1602 I2C1SCL → Pin 26, SDA → Pin 5 (I2C)

🔌 Wiring tip: Connect LCD VCC to 5V and GND to GND. Use SCL=26 and SDA=5 as in the official reference for LCD.
📍 Pin map snapshot: Pins 26 (SCL) and 5 (SDA) are used for I2C. Keep other pins free for later projects.


✅ Before you start

  • Plug in the USB and open the serial monitor.
  • Test print shows:
print("Ready!")  # Confirm serial is working

🎮 Microprojects (5 mini missions)

🎮 Microproject 3.3.1 – LCD initialization

Goal: Create the I2C bus and the LCD object, then show “Clu‑Bots”.

Blocks used:

  • I2C setup: Make i2c_extend with SCL=26, SDA=5
  • LCD setup: Create lcd with width 16, address 0x27
  • LCD show: Print at row 0, centered

Block sequence:

  1. Setup I2C bus (SCL=26, SDA=5, 100000 Hz)
  2. Create LCD (width=16, addr=0x27)
  3. Show “Clu‑Bots” centered at row 0

MicroPython code:

# Microproject 3.3.1 – Initialize LCD and show text

import machine                             # Load hardware/I2C library
import i2clcd                              # Load LCD library (I2C 1602)

i2c_extend = machine.SoftI2C(              # Create software I2C bus
    scl = machine.Pin(26),                 # Use Pin 26 for SCL (clock)
    sda = machine.Pin(5),                  # Use Pin 5 for SDA (data)
    freq = 100000                          # Set I2C speed to 100 kHz
)

lcd = i2clcd.LCD(                          # Create LCD controller object
    i2c_extend,                            # Pass the I2C bus we just made
    lcd_width = 16,                        # LCD has 16 columns per row
    i2c_addr = 0x27                        # Typical I2C address for 1602 adapters
)

print("[Init] LCD ready at 0x27, width=16")# Log successful setup
lcd.shows('Clu-Bots',                      # Show a message on the LCD
          column = 0,                      # Start at column 0
          line = 0,                        # Use top row (row 0)
          center = True)                   # Center text horizontally
print("[LCD] Displayed: Clu-Bots")         # Confirm on serial

Reflection: You made your robot speak on a screen—nice first step!
Challenge:

  • Easy: Change the message to your name.
  • Harder: Show text on row 1 (line=1) with center=True.

🎮 Microproject 3.3.2 – Static message

Goal: Display two lines: title on row 0 and status on row 1.

Blocks used:

  • LCD show: Print strings at specific row/column
  • Delay: Pause to read the screen

Block sequence:

  1. Show “Status:” at row 0, col 0
  2. Show “Ready” at row 1, col 0
  3. Wait for viewing

MicroPython code:

# Microproject 3.3.2 – Show a static 2-line message

import machine                              # Load hardware/I2C library
import i2clcd                               # Load LCD library
import time                                  # Load time library for delays

i2c_extend = machine.SoftI2C(               # Create I2C bus for LCD
    scl = machine.Pin(26),                  # SCL on Pin 26
    sda = machine.Pin(5),                   # SDA on Pin 5
    freq = 100000                           # I2C speed 100 kHz
)

lcd = i2clcd.LCD(                           # Create LCD object
    i2c_extend,                             # Use our I2C bus
    lcd_width = 16,                         # 16 columns LCD
    i2c_addr = 0x27                         # I2C address of LCD
)

lcd.shows('Status:',                        # Print title text
          column = 0,                       # Start at first column
          line = 0,                         # Top row
          center = False)                   # No centering, left aligned
print("[LCD] Row0: Status:")                # Serial log

lcd.shows('Ready',                          # Print status text
          column = 0,                       # Start at first column
          line = 1,                         # Second row
          center = False)                   # Left aligned
print("[LCD] Row1: Ready")                  # Serial log

time.sleep_ms(1500)                         # Pause for a moment to read

Reflection: Two clear lines—title and status—make your UI readable.
Challenge:

  • Easy: Change “Ready” to “Running…”.
  • Harder: Center the title and keep the status left aligned.

🎮 Microproject 3.3.3 – Message displacement (scroll effect)

Goal: Simulate movement: clear, then print shifted messages.

Blocks used:

  • LCD clear: Clean the display
  • LCD show: Print at different columns
  • Delay: Create animation timing

Block sequence:

  1. Clear screen
  2. Print “Hello” moving from col 0 to col 10 on row 0
  3. Delay between steps

MicroPython code:

# Microproject 3.3.3 – Displace text across the LCD

import machine                               # Load hardware/I2C library
import i2clcd                                # Load LCD library
import time                                  # Load time library for delays

i2c_extend = machine.SoftI2C(                # Create I2C bus
    scl = machine.Pin(26),                   # SCL pin
    sda = machine.Pin(5),                    # SDA pin
    freq = 100000                            # I2C speed
)

lcd = i2clcd.LCD(                            # Create LCD object
    i2c_extend,                              # I2C bus
    lcd_width = 16,                          # 16 columns
    i2c_addr = 0x27                          # LCD I2C address
)

for col in range(0, 11):                     # Loop through columns 0..10
    lcd.clear()                              # Clear the entire screen
    print("[LCD] Clear display")             # Serial log: cleared
    lcd.shows('Hello',                       # Show text to move
              column = col,                  # Shifted column position
              line = 0,                      # Top row
              center = False)                # Left aligned at chosen col
    print("[LCD] Row0 col", col, ": Hello")  # Serial log current position
    time.sleep_ms(200)                        # Short delay for animation feel

Reflection: You created motion with simple steps—like a basic marquee.
Challenge:

  • Easy: Move on row 1 instead.
  • Harder: Bounce back (move right, then left).

🎮 Microproject 3.3.4 – Display variable values

Goal: Show a changing counter on the LCD with formatting.

Blocks used:

  • Variable: Count up
  • LCD show: Print dynamic content
  • Delay: Control update speed

Block sequence:

  1. Start counter at 0
  2. Show “Count: N” on row 1
  3. Increase N and repeat

MicroPython code:

# Microproject 3.3.4 – Print a changing counter on LCD

import machine                                 # Load hardware/I2C library
import i2clcd                                  # Load LCD library
import time                                    # Load time library

i2c_extend = machine.SoftI2C(                  # Create I2C bus
    scl = machine.Pin(26),                     # SCL pin
    sda = machine.Pin(5),                      # SDA pin
    freq = 100000                              # I2C speed
)

lcd = i2clcd.LCD(                              # Create LCD object
    i2c_extend,                                # I2C bus
    lcd_width = 16,                            # 16 columns width
    i2c_addr = 0x27                            # LCD I2C address
)

count = 0                                      # Initialize counter variable
print("[Init] Counter=0")                      # Serial log: start value

while True:                                    # Continuous update loop
    lcd.clear()                                # Clear screen to avoid overlap
    print("[LCD] Clear")                       # Serial log: cleared
    lcd.shows('Count:',                        # Show label on row 0
              column = 0,                      # Column 0
              line = 0,                        # Top row
              center = False)                  # Left aligned
    lcd.shows(str(count),                      # Show counter value (as text)
              column = 7,                      # After "Count: "
              line = 0,                        # Same row for one-line display
              center = False)                  # Left aligned
    print("[LCD] Count:", count)               # Serial log: current value
    count = count + 1                          # Increase counter by 1
    time.sleep_ms(500)                         # Update twice per second

Reflection: Numbers on screen help you monitor robot state in real time.
Challenge:

  • Easy: Show the count on row 1 instead.
  • Harder: Reset the counter at 100 with a friendly message.

🎮 Microproject 3.3.5 – Multi‑screen interface

Goal: Alternate between two screens: TITLE and DATA.

Blocks used:

  • LCD show: Print different screens
  • Delay: Time between screens
  • Variable: Simple page toggle

Block sequence:

  1. Show Screen A (title)
  2. Wait, then show Screen B (data)
  3. Repeat

MicroPython code:

# Microproject 3.3.5 – Alternate between two LCD screens

import machine                                   # Load hardware/I2C library
import i2clcd                                    # Load LCD library
import time                                      # Load time library

i2c_extend = machine.SoftI2C(                    # Create I2C bus
    scl = machine.Pin(26),                       # SCL pin
    sda = machine.Pin(5),                        # SDA pin
    freq = 100000                                # I2C speed
)

lcd = i2clcd.LCD(                                # Create LCD object
    i2c_extend,                                  # I2C bus
    lcd_width = 16,                              # 16 columns width
    i2c_addr = 0x27                              # LCD I2C address
)

page = 0                                         # Toggle variable for pages
value = 42                                       # Example data value to display
print("[Init] Multi-screen ready")               # Serial log: ready

while True:                                      # Loop to alternate screens
    lcd.clear()                                  # Clear before drawing a new page
    print("[LCD] Clear")                         # Serial log: cleared
    if page == 0:                                # If we are on page 0
        lcd.shows('Clu-Bots',                    # Show title text
                  column = 0,                    # Column 0
                  line = 0,                      # Top row
                  center = True)                 # Centered for a title look
        lcd.shows('LCD Station',                 # Subtitle text
                  column = 0,                    # Column 0
                  line = 1,                      # Second row
                  center = True)                 # Center for symmetry
        print("[LCD] Page 0: Title")             # Serial log: title page
    else:                                        # Otherwise page 1 (data page)
        lcd.shows('Value:',                      # Label text
                  column = 0,                    # Column 0
                  line = 0,                      # Top row
                  center = False)                # Left aligned
        lcd.shows(str(value),                    # Show data value
                  column = 7,                    # After "Value: "
                  line = 0,                      # Same row
                  center = False)                # Left aligned
        lcd.shows('OK',                          # Status indicator
                  column = 0,                    # Column 0
                  line = 1,                      # Second row
                  center = False)                # Left aligned
        print("[LCD] Page 1: Data", value)       # Serial log: data page
    time.sleep_ms(1000)                           # Hold page for 1 second
    page = 1 - page                               # Toggle page (0→1, 1→0)

Reflection: Two pages give your robot a simple dashboard—clean and tidy.
Challenge:

  • Easy: Change the hold time to 500 ms for faster switching.
  • Harder: Add a third page showing “Mode: TEST”.

✨ Main project – Complete display station

🔧 Blocks steps (with glossary)

  • I2C setup: Make i2c_extend with SCL=26 and SDA=5
  • LCD setup: Create lcd at address 0x27, width 16
  • LCD show: Print multiple lines and pages
  • Variable: Toggle screens and update values
  • Delay: Control readability

Block sequence:

  1. Setup I2C and LCD (width=16, addr=0x27)
  2. Show title on page 0; show data on page 1
  3. Toggle pages each second
  4. Update a counter value on page 1

🐍 MicroPython code (mirroring blocks)

# Project 3.3 – Complete Display Station

import machine                                   # Load hardware/I2C library
import i2clcd                                    # Load LCD library
import time                                      # Load time library

i2c_extend = machine.SoftI2C(                    # Create I2C bus with pins
    scl = machine.Pin(26),                       # SCL pin on 26 (per reference)
    sda = machine.Pin(5),                        # SDA pin on 5 (per reference)
    freq = 100000                                # I2C frequency 100 kHz
)

lcd = i2clcd.LCD(                                # Create the LCD controller
    i2c_extend,                                  # Pass our I2C bus
    lcd_width = 16,                              # LCD width is 16 columns
    i2c_addr = 0x27                              # Typical I2C address for 1602
)

print("[Init] Display station ready")            # Serial log: setup success

counter = 0                                      # Variable to show changing data
page = 0                                         # Variable to toggle pages

while True:                                      # Main loop for the display station
    lcd.clear()                                  # Clear before drawing a page
    print("[LCD] Clear")                         # Serial log: cleared

    if page == 0:                                # Page 0: Title/branding
        lcd.shows('Clu-Bots',                    # Title text
                  column = 0,                    # Column 0
                  line = 0,                      # Top row
                  center = True)                 # Center the title
        lcd.shows('Display v1',                  # Subtitle
                  column = 0,                    # Column 0
                  line = 1,                      # Bottom row
                  center = True)                 # Center subtitle
        print("[LCD] Page 0 ready")              # Serial log: title page
    else:                                        # Page 1: Data page
        lcd.shows('Count:',                      # Label on row 0
                  column = 0,                    # Column 0
                  line = 0,                      # Top row
                  center = False)                # Left aligned label
        lcd.shows(str(counter),                  # Show counter value
                  column = 7,                    # After label
                  line = 0,                      # Same row
                  center = False)                # Left aligned value
        lcd.shows('OK',                          # Status indicator on row 1
                  column = 0,                    # Column 0
                  line = 1,                      # Second row
                  center = False)                # Left aligned
        print("[LCD] Page 1: counter =", counter) # Serial log: data page

        counter = counter + 1                    # Increase counter value

    time.sleep_ms(1000)                           # Keep page visible for 1 second
    page = 1 - page                               # Toggle page for next loop

📖 External explanation

  • What it teaches: How to initialize an LCD, show text, animate movement, and build multi‑page displays.
  • Why it works: I2C lets the board talk to the LCD with two wires; the LCD library places text at column/row.
  • Key concept: Clear screen + show at column/row = simple and readable user interfaces.

✨ Story time

Your robot just got a face—this LCD is its dashboard. It can greet, report, and guide your missions like a tiny control panel.


🕵️ Debugging (2)

🐞 Debugging 3.3.A – LCD does not initialize

Problem: Nothing shows on the LCD.
Clues: Black rectangles or no text; serial shows only init messages.

Broken code:

lcd = i2clcd.LCD(i2c_extend, lcd_width=16, i2c_addr=0x3F)  # Wrong address for this module

Fixed code:

lcd = i2clcd.LCD(i2c_extend, lcd_width=16, i2c_addr=0x27)  # Use 0x27 per reference

Why it works: The LCD backpack must match its I2C address.
Avoid next time: Check the label or try 0x27 first (common).


🐞 Debugging 3.3.B – Corrupt characters

Problem: Random symbols or broken text appear.
Clues: Fast updates without clear or overlapping prints.

Broken code:

lcd.shows('Clu-Bots', column=10, line=0, center=False)  # Prints off the screen range

Fixed code:

lcd.clear()                                            # Clear before reprinting
lcd.shows('Clu-Bots', column=0, line=0, center=True)   # Keep inside 0–15 columns

Why it works: Clearing and using valid positions prevents overlaps and overflow.
Avoid next time: Respect 0–15 columns, 0–1 rows; clear before new layouts.


✅ Final checklist

  • I saw the LCD show a centered “Clu‑Bots”
  • I displayed two lines clearly
  • I moved text across the screen
  • I showed a changing value
  • I built a two‑page mini interface

📚 Extras

  • 🧠 Student tip: Short messages fit best—use clear labels like “Mode” or “Count”.
  • 🧑‍🏫 Instructor tip: Have students verify I2C pins (SCL=26, SDA=5) and address (0x27) before coding.
  • 📖 Glossary:
    • I2C: Two‑wire communication for displays/sensors (SCL clock, SDA data).
    • Column/row: Position on the LCD (columns 0–15, rows 0–1).
    • Address: The I2C number that identifies the device (e.g., 0x27).
  • 💡 Mini tips:
    • Clear before large layout changes.
    • Center titles; left align data.
    • Keep delays around 300–1000 ms for readable updates.ing, stop and f
On this page