Once you've finished setting up your Feather RP2040 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT
import time
import board
import simpleio
import adafruit_ds3231
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
from adafruit_ht16k33 import segments
from adafruit_debouncer import Button
from adafruit_seesaw import seesaw, rotaryio, digitalio
# min and max display brightness range
# value must be 0.0 to 1.0
max_brightness = 1
min_brightness = 0.01
# weekday hours to have clock on max brightness
# (24-hour time)
weekday_wakeup = 8
weekday_sleep = 21
# weekend hours to have clock on max brightness
# (24-hour time)
weekend_wakeup = 9
weekend_sleep = 23
i2c = board.STEMMA_I2C()
rtc = adafruit_ds3231.DS3231(i2c)
seesaw = seesaw.Seesaw(i2c, addr=0x36)
seesaw.pin_mode(24, seesaw.INPUT_PULLUP)
ss_pin = digitalio.DigitalIO(seesaw, 24)
button = Button(ss_pin, long_duration_ms=1000)
encoder = rotaryio.IncrementalEncoder(seesaw)
last_position = 0
# pylint: disable-msg=using-constant-test
if False: # change to True if you want to set the time!
# year, mon, date, hour, min, sec, wday, yday, isdst
t = time.struct_time((2024, 1, 25, 15, 7, 0, 3, -1, -1))
# you must set year, mon, date, hour, min, sec and weekday
# yearday is not supported, isdst can be set but we don't do anything with it at this time
print("Setting time to:", t) # uncomment for debugging
rtc.datetime = t
print()
# pylint: enable-msg=using-constant-test
display = segments.BigSeg7x4(i2c)
display.fill(0)
display.brightness = max_brightness
display.colon = True
def clock_conversion(h, m, set_brightness):
# pylint: disable-msg=simplifiable-if-expression
am_pm = False if h < 12 else True
hour_12 = h if h <= 12 else h - 12
if hour_12 == 0:
hour_12 = 12
display.print(f"{(hour_12):02}:{m:02}") # Use for leading zero re. 09:35
# display.print(f"{hour_12:2}:{m:02}") # uncomment to suppress leading zero
# # (shows 1:00 instead of 01:00)
display.ampm = am_pm
if set_brightness:
if awake_hours[0] <= h <= awake_hours[1] - 1:
display.brightness = max_brightness
elif h is awake_hours[0] - 1:
bright = simpleio.map_range(m, 0, 59, min_brightness, max_brightness)
display.brightness = bright
elif h is awake_hours[1]:
bright = simpleio.map_range(m, 0, 59, max_brightness, min_brightness)
display.brightness = bright
else:
display.brightness = min_brightness
else:
display.brightness = max_brightness
clock_clock = ticks_ms()
clock_timer = 1 * 1000
clock_mode = True
set_hour = True
power_up = True
hour = 0
minute = 0
while True:
if clock_mode:
button.update()
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
t = rtc.datetime
if t.tm_wday in range(5, 6):
awake_hours = [weekend_wakeup, weekend_sleep]
else:
awake_hours = [weekday_wakeup, weekday_sleep]
if t.tm_sec < 1 or power_up:
power_up = False
clock_conversion(t.tm_hour, t.tm_min, True)
clock_clock = ticks_add(clock_clock, clock_timer)
else:
button.update()
position = -encoder.position
if position != last_position:
if position > last_position:
if set_hour:
hour = (hour + 1) % 24
else:
minute = (minute + 1) % 60
else:
if set_hour:
hour = (hour - 1) % 24
else:
minute = (minute - 1) % 60
clock_conversion(hour, minute, False)
last_position = position
if button.short_count:
set_hour = not set_hour
# toggling dots with not did not seem to work consistantly
# so setting manually
if set_hour:
display.top_left_dot = True
display.bottom_left_dot = False
else:
display.top_left_dot = False
display.bottom_left_dot = True
if button.long_press:
if not clock_mode:
t = rtc.datetime
new_t = time.struct_time((t.tm_year, t.tm_mon, t.tm_mday,
hour, minute, t.tm_sec, t.tm_wday,
t.tm_yday, t.tm_isdst))
print("Setting time to:", new_t)
rtc.datetime = new_t
clock_clock = ticks_add(clock_clock, clock_timer)
power_up = True
display.top_left_dot = False
display.bottom_left_dot = False
else:
set_hour = True
t = rtc.datetime
hour = t.tm_hour
minute = t.tm_min
clock_mode = not clock_mode
display.blink_rate = not display.blink_rate
Upload the Code and Libraries to the Feather RP2040
After downloading the Project Bundle, plug your Feather RP2040 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Feather RP2040's CIRCUITPY drive:
- lib folder
- code.py
Your Feather RP2040 CIRCUITPY drive should look like this after copying the lib folder and the code.py file.
How the CircuitPython Code Works
At the top of the code are user configurable settings for the clock. The first two are for the brightness range. The max_brightness is the setting the clock will have during the day and min_brightness is the setting the clock will have overnight. The next settings are for the hours that trigger the brightness to change during the week and during the weekend. These hours are in 24-hour time.
# min and max display brightness range # value must be 0.0 to 1.0 max_brightness = 1 min_brightness = 0.01 # weekday hours to have clock on max brightness # (24-hour time) weekday_wakeup = 8 weekday_sleep = 21 # weekend hours to have clock on max brightness # (24-hour time) weekend_wakeup = 9 weekend_sleep = 23
I2C
Next all of the breakouts are instantiated over I2C. The button on the rotary encoder is passed as a Button object to the adafruit_debouncer library.
i2c = board.STEMMA_I2C() rtc = adafruit_ds3231.DS3231(i2c) seesaw = seesaw.Seesaw(i2c, addr=0x36) seesaw.pin_mode(24, seesaw.INPUT_PULLUP) ss_pin = digitalio.DigitalIO(seesaw, 24) button = Button(ss_pin, long_duration_ms=1000) encoder = rotaryio.IncrementalEncoder(seesaw) last_position = 0 display = segments.BigSeg7x4(i2c)
Set the RTC
There is a bit of code that lets you initially set the RTC module. If you change the if statement to True, you can edit the struct_time object to match your current time and save the code to program the RTC.
Remember to change it back to False and resave it when done setting the time, otherwise if the board is reset or power cycled the time we be incorrectly set.
if False: # change to True if you want to set the time!
# year, mon, date, hour, min, sec, wday, yday, isdst
t = time.struct_time((2024, 1, 25, 15, 7, 0, 3, -1, -1))
# you must set year, mon, date, hour, min, sec and weekday
# yearday is not supported, isdst can be set but we don't do anything with it at this time
print("Setting time to:", t) # uncomment for debugging
rtc.datetime = t
print()
Clock Conversion
There is a function called clock_conversion that takes care of converting the time from the RTC to 12-hour time for displaying on the 7-segment display. It also adjusts the display brightness.
def clock_conversion(h, m, set_brightness):
# pylint: disable-msg=simplifiable-if-expression
am_pm = False if h < 12 else True
hour_12 = h if h <= 12 else h - 12
if hour_12 == 0:
hour_12 = 12
display.print(f"{(hour_12):02}:{m:02}") # Use for leading zero re. 09:35
# display.print(f"{hour_12:2}:{m:02}") # uncomment to suppress leading zero
# # (shows 1:00 instead of 01:00)
display.ampm = am_pm
if set_brightness:
if awake_hours[0] <= h <= awake_hours[1] - 1:
display.brightness = max_brightness
elif h is awake_hours[0] - 1:
bright = simpleio.map_range(m, 0, 59, min_brightness, max_brightness)
display.brightness = bright
elif h is awake_hours[1]:
bright = simpleio.map_range(m, 0, 59, max_brightness, min_brightness)
display.brightness = bright
else:
display.brightness = min_brightness
else:
display.brightness = max_brightness
Note the default behavior is to display a leading zero for times between 01:00 and 09:59. It you'd rather have a "space/blank" leading time, Comment the one line and uncomment out the others as shown below:
Default (leading zero):
display.print(f"{(hour_12):02}:{m:02}") # Use for leading zero re. 09:35
# display.print(f"{hour_12:2}:{m:02}") # uncomment to suppress leading zero
Suppress leading zero:
# display.print(f"{(hour_12):02}:{m:02}") # Use for leading zero re. 09:35
display.print(f"{hour_12:2}:{m:02}") # uncomment to suppress leading zero
The Loop
In the loop, ticks is used to check the RTC every second. When the minute advances, the clock_conversion function is called to update the display. The awake_hours (full brightness hours on the weekend versus weekdays) are also adjusted depending on the reading from the RTC.
if clock_mode:
button.update()
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
t = rtc.datetime
if t.tm_wday in range(5, 6):
awake_hours = [weekend_wakeup, weekend_sleep]
else:
awake_hours = [weekday_wakeup, weekday_sleep]
if t.tm_sec < 1 or power_up:
power_up = False
clock_conversion(t.tm_hour, t.tm_min, True)
clock_clock = ticks_add(clock_clock, clock_timer)
Set the Time
If a long press is read from the button on the encoder while in clock_mode, clock_mode is set to False and you are able to use the encoder to adjust the hour and minute settings. While in this mode, the display blinks. When you long press the button again, it updates the RTC with the hour and minute settings you've just entered with the encoder and goes back to clock_mode.
else:
button.update()
position = -encoder.position
if position != last_position:
if position > last_position:
if set_hour:
hour = (hour + 1) % 24
else:
minute = (minute + 1) % 60
else:
if set_hour:
hour = (hour - 1) % 24
else:
minute = (minute - 1) % 60
clock_conversion(hour, minute, False)
last_position = position
if button.short_count:
set_hour = not set_hour
# toggling dots with not did not seem to work consistantly
# so setting manually
if set_hour:
display.top_left_dot = True
display.bottom_left_dot = False
else:
display.top_left_dot = False
display.bottom_left_dot = True
if button.long_press:
if not clock_mode:
t = rtc.datetime
new_t = time.struct_time((t.tm_year, t.tm_mon, t.tm_mday,
hour, minute, t.tm_sec, t.tm_wday,
t.tm_yday, t.tm_isdst))
print("Setting time to:", new_t)
rtc.datetime = new_t
clock_clock = ticks_add(clock_clock, clock_timer)
power_up = True
display.top_left_dot = False
display.bottom_left_dot = False
else:
set_hour = True
t = rtc.datetime
hour = t.tm_hour
minute = t.tm_min
clock_mode = not clock_mode
display.blink_rate = not display.blink_rate
Page last edited October 22, 2025
Text editor powered by tinymce.