from machine import I2C, Pin
from time import sleep
# Setup I2C
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
I2C_ADDR = 0x27 # Adjust if needed
# LCD constants
LCD_WIDTH = 20
LCD_LINE_1 = 0x80
LCD_LINE_2 = 0xC0
LCD_LINE_3 = 0x94
LCD_LINE_4 = 0xD4
LCD_BACKLIGHT = 0x08
ENABLE = 0b00000100
# Send byte to LCD
def lcd_strobe(data):
i2c.writeto(I2C_ADDR, bytes([data | ENABLE | LCD_BACKLIGHT]))
sleep(0.0005)
i2c.writeto(I2C_ADDR, bytes([(data & ~ENABLE) | LCD_BACKLIGHT]))
sleep(0.0001)
def lcd_write_four_bits(data):
i2c.writeto(I2C_ADDR, bytes([data | LCD_BACKLIGHT]))
lcd_strobe(data)
def lcd_write_cmd(cmd):
lcd_write_four_bits(cmd & 0xF0)
lcd_write_four_bits((cmd << 4) & 0xF0)
def lcd_write_char(char):
lcd_write_four_bits((char & 0xF0) | 0x01)
lcd_write_four_bits(((char << 4) & 0xF0) | 0x01)
def lcd_init():
sleep(0.02)
lcd_write_four_bits(0x30)
sleep(0.005)
lcd_write_four_bits(0x30)
sleep(0.001)
lcd_write_four_bits(0x30)
lcd_write_four_bits(0x20)
lcd_write_cmd(0x28) # 4-bit, 2 lines, 5x8 font
lcd_write_cmd(0x0C) # Display on, cursor off, blink off
lcd_write_cmd(0x06) # Entry mode
lcd_write_cmd(0x01) # Clear display
sleep(0.002)
def lcd_clear():
lcd_write_cmd(0x01)
sleep(0.002)
def lcd_set_cursor(line):
lcd_write_cmd(line)
def lcd_puts(message, line):
lcd_set_cursor(line)
msg = str(message) # Safely ensure it's a string
padded = msg + ' ' * (LCD_WIDTH - len(msg)) # Manual right-padding
for char in padded[:LCD_WIDTH]:
lcd_write_char(ord(char))
# Timer Function
def format_time(seconds):
mins = seconds // 60
secs = seconds % 60
return "{:02}:{:02}".format(mins, secs)
def timer(seconds):
lcd_clear()
lcd_puts("Countdown Timer", LCD_LINE_1)
for t in range(seconds, -1, -1):
lcd_puts("Time Left: " + format_time(t), LCD_LINE_2)
sleep(1)
lcd_puts(" Time's up! ", LCD_LINE_3)
# === Main ===
lcd_init()
timer(120) # Countdown from 2 minutes