Skip to content

Character LCD Clock

The LCD1602 is a low cost ($5) character LCD display with 16 characters in two rows. They frequently come with an I2C interface. In this kit we combine this display with a real-time clock chip to create a clock that will display the date, time and temperature

I2C Scanner

In our kit, we put the I2C data pins on GPIO 0 (row 1 of the breadboard) and we put the I2C clock pin on GPIO 1 (row 2 of the breadboard).

When we run the I2C scanner we should be able to see the address of the LCD display and the real-time clock.

Here is the I2C scanner code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import machine
I2C_SDA_PIN = 0
I2C_SCL_PIN = 1
i2c=machine.I2C(0,sda=machine.Pin(I2C_SDA_PIN), scl=machine.Pin(I2C_SCL_PIN), freq=400000)

print('Scanning I2C bus.')
devices = i2c.scan() # this returns a list of devices
device_count = len(devices)
if device_count == 0:
    print('No i2c device found.')
else:
    print(device_count, 'devices found.')
for device in devices:
    print('Decimal address:', device, ", Hex address: ", hex(device))

LCD1602 MicroPython Libraries

Because the LCD1602 is a common display, there are several LCD1602 libraries. Many of the share a common interface language.

Here is how we initialize the LCD driver

1
2
3
4
5
6
I2C_ADDR     = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

Sample Clock Program

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from machine import I2C, Pin
from lcd_api import LcdApi
from pico_i2c_lcd import I2cLcd
from utime import sleep, localtime

I2C_ADDR     = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

while True:
    # Clear the display before writing new content
    lcd.clear()

    # change this line to read the RTC time
    now = localtime()
    year = now[0]
    month = now[1]
    day = now[2]
    hour = now[3]
    minute = now[4]
    second = now[5]

    if hour == 0:
        # Midnight edge case
        hour = 12
        am_pm = 'AM'
    elif hour == 12:
        # Noon edge case
        am_pm = 'PM'
    elif hour > 12:
        # Afternoon hours
        hour -= 12
        am_pm = 'PM'
    else:
        # Morning hours
        am_pm = 'AM'

    # Format date on first row - centered
    date_str = f"{month:02d}/{day:02d}/{year}"
    lcd.move_to((16 - len(date_str)) // 2, 0)  # Center the date
    lcd.putstr(date_str)

    # Format time on second row with seconds
    time_str = f"{hour}:{minute:02d}:{second:02d} {am_pm}"
    lcd.move_to((16 - len(time_str)) // 2, 1)  # Center the time
    lcd.putstr(time_str)

    sleep(1)

Purchasing

I recommend getting the version with the

eBay Listing with I2c Backpack

References

eBay Search for 16X3 LCD Display I2C