# Experiment C: Clock, Character LCD & Circuit Communication
# Complete RTC clock with multiple display modes
import machine
import utime
from machine import I2C, Pin
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
import ds1307
# ============ HARDWARE SETUP ============
I2C_ADDR_LCD = 0x27
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
# Initialize peripherals
lcd = I2cLcd(i2c, I2C_ADDR_LCD, 2, 16)
rtc = ds1307.DS1307(i2c)
button = Pin(5, Pin.IN, Pin.PULL_UP) # Optional mode button
# ============ DISPLAY MODES ============
class ClockModes:
MODE_24H = 0
MODE_12H = 1
MODE_DATE = 2
MODE_TIMER = 3
MODE_NAMES = {
MODE_24H: "24-Hour Clock",
MODE_12H: "12-Hour Clock",
MODE_DATE: "Date Display",
MODE_TIMER: "Stopwatch"
}
# ============ CUSTOM CHARACTERS (FIXED) ============
def create_custom_chars(lcd):
"""Create custom characters for LCD - CORRECTED VERSION"""
try:
# Only create if the method exists
if hasattr(lcd, 'custom_char'):
# Create 8 custom characters (0-7)
# Simple block characters for progress bar
for i in range(8):
# Create different fill levels (0-7 pixels filled)
data = []
for row in range(8):
if row < 8 - i:
data.append(0x00) # Empty
else:
data.append(0x1F) # Filled
lcd.custom_char(i, bytearray(data))
print("Custom characters created successfully")
else:
print("Note: custom_char method not available")
except Exception as e:
print(f"Error creating custom chars: {e}")
# ============ TIME FUNCTIONS ============
def get_formatted_time_24h(rtc):
year, month, day, weekday, hour, minute, second, _ = rtc.datetime()
time_str = f"{hour:02d}:{minute:02d}:{second:02d}"
date_str = f"{day:02d}/{month:02d}/{year}"
return time_str, date_str, weekday
def get_formatted_time_12h(rtc):
year, month, day, weekday, hour, minute, second, _ = rtc.datetime()
# Convert to 12-hour format
if hour == 0:
display_hour = 12
period = "AM"
elif hour < 12:
display_hour = hour
period = "AM"
elif hour == 12:
display_hour = 12
period = "PM"
else:
display_hour = hour - 12
period = "PM"
time_str = f"{display_hour:02d}:{minute:02d}:{second:02d} {period}"
date_str = f"{day:02d}/{month:02d}/{year}"
return time_str, date_str, weekday
# ============ DISPLAY FUNCTIONS (SIMPLIFIED) ============
def display_24h_clock(lcd, rtc):
time_str, date_str, weekday = get_formatted_time_24h(rtc)
lcd.clear()
lcd.putstr("[24H] " + time_str)
lcd.move_to(0, 1)
lcd.putstr("Date: " + date_str)
def display_12h_clock(lcd, rtc):
time_str, date_str, weekday = get_formatted_time_12h(rtc)
lcd.clear()
lcd.putstr("[12H] " + time_str)
lcd.move_to(0, 1)
lcd.putstr("Date: " + date_str)
def display_date(lcd, rtc):
year, month, day, weekday, hour, minute, second, _ = rtc.datetime()
month_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
day_names = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
lcd.clear()
lcd.putstr(f"{day:02d} {month_names[month-1]} {year}")
lcd.move_to(0, 1)
lcd.putstr(day_names[weekday])
# Simple progress indicator using regular characters
progress = int((hour * 60 + minute) / (24 * 60) * 16) # 0-16 chars
lcd.move_to(0, 1)
lcd.putstr("[" + "=" * progress + " " * (16 - progress - 2) + "]")
# ============ MAIN PROGRAM ============
def main():
# Initialization
print("=" * 50)
print("Experiment C: Clock, Character LCD & Circuit Communication")
print("=" * 50)
# Try to create custom characters (optional)
try:
create_custom_chars(lcd)
except:
print("Proceeding without custom characters")
current_mode = ClockModes.MODE_24H
# Check if time needs setting
print("\nChecking RTC time...")
try:
test_time = rtc.datetime()
print(f"RTC Time: {test_time[3]}/{test_time[2]}/{test_time[0]} {test_time[4]}:{test_time[5]:02d}:{test_time[6]:02d}")
except:
print("Setting default time...")
# Set to current date/time example
rtc.datetime((2024, 1, 15, 0, 14, 30, 0, 0))
print("\n=== Clock Started ===")
print("Press button (GP5) to change modes")
print("Modes: 24H → 12H → Date → Timer → 24H")
# Main loop
last_button_check = utime.ticks_ms()
debounce_delay = 300
while True:
# Mode switching with button
current_time = utime.ticks_ms()
if button.value() == 0 and utime.ticks_diff(current_time, last_button_check) > debounce_delay:
current_mode = (current_mode + 1) % 4
print(f"\nMode: {ClockModes.MODE_NAMES[current_mode]}")
last_button_check = current_time
# Display based on current mode
if current_mode == ClockModes.MODE_24H:
display_24h_clock(lcd, rtc)
elif current_mode == ClockModes.MODE_12H:
display_12h_clock(lcd, rtc)
elif current_mode == ClockModes.MODE_DATE:
display_date(lcd, rtc)
elif current_mode == ClockModes.MODE_TIMER:
lcd.clear()
lcd.putstr("Stopwatch Mode")
lcd.move_to(0, 1)
lcd.putstr("Press to start/stop")
# Serial output for monitoring
year, month, day, weekday, hour, minute, second, _ = rtc.datetime()
mode_display = ClockModes.MODE_NAMES[current_mode][:10]
print(f"{hour:02d}:{minute:02d}:{second:02d} [{mode_display}]", end='\r')
utime.sleep(0.5)
# ============ START PROGRAM ============
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
lcd.clear()
lcd.putstr("Clock Stopped")
print("\n\nExperiment completed successfully!")
except Exception as e:
print(f"\nError: {e}")
lcd.clear()
lcd.putstr("Error occurred")