Pico W I2C LCD1602 on GP6 and GP7
MicroPython on a Pico W: an I2C LCD1602 on I2C1 (SDA GP6, SCL GP7) at 0x27 shows two messages in turn, driven by a small lcd1602.py. The whole build, a Raspberry Pi Pico W and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $10. On Mokxi they're free.
What you'll learn
- Wiring an I2C device to a Pico W's SDA and SCL pins
- Scanning the I2C bus to see which addresses answer
- Putting display code in a helper module
- Writing two lines of text to a 16x2 display
- Difficulty: Beginner
- Time: About 15 minutes
- Board: Raspberry Pi Pico W
- Parts: 3
How it works
The LCD's I2C backpack needs only four wires: power, ground, SDA on GP6 and SCL on GP7. These two pins are the Pico W's second I2C bus, I2C1. The script opens it at 400 kHz and prints the addresses it finds.
A helper file, lcd1602.py, does the talking. It starts the display at the default address 0x27 and sends every byte as two 4-bit halves.
The main loop shows Hello, Kepler! over Pico W is here, waits 2 seconds, then shows MicroPython over on an LCD1602, waits 2 more and repeats.
Parts list
3 parts, plus the jumper wires. They retail for about $10; on Mokxi they're free.
- 1 × Raspberry Pi Pico W
- 1 × Character LCD with I2C backpackIn Claw Machine Kit, Vending Machine Kit, Rhythm Game Kit.
- 1 × Power, 5 V
Kits that can build it
These 2 starter kits have every part in the circuit. Each kit's page lists what else it can build.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Character LCD with I2C backpack pin SDA | Raspberry Pi Pico W pin GP6 |
| Character LCD with I2C backpack pin SCL | Raspberry Pi Pico W pin GP7 |
| Character LCD with I2C backpack pin GND | Ground |
| Character LCD with I2C backpack pin VCC | 5 V |
The code
The MicroPython code exactly as the editor opens it. Change a line there and press Run: the board runs it on the official MicroPython firmware, with nothing to compile.
# Liquid crystal display: an LCD1602 on I2C1, SDA on GP6 and SCL on GP7.
# lcd1602.py, in its own tab, does the talking.
from machine import I2C, Pin
from lcd1602 import LCD1602
import time
i2c = I2C(1, sda=Pin(6), scl=Pin(7), freq=400000)
print("I2C:", [hex(a) for a in i2c.scan()])
lcd = LCD1602(i2c)
while True:
lcd.show("Hello, Kepler!", "Pico W is here")
print("message 1")
time.sleep(2)
lcd.show("MicroPython", "on an LCD1602")
print("message 2")
time.sleep(2)
# lcd1602.py: a 16x2 character LCD on a PCF8574 I2C backpack.
# The backpack's P0 is RS, P2 is E, P3 is the backlight and P4 to P7 are
# the display's D4 to D7, so every byte is sent as two 4-bit halves.
import time
class LCD1602:
def __init__(self, i2c, addr=0x27):
self.i2c = i2c
self.addr = addr
self.light = 0x08
time.sleep_ms(50)
for half in (0x30, 0x30, 0x30, 0x20): # wake up, then 4-bit mode
self._half(half, 0)
time.sleep_ms(5)
self.command(0x28) # two lines, 5x8 dots
self.command(0x0C) # display on, no cursor
self.command(0x06) # move right after a character
self.clear()
def _send(self, bits):
self.i2c.writeto(self.addr, bytes([bits | self.light]))
def _half(self, bits, rs):
self._send(bits | rs | 0x04) # E high...
self._send(bits | rs) # ...and low: the LCD reads it
def _byte(self, value, rs):
self._half(value & 0xF0, rs)
self._half((value << 4) & 0xF0, rs)
def command(self, value):
self._byte(value, 0)
if value < 4:
time.sleep_ms(2) # clear and home are slow
def clear(self):
self.command(0x01)
def move_to(self, col, row):
self.command(0x80 | (col + 0x40 * row))
def write(self, text):
for ch in text:
self._byte(ord(ch), 1)
def show(self, line1, line2=""):
self.move_to(0, 0)
self.write("%-16s" % line1[:16])
self.move_to(0, 1)
self.write("%-16s" % line2[:16])
Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The screen is lit but empty. This project
Turn the contrast dial on the backpack. Also check that SDA is on GP6 and SCL on GP7. - The scan prints an empty list. This project
Check power and ground, and make sure SDA and SCL are not swapped. - Your module has a different address. This project
The script uses 0x27. Some backpacks use 0x3f, so pass that address toLCD1602. - The screen stays blank or shows only a row of blocks. Character LCD with I2C backpack
The I2C address is usually 0x27 or 0x3F. Run an I2C scanner to find yours. Then turn the contrast trimmer on the backpack slowly until text appears. - The backlight is on but there is no text, or text is garbled. Character LCD with I2C backpack
Wire SDA and SCL to the right pins (A4 and A5 on an Uno), power it from 5 V, and call lcd.init() and the backlight call in setup. - Pins are powered from 5 V, or a 5 V signal goes into a GPIO. The RP2040 pins are 3.3 V only and are not 5 V tolerant. Raspberry Pi Pico W
Power the board from VBUS or VSYS at 5 V, but keep GPIO signals at 3.3 V. Use a level shifter or a divider for 5 V parts. - WiFi code fails to connect, or the on-board LED code does nothing. The LED on the Pico W is not on GP25 like on the plain Pico. Raspberry Pi Pico W
Use the board's LED_BUILTIN name so the library drives it through the WiFi chip. Join a 2.4 GHz network only, with the right SSID and password, and wait for the link before sending.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.