Skip to content

Real-Time Clocks and Display Drivers for Clocks and Watches

Summary

This chapter covers the specialty Pico clock and watch projects. It introduces real-time clock modules (the DS3231 and its coin-cell backup battery), timekeeping accuracy, and two ways to set the correct time: NTP network time sync and manual epoch/time-zone handling. It then surveys the display driver families used to build a clock face -- seven-segment displays (TM1637), shift registers (74HC595), character LCDs (LCD1602), and TFT and round displays (ILI9341, GC9A01) -- along with watch-face design, alarm/stopwatch/timer features, and the low-power and deep-sleep techniques needed for a battery-powered wearable. Students finishing this chapter will be able to build a working clock or watch face on at least one display type and keep it synchronized to network time.

Concepts Covered

This chapter covers the following 34 concepts from the learning graph:

  1. Real Time Clock
  2. DS3231 Module
  3. Coin Cell Battery
  4. Timekeeping Accuracy
  5. NTP Time Sync
  6. Network Time Protocol
  7. Epoch Time
  8. Time Zone Offset
  9. Seven Segment Display
  10. TM1637 Driver
  11. Shift Register
  12. 74HC595 Chip
  13. LCD Character Display
  14. LCD1602 Module
  15. TFT Display
  16. ILI9341 Driver
  17. Round Display
  18. GC9A01 Driver
  19. Watch Face Design
  20. Analog Clock Hands
  21. Digital Clock Format
  22. Alarm Feature
  23. Stopwatch Feature
  24. Timer Feature
  25. Wearable Enclosure
  26. Wristband Mounting
  27. Battery Life Optimization
  28. Sleep Mode
  29. Deep Sleep
  30. Low Power Design
  31. Clock Update Interval
  32. Time Formatting Code
  33. Daylight Saving Time
  34. Custom Watch Strap

Prerequisites

This chapter builds on concepts from:


Let's Build Something That Keeps Time

Berry waving welcome This chapter is a specialty detour from robots: clocks and watches. You'll meet a chip that keeps perfect time even when your Pico is completely powered off, a whole family of display technologies for showing that time, and the low-power tricks that let a watch run for weeks on a battery smaller than a coin. Let's build something that never forgets what time it is!

Keeping Accurate Time: Real-Time Clock Modules

A Pico has no built-in sense of the actual wall-clock date and time -- left on its own, it only knows how many milliseconds have passed since it was last powered on, starting back at zero every time it resets. A real-time clock (RTC) is a dedicated hardware module built specifically to track the current date and time continuously, independent of whatever the microcontroller connected to it is doing, including through the microcontroller being reset or fully powered off. The specific RTC module used throughout this book's clock and watch projects is the DS3231 module: an I2C-connected real-time clock chip known for unusually high precision compared to cheaper RTC alternatives, thanks to a built-in temperature-compensated oscillator that automatically corrects for small timing drifts caused by temperature changes.

What actually lets a DS3231 module keep running while the rest of the circuit is unpowered is a coin cell battery -- a small, flat, disc-shaped battery mounted directly on the RTC module, wired to power only the clock-keeping circuitry, so the DS3231 can continue counting seconds for months or years even when the Pico it's attached to is completely disconnected from any other power source.

Berry's Gentle Warning

Berry warning Coin cell batteries are small enough to be a serious choking and chemical-burn hazard if swallowed, and this matters more here than in most of this book's projects because clock and watch builds are often handled by younger makers. Always install a coin cell with an adult present, double-check its polarity against the module's markings before seating it, and store spares somewhere they can't be mistaken for anything edible.

How well any clock -- RTC-based or otherwise -- actually holds the correct time over days and weeks is its timekeeping accuracy, usually expressed as how many seconds it drifts per day or per month. A basic microcontroller clock built from nothing but the Pico's internal timer can drift by several seconds a day; a DS3231's temperature-compensated design typically holds accuracy within a couple of minutes per year, which is the main reason this book's clock projects use a dedicated RTC module rather than just tracking elapsed milliseconds in code.

Setting the Time: NTP and Epoch

