MicroPython I2C LCD1602 on a Pico, GP14 and GP15
MicroPython on a Raspberry Pi Pico: an I2C LCD1602 on GP14 and GP15 shows a greeting on its first line and a counter that ticks every second. The whole build, a Raspberry Pi Pico 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 $8. On Mokxi they're free.
What you'll learn
- Wiring an I2C device to a Pico's SDA and SCL pins
- Scanning the I2C bus to find an address
- Splitting display code into a helper module
- Showing a changing number on a 16x2 LCD
- Difficulty: Beginner
- Time: About 15 minutes
- Board: Raspberry Pi Pico
- Parts: 3
How it works
The LCD's I2C backpack needs only four wires: power, ground, SDA on GP14 and SCL on GP15. The script opens I2C bus 1 at 400 kHz and scans it to find the backpack's address.
A helper file, lcd1602.py, does the talking. It sends each byte to the display as two 4-bit halves, because the backpack connects only four data lines.
The main loop writes Hello, Pico! on the first line and count: followed by a number on the second. The number goes up by one each second and also prints to the console.
Parts list
3 parts, plus the jumper wires. They retail for about $8; on Mokxi they're free.
- 1 × Raspberry Pi PicoIn Fight Stick Kit.
- 1 × Character LCD with I2C backpackIn Claw Machine Kit, Vending Machine Kit, Rhythm Game Kit.
- 1 × Power, 5 V
Kits that can build it
This starter kit has 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 pin GP14 |
| Character LCD with I2C backpack pin SCL | Raspberry Pi Pico pin GP15 |
| 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.
# An I2C LCD1602 on I2C bus 1: SDA on GP14, SCL on GP15. The scan finds
# the backpack's address; lcd1602.py, in the next tab, does the rest.
from machine import I2C, Pin
import time
from lcd1602 import LCD1602
i2c = I2C(1, sda=Pin(14), scl=Pin(15), freq=400000)
found = i2c.scan()
print("I2C:", [hex(a) for a in found])
lcd = LCD1602(i2c, found[0])
count = 0
while True:
lcd.show("Hello, Pico!", "count: %d" % count)
print("count", count)
count += 1
time.sleep(1)
# 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 script stops with an error right after the scan. This project
The scan found nothing. Check SDA on GP14, SCL on GP15, and the power and ground wires. - The backlight is on but there is no text. This project
Turn the contrast dial on the backpack. - The text does not change. This project
Check that the script is still running. The count goes up once per second. - 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. - The Pico does not show up as a drive, or the program will not load. Raspberry Pi Pico
Hold the BOOTSEL button while you plug in USB. A drive named RPI-RP2 appears. Then copy the UF2 file onto it. - A 5 V signal or sensor is wired to a GPIO pin. Raspberry Pi Pico
Pico GPIO pins are 3.3 V only and are not 5 V tolerant. Use a level shifter or a voltage divider for any 5 V output going into the board.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.