A brand-new DS3231 module doesn't know the current date and time any more than the Pico does -- something still has to tell it, at least once. NTP time sync is the process of setting a device's clock automatically by requesting the current time from a trusted, internet-connected time server, using the Network Time Protocol (NTP): a standard protocol computers and devices worldwide use to exchange precise time information, accurate to a small fraction of a second even after accounting for the delay of sending the request over the network.

import network, ntptime, machine

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("your-wifi-name", "your-wifi-password")

ntptime.settime()   # sets the Pico's internal clock from an NTP server

ntptime.settime() is available on Pico W boards with Wi-Fi connectivity; it contacts a default NTP server over the network, reads back the current time, and sets the Pico's own internal real-time clock to match -- your code can then read that value and use it to set the DS3231 module, so the DS3231 keeps counting accurately from a correct starting point even after the Wi-Fi connection is gone.

Whatever the time source, computers and devices need a single, unambiguous way to represent "a moment in time" as a plain number, and that's exactly what epoch time provides: the number of seconds that have elapsed since a fixed reference moment (January 1, 1970, at 00:00:00 UTC, for nearly every system you'll encounter), so any two devices comparing the same epoch number are guaranteed to be talking about the exact same instant regardless of where in the world either of them is.

An epoch number on its own says nothing about what a human would read on a wall clock in any particular place, though -- that depends on a time zone offset: the fixed number of hours (and sometimes minutes) a local clock differs from UTC time, which your code has to add to (or subtract from) an epoch value before formatting it into a locally readable time. Twice a year in many regions, that offset itself changes for part of the year -- daylight saving time is the practice of shifting local clocks forward by one hour for part of the year and back again later, which a clock project has to account for explicitly in code, since an RTC chip has no built-in awareness of daylight saving rules on its own.

Berry's Key Insight

Berry thinking Epoch time, time zone offset, and daylight saving time are really three separate, stackable adjustments -- not one combined idea. A clock's internal math should always store and compare epoch time, and only apply the time zone offset (plus a daylight-saving adjustment, if currently in effect) at the very last step, right before formatting something a human is about to read. Do the adjustment any earlier and every later calculation risks being off by exactly one time zone or one daylight-saving hour.

Now that epoch time, time zone offset, and daylight saving time have all been defined, the diagram below lets you convert a raw epoch number into readable local time under different settings.

Diagram: Epoch Time and Time Zone Converter

Run the Epoch Time and Time Zone Converter MicroSim fullscreen

Epoch Time and Time Zone Converter (MicroSim)

Type: microsim sim-id: epoch-time-timezone-converter
Library: p5.js
Status: Specified

Learning objective: Students will apply (Bloom L3: Apply) a time zone offset and a daylight saving adjustment to convert a raw epoch timestamp into correct local wall-clock time.

Canvas: 700x360px, responsive -- recompute panel widths from windowWidth in windowResized().

Layout: a left panel displaying a large scrubbable epoch-time number with a human-readable UTC date/time directly beneath it. A right panel shows the computed local date/time, updating live as controls change, alongside a small formula readout: "Local = UTC + Offset [+ 1hr DST]".

Controls: a createSlider() labeled "Epoch Time" spanning a one-year range (default set to the current date) that scrubs the displayed moment forward and backward; a createSelect() dropdown labeled "Time Zone Offset" with common whole and half-hour offsets from UTC-12 to UTC+14; a createCheckbox() labeled "Daylight Saving Time Active" (unchecked by default) that adds or removes exactly one hour from the computed local time when toggled.

Interaction: moving the Epoch Time slider live-updates both the UTC and local readouts simultaneously; toggling the Daylight Saving checkbox visibly shifts only the local-time readout by one hour with a brief highlight animation on the changed digits, making clear that DST affects the local conversion step only, never the underlying epoch or UTC value. Hovering the formula readout shows a tooltip restating the three-part conversion in plain language, matching the surrounding chapter text.

Implementation: p5.js, epoch-to-date conversion using JavaScript's built-in Date object for UTC computation, with the selected offset and DST checkbox applied as simple additional minute/hour adjustments before formatting the local-time string. Recompute all layout positions from windowWidth inside windowResized().

A Tour of Display Driver Families

A clock is only useful once it can show the time it's keeping, and unlike the single OLED display from the previous chapter, clock and watch projects draw on a much wider family of display technologies -- each with its own driver chip, wiring style, and best-fit use case. This chapter surveys five families; the companion book Clocks and Watches goes far deeper into each one.

The simplest and most recognizable is the seven-segment display: a display made of seven individually controllable bar-shaped LED segments (plus often an eighth for a decimal point) arranged so that lighting different combinations of segments forms any digit from 0 to 9. Rather than wiring each segment to its own Pico pin, most seven-segment clock modules use a TM1637 driver: a small controller chip, mounted on the display module, that accepts simple two-wire digital commands from the Pico and internally handles lighting the correct combination of segments -- similar in spirit to how the SSD1306 driver from the previous chapter handled OLED pixels.

import tm1637
from machine import Pin

display = tm1637.TM1637(clk=Pin(2), dio=Pin(3))
display.numbers(12, 30)   # shows "12:30" with the colon lit

TM1637(clk=Pin(2), dio=Pin(3)) sets up the two digital pins the driver chip uses for its own simple two-wire protocol (distinct from I2C, though similar in spirit), and display.numbers(12, 30) is a high-level convenience method that converts two separate numbers into the correct lit-segment pattern for a four-digit clock display, including the center colon.

Some display modules skip a dedicated driver chip entirely and instead rely on a more general-purpose component. A shift register is a digital chip that converts a serial stream of bits -- sent one at a time over a single data wire -- into multiple parallel output signals held steady on separate output pins, letting a Pico control many more output lines than it has physical GPIO pins available by trading a little bit of extra timing for far fewer wires. The specific shift-register chip most commonly used in this book's clock kits is the 74HC595 chip, an 8-bit shift register that can, for example, drive all eight segments of one digit (or an entire small LED matrix) from just three Pico pins: data, clock, and latch.

Berry's Key Insight

Berry thinking A TM1637 driver and a 74HC595 shift register are solving the same underlying problem -- "I need to control more outputs than I have pins for" -- but at different levels. The TM1637 is a specialized chip that already knows about seven-segment digits; a 74HC595 is a general-purpose building block with no idea what it's connected to at all. That generality is exactly why shift registers show up in so many different kinds of projects beyond just clocks.

Not every clock display uses individual LED segments at all. A LCD character display shows fixed-position text characters using liquid-crystal display technology rather than individually lit LEDs, and the specific module used throughout this book's kits is the LCD1602 module -- a common, inexpensive character LCD with a fixed grid of 16 columns by 2 rows, each cell capable of displaying one text character from a small built-in font, controlled over I2C through a small backpack board rather than the many raw data pins older LCD1602 wiring required.

For full-color, higher-resolution clock faces, this book's kits move to a TFT display: a thin-film-transistor liquid-crystal display capable of showing full-color graphics and text at a much higher resolution than a character LCD, typically driven over SPI (the protocol introduced in the previous chapter) rather than I2C, since SPI's higher speed is needed to push a full-color image fast enough to feel responsive. The specific driver chip behind most rectangular TFT modules in this book's kits is the ILI9341 driver, a widely used TFT display driver chip supporting resolutions up to 320x240 pixels in 16-bit color.

Finally, watch-face projects specifically favor a round display: a display module whose visible screen area is circular rather than rectangular, which matches the shape of a traditional analog watch face far more naturally than a rectangular TFT ever could. The specific driver chip behind most round displays in this book's kits is the GC9A01 driver, a TFT-style driver chip built for round display modules, also SPI-controlled and supporting full color, but wired to a circular pixel layout instead of a rectangular one.

Now that all five display driver families have been introduced in prose, the diagram below organizes them side by side so you can compare protocol, resolution, and best-fit use case at a glance.

Diagram: Display Driver Family Explorer

Run the Display Driver Family Explorer MicroSim fullscreen

Display Driver Family Explorer (interactive infographic)

Type: interactive-infographic sim-id: display-driver-family-explorer
Library: p5.js
Status: Specified

Learning objective: Students will classify (Bloom L2: Understand) each display driver family by its communication protocol, typical resolution, and best-fit clock or watch use case.

Canvas: 700x460px, responsive -- recompute a cardWidth from windowWidth in windowResized() collapsing a 5-wide card row to a 2-column grid below 640px and a single stacked column below 400px.

Layout: five rounded-rectangle cards -- Seven-Segment (TM1637), Shift Register (74HC595), LCD Character (LCD1602), TFT (ILI9341), Round (GC9A01) -- each showing the family name, driver chip name, and a small icon drawn with p5.js primitives representing its physical shape (segmented digit glyph, small chip-and-pins glyph, grid-of-text glyph, rectangle-with-gradient-fill glyph, circle-with-gradient-fill glyph respectively).

Interaction: clicking a card flips it to reveal three quick facts pulled directly from the surrounding chapter prose: communication protocol (two-wire / SPI / I2C), typical resolution or digit count, and one best-fit use case (e.g., GC9A01: "SPI, full color, circular -- best for analog watch faces"). Hovering a card (desktop) or single-tapping (touch) highlights its border before a second interaction flips it. A createButton() labeled "Compare All" flips every card simultaneously for quick side-by-side review.

Implementation: p5.js. Card data stored as an array of five objects {name, chip, protocol, resolution, useCase, isFlipped}. Draw with rect() and rounded corners; flip rendered as an instantaneous text swap rather than a 3D animation for simplicity and classroom-device performance. Hit-testing via rectangle bounds-checking in mousePressed(); recompute grid layout in windowResized().

Because a shift register's serial-to-parallel behavior is genuinely harder to picture than the other four families -- there's no obvious visual metaphor for "bits arriving one at a time" the way a circular screen or a text grid is self-explanatory -- it's worth a dedicated, closer look before moving on to designing an actual clock face.

Diagram: Shift Register Bit-Shift Visualizer

Run the Shift Register Bit-Shift Visualizer MicroSim fullscreen

Shift Register Bit-Shift Visualizer (MicroSim)

Type: microsim sim-id: shift-register-bit-shift-visualizer
Library: p5.js
Template: https://github.com/dmccreary/clocks-and-watches/tree/main/docs/sims/shift-register
Status: Specified

Learning objective: Students will explain (Bloom L2: Understand) how a 74HC595 shift register converts a serial bit stream, sent one bit at a time, into eight steady parallel output signals.

Canvas: 700x420px, responsive -- recompute the bit-slot and output-pin spacing from windowWidth in windowResized().

Layout: a schematic 74HC595 chip drawn as a rectangle with three labeled input pins on the left (Data, Clock, Latch) and eight labeled output pins along the bottom (Q0-Q7), each output pin connected to a small LED icon that lights when that output is HIGH. Above the chip, a horizontal row of 8 bit slots represents the serial data queued to be shifted in, shown as a sequence of filled (1) or empty (0) circles.

Controls: a createButton() labeled "Load Random Pattern" that randomizes the 8-bit input sequence; a createButton() labeled "Shift Next Bit" that advances one clock pulse, moving the next queued bit into the chip's internal register and shifting all previously loaded bits one position over (visualized as a brief animated pulse traveling along the Clock pin into the chip); a createButton() labeled "Latch Output" that copies the chip's current internal register to the eight output LEDs simultaneously, all at once.

Interaction: clicking "Shift Next Bit" repeatedly visibly fills the chip's internal register bit by bit, but the output LEDs do not change until "Latch Output" is clicked -- directly demonstrating that shifting and outputting are two separate steps. Hovering the Latch pin shows a tooltip explaining that separating shift-in from latch-out prevents a display from flickering through every partial, in-progress bit pattern while it's being loaded. A running text readout below the chip states "Bits shifted in: [n] / 8" and, once latched, "Output pattern: [binary value]".

Implementation: p5.js. Internal register modeled as an 8-element boolean array, with Shift Next Bit performing an array shift-and-insert operation each click. Output LEDs redraw from a separate "latched" copy of that array, updated only by the Latch button. Recompute chip and pin positions from windowWidth/windowHeight in windowResized().

Zooming out from individual driver chips, the poster below compares the three broader display technology families -- OLED, TFT, and ePaper -- on resolution, color, power draw, and refresh speed.

Diagram: Display Technologies Compared

Run the Display Technologies Compared poster fullscreen

Display Technologies Compared (reused poster)

Type: interactive-infographic-poster
sim-id: display-technologies
Status: Reused
Source: https://dmccreary.github.io/learning-micropython/posters/display-technologies/
Source Repo: https://github.com/dmccreary/learning-micropython/tree/main/docs/posters/display-technologies

Reused from the companion book Learning MicroPython's poster catalog. Bridges the OLED display from Chapter 8 and the TFT/round displays just covered in this section, and introduces ePaper as a third option this book's kits don't use.

Designing a Clock or Watch Face

With a real-time clock keeping accurate time and a display driver able to show it, the remaining question is purely design: what should the clock actually look like? Watch face design is the process of deciding how a clock's current time is visually represented on its display -- the layout, style, and elements shown -- independent of which specific display hardware is rendering it.

Two fundamentally different representations cover nearly every clock face you'll build. Analog clock hands represent time as the rotation angle of one or more drawn lines (hour, minute, and sometimes second hands) sweeping around a circular face, exactly the way a traditional mechanical watch does, and are a natural fit for a round display. A digital clock format instead represents time as literal text characters -- "14:07" or "2:07 PM" -- and is the natural fit for a seven-segment display, an LCD character display, or simply a simpler design choice on a TFT or round display.

Redrawing an entire clock face every possible millisecond would waste processing time and battery power for no visible benefit, since a human can't perceive changes faster than a fraction of a second anyway. The clock update interval is the deliberately chosen delay between one redraw of the clock face and the next -- often once per second for a digital format showing whole seconds, or less frequently for a face that only shows hours and minutes.

Whatever the chosen format, getting from a raw time value to something readable on screen takes one more step: time formatting code is the code responsible for converting a raw time value (hour, minute, second, each stored as a plain number) into the correctly formatted, human-readable string or shape a chosen watch face design actually displays -- padding a single-digit minute with a leading zero so "5" becomes "05," for instance, or converting an hour number into the correct rotation angle in degrees for an analog hand.

def format_digital(hour, minute):
    return "{:02d}:{:02d}".format(hour, minute)

def hand_angle_degrees(value, max_value):
    return (value / max_value) * 360

minute_hand_angle = hand_angle_degrees(minute, 60)   # 0-360 degrees
hour_hand_angle = hand_angle_degrees(hour % 12, 12)  # 0-360 degrees

format_digital() is time formatting code for a digital clock format: "{:02d}" pads each number to two digits with a leading zero if needed, so 5 becomes "05" rather than a confusing single-digit "5:7". hand_angle_degrees() is time formatting code for an analog clock hands design instead: it converts a raw value (like minute, which ranges 0-59) into a rotation angle in degrees by treating a full circle as the value's maximum, which is exactly the calculation a drawing routine needs before it can actually rotate a hand shape into position.

Now that analog clock hands, digital clock format, and clock update interval are all defined, the diagram below lets you compare both watch face styles side by side, both driven from the same underlying time.

Diagram: Analog and Digital Watch Face Designer

Run the Analog and Digital Watch Face Designer MicroSim fullscreen

Analog and Digital Watch Face Designer (MicroSim)

Type: microsim sim-id: analog-digital-watch-face-designer
Library: p5.js
Template: https://github.com/dmccreary/microsims/tree/main/docs/sims/analog-clock
Status: Specified

Learning objective: Students will compare (Bloom L4: Analyze) how analog clock hands and digital clock format each represent the identical real-time clock reading, and observe the visible effect of clock update interval on redraw smoothness.

Canvas: 700x420px, responsive -- recompute both face panels' scale from windowWidth in windowResized(), stacking them vertically below 600px wide.

Layout: two side-by-side panels sharing one simulated clock time -- a left panel showing an analog watch face (circular outline, hour/minute/second hands as rotated line segments) and a right panel showing the same time in digital clock format on a simulated seven-segment-style readout.

Controls: a createSlider() labeled "Simulated Time (minutes since midnight)" (range 0-1439, default set to current time) scrubbing both faces simultaneously; a createSlider() labeled "Clock Update Interval (ms)" (range 0-2000, default 1000) controlling how often both faces actually redraw, with a visible small "tick" flash on each redraw event; a createCheckbox() labeled "Show Seconds" toggling the second hand on the analog face and a seconds field on the digital readout.

Interaction: at a large update interval (over 1000 ms), the second hand and digital seconds field visibly jump in noticeable steps rather than sweeping smoothly, directly demonstrating the update-interval tradeoff described in the chapter text; at very low intervals the motion looks continuous. Hovering either face's hour or minute value shows a tooltip stating the underlying raw value and its converted angle or formatted string, tying directly back to the hand_angle_degrees() and format_digital() functions in the surrounding prose.

Implementation: p5.js, hand angles computed each redraw with map() from raw time values to 0-360 degrees and drawn with rotate(); digital format string built with JavaScript's padStart(2, '0') as the direct equivalent of the chapter's Python "{:02d}" formatting. Redraw timing gated by a millis()-based check against the Clock Update Interval slider value rather than redrawing every animation frame, so the interval's visual effect is genuine rather than simulated.

Beyond Telling Time: Alarms, Stopwatches, and Timers

Once a clock reliably tracks and displays the current time, three closely related features build directly on top of it, each comparing the current time against a different kind of target. An alarm feature compares the current time against one or more stored target times and triggers a sound or visual signal the moment the current time matches, exactly the way a bedside alarm clock works. A stopwatch feature measures and displays elapsed time counting upward from the moment it was started, until it's stopped or reset -- useful for timing an activity of unknown length. A timer feature does the opposite: it counts downward from a chosen starting duration to zero, then signals when that countdown completes, useful for a fixed, known duration like a five-minute study break.

The table below compares the three now that each has been explained in prose.

Feature Direction Comparison Typical trigger
Alarm Fixed point in time Current time == target time Sound/visual at a specific moment
Stopwatch Counts up from zero Elapsed time since start Manually stopped by the user
Timer Counts down to zero Remaining time until zero Sound/visual when countdown ends

Building a Wearable

A clock that sits on a desk has very different physical requirements from a watch worn on a wrist, and this book's watch-tier kits are specifically designed to be worn. A wearable enclosure is the physical housing that protects a watch's electronics -- Pico, RTC module, display, coin cell battery -- while remaining small and light enough to be worn comfortably, usually 3D-printed or laser-cut to the kit's specific board dimensions. Getting that enclosure actually onto a wrist requires wristband mounting: the specific hardware and design features (strap slots, pin bars, adjustable clasps) that attach the enclosure to a band that wraps around a wrist.

Because "one size fits all" rarely holds true for wrist sizes across a classroom of students, many builders design a custom watch strap -- a wristband made specifically for a particular wearer or project, whether 3D-printed, laser-cut from fabric or leather, or assembled from purchased strap hardware -- rather than relying on a single fixed-size strap included in a kit.

You've Got This!

Berry encouraging you Fitting a Pico, an RTC module, a display, and a coin cell battery into something small enough to comfortably wear is a genuinely tricky design constraint -- way tighter than anything else in this book so far. If your first enclosure attempt comes out a little bulky, that's completely normal engineering iteration, not a failed build. Measure, adjust, print again.

Making the Battery Last

A desktop clock plugged into a wall has no reason to worry about power consumption. A wrist-worn watch running on a small battery has almost no other concern. Battery life optimization is the general practice of reducing a device's power consumption specifically to extend how long it can run on a given battery, and for a watch, it's often the difference between a project that survives a school week and one that dies by lunchtime.

Two related hardware features make that optimization possible on the Pico. Sleep mode is a low-power state where the processor pauses most activity but can wake quickly in response to a timer or an external event, using dramatically less power than fully active operation while still being able to resume in a fraction of a second. Deep sleep is an even lower-power state that shuts down far more of the microcontroller's internal circuitry than sleep mode does, using still less power in exchange for a slower, more limited wake-up process -- typically only a full reset rather than resuming exactly where the program left off.

import machine

# Update the display, then sleep until the next update is due
update_watch_face()
machine.lightsleep(1000)     # sleep mode -- wake automatically after 1 second

# For much longer idle stretches, e.g. overnight:
machine.deepsleep(8 * 60 * 60 * 1000)   # deep sleep for 8 hours

machine.lightsleep(1000) puts the Pico into sleep mode for one second, which is a natural fit right after a clock face redraw -- there's nothing useful to compute again until the next clock update interval arrives anyway, so sleeping through that gap saves real power compared to spinning in an active loop doing nothing. machine.deepsleep(8 * 60 * 60 * 1000) puts the Pico into the much deeper power-saving state for eight hours, appropriate for a watch that doesn't need to update its face at all overnight, accepting that the program restarts from the beginning on waking rather than resuming mid-loop.

Combining these sleep states thoughtfully with everything else in this chapter -- a slower clock update interval, a dimmer display contrast setting, sleeping between updates instead of polling constantly -- is the essence of low-power design: designing a whole project's hardware and software choices around minimizing power consumption from the very start, rather than trying to patch power savings on at the end.

Let's compare all of this side by side before wrapping up: how update interval, sleep mode, and deep sleep each trade responsiveness for battery life.

Diagram: Power Mode and Battery Life Simulator

Run the Power Mode and Battery Life Simulator MicroSim fullscreen

Power Mode and Battery Life Simulator (MicroSim)

Type: microsim sim-id: power-mode-battery-life-simulator
Library: p5.js
Template: https://github.com/dmccreary/microsims/tree/main/docs/sims/battery-life
Status: Specified

Learning objective: Students will evaluate (Bloom L5: Evaluate) the tradeoff between clock update interval and estimated battery life across active, sleep, and deep sleep power modes.

Canvas: 700x420px, responsive -- recompute the current-draw bar chart and estimated-life readout layout from windowWidth in windowResized().

Layout: a horizontal bar chart showing simulated current draw (in milliamps, on a log-scaled axis) for three power modes -- Active, Sleep, Deep Sleep -- as three colored bars (raspberry red for Active, copper gold for Sleep, circuit green for Deep Sleep). Beneath the chart, a large readout displays "Estimated battery life: [X days, Y hours]" computed from the currently selected mix of modes and a fixed coin-cell capacity assumption.

Controls: a createSlider() labeled "Clock Update Interval (seconds)" (range 1-60, default 5) controlling how often the simulated device wakes from sleep mode into active mode to redraw; a createSlider() labeled "Percent Time in Deep Sleep" (range 0-95, default 0) representing how much of each day the watch spends in deep sleep (e.g., overnight) rather than cycling between active and sleep; a createButton() labeled "Reset to Always-On" that sets update interval to 1 second and deep-sleep percentage to 0, showing the worst-case battery life for comparison.

Interaction: moving either slider immediately recalculates and animates the estimated-battery-life readout counting up or down to its new value, and the three bars' relative heights update to reflect the new time-weighted average current draw. Hovering any bar shows a tooltip with that mode's approximate current draw in milliamps and one sentence describing when a real watch would use it, matching the surrounding chapter text. Clicking "Reset to Always-On" animates the readout dropping sharply, visually demonstrating just how much battery life sleep and deep sleep recover.

Implementation: p5.js, battery life estimated with a simple weighted-average formula: total current draw = (active fraction x active mA) + (sleep fraction x sleep mA) + (deep-sleep fraction x deep-sleep mA), then estimated hours = assumed battery capacity (mAh) / total current draw (mA). Active fraction derived from the update-interval slider (shorter interval means proportionally more time active). Recompute chart and text layout from windowWidth in windowResized().

Bringing It Together

You've now built the specialty half of this book's Pico projects: a clock that keeps accurate time on its own hardware, synced correctly across time zones and daylight saving changes, shown through whichever display driver family fits your project best, and, if you took it all the way to a watch, running for days on a battery small enough to disappear onto a wrist. Every display driver, timing technique, and low-power trick in this chapter reuses the same core skills from earlier in the book -- I2C and SPI communication, frame buffers and drawing primitives, non-blocking behavior loops -- applied to a new, wearable form factor. From here, the rest of Learning STEM with Raspberry Pi Hardware moves up to bigger hardware tiers: the Pi 500+ keyboard computer and the Pi 5 with real-time AI vision, where these same computational-thinking habits scale up to full Linux computing.

You Unlocked a Superpower!

Berry celebrating From a bouncing button all the way to a battery-sipping wristwatch that never loses track of time -- that's a berry impressive stretch of superpowers to pick up. Every wire really does tell a story, and yours has been a great one so far. STEM is our superpower -- let's keep building!

See Annotated References