From a14585d1b8576932342690d85bfec44d3e07c93b Mon Sep 17 00:00:00 2001 From: Dan Mccreary Date: Sun, 29 Dec 2024 10:05:41 -0600 Subject: [PATCH] Deployed 950a609 with MkDocs version: 1.6.1 --- glossary/index.html | 2834 +++++++++++++++++++++++++++----------- search/search_index.json | 2 +- 2 files changed, 2040 insertions(+), 796 deletions(-) diff --git a/glossary/index.html b/glossary/index.html index 91277844..08158677 100644 --- a/glossary/index.html +++ b/glossary/index.html @@ -682,915 +682,855 @@ +
  • + + + Libraries + + - +
  • - +
  • + + + Loading Drivers + + - - - +
  • +
  • + + + Logging + + +
  • + +
  • + + + Logging Time Data to an SD Card + + - - -
  • - - - - - FAQ - - - - -
  • - - - - - - - - - -
  • - - - - - References - - - - -
  • - - - - + +
  • + + + Loops + + - - - -
  • - - - - - Contact - - - - -
  • - - - - + +
  • + + + Math Module + + - - - -
  • - - - - - FAQ - - - - -
  • - - - - - - - - - - - -
    -
    -
    - - - + + + + + + + + + + + +
  • + + + + + FAQ + + + + +
  • + + + + + + + + + +
  • + + + + + References + + + + +
  • + + + + + + + + + +
  • + + + + + Contact + + + + +
  • + + + + + + + + + +
  • + + + + + FAQ + + + + +
  • + + + + + +
    +
    +
    + + + +
    + -
    - - - -
    -
    - - - + + +
  • + + + Battery Tools + + +
  • + +
  • + + + Blitting + + - - -

    Glossary of Terms DIY Clocks and Watches with MicroPython

    -

    Abstraction

    -

    A technique for managing complexity by hiding unnecessary details while keeping essential features visible.

    -

    Example: Using a display_time() function that accepts hours and minutes without needing to know how individual LED segments are controlled.

    -

    Breadboard

    -

    A reusable plastic board with holes and internal connections for prototyping electronic circuits without soldering.

    -

    Example: Connecting LED displays and buttons to the Pico W using jumper wires on a breadboard.

    -

    Button Debouncing

    -

    A technique to prevent false button readings caused by mechanical switch contacts bouncing when pressed or released.

    -

    Example: debounce_time = 100 in button configuration prevents multiple accidental triggers.

    -

    Callback Function

    -

    A function passed as an argument to another function, which will be executed when a specific event occurs.

    -

    Example: button_mode_irq function that runs whenever the mode button is pressed.

    -

    Digital Display

    -

    An electronic output device that shows numbers, letters, or symbols using discrete segments or pixels.

    -

    Example: Four-digit seven-segment LED display showing hours and minutes.

    -

    DS1307

    -

    Event Handler

    -

    A function that responds to specific occurrences like button presses or timer updates.

    -

    Example: The button_mode_irq function handles mode button press events.

    -

    GPIO Pin

    -

    General Purpose Input/Output connection on a microcontroller that can be programmed to send or receive electrical signals.

    -

    Example: Using GPIO pin 16 for the mode button: mode_pin = Pin(16, Pin.IN, Pin.PULL_UP)

    -

    I2C

    -

    A communication protocol that allows multiple digital components to exchange data using just two wires plus power and ground.

    -

    Interrupt

    -

    A signal that causes the microcontroller to pause its current task and handle a high-priority event.

    -

    LED Matrix

    -

    An array of light-emitting diodes arranged in rows and columns that can display patterns, numbers, or text.

    -

    MicroPython

    -

    A streamlined version of Python programming language designed to run on microcontrollers and embedded systems.

    -

    OLED Display

    -

    A thin, bright display that uses organic light-emitting diodes to show text and graphics without a backlight.

    -

    Pin

    -

    A metal connector on electronic components that carries electrical signals or power.

    -

    Pull-up Resistor

    -

    An electronic component that ensures a consistent voltage level on input pins when buttons or switches are not pressed.

    -

    Example: Using internal pull-up resistors with Pin.PULL_UP for button inputs.

    -

    PWM

    -

    Pulse Width Modulation - a technique for creating varying levels of brightness or speed by rapidly switching a signal on and off.

    -

    Raspberry Pi Pico W

    -

    A small, low-cost microcontroller board with built-in wireless capabilities, designed for learning and DIY projects.

    -

    Real-Time Clock (RTC)

    -

    A specialized chip or circuit that keeps accurate time even when main power is removed.

    -

    Example: Using the RTC module to maintain accurate time: rtc = RTC()

    -

    Seven-Segment Display

    -

    A display made of seven LED segments plus a decimal point that can show numbers and some letters.

    -

    Example: Creating patterns for digits using segments 'a' through 'g': SEGMENTS = {'a': 4, 'b': 3, 'c': 2, 'd': 7, 'e': 6, 'f': 5, 'g': 1}

    -

    Shift Register

    -

    An integrated circuit that converts serial data into parallel outputs, useful for controlling multiple LEDs with fewer pins.

    -

    Example: Using SR74HC595 shift register to control display segments.

    -

    SPI

    -

    Serial Peripheral Interface - a fast communication protocol for connecting digital components using multiple signal lines.

    -

    State Machine

    -

    A programming concept where a system can be in one of several defined states, with specific rules for transitioning between them.

    -

    Example: Clock modes including "run", "set hour", "set minute", and "set AM/PM".

    -

    USB Power

    -

    A 5-volt power source available through Universal Serial Bus connections, commonly used for powering small electronic projects.

    -

    Web Services

    -

    Online resources that provide data or functionality through standard internet protocols.

    -

    Example: Fetching current time from an internet time server for clock synchronization.

    +
  • + +
  • + + + Breadboard + + + +
  • + +
  • + + + Button Debouncing + + + +
  • + +
  • + + + Button Input Handling + + + +
  • + +
  • + + + Callback Function + + + +
  • + +
  • + + + Changing Fonts + + + +
  • + +
  • + + + Chimes + + + +
  • + +
  • + + + Chronograph + + + +
  • + +
  • + + + Color Animations + + + +
  • + +
  • + + + Color Conversion + + + +
  • + +
  • + + + Color Conversion & Palettes + + + +
  • + +
  • + + + Color Depth + + + +
  • + +
  • + + + Concurrency + + + +
  • + +
  • + + + Conditionals + + + +
  • + +
  • + + + Connecting Speakers + + + +
  • + +
  • + + + Console Output + + + +
  • + +
  • + + + Cuckoo Clock + + + +
  • + +
  • + + + Custom Font + + + +
  • + +
  • + + + Custom Segment Display + + + +
  • + +
  • + + + DS1307 + + + +
  • + +
  • + + + DS3231 + + + +
  • + +
  • + + + Date and Calendar Display + + + +
  • + +
  • + + + Daylight Saving Time + + + +
  • + +
  • + + + Deep Sleep + + + +
  • + +
  • + + + Digital Display + + + +
  • + +
  • + + + Display Driver + + + +
  • + +
  • + + + Display Technology Comparison + + + +
  • + +
  • + + + Double Buffering + + + +
  • + +
  • + + + Drawing Arcs + + + +
  • + +
  • + + + Drawing Circles + + + +
  • + +
  • + + + Drawing Ellipses + + + +
  • + +
  • + + + Drawing Hands + + + +
  • + +
  • + + + Drawing Libraries + + + +
  • + +
  • + + + Drawing Lines + + + +
  • + +
  • + + + Drawing Numbers + + + +
  • + +
  • + + + Drawing Pixels + + + +
  • + +
  • + + + Drawing Polygons + + + +
  • + +
  • + + + Drawing Primitives + + + +
  • + +
  • + + + Drawing Rectangles + + + +
  • + +
  • + + + Drawing Text + + + +
  • + +
  • + + + Drawing Tick Marks + + + +
  • + +
  • + + + E-Paper Display + + + +
  • + +
  • + + + Error Handling and Recovery + + + +
  • + +
  • + + + External RTC + + + +
  • + +
  • + + + External Sensors + + + +
  • + +
  • + + + Fast Redraw + + + +
  • + +
  • + + + Filesystem + + + +
  • + +
  • + + + Flicker Reduction + + + +
  • + +
  • + + + Framebuffer + + + +
  • + +
  • + + + Functions + + + +
  • + +
  • + + + GPIO Pin + + + +
  • + +
  • + + + Generating Waveforms for Audio + + + +
  • + +
  • + + + Ghosting + + + +
  • + +
  • + + + Hardware Documentation + + + +
  • + +
  • + + + I2C + + + +
  • + +
  • + + + I2C Sensors + + + +
  • + +
  • + + + Implementing Clock Themes + + + +
  • + +
  • + + + Incremental Drawing + + + +
  • + +
  • + + + Interrupt + + + +
  • + +
  • + + + JSON + + + +
  • + +
  • + + + LED Clock Displays + + + +
  • + +
  • + + + LED Matrix + + + +
  • + +
  • + + + LiPo Charging + + + +
  • + +
  • + + + LiPo Charging Circuit + + + +
  • + +
  • + + + Libraries + + + +
  • + +
  • + + + Loading Drivers + + + +
  • + +
  • + + + Logging + + + +
  • + +
  • + + + Logging Time Data to an SD Card + + + +
  • + +
  • + + + Loops + + + +
  • + +
  • + + + Math Module + + + +
  • + +
  • + + + Menu System + + + +
  • + +
  • + + + Menu Systems for Watch Settings + + + +
  • + +
  • + + + MicroPython + + + +
  • + +
  • + + + MicroPython Drawing + + + +
  • + +
  • + + + MicroPython Syntax + + + +
  • + +
  • + + + MicroPython network + + + +
  • + +
  • + + + Network Time Protocol (NTP) + + + +
  • + +
  • + + + OLED Display + + + +
  • + +
  • + + + PWM + + + +
  • + +
  • + + + PWM Audio + + + +
  • + +
  • + + + Partial Refresh + + + +
  • + +
  • + + + Partial Screen Updates + + + +
  • + +
  • + + + Pedometer + + + +
  • + +
  • + + + Pin + + + +
  • + +
  • + + + Power Management + + + +
  • + +
  • + + + Power Monitoring + + + +
  • + +
  • + + + Pull-up Resistor + + + +
  • + +
  • + + + Raspberry Pi Pico W + + + +
  • + +
  • + + + Real-Time Clock (RTC) + + + +
  • + +
  • + + + Real-time Clock (RTC) Overview + + + +
  • + +
  • + + + Rotary Encoder + + + +
  • + +
  • + + + SPI + + + +
  • + +
  • + + + SPI Interface + + + +
  • + +
  • + + + Screen Tearing Prevention + + + +
  • + +
  • + + + Screen Update + + + +
  • + +
  • + + + Screen Via SPI + + + +
  • + +
  • + + + Servo Motor + + + +
  • + +
  • + + + Setting System Clock + + + +
  • + +
  • + + + Setting Time with Buttons + + + +
  • + +
  • + + + Setting Up I²C Communication + + + +
  • + +
  • + + + Setting Up Wi‑Fi on the Pico W + + + +
  • + +
  • + + + Seven-Segment Display + + + +
  • + +
  • + + + Shift Register + + + +
  • + +
  • + + + Sleep Mode + + + +
  • + +
  • + + + Sleep Scheduling + + + +
  • + +
  • + + + Smartwatch Displays + + + +
  • + +
  • + + + Sound Encoding + + + +
  • + +
  • + + + State Machine + + + +
  • + +
  • + + + Step Counting (Pedometer) + + + +
  • + +
  • + + + Stopwatch + + + +
  • + +
  • + + + Synchronizing Time from the PC + + + +
  • + +
  • + + + TFT Displays + + + +
  • + +
  • + + + Temperature Sensor + + + +
  • + +
  • + + + Temperature and Humidity + + + +
  • + +
  • + + + Thonny IDE + + + +
  • + +
  • + + + Time Module + + + +
  • + +
  • + + + Time Synchronization + + + +
  • + +
  • + + + Time Zone + + + +
  • + +
  • + + + Time-Based Tasks with uasyncio + + + +
  • + +
  • + + + Timer + + + +
  • + +
  • + + + Timer-Based Events + + + +
  • + +
  • + + + USB Power + + + +
  • + +
  • + + + UTC + + + +
  • + +
  • + + + Ultra-Low Power + + + +
  • + +
  • + + + Using 16 Bits to Represent Color + + + +
  • + +
  • + + + Wake on Alarm + + + +
  • + +
  • + + + Watch Face Design + + + +
  • + +
  • + + + Watchdog Timer + + + +
  • + +
  • + + + Weather Updates + + + +
  • + +
  • + + + Web Services + + + +
  • + +
  • + + + Wi-Fi Module + + + +
  • + +
  • + + + Wi‑Fi–Based Weather Updates + + + +
  • + +
  • + + + World Clock + + + +
  • + +
  • + + + datetime Objects + + + +
  • + +
  • + + + localtime() Function + + + +
  • + +
  • + + + math.sin() and math.cos() + + + +
  • + +
  • + + + micropython-ufont Library + + + +
  • + + + + +
    + + + + + +
    +
    + + + + + + + +

    Glossary of Terms DIY Clocks and Watches with MicroPython

    +

    12-Hour vs 24-Hour Formats

    +

    Methods for displaying time in either 12-hour (AM/PM) or 24-hour (military) format, including conversion between the two.

    +

    Example: Converting 13:00 to 1:00 PM and handling the AM/PM indicator.

    3D Printing Watch Enclosures

    A process of creating custom protective cases for watch components using additive manufacturing technology.

    +

    Abstraction

    +

    A technique for managing complexity by hiding unnecessary details while keeping essential features visible.

    +

    Example: Using a display_time() function that accepts hours and minutes without needing to know how individual LED segments are controlled.

    Accelerometer

    A sensor that measures physical acceleration and orientation, useful for tilt-based display activation.

    Example: Detecting when a user lifts their wrist to view the watch face.

    @@ -2261,14 +3521,47 @@

    Asynchronous Programming

    Example: Using uasyncio to handle display updates while monitoring button presses.

    Battery Backup

    A power system that maintains time and settings when main power is disconnected.

    +

    Battery Drain Calculation

    +

    The process of measuring and estimating power consumption to determine battery life.

    +

    Example: Measuring current draw during different display update modes.

    Battery Power

    Portable electrical energy storage used to operate mobile timepieces.

    Example: Calculating power consumption to estimate battery life.

    +

    Battery Tools

    +

    Instruments and methods for measuring power consumption and battery health.

    +

    Example: Using multimeters to measure current draw in different modes.

    Blitting

    A technique for rapidly copying rectangular portions of memory to update displays efficiently.

    Example: Using framebuffer operations to reduce screen flicker.

    +

    Breadboard

    +

    A reusable plastic board with holes and internal connections for prototyping electronic circuits without soldering.

    +

    Example: Connecting LED displays and buttons to the Pico W using jumper wires on a breadboard.

    +

    Button Debouncing

    +

    A technique to prevent false button readings caused by mechanical switch contacts bouncing when pressed or released.

    +

    Example: debounce_time = 100 in button configuration prevents multiple accidental triggers.

    +

    Button Input Handling

    +

    Software techniques for detecting and responding to button presses.

    +

    Example: Using interrupts and debouncing for reliable input detection.

    +

    Callback Function

    +

    A function passed as an argument to another function, which will be executed when a specific event occurs.

    +

    Example: button_mode_irq function that runs whenever the mode button is pressed.

    +

    Changing Fonts

    +

    The process of modifying text appearance by loading and applying different typefaces.

    +

    Example: Using the micropython-ufont library to load compact digital number styles.

    +

    Chimes

    +

    Musical or tone sequences played at specific intervals or times.

    +

    Example: Playing Westminster quarter-hour chimes using PWM audio output.

    Chronograph

    A timepiece with both timekeeping and stopwatch capabilities.

    +

    Color Animations

    +

    Dynamic changes in display colors to create visual effects or indicate status.

    +

    Example: Gradually shifting background colors throughout the day.

    +

    Color Conversion

    +

    The process of transforming between different color representation systems.

    +

    Example: Converting RGB colors to 16-bit format for TFT displays.

    +

    Color Conversion & Palettes

    +

    Methods for transforming between different color representations and managing limited color sets.

    +

    Example: Converting RGB colors to display-specific formats and creating custom color themes.

    Color Depth

    The number of bits used to represent colors in a display.

    Example: Using 16 bits per pixel to show 65,536 different colors.

    @@ -2278,415 +3571,366 @@

    Concurrency

    Conditionals

    Programming statements that perform different actions based on whether a condition is true or false.

    Example: Switching between 12-hour and 24-hour time formats.

    +

    Connecting Speakers

    +

    Methods for attaching and controlling audio output devices to create sound effects and alarms.

    +

    Example: Wiring a piezo speaker to a PWM-capable GPIO pin for generating tones.

    +

    Console Output

    +

    Text-based information displayed in the development environment for debugging.

    +

    Example: print("Current time:", hours, ":", minutes)

    +

    Cuckoo Clock

    +

    A timepiece that marks specific hours with sound and optional mechanical movement.

    +

    Example: Playing bird sounds and activating a servo at the top of each hour.

    Custom Font

    A specialized set of character designs loaded into memory for display purposes.

    Example: Loading compact number fonts using the micropython-ufont library.

    +

    Custom Segment Display

    +

    A specialized arrangement of LED segments for showing numbers or characters.

    +

    Example: Creating unique digit patterns using individual LED segments.

    +

    DS1307

    +

    DS3231

    +

    A high-precision real-time clock (RTC) integrated circuit with temperature compensation for accurate timekeeping.

    +

    Example: Using the DS3231 to maintain time accuracy within seconds per month.

    +

    Date and Calendar Display

    +

    Showing current date information including day of week, month, and year.

    +

    Example: Formatting and displaying full date alongside time information.

    Daylight Saving Time

    A seasonal time adjustment typically involving a one-hour shift.

    Example: Automatically adjusting clock time based on DST rules.

    Deep Sleep

    A low-power mode that disables most system functions to conserve energy.

    Example: Entering sleep mode when the watch face isn't being viewed.

    +

    Digital Display

    +

    An electronic output device that shows numbers, letters, or symbols using discrete segments or pixels.

    +

    Example: Four-digit seven-segment LED display showing hours and minutes.

    Display Driver

    Software that controls how information is shown on a specific type of display.

    Example: Using the ST7735 driver for TFT LCD screens.

    +

    Display Technology Comparison

    +

    Analysis of different screen types' advantages and limitations.

    +

    Example: Evaluating power consumption versus update speed for various displays.

    Double Buffering

    A technique using two memory areas to prepare the next frame while displaying the current one.

    Example: Creating smooth animations without visible drawing operations.

    +

    Drawing Arcs

    +

    Creating curved lines as portions of circles on displays.

    +

    Example: Drawing round clock face elements and decorative features.

    +

    Drawing Circles

    +

    Creating perfect circular shapes on displays.

    +

    Example: Drawing clock face outlines and hour markers.

    +

    Drawing Ellipses

    +

    Creating oval shapes on displays.

    +

    Example: Designing stylized clock faces and decorative elements.

    +

    Drawing Hands

    +

    Creating moving indicators for hours, minutes, and seconds.

    +

    Example: Using line drawing functions to show analog time.

    +

    Drawing Libraries

    +

    Software collections that provide functions for creating visual elements.

    +

    Example: Using built-in graphics functions to draw clock hands and numbers.

    +

    Drawing Lines

    +

    Creating straight line segments on displays.

    +

    Example: Drawing clock hand indicators and markings.

    +

    Drawing Numbers

    +

    Displaying numerical values on screen.

    +

    Example: Showing digital time values and markers.

    +

    Drawing Pixels

    +

    Setting individual display points for custom graphics.

    +

    Example: Creating fine details in watch face designs.

    +

    Drawing Polygons

    +

    Creating shapes with multiple straight sides.

    +

    Example: Making custom hour markers and decorative elements.

    +

    Drawing Primitives

    +

    Basic shapes and elements used to create more complex visual displays.

    +

    Example: Using lines and arcs to create clock hands.

    +

    Drawing Rectangles

    +

    Creating four-sided shapes with right angles.

    +

    Example: Drawing display borders and menu backgrounds.

    +

    Drawing Text

    +

    Displaying characters and strings on screen.

    +

    Example: Showing time, date, and menu options.

    +

    Drawing Tick Marks

    +

    Creating small indicators around a clock face.

    +

    Example: Marking hours and minutes on an analog display.

    E-Paper Display

    A low-power screen technology that maintains its image without constant power.

    Example: Using partial updates to change only modified portions of the display.

    +

    Error Handling and Recovery

    +

    Techniques for detecting and recovering from timing errors, power issues, or communication failures.

    +

    Example: Implementing watchdog timers and automatic resynchronization after power loss.#### Event Handler +A function that responds to specific occurrences like button presses or timer updates.

    +

    Example: The button_mode_irq function handles mode button press events.

    External RTC

    A separate timekeeping chip that maintains accurate time independent of the main processor.

    Example: Using a DS3231 module for precise timekeeping.

    +

    External Sensors

    +

    Additional hardware components that measure environmental conditions.

    +

    Example: Reading temperature and humidity for weather display.

    +

    Fast Redraw

    +

    Techniques for updating displays quickly to maintain smooth animation.

    +

    Example: Using hardware acceleration for screen updates.

    Filesystem

    A system for storing and organizing files on the microcontroller.

    Example: Saving configuration settings and logs to internal storage.

    +

    Flicker Reduction

    +

    Methods to minimize visible display instability during updates.

    +

    Example: Using double buffering to prevent partial frame displays.

    Framebuffer

    A region of memory that holds the complete contents of a display.

    Example: Modifying pixel data before updating the screen.

    Functions

    Reusable blocks of code that perform specific tasks.

    Example: Creating a function to convert between 12-hour and 24-hour formats.

    -

    Ghosting

    -

    A visual artifact where previous images remain partially visible on certain display types.

    -

    Example: Using display clearing techniques on e-paper screens.

    -

    I2C Sensors

    -

    Digital components that communicate using the I2C protocol to provide measurements.

    -

    Example: Reading temperature and humidity data for weather display.

    -

    Interrupt

    -

    A signal that temporarily pauses normal program execution to handle important events.

    -

    Example: Responding immediately to button presses.

    -

    JSON

    -

    A text-based data format commonly used for exchanging information with web services.

    -

    Example: Parsing weather data from online APIs.

    -

    Libraries

    -

    Collections of pre-written code that provide useful functions and features.

    -

    Example: Using the math module for trigonometric calculations.

    -

    LiPo Charging

    -

    The process of safely recharging Lithium Polymer batteries.

    -

    Example: Implementing USB charging circuits with protection features.

    -

    Logging

    -

    The practice of recording program events and data for debugging or analysis.

    -

    Example: Saving timing discrepancies to investigate accuracy issues.

    -

    Loops

    -

    Programming structures that repeat code blocks multiple times.

    -

    Example: Continuously updating the display every second.

    -

    Math Module

    -

    A collection of mathematical functions for complex calculations.

    -

    Example: Using trigonometry to position clock hands.

    - -

    An interface allowing users to navigate options and settings.

    -

    Example: Creating hierarchical settings menus for watch configuration.

    -

    Network Time Protocol (NTP)

    -

    A method for synchronizing time over the internet.

    -

    Example: Updating the RTC from online time servers.

    -

    Partial Refresh

    -

    Updating only changed portions of a display to improve efficiency.

    -

    Example: Refreshing only the seconds digits each update.

    -

    Pedometer

    -

    A feature that counts steps using motion sensor data.

    -

    Example: Calculating daily step counts from accelerometer readings.

    -

    Power Management

    -

    Techniques for minimizing and controlling energy consumption.

    -

    Example: Using sleep modes and efficient display updates.

    -

    PWM Audio

    -

    Using Pulse Width Modulation to generate sounds and tones.

    -

    Example: Creating alarm beeps and hourly chimes.

    -

    Rotary Encoder

    -

    A input device that converts rotational movement into digital signals.

    -

    Example: Using encoder rotation to adjust time settings.

    -

    Screen Update

    -

    The process of refreshing display contents to show new information.

    -

    Example: Efficiently updating only changed portions of the time display.

    -

    Servo Motor

    -

    An actuator that can rotate to precise positions.

    -

    Example: Moving physical clock hands on a hybrid display.

    -

    Sleep Mode

    -

    A low-power state that reduces energy consumption.

    -

    Example: Entering deep sleep between display updates.

    -

    SPI Interface

    -

    A high-speed serial communication protocol for connecting displays and sensors.

    -

    Example: Transferring data to TFT displays efficiently.

    -

    Temperature Sensor

    -

    A component that measures ambient temperature.

    -

    Example: Displaying current temperature alongside time.

    -

    Thonny IDE

    -

    An integrated development environment optimized for MicroPython programming.

    -

    Example: Using Thonny to upload code and debug timing issues.

    -

    Time Zone

    -

    A region that observes a uniform standard time.

    -

    Example: Converting between local time and UTC.

    -

    Timer

    -

    A system resource that generates regular time-based events.

    -

    Example: Creating precise one-second update intervals.

    -

    UTC

    -

    Coordinated Universal Time, the primary time standard for global time coordination.

    -

    Example: Converting local time to UTC for synchronization.

    -

    Watchdog Timer

    -

    A hardware feature that resets the system if the program stops responding.

    -

    Example: Ensuring reliability in long-running clock applications.

    -

    Weather Updates

    -

    Real-time weather information obtained through internet services.

    -

    Example: Displaying temperature and forecast alongside time.

    -

    Wi-Fi Module

    -

    Hardware that enables wireless network connectivity.

    -

    Example: Connecting to the internet for time synchronization.

    -

    World Clock

    -

    A timepiece that displays times for multiple time zones simultaneously.

    -

    Example: Showing local time alongside other major cities' times.

    -

    DIY Clocks and Watches with MicroPython: Glossary

    -

    3D Printing Watch Enclosures

    -

    A process of creating custom protective cases for watch components using additive manufacturing technology.

    -

    Accelerometer

    -

    A sensor that measures physical acceleration and orientation, useful for tilt-based display activation.

    -

    Example: Detecting when a user lifts their wrist to view the watch face.

    -

    Alarm

    -

    A scheduled alert that triggers audio, visual, or vibration notifications at specific times.

    -

    Example: Setting multiple daily alarms using the RTC module.

    -

    Analog Clock Face

    -

    A traditional clock display using rotating hands to show time on a circular dial.

    -

    Example: Drawing hour and minute hands using math.sin() and math.cos() for position calculations.

    -

    Animation

    -

    The process of creating movement by rapidly updating display contents.

    -

    Example: Smoothly rotating second hands or creating blinking colons between hours and minutes.

    -

    Asynchronous Programming

    -

    A coding technique that allows multiple tasks to run concurrently without blocking each other.

    -

    Example: Using uasyncio to handle display updates while monitoring button presses.

    -

    Battery Backup

    -

    A power system that maintains time and settings when main power is disconnected.

    -

    Battery Power

    -

    Portable electrical energy storage used to operate mobile timepieces.

    -

    Example: Calculating power consumption to estimate battery life.

    -

    Blitting

    -

    A technique for rapidly copying rectangular portions of memory to update displays efficiently.

    -

    Example: Using framebuffer operations to reduce screen flicker.

    -

    Chronograph

    -

    A timepiece with both timekeeping and stopwatch capabilities.

    -

    Color Depth

    -

    The number of bits used to represent colors in a display.

    -

    Example: Using 16 bits per pixel to show 65,536 different colors.

    -

    Concurrency

    -

    The ability to handle multiple tasks or events simultaneously in a program.

    -

    Example: Updating the display while checking for button presses.

    -

    Conditionals

    -

    Programming statements that perform different actions based on whether a condition is true or false.

    -

    Example: Switching between 12-hour and 24-hour time formats.

    -

    Custom Font

    -

    A specialized set of character designs loaded into memory for display purposes.

    -

    Example: Loading compact number fonts using the micropython-ufont library.

    -

    Daylight Saving Time

    -

    A seasonal time adjustment typically involving a one-hour shift.

    -

    Example: Automatically adjusting clock time based on DST rules.

    -

    Deep Sleep

    -

    A low-power mode that disables most system functions to conserve energy.

    -

    Example: Entering sleep mode when the watch face isn't being viewed.

    -

    Display Driver

    -

    Software that controls how information is shown on a specific type of display.

    -

    Example: Using the ST7735 driver for TFT LCD screens.

    -

    Double Buffering

    -

    A technique using two memory areas to prepare the next frame while displaying the current one.

    -

    Example: Creating smooth animations without visible drawing operations.

    -

    E-Paper Display

    -

    A low-power screen technology that maintains its image without constant power.

    -

    Example: Using partial updates to change only modified portions of the display.

    -

    External RTC

    -

    A separate timekeeping chip that maintains accurate time independent of the main processor.

    -

    Example: Using a DS3231 module for precise timekeeping.

    -

    Filesystem

    -

    A system for storing and organizing files on the microcontroller.

    -

    Example: Saving configuration settings and logs to internal storage.

    -

    Framebuffer

    -

    A region of memory that holds the complete contents of a display.

    -

    Example: Modifying pixel data before updating the screen.

    -

    Functions

    -

    Reusable blocks of code that perform specific tasks.

    -

    Example: Creating a function to convert between 12-hour and 24-hour formats.

    -

    Ghosting

    +

    GPIO Pin

    +

    General Purpose Input/Output connection on a microcontroller that can be programmed to send or receive electrical signals.

    +

    Example: Using GPIO pin 16 for the mode button: mode_pin = Pin(16, Pin.IN, Pin.PULL_UP)

    +

    Generating Waveforms for Audio

    +

    Creating electrical signals for producing sounds and tones using digital-to-analog conversion or PWM.

    +

    Example: Synthesizing different frequencies for alarm sounds and hourly chimes.

    +

    Ghosting

    A visual artifact where previous images remain partially visible on certain display types.

    Example: Using display clearing techniques on e-paper screens.

    -

    I2C Sensors

    +

    Hardware Documentation

    +

    Technical specifications and usage instructions for electronic components.

    +

    Example: Consulting pinout diagrams for display connections.

    +

    I2C

    +

    A communication protocol that allows multiple digital components to exchange data using just two wires plus power and ground.

    +

    I2C Sensors

    Digital components that communicate using the I2C protocol to provide measurements.

    Example: Reading temperature and humidity data for weather display.

    -

    Interrupt

    +

    Implementing Clock Themes

    +

    Creating customizable visual styles for clock displays, including colors, fonts, and layouts.

    +

    Example: Allowing users to switch between day/night themes or seasonal variations.

    +

    Incremental Drawing

    +

    Updating only the necessary portions of a display to improve efficiency.

    +

    Example: Refreshing only the seconds indicator rather than the full screen.

    +

    Interrupt

    A signal that temporarily pauses normal program execution to handle important events.

    Example: Responding immediately to button presses.

    -

    JSON

    +

    JSON

    A text-based data format commonly used for exchanging information with web services.

    Example: Parsing weather data from online APIs.

    -

    Libraries

    -

    Collections of pre-written code that provide useful functions and features.

    -

    Example: Using the math module for trigonometric calculations.

    -

    LiPo Charging

    +

    LED Clock Displays

    +

    A digital timepiece display using light-emitting diodes arranged in segments or matrices to show time information.

    +

    Example: Using a four-digit seven-segment LED display to show hours and minutes.

    +

    LED Matrix

    +

    An array of light-emitting diodes arranged in rows and columns that can display patterns, numbers, or text.

    +

    LiPo Charging

    The process of safely recharging Lithium Polymer batteries.

    Example: Implementing USB charging circuits with protection features.

    -

    Logging

    +

    LiPo Charging Circuit

    +

    Electronic system for safely charging Lithium Polymer batteries while protecting against overcharge and overdischarge.

    +

    Example: Implementing USB charging with voltage regulation and protection features.

    +

    Libraries

    +

    Collections of pre-written code that provide useful functions and features.

    +

    Example: Using the math module for trigonometric calculations.

    +

    Loading Drivers

    +

    Installing and initializing software that controls specific hardware components.

    +

    Example: Importing and configuring TFT display drivers.

    +

    Logging

    The practice of recording program events and data for debugging or analysis.

    Example: Saving timing discrepancies to investigate accuracy issues.

    -

    Loops

    +

    Logging Time Data to an SD Card

    +

    Recording timestamped information to external storage for debugging or data collection.

    +

    Example: Saving temperature readings with timestamps every hour.

    +

    Loops

    Programming structures that repeat code blocks multiple times.

    Example: Continuously updating the display every second.

    -

    Math Module

    +

    Math Module

    A collection of mathematical functions for complex calculations.

    Example: Using trigonometry to position clock hands.

    - +

    An interface allowing users to navigate options and settings.

    Example: Creating hierarchical settings menus for watch configuration.

    -

    Network Time Protocol (NTP)

    + +

    Hierarchical interface structures for configuring watch parameters and features.

    +

    Example: Creating nested menus for time, alarm, and display settings.

    +

    MicroPython

    +

    A streamlined version of Python programming language designed to run on microcontrollers and embedded systems.

    +

    MicroPython Drawing

    +

    Built-in functions for creating visual elements on displays.

    +

    Example: Using framebuf methods to draw shapes and text.

    +

    MicroPython Syntax

    +

    The specific programming language rules and structure for MicroPython code.

    +

    Example: Using Python-style indentation for code blocks.

    +

    MicroPython network

    +

    A module providing Wi-Fi and network connectivity functions.

    +

    Example: Connecting to wireless networks for time synchronization.

    +

    Network Time Protocol (NTP)

    A method for synchronizing time over the internet.

    Example: Updating the RTC from online time servers.

    -

    Partial Refresh

    +

    OLED Display

    +

    A thin, bright display that uses organic light-emitting diodes to show text and graphics without a backlight.

    +

    PWM

    +

    Pulse Width Modulation - a technique for creating varying levels of brightness or speed by rapidly switching a signal on and off.

    +

    PWM Audio

    +

    Using Pulse Width Modulation to generate sounds and tones.

    +

    Example: Creating alarm beeps and hourly chimes.

    +

    Partial Refresh

    Updating only changed portions of a display to improve efficiency.

    Example: Refreshing only the seconds digits each update.

    -

    Pedometer

    +

    Partial Screen Updates

    +

    Techniques for refreshing only the changed portions of a display to improve efficiency and reduce flicker.

    +

    Example: Updating only the seconds digits while leaving hours and minutes static.

    +

    Pedometer

    A feature that counts steps using motion sensor data.

    Example: Calculating daily step counts from accelerometer readings.

    -

    Power Management

    +

    Pin

    +

    A metal connector on electronic components that carries electrical signals or power.

    +

    Power Management

    Techniques for minimizing and controlling energy consumption.

    Example: Using sleep modes and efficient display updates.

    -

    PWM Audio

    -

    Using Pulse Width Modulation to generate sounds and tones.

    -

    Example: Creating alarm beeps and hourly chimes.

    -

    Rotary Encoder

    +

    Power Monitoring

    +

    Methods for measuring and tracking power consumption in battery-operated devices.

    +

    Example: Logging battery voltage and current draw to optimize device lifetime.

    +

    Pull-up Resistor

    +

    An electronic component that ensures a consistent voltage level on input pins when buttons or switches are not pressed.

    +

    Example: Using internal pull-up resistors with Pin.PULL_UP for button inputs.

    +

    Raspberry Pi Pico W

    +

    A small, low-cost microcontroller board with built-in wireless capabilities, designed for learning and DIY projects.

    +

    Real-Time Clock (RTC)

    +

    A specialized chip or circuit that keeps accurate time even when main power is removed.

    +

    Example: Using the RTC module to maintain accurate time: rtc = RTC()

    +

    Real-time Clock (RTC) Overview

    +

    A comprehensive explanation of how real-time clock modules maintain accurate time, including initialization, synchronization, and backup power considerations.

    +

    Example: Understanding how the RTC maintains time even when main power is disconnected.

    +

    Rotary Encoder

    A input device that converts rotational movement into digital signals.

    Example: Using encoder rotation to adjust time settings.

    -

    Screen Update

    +

    SPI

    +

    Serial Peripheral Interface - a fast communication protocol for connecting digital components using multiple signal lines.

    +

    SPI Interface

    +

    A high-speed serial communication protocol for connecting displays and sensors.

    +

    Example: Transferring data to TFT displays efficiently.

    +

    Screen Tearing Prevention

    +

    Techniques to avoid visual artifacts caused by updating display content while it's being refreshed.

    +

    Example: Using vsync or double buffering to ensure clean display updates.

    +

    Screen Update

    The process of refreshing display contents to show new information.

    Example: Efficiently updating only changed portions of the time display.

    -

    Servo Motor

    +

    Screen Via SPI

    +

    High-speed serial communication method for updating displays.

    +

    Example: Sending framebuffer data to TFT screens efficiently.

    +

    Servo Motor

    An actuator that can rotate to precise positions.

    Example: Moving physical clock hands on a hybrid display.

    -

    Sleep Mode

    +

    Setting System Clock

    +

    Configuring the internal timekeeping system with accurate time.

    +

    Example: Updating RTC time from an external time source.

    +

    Setting Time with Buttons

    +

    Interface design and implementation for adjusting clock time using physical buttons.

    +

    Example: Using mode, increment, and decrement buttons to set hours and minutes.

    +

    Setting Up I²C Communication

    +

    Configuring and using the Inter-Integrated Circuit (I²C) protocol for connecting multiple devices.

    +

    Example: Initializing I²C bus for communicating with RTC and sensor modules.

    +

    Setting Up Wi‑Fi on the Pico W

    +

    Process of configuring wireless network connectivity on the Raspberry Pi Pico W microcontroller.

    +

    Example: Connecting to a local network using SSID and password credentials.

    +

    Seven-Segment Display

    +

    A display made of seven LED segments plus a decimal point that can show numbers and some letters.

    +

    Example: Creating patterns for digits using segments 'a' through 'g': SEGMENTS = {'a': 4, 'b': 3, 'c': 2, 'd': 7, 'e': 6, 'f': 5, 'g': 1}

    +

    Shift Register

    +

    An integrated circuit that converts serial data into parallel outputs, useful for controlling multiple LEDs with fewer pins.

    +

    Example: Using SR74HC595 shift register to control display segments.

    +

    Sleep Mode

    A low-power state that reduces energy consumption.

    Example: Entering deep sleep between display updates.

    -

    SPI Interface

    -

    A high-speed serial communication protocol for connecting displays and sensors.

    -

    Example: Transferring data to TFT displays efficiently.

    -

    Temperature Sensor

    +

    Sleep Scheduling

    +

    Managing when the device enters and exits low-power states.

    +

    Example: Programming wake-up times for hourly updates.

    +

    Smartwatch Displays

    +

    Advanced display modules designed specifically for wearable devices, optimizing size, power consumption, and readability.

    +

    Example: Using a small, high-resolution display with automatic brightness adjustment.

    +

    Sound Encoding

    +

    Methods for storing and playing audio data for alarms and notifications.

    +

    Example: Converting WAV files to suitable format for playback.

    +

    State Machine

    +

    A programming concept where a system can be in one of several defined states, with specific rules for transitioning between them.

    +

    Example: Clock modes including "run", "set hour", "set minute", and "set AM/PM".

    +

    Step Counting (Pedometer)

    +

    Using motion sensors to detect and count walking steps for fitness tracking.

    +

    Example: Processing accelerometer data to identify step patterns and maintain daily count.

    +

    Stopwatch

    +

    A timing device that measures elapsed time from a starting point, typically with precision to fractions of a second.

    +

    Example: Implementing start, stop, and lap timing functions with millisecond accuracy.

    +

    Synchronizing Time from the PC

    +

    The process of setting a microcontroller's clock using the connected computer's time.

    +

    Example: Using Thonny IDE to automatically update the Pico's RTC when uploading code.

    +

    TFT Displays

    +

    Thin-film-transistor liquid crystal displays for showing color graphics.

    +

    Example: Using ST7735 or ILI9341 displays for watch faces.

    +

    Temperature Sensor

    A component that measures ambient temperature.

    Example: Displaying current temperature alongside time.

    -

    Thonny IDE

    +

    Temperature and Humidity

    +

    Integration of environmental sensors to display current conditions alongside time.

    +

    Example: Reading DHT22 sensor data to show temperature and humidity with clock display.

    +

    Thonny IDE

    An integrated development environment optimized for MicroPython programming.

    Example: Using Thonny to upload code and debug timing issues.

    -

    Time Zone

    +

    Time Module

    +

    MicroPython library for handling time-related operations.

    +

    Example: Using scheduling functions for regular updates.

    +

    Time Synchronization

    +

    Process of updating device time from an accurate external source.

    +

    Example: Getting current time from network time servers.

    +

    Time Zone

    A region that observes a uniform standard time.

    Example: Converting between local time and UTC.

    -

    Timer

    +

    Time-Based Tasks with uasyncio

    +

    Scheduling and managing time-dependent operations using MicroPython's asynchronous I/O framework.

    +

    Example: Updating multiple display elements at different intervals without blocking.

    +

    Timer

    A system resource that generates regular time-based events.

    Example: Creating precise one-second update intervals.

    -

    UTC

    +

    Timer-Based Events

    +

    Actions triggered by internal timing mechanisms.

    +

    Example: Updating display elements at specific intervals.

    +

    USB Power

    +

    A 5-volt power source available through Universal Serial Bus connections, commonly used for powering small electronic projects.

    +

    UTC

    Coordinated Universal Time, the primary time standard for global time coordination.

    Example: Converting local time to UTC for synchronization.

    -

    Watchdog Timer

    +

    Ultra-Low Power

    +

    Operating modes and techniques that minimize energy consumption.

    +

    Example: Using sleep modes and efficient screen updates.

    +

    Using 16 Bits to Represent Color

    +

    A color depth specification that allocates 16 bits per pixel, typically with 5 bits for red, 6 for green, and 5 for blue (RGB565 format).

    +

    Example: Converting RGB colors to 16-bit format for efficient storage and display.

    +

    Wake on Alarm

    +

    Feature that activates the device from sleep mode at specific times.

    +

    Example: Waking the display for scheduled notifications.

    +

    Watch Face Design

    +

    Principles and techniques for creating visually appealing and functional clock displays.

    +

    Example: Balancing aesthetics and readability in analog and digital layouts.

    +

    Watchdog Timer

    A hardware feature that resets the system if the program stops responding.

    Example: Ensuring reliability in long-running clock applications.

    -

    Weather Updates

    -

    Real-time weather information obtained through internet services.

    -

    Example: Displaying temperature and forecast alongside time.

    -

    Wi-Fi Module

    +

    Weather Updates

    +

    Real-time environmental data obtained through internet services.

    +

    Example: Displaying current conditions alongside time.

    +

    Web Services

    +

    Online resources that provide data or functionality through standard internet protocols.

    +

    Example: Fetching current time from an internet time server for clock synchronization.

    +

    Wi-Fi Module

    Hardware that enables wireless network connectivity.

    Example: Connecting to the internet for time synchronization.

    -

    World Clock

    +

    Wi‑Fi–Based Weather Updates

    +

    Retrieving and displaying current weather conditions using wireless internet connectivity.

    +

    Example: Fetching temperature, humidity, and forecast data from online weather services.

    +

    World Clock

    A timepiece that displays times for multiple time zones simultaneously.

    Example: Showing local time alongside other major cities' times.

    -

    Battery Drain Calculation

    -

    The process of measuring and estimating power consumption to determine battery life.

    -

    Example: Measuring current draw during different display update modes.

    -

    Changing Fonts

    -

    The process of modifying text appearance by loading and applying different typefaces.

    -

    Example: Using the micropython-ufont library to load compact digital number styles.

    -

    Color Animations

    -

    Dynamic changes in display colors to create visual effects or indicate status.

    -

    Example: Gradually shifting background colors throughout the day.

    -

    Color Conversion

    -

    The process of transforming between different color representation systems.

    -

    Example: Converting RGB colors to 16-bit format for TFT displays.

    -

    Console Output

    -

    Text-based information displayed in the development environment for debugging.

    -

    Example: print("Current time:", hours, ":", minutes)

    -

    Cuckoo Clock

    -

    A timepiece that marks specific hours with sound and optional mechanical movement.

    -

    Example: Playing bird sounds and activating a servo at the top of each hour.

    datetime Objects

    Programming structures that store date and time information together.

    Example: Converting between timestamp integers and datetime format.

    -

    Drawing Libraries

    -

    Software collections that provide functions for creating visual elements.

    -

    Example: Using built-in graphics functions to draw clock hands and numbers.

    -

    Drawing Primitives

    -

    Basic shapes and elements used to create more complex visual displays.

    -

    Example: Using lines and arcs to create clock hands.

    -

    Fast Redraw

    -

    Techniques for updating displays quickly to maintain smooth animation.

    -

    Example: Using hardware acceleration for screen updates.

    -

    Flicker Reduction

    -

    Methods to minimize visible display instability during updates.

    -

    Example: Using double buffering to prevent partial frame displays.

    -

    Hardware Documentation

    -

    Technical specifications and usage instructions for electronic components.

    -

    Example: Consulting pinout diagrams for display connections.

    -

    Incremental Drawing

    -

    Updating only the necessary portions of a display to improve efficiency.

    -

    Example: Refreshing only the seconds indicator rather than the full screen.

    -

    Loading Drivers

    -

    Installing and initializing software that controls specific hardware components.

    -

    Example: Importing and configuring TFT display drivers.

    localtime() Function

    A MicroPython function that returns the current time as a tuple of values.

    Example: year, month, day, hour, minute, second = localtime()

    math.sin() and math.cos()

    Trigonometric functions used for calculating positions on circular displays.

    Example: Computing analog clock hand coordinates.

    -

    MicroPython Drawing

    -

    Built-in functions for creating visual elements on displays.

    -

    Example: Using framebuf methods to draw shapes and text.

    -

    MicroPython network

    -

    A module providing Wi-Fi and network connectivity functions.

    -

    Example: Connecting to wireless networks for time synchronization.

    -

    MicroPython Syntax

    -

    The specific programming language rules and structure for MicroPython code.

    -

    Example: Using Python-style indentation for code blocks.

    -

    Screen Via SPI

    -

    High-speed serial communication method for updating displays.

    -

    Example: Sending framebuffer data to TFT screens efficiently.

    -

    Setting System Clock

    -

    Configuring the internal timekeeping system with accurate time.

    -

    Example: Updating RTC time from an external time source.

    -

    Sleep Scheduling

    -

    Managing when the device enters and exits low-power states.

    -

    Example: Programming wake-up times for hourly updates.

    -

    Sound Encoding

    -

    Methods for storing and playing audio data for alarms and notifications.

    -

    Example: Converting WAV files to suitable format for playback.

    -

    TFT Displays

    -

    Thin-film-transistor liquid crystal displays for showing color graphics.

    -

    Example: Using ST7735 or ILI9341 displays for watch faces.

    -

    Timer-Based Events

    -

    Actions triggered by internal timing mechanisms.

    -

    Example: Updating display elements at specific intervals.

    -

    Ultra-Low Power

    -

    Operating modes and techniques that minimize energy consumption.

    -

    Example: Using sleep modes and efficient screen updates.

    -

    Battery Tools

    -

    Instruments and methods for measuring power consumption and battery health.

    -

    Example: Using multimeters to measure current draw in different modes.

    -

    Button Input Handling

    -

    Software techniques for detecting and responding to button presses.

    -

    Example: Using interrupts and debouncing for reliable input detection.

    -

    Custom Segment Display

    -

    A specialized arrangement of LED segments for showing numbers or characters.

    -

    Example: Creating unique digit patterns using individual LED segments.

    -

    Display Technology Comparison

    -

    Analysis of different screen types' advantages and limitations.

    -

    Example: Evaluating power consumption versus update speed for various displays.

    -

    Drawing Arcs

    -

    Creating curved lines as portions of circles on displays.

    -

    Example: Drawing round clock face elements and decorative features.

    -

    Drawing Circles

    -

    Creating perfect circular shapes on displays.

    -

    Example: Drawing clock face outlines and hour markers.

    -

    Drawing Ellipses

    -

    Creating oval shapes on displays.

    -

    Example: Designing stylized clock faces and decorative elements.

    -

    Drawing Hands

    -

    Creating moving indicators for hours, minutes, and seconds.

    -

    Example: Using line drawing functions to show analog time.

    -

    Drawing Lines

    -

    Creating straight line segments on displays.

    -

    Example: Drawing clock hand indicators and markings.

    -

    Drawing Numbers

    -

    Displaying numerical values on screen.

    -

    Example: Showing digital time values and markers.

    -

    Drawing Pixels

    -

    Setting individual display points for custom graphics.

    -

    Example: Creating fine details in watch face designs.

    -

    Drawing Polygons

    -

    Creating shapes with multiple straight sides.

    -

    Example: Making custom hour markers and decorative elements.

    -

    Drawing Rectangles

    -

    Creating four-sided shapes with right angles.

    -

    Example: Drawing display borders and menu backgrounds.

    -

    Drawing Text

    -

    Displaying characters and strings on screen.

    -

    Example: Showing time, date, and menu options.

    -

    Drawing Tick Marks

    -

    Creating small indicators around a clock face.

    -

    Example: Marking hours and minutes on an analog display.

    -

    External Sensors

    -

    Additional hardware components that measure environmental conditions.

    -

    Example: Reading temperature and humidity for weather display.

    -

    Time Module

    -

    MicroPython library for handling time-related operations.

    -

    Example: Using scheduling functions for regular updates.

    -

    Time Synchronization

    -

    Process of updating device time from an accurate external source.

    -

    Example: Getting current time from network time servers.

    -

    Wake on Alarm

    -

    Feature that activates the device from sleep mode at specific times.

    -

    Example: Waking the display for scheduled notifications.

    -

    Weather Updates

    -

    Real-time environmental data obtained through internet services.

    -

    Example: Displaying current conditions alongside time.

    +

    micropython-ufont Library

    +

    A specialized library for handling compact font rendering in MicroPython applications.

    +

    Example: Loading custom digit fonts optimized for small displays.

    diff --git a/search/search_index.json b/search/search_index.json index 7c3ab100..f16e8970 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Designing and Building Clocks and Watches with MicroPython and AI","text":"

    Welcome to the Clocks and Watches website!

    This website is a resource for teachers, mentors and students who want to have fun hands-on ways to learn computational thinking using the popular Python language. This course gives junior high and high school students the tools to design and build their own digital clocks and smart watches using low-cost components.

    This website contains detailed instructions for finding low-cost parts (many under $20/student) and customizing your custom clock and watch displays using MicroPython.

    These projects have only recently been possible due to the following developments:

    1. The 2021 release of the powerful $4 Raspberry Pi Pico microcontroller. It had almost 100x the power of the Arduino Uno and sold for 1/8th the price.
    2. The availability of low-cost high-contrast OLED and TFT displays for as low as $7 each. When we use the $4 Raspberry Pi Pico our classrooms can create a development system for under $15.
    3. The support of highly-optimized drawing of complex ellipse and polygon shapes into the frame buffer by the MicroPython runtime. This only became available in version 20 of the standard MicroPython runtime released in April of 2023. Before this every clock and watch project used custom math functions that slowed drawing times.
    4. The ability of WiFi-enabled microcontrollers that can synchronize with centralized time services using standard WiFi networks. We use the $5 Raspberry Pi Pico W in many of our projects.
    5. The availability of low-cost yet ultra-precise real-time clock chips like the DS3231.

    Our goal is to provide fun ways to teach computational thinking to a wide variety of students from 6th to 12th grades. If you can type, we have fun lesson plans from drawing simple shapes to complex clock and watch face designs.

    "},{"location":"#acknowledgments","title":"Acknowledgments","text":"

    I want to thank everyone in the MicroPython community for sharing their code. Each of the displays requires MicroPython drivers that have special features to keep drawing fast. We could not have high-quality lesson plans without your contributions. If I have not referenced the cool features of your drivers, please let me know!

    "},{"location":"#feedback-and-comments","title":"Feedback and Comments","text":"

    If you have any comments or feedback, please feel free to post these to our GitHub Issues. I don't check these issues every day, so please be patient and connect with others in the MicroPython community if you have urgent questions for a classroom.

    Good Luck! - Dan McCreary on LinkedIn

    "},{"location":"about/","title":"About the MicroPython Clocks and Watchs Site","text":"

    My STEM students often hold a special facination with timekeeping. I don't know exactly what it is that gets them so excited about these projects. But the bottom line is they quickly become motivated to learn Python to create their own timekeeping devices that are customized to their interests. Owning their own devices and showing off these projects to their friends is also a big plus.

    At the core of Project Based Learning (PBL) is the desire to allow students to pick their own projects. My role as a mentor is to have a rich set of projects they can get started on. They may not understand all the components, but to fix and modify the projects they end up learning faster than if I gave them a dozen lectures with PowerPoint.

    "},{"location":"about/#the-timeless-allure-of-timekeeping-sparking-a-passion-for-coding-with-micropython-clocks-and-watches","title":"The Timeless Allure of Timekeeping: Sparking a Passion for Coding with MicroPython Clocks and Watches","text":"

    In a world driven by digital innovation, the essence of time remains universally compelling. From the ancient sundials to the modern-day smartwatches, humans have always been fascinated by the pursuit of measuring time. This intrigue, particularly among the younger generation, is why a library of fun MicroPython Clocks and Watches serves as an exceptional entry point into the universe of coding and computational thinking.

    "},{"location":"about/#tapping-into-the-childs-natural-curiosity","title":"Tapping into the Child's Natural Curiosity","text":"

    Children possess an innate sense of wonder. The ticking of a clock or the changing digits on a digital watch captivates their imagination. They question how it works, what makes it tick, and how they can possibly create one of their own. By introducing them to a collection of engaging MicroPython timekeeping projects, we are not only answering their questions but also kindling a flame of creativity and innovation.

    "},{"location":"about/#from-boring-lectures-to-tangible-results","title":"From Boring Lectures to Tangible Results","text":"

    Traditional pedagogical methods, characterized by long hours of lectures, often fail to hold the attention of young learners. However, project-based learning flips this paradigm. When a child is given the tools and guidance to create their very own digital clock or watch, the learning process transforms. They're no longer passive recipients of information but active creators, brimming with ideas and enthusiasm.

    A MicroPython Clock project, for instance, isn\u2019t just a coding endeavor; it's a journey. From understanding the concept, drafting the design, writing the first line of code, to finally witnessing their creation come to life \u2013 every step is a lesson in problem-solving, critical thinking, and perseverance.

    "},{"location":"about/#building-blocks-of-computational-thinking","title":"Building Blocks of Computational Thinking","text":"

    Computational thinking is a cornerstone of modern education. It\u2019s not just about writing code, but a way of approaching problems logically, breaking them down into smaller tasks, and finding efficient solutions. By creating a timekeeping device, children undergo a practical exercise in computational thinking. They decide the features they want, debug issues, and constantly refine their work, all while having fun!

    "},{"location":"about/#social-construction-the-joy-of-shared-creation","title":"Social Construction: The Joy of Shared Creation","text":"

    Imagine a part of every school library or a display case where clocks and watches are on display. Each devices can tell its unique story, representing a young coder's journey. Sharing these creations allows children to learn from each other, celebrate their achievements, and draw inspiration. Such a collaborative environment fosters not just coding skills but also empathy, teamwork, and a sense of community. Technically, we call group building projects Social constructivism. And there is ample research to show that students that learn in groups have higer participation rates and can usually develop better outcomes.

    "},{"location":"about/#engineered-for-user-experience","title":"Engineered for User Experience","text":"

    Great STEM projects don't just fall off a shelf into our laps. They need to be designed and tested carefully using the same agile processes that we use in software development. User Experience (UX) professionals need to help us observe our students using and learning from our lessons.

    "},{"location":"about/#in-conclusion","title":"In Conclusion","text":"

    A library of MicroPython Clocks and Watches isn't just a collection of projects; it\u2019s a treasure trove of experiences, learnings, and memories. By introducing children to the magic of timekeeping in the digital age, we are equipping them with skills for the future, fostering a love for coding, and most importantly, reminding them that learning can be both fun and profoundly meaningful. The timeless allure of time, coupled with the dynamic world of coding, creates a perfect blend to mold the innovators and thinkers of tomorrow.

    "},{"location":"contact/","title":"Contact","text":"

    Dan McCreary on LinkedIn

    "},{"location":"course-description/","title":"Course Description","text":"

    Course Title: Building Clocks and Watches with MicroPython Duration: 14 Weeks Target Audience: High School Students Learning Computational Thinking

    Course Description: In this 14-week, hands-on course, high school students will learn to design and program functional timekeeping devices---from simple LED clocks to sophisticated stopwatches and web-connected displays---using MicroPython on the Raspberry Pi Pico W. Throughout the course, students will be guided by hands on labs, moving from foundational knowledge to creative invention.

    1. Remember: Students begin by identifying essential electronic components---breadboards, microcontrollers, buttons, knobs, real-time clocks, and displays---and recalling the fundamental concepts of MicroPython programming.
    2. Understand: Through teacher-led demonstrations, students explore how timing functions, input/output operations, and hardware connections work together to create a basic LED clock. They deepen their grasp of computational thinking by examining concepts like abstraction (focusing on relevant details) and decomposition (breaking large problems into smaller parts). They proceed to use these concepts to customize clock and watch faces using graphic displays.
    3. Apply: As their skills grow, students practice wiring and programming a 128\u00d764 OLED display, interfacing with web services to fetch real-time data. They also implement stopwatches and timers, applying algorithms and pattern-matching techniques to manage user inputs and display outputs accurately.
    4. Analyze: Learners diagnose and troubleshoot various clock behaviors, studying how code efficiency and hardware choices influence device performance. They dissect timing errors, lag issues, and integration problems, refining both their programming and problem-solving skills.
    5. Evaluate: Working in teams, students test multiple clock designs to compare accuracy, power consumption, and user experience. They assess trade-offs---such as display readability vs. complexity---and refine solutions based on feedback, cost, and practicality. They can also work with AI to design new clocks.
    6. Create: Ultimately, students design and assemble their own custom timekeeping projects, combining LEDs, OLED displays, push buttons, and encoders. This final challenge showcases their ability to unify hardware and code into a polished, functioning prototype.

    By the end of the course, students will have built a diverse collection of digital clocks, stopwatches, and timers while gaining a rich understanding of electronics, computational thinking, and MicroPython. They will leave empowered to continue exploring the world of embedded systems and creative hardware projects that blend into the AI-powered home.

    "},{"location":"faq/","title":"Building Clocks and Watches with MicroPython - Frequently Asked Questions","text":""},{"location":"faq/#general-course-information","title":"General Course Information","text":""},{"location":"faq/#what-prior-knowledge-do-i-need-for-this-course","title":"What prior knowledge do I need for this course?","text":"

    No specific electronics or programming experience is required. However, basic computer literacy and comfort with mathematics at a high school level will be helpful. The course starts with fundamentals and builds up gradually.

    "},{"location":"faq/#how-long-is-each-class-session","title":"How long is each class session?","text":"

    While the course runs for 14 weeks, specific class session lengths are determined by your school's schedule. Contact your instructor for the exact timing of your sessions.

    "},{"location":"faq/#do-i-need-to-purchase-my-own-equipment","title":"Do I need to purchase my own equipment?","text":"

    Check with your instructor about equipment policies. Generally, core components like the Raspberry Pi Pico W and basic electronics will be provided, but you may want to purchase additional components for your final project.

    "},{"location":"faq/#what-software-do-i-need-to-install","title":"What software do I need to install?","text":"

    You'll need the Thonny IDE (a Python editor designed for MicroPython), which is free and works on Windows, Mac, and Linux. Your instructor will guide you through the installation process during the first week.

    "},{"location":"faq/#technical-questions","title":"Technical Questions","text":""},{"location":"faq/#what-is-micropython-and-how-is-it-different-from-regular-python","title":"What is MicroPython and how is it different from regular Python?","text":"

    MicroPython is a streamlined version of Python designed to run on microcontrollers. While it maintains Python's core features and syntax, it's optimized for hardware control and has special libraries for working with electronic components.

    "},{"location":"faq/#what-is-a-raspberry-pi-pico-w","title":"What is a Raspberry Pi Pico W?","text":"

    The Raspberry Pi Pico W is a small, affordable microcontroller board with built-in Wi-Fi. It's perfect for learning because it's user-friendly, well-documented, and has plenty of input/output pins for connecting different components.

    "},{"location":"faq/#will-we-be-doing-any-soldering","title":"Will we be doing any soldering?","text":"

    Most projects will use breadboards for non-permanent connections. Some optional advanced projects might involve soldering, but this will be optional and supervised.

    "},{"location":"faq/#how-accurate-will-our-clocks-be","title":"How accurate will our clocks be?","text":"

    The accuracy depends on the components used. With the basic oscillator, clocks might drift a few seconds per day. When we add a Real-Time Clock (RTC) module, accuracy improves significantly to within a few seconds per month.

    "},{"location":"faq/#project-related-questions","title":"Project-Related Questions","text":""},{"location":"faq/#what-kind-of-displays-will-we-use","title":"What kind of displays will we use?","text":"

    We'll work with several types: - Simple LEDs for basic digital displays - 128\u00d764 OLED displays for more sophisticated interfaces - Other display options for final projects

    "},{"location":"faq/#can-i-create-my-own-custom-clock-design-for-the-final-project","title":"Can I create my own custom clock design for the final project?","text":"

    Yes! The final project is designed to be creative and personal. You can combine different components and features we've learned about to create something unique.

    "},{"location":"faq/#how-will-we-handle-time-zones-and-daylight-saving-time","title":"How will we handle time zones and daylight saving time?","text":"

    We'll learn to sync time using web services (when Wi-Fi is available) and program time zone adjustments. Managing daylight saving time will be covered as part of the advanced features.

    "},{"location":"faq/#learning-and-assessment","title":"Learning and Assessment","text":""},{"location":"faq/#how-will-i-be-graded","title":"How will I be graded?","text":"

    Assessment typically includes:

    • Participation in class activities and discussions
    • Ability to work in teams
    • Completion of hands-on labs and exercises
    • Quality and functionality of projects
    • Final project presentation and documentation
    "},{"location":"faq/#what-happens-if-my-clock-doesnt-work","title":"What happens if my clock doesn't work?","text":"

    Troubleshooting is a crucial part of the learning process. You'll have support from instructors and peers, and we'll learn systematic debugging approaches. Making mistakes and fixing them is how we learn!

    "},{"location":"faq/#can-i-work-with-ai-tools-during-the-course","title":"Can I work with AI tools during the course?","text":"

    Yes, part of the course includes learning how to effectively use AI tools for design and problem-solving. We'll cover best practices for AI collaboration while ensuring you understand the fundamental concepts.

    "},{"location":"faq/#hardware-and-components","title":"Hardware and Components","text":""},{"location":"faq/#what-happens-if-i-accidentally-damage-a-component","title":"What happens if I accidentally damage a component?","text":"

    Don't worry! Learning electronics involves some trial and error. Basic components are relatively inexpensive and replaceable. Just inform your instructor if something breaks.

    "},{"location":"faq/#how-do-breadboards-work","title":"How do breadboards work?","text":"

    A breadboard is a reusable platform for creating temporary electrical connections. We'll spend time early in the course understanding how they work and practicing proper connection techniques.

    "},{"location":"faq/#whats-the-difference-between-digital-and-analog-inputsoutputs","title":"What's the difference between digital and analog inputs/outputs?","text":"

    Digital signals are either on (1) or off (0), while analog signals can have many values in between. We'll use both types: digital for buttons and simple LEDs, analog for sensors and variable controls.

    "},{"location":"faq/#programming-concepts","title":"Programming Concepts","text":""},{"location":"faq/#do-i-need-to-memorize-all-the-micropython-commands","title":"Do I need to memorize all the MicroPython commands?","text":"

    No, you don't need to memorize everything. We'll provide reference materials, and part of learning is knowing how to find and use documentation effectively.

    "},{"location":"faq/#what-if-i-miss-a-class-and-fall-behind","title":"What if I miss a class and fall behind?","text":"

    Each concept builds on previous learning, but we'll provide catch-up resources and extra help sessions. Talk to your instructor as soon as possible if you fall behind.

    "},{"location":"faq/#how-will-we-debug-our-code","title":"How will we debug our code?","text":"

    We'll learn several debugging techniques:

    • Using print statements for troubleshooting
    • Reading error messages
    • Using the Thonny debugger
    • Systematic problem-solving approaches
    "},{"location":"faq/#safety-and-best-practices","title":"Safety and Best Practices","text":""},{"location":"faq/#is-there-any-risk-of-electric-shock","title":"Is there any risk of electric shock?","text":"

    The Pico W and components we use operate at very low voltages (3.3V or 5V) which are safe to handle. However, we'll still learn and follow proper safety procedures.

    "},{"location":"faq/#how-do-i-protect-the-electronic-components","title":"How do I protect the electronic components?","text":"

    We'll cover basic handling procedures including:

    • Static electricity precautions
    • Proper connection techniques
    • Component storage and handling
    • Avoiding common mistakes that could damage components
    "},{"location":"faq/#advanced-topics-and-extensions","title":"Advanced Topics and Extensions","text":""},{"location":"faq/#can-we-add-features-like-alarms-or-stopwatch-functions","title":"Can we add features like alarms or stopwatch functions?","text":"

    Yes! As you progress through the course, you'll learn to add various features including:

    • Multiple alarms
    • Stopwatch and timer functions
    • Custom sounds and alerts
    • Special display effects
    "},{"location":"faq/#will-we-learn-about-power-management","title":"Will we learn about power management?","text":"

    Yes, we'll cover power management including:

    • Battery operation
    • Sleep modes
    • Power-efficient programming
    • Battery life optimization
    "},{"location":"faq/#future-applications","title":"Future Applications","text":""},{"location":"faq/#can-i-use-these-skills-for-other-projects","title":"Can I use these skills for other projects?","text":"

    Absolutely! The skills you'll learn apply to many other electronics and programming projects:

    • Other types of electronic devices
    • Home automation projects
    • Sensor-based systems
    • IoT (Internet of Things) devices
    "},{"location":"faq/#how-does-this-course-prepare-me-for-further-study","title":"How does this course prepare me for further study?","text":"

    This course builds valuable skills for:

    • Computer science courses
    • Engineering programs
    • Electronics projects
    • General problem-solving
    • Understanding modern technology
    "},{"location":"faq/#tools-and-resources","title":"Tools and Resources","text":""},{"location":"faq/#what-online-resources-can-we-use","title":"What online resources can we use?","text":"

    We'll use various resources including:

    • MicroPython documentation
    • Raspberry Pi Pico documentation
    • Component datasheets
    • Online simulators
    • Programming reference guides
    "},{"location":"faq/#will-we-use-version-control-like-git","title":"Will we use version control like Git?","text":"

    While not required, we'll introduce basic version control concepts and how they can help manage your code as projects become more complex.

    "},{"location":"faq/#collaboration-and-community","title":"Collaboration and Community","text":""},{"location":"faq/#can-we-work-in-teams","title":"Can we work in teams?","text":"

    Yes! Many activities will involve pair programming or team collaboration. The final project can be individual or team-based, depending on complexity and scope.

    "},{"location":"faq/#how-can-we-share-our-projects-with-others","title":"How can we share our projects with others?","text":"

    We'll discuss ways to:

    • Document your work
    • Create project presentations
    • Share code responsibly
    • Collaborate with other students
    • Showcase your projects
    "},{"location":"faq/#getting-help","title":"Getting Help","text":""},{"location":"faq/#what-if-i-get-stuck-on-a-problem","title":"What if I get stuck on a problem?","text":"

    Multiple support options are available:

    • In-class help from instructors
    • Peer support
    • Office hours
    • Online resources
    • Lab assistance sessions
    "},{"location":"faq/#can-i-get-extra-help-outside-of-class","title":"Can I get extra help outside of class?","text":"

    Yes, instructors will have office hours and may offer additional lab time for students who want extra practice or help.

    "},{"location":"faq/#course-materials","title":"Course Materials","text":""},{"location":"faq/#what-should-i-bring-to-class","title":"What should I bring to class?","text":"

    Typically you'll need:

    • Notebook for taking notes
    • Computer (if not provided)
    • Any assigned reading materials
    • Your project components once distributed
    "},{"location":"faq/#how-should-i-store-and-transport-my-projects","title":"How should I store and transport my projects?","text":"

    We'll provide guidance on:

    • Component storage
    • Project organization
    • Safe transport methods
    • Protecting delicate components
    "},{"location":"faq/#final-projects","title":"Final Projects","text":""},{"location":"faq/#what-makes-a-good-final-project","title":"What makes a good final project?","text":"

    Strong final projects typically:

    • Solve a real problem or fulfill a genuine need
    • Demonstrate technical skills learned in the course
    • Show creativity and originality
    • Are well-documented
    • Function reliably
    "},{"location":"faq/#can-i-continue-working-on-my-project-after-the-course-ends","title":"Can I continue working on my project after the course ends?","text":"

    Yes! You'll have the knowledge to continue developing and improving your projects. We'll discuss ways to extend your learning and continue exploring electronics and programming.

    "},{"location":"glossary/","title":"Glossary of Terms DIY Clocks and Watches with MicroPython","text":""},{"location":"glossary/#abstraction","title":"Abstraction","text":"

    A technique for managing complexity by hiding unnecessary details while keeping essential features visible.

    Example: Using a display_time() function that accepts hours and minutes without needing to know how individual LED segments are controlled.

    "},{"location":"glossary/#breadboard","title":"Breadboard","text":"

    A reusable plastic board with holes and internal connections for prototyping electronic circuits without soldering.

    Example: Connecting LED displays and buttons to the Pico W using jumper wires on a breadboard.

    "},{"location":"glossary/#button-debouncing","title":"Button Debouncing","text":"

    A technique to prevent false button readings caused by mechanical switch contacts bouncing when pressed or released.

    Example: debounce_time = 100 in button configuration prevents multiple accidental triggers.

    "},{"location":"glossary/#callback-function","title":"Callback Function","text":"

    A function passed as an argument to another function, which will be executed when a specific event occurs.

    Example: button_mode_irq function that runs whenever the mode button is pressed.

    "},{"location":"glossary/#digital-display","title":"Digital Display","text":"

    An electronic output device that shows numbers, letters, or symbols using discrete segments or pixels.

    Example: Four-digit seven-segment LED display showing hours and minutes.

    "},{"location":"glossary/#ds1307","title":"DS1307","text":""},{"location":"glossary/#event-handler","title":"Event Handler","text":"

    A function that responds to specific occurrences like button presses or timer updates.

    Example: The button_mode_irq function handles mode button press events.

    "},{"location":"glossary/#gpio-pin","title":"GPIO Pin","text":"

    General Purpose Input/Output connection on a microcontroller that can be programmed to send or receive electrical signals.

    Example: Using GPIO pin 16 for the mode button: mode_pin = Pin(16, Pin.IN, Pin.PULL_UP)

    "},{"location":"glossary/#i2c","title":"I2C","text":"

    A communication protocol that allows multiple digital components to exchange data using just two wires plus power and ground.

    "},{"location":"glossary/#interrupt","title":"Interrupt","text":"

    A signal that causes the microcontroller to pause its current task and handle a high-priority event.

    "},{"location":"glossary/#led-matrix","title":"LED Matrix","text":"

    An array of light-emitting diodes arranged in rows and columns that can display patterns, numbers, or text.

    "},{"location":"glossary/#micropython","title":"MicroPython","text":"

    A streamlined version of Python programming language designed to run on microcontrollers and embedded systems.

    "},{"location":"glossary/#oled-display","title":"OLED Display","text":"

    A thin, bright display that uses organic light-emitting diodes to show text and graphics without a backlight.

    "},{"location":"glossary/#pin","title":"Pin","text":"

    A metal connector on electronic components that carries electrical signals or power.

    "},{"location":"glossary/#pull-up-resistor","title":"Pull-up Resistor","text":"

    An electronic component that ensures a consistent voltage level on input pins when buttons or switches are not pressed.

    Example: Using internal pull-up resistors with Pin.PULL_UP for button inputs.

    "},{"location":"glossary/#pwm","title":"PWM","text":"

    Pulse Width Modulation - a technique for creating varying levels of brightness or speed by rapidly switching a signal on and off.

    "},{"location":"glossary/#raspberry-pi-pico-w","title":"Raspberry Pi Pico W","text":"

    A small, low-cost microcontroller board with built-in wireless capabilities, designed for learning and DIY projects.

    "},{"location":"glossary/#real-time-clock-rtc","title":"Real-Time Clock (RTC)","text":"

    A specialized chip or circuit that keeps accurate time even when main power is removed.

    Example: Using the RTC module to maintain accurate time: rtc = RTC()

    "},{"location":"glossary/#seven-segment-display","title":"Seven-Segment Display","text":"

    A display made of seven LED segments plus a decimal point that can show numbers and some letters.

    Example: Creating patterns for digits using segments 'a' through 'g': SEGMENTS = {'a': 4, 'b': 3, 'c': 2, 'd': 7, 'e': 6, 'f': 5, 'g': 1}

    "},{"location":"glossary/#shift-register","title":"Shift Register","text":"

    An integrated circuit that converts serial data into parallel outputs, useful for controlling multiple LEDs with fewer pins.

    Example: Using SR74HC595 shift register to control display segments.

    "},{"location":"glossary/#spi","title":"SPI","text":"

    Serial Peripheral Interface - a fast communication protocol for connecting digital components using multiple signal lines.

    "},{"location":"glossary/#state-machine","title":"State Machine","text":"

    A programming concept where a system can be in one of several defined states, with specific rules for transitioning between them.

    Example: Clock modes including \"run\", \"set hour\", \"set minute\", and \"set AM/PM\".

    "},{"location":"glossary/#usb-power","title":"USB Power","text":"

    A 5-volt power source available through Universal Serial Bus connections, commonly used for powering small electronic projects.

    "},{"location":"glossary/#web-services","title":"Web Services","text":"

    Online resources that provide data or functionality through standard internet protocols.

    Example: Fetching current time from an internet time server for clock synchronization.

    "},{"location":"glossary/#3d-printing-watch-enclosures","title":"3D Printing Watch Enclosures","text":"

    A process of creating custom protective cases for watch components using additive manufacturing technology.

    "},{"location":"glossary/#accelerometer","title":"Accelerometer","text":"

    A sensor that measures physical acceleration and orientation, useful for tilt-based display activation.

    Example: Detecting when a user lifts their wrist to view the watch face.

    "},{"location":"glossary/#alarm","title":"Alarm","text":"

    A scheduled alert that triggers audio, visual, or vibration notifications at specific times.

    Example: Setting multiple daily alarms using the RTC module.

    "},{"location":"glossary/#analog-clock-face","title":"Analog Clock Face","text":"

    A traditional clock display using rotating hands to show time on a circular dial.

    Example: Drawing hour and minute hands using math.sin() and math.cos() for position calculations.

    "},{"location":"glossary/#animation","title":"Animation","text":"

    The process of creating movement by rapidly updating display contents.

    Example: Smoothly rotating second hands or creating blinking colons between hours and minutes.

    "},{"location":"glossary/#asynchronous-programming","title":"Asynchronous Programming","text":"

    A coding technique that allows multiple tasks to run concurrently without blocking each other.

    Example: Using uasyncio to handle display updates while monitoring button presses.

    "},{"location":"glossary/#battery-backup","title":"Battery Backup","text":"

    A power system that maintains time and settings when main power is disconnected.

    "},{"location":"glossary/#battery-power","title":"Battery Power","text":"

    Portable electrical energy storage used to operate mobile timepieces.

    Example: Calculating power consumption to estimate battery life.

    "},{"location":"glossary/#blitting","title":"Blitting","text":"

    A technique for rapidly copying rectangular portions of memory to update displays efficiently.

    Example: Using framebuffer operations to reduce screen flicker.

    "},{"location":"glossary/#chronograph","title":"Chronograph","text":"

    A timepiece with both timekeeping and stopwatch capabilities.

    "},{"location":"glossary/#color-depth","title":"Color Depth","text":"

    The number of bits used to represent colors in a display.

    Example: Using 16 bits per pixel to show 65,536 different colors.

    "},{"location":"glossary/#concurrency","title":"Concurrency","text":"

    The ability to handle multiple tasks or events simultaneously in a program.

    Example: Updating the display while checking for button presses.

    "},{"location":"glossary/#conditionals","title":"Conditionals","text":"

    Programming statements that perform different actions based on whether a condition is true or false.

    Example: Switching between 12-hour and 24-hour time formats.

    "},{"location":"glossary/#custom-font","title":"Custom Font","text":"

    A specialized set of character designs loaded into memory for display purposes.

    Example: Loading compact number fonts using the micropython-ufont library.

    "},{"location":"glossary/#daylight-saving-time","title":"Daylight Saving Time","text":"

    A seasonal time adjustment typically involving a one-hour shift.

    Example: Automatically adjusting clock time based on DST rules.

    "},{"location":"glossary/#deep-sleep","title":"Deep Sleep","text":"

    A low-power mode that disables most system functions to conserve energy.

    Example: Entering sleep mode when the watch face isn't being viewed.

    "},{"location":"glossary/#display-driver","title":"Display Driver","text":"

    Software that controls how information is shown on a specific type of display.

    Example: Using the ST7735 driver for TFT LCD screens.

    "},{"location":"glossary/#double-buffering","title":"Double Buffering","text":"

    A technique using two memory areas to prepare the next frame while displaying the current one.

    Example: Creating smooth animations without visible drawing operations.

    "},{"location":"glossary/#e-paper-display","title":"E-Paper Display","text":"

    A low-power screen technology that maintains its image without constant power.

    Example: Using partial updates to change only modified portions of the display.

    "},{"location":"glossary/#external-rtc","title":"External RTC","text":"

    A separate timekeeping chip that maintains accurate time independent of the main processor.

    Example: Using a DS3231 module for precise timekeeping.

    "},{"location":"glossary/#filesystem","title":"Filesystem","text":"

    A system for storing and organizing files on the microcontroller.

    Example: Saving configuration settings and logs to internal storage.

    "},{"location":"glossary/#framebuffer","title":"Framebuffer","text":"

    A region of memory that holds the complete contents of a display.

    Example: Modifying pixel data before updating the screen.

    "},{"location":"glossary/#functions","title":"Functions","text":"

    Reusable blocks of code that perform specific tasks.

    Example: Creating a function to convert between 12-hour and 24-hour formats.

    "},{"location":"glossary/#ghosting","title":"Ghosting","text":"

    A visual artifact where previous images remain partially visible on certain display types.

    Example: Using display clearing techniques on e-paper screens.

    "},{"location":"glossary/#i2c-sensors","title":"I2C Sensors","text":"

    Digital components that communicate using the I2C protocol to provide measurements.

    Example: Reading temperature and humidity data for weather display.

    "},{"location":"glossary/#interrupt_1","title":"Interrupt","text":"

    A signal that temporarily pauses normal program execution to handle important events.

    Example: Responding immediately to button presses.

    "},{"location":"glossary/#json","title":"JSON","text":"

    A text-based data format commonly used for exchanging information with web services.

    Example: Parsing weather data from online APIs.

    "},{"location":"glossary/#libraries","title":"Libraries","text":"

    Collections of pre-written code that provide useful functions and features.

    Example: Using the math module for trigonometric calculations.

    "},{"location":"glossary/#lipo-charging","title":"LiPo Charging","text":"

    The process of safely recharging Lithium Polymer batteries.

    Example: Implementing USB charging circuits with protection features.

    "},{"location":"glossary/#logging","title":"Logging","text":"

    The practice of recording program events and data for debugging or analysis.

    Example: Saving timing discrepancies to investigate accuracy issues.

    "},{"location":"glossary/#loops","title":"Loops","text":"

    Programming structures that repeat code blocks multiple times.

    Example: Continuously updating the display every second.

    "},{"location":"glossary/#math-module","title":"Math Module","text":"

    A collection of mathematical functions for complex calculations.

    Example: Using trigonometry to position clock hands.

    "},{"location":"glossary/#menu-system","title":"Menu System","text":"

    An interface allowing users to navigate options and settings.

    Example: Creating hierarchical settings menus for watch configuration.

    "},{"location":"glossary/#network-time-protocol-ntp","title":"Network Time Protocol (NTP)","text":"

    A method for synchronizing time over the internet.

    Example: Updating the RTC from online time servers.

    "},{"location":"glossary/#partial-refresh","title":"Partial Refresh","text":"

    Updating only changed portions of a display to improve efficiency.

    Example: Refreshing only the seconds digits each update.

    "},{"location":"glossary/#pedometer","title":"Pedometer","text":"

    A feature that counts steps using motion sensor data.

    Example: Calculating daily step counts from accelerometer readings.

    "},{"location":"glossary/#power-management","title":"Power Management","text":"

    Techniques for minimizing and controlling energy consumption.

    Example: Using sleep modes and efficient display updates.

    "},{"location":"glossary/#pwm-audio","title":"PWM Audio","text":"

    Using Pulse Width Modulation to generate sounds and tones.

    Example: Creating alarm beeps and hourly chimes.

    "},{"location":"glossary/#rotary-encoder","title":"Rotary Encoder","text":"

    A input device that converts rotational movement into digital signals.

    Example: Using encoder rotation to adjust time settings.

    "},{"location":"glossary/#screen-update","title":"Screen Update","text":"

    The process of refreshing display contents to show new information.

    Example: Efficiently updating only changed portions of the time display.

    "},{"location":"glossary/#servo-motor","title":"Servo Motor","text":"

    An actuator that can rotate to precise positions.

    Example: Moving physical clock hands on a hybrid display.

    "},{"location":"glossary/#sleep-mode","title":"Sleep Mode","text":"

    A low-power state that reduces energy consumption.

    Example: Entering deep sleep between display updates.

    "},{"location":"glossary/#spi-interface","title":"SPI Interface","text":"

    A high-speed serial communication protocol for connecting displays and sensors.

    Example: Transferring data to TFT displays efficiently.

    "},{"location":"glossary/#temperature-sensor","title":"Temperature Sensor","text":"

    A component that measures ambient temperature.

    Example: Displaying current temperature alongside time.

    "},{"location":"glossary/#thonny-ide","title":"Thonny IDE","text":"

    An integrated development environment optimized for MicroPython programming.

    Example: Using Thonny to upload code and debug timing issues.

    "},{"location":"glossary/#time-zone","title":"Time Zone","text":"

    A region that observes a uniform standard time.

    Example: Converting between local time and UTC.

    "},{"location":"glossary/#timer","title":"Timer","text":"

    A system resource that generates regular time-based events.

    Example: Creating precise one-second update intervals.

    "},{"location":"glossary/#utc","title":"UTC","text":"

    Coordinated Universal Time, the primary time standard for global time coordination.

    Example: Converting local time to UTC for synchronization.

    "},{"location":"glossary/#watchdog-timer","title":"Watchdog Timer","text":"

    A hardware feature that resets the system if the program stops responding.

    Example: Ensuring reliability in long-running clock applications.

    "},{"location":"glossary/#weather-updates","title":"Weather Updates","text":"

    Real-time weather information obtained through internet services.

    Example: Displaying temperature and forecast alongside time.

    "},{"location":"glossary/#wi-fi-module","title":"Wi-Fi Module","text":"

    Hardware that enables wireless network connectivity.

    Example: Connecting to the internet for time synchronization.

    "},{"location":"glossary/#world-clock","title":"World Clock","text":"

    A timepiece that displays times for multiple time zones simultaneously.

    Example: Showing local time alongside other major cities' times.

    "},{"location":"glossary/#diy-clocks-and-watches-with-micropython-glossary","title":"DIY Clocks and Watches with MicroPython: Glossary","text":""},{"location":"glossary/#3d-printing-watch-enclosures_1","title":"3D Printing Watch Enclosures","text":"

    A process of creating custom protective cases for watch components using additive manufacturing technology.

    "},{"location":"glossary/#accelerometer_1","title":"Accelerometer","text":"

    A sensor that measures physical acceleration and orientation, useful for tilt-based display activation.

    Example: Detecting when a user lifts their wrist to view the watch face.

    "},{"location":"glossary/#alarm_1","title":"Alarm","text":"

    A scheduled alert that triggers audio, visual, or vibration notifications at specific times.

    Example: Setting multiple daily alarms using the RTC module.

    "},{"location":"glossary/#analog-clock-face_1","title":"Analog Clock Face","text":"

    A traditional clock display using rotating hands to show time on a circular dial.

    Example: Drawing hour and minute hands using math.sin() and math.cos() for position calculations.

    "},{"location":"glossary/#animation_1","title":"Animation","text":"

    The process of creating movement by rapidly updating display contents.

    Example: Smoothly rotating second hands or creating blinking colons between hours and minutes.

    "},{"location":"glossary/#asynchronous-programming_1","title":"Asynchronous Programming","text":"

    A coding technique that allows multiple tasks to run concurrently without blocking each other.

    Example: Using uasyncio to handle display updates while monitoring button presses.

    "},{"location":"glossary/#battery-backup_1","title":"Battery Backup","text":"

    A power system that maintains time and settings when main power is disconnected.

    "},{"location":"glossary/#battery-power_1","title":"Battery Power","text":"

    Portable electrical energy storage used to operate mobile timepieces.

    Example: Calculating power consumption to estimate battery life.

    "},{"location":"glossary/#blitting_1","title":"Blitting","text":"

    A technique for rapidly copying rectangular portions of memory to update displays efficiently.

    Example: Using framebuffer operations to reduce screen flicker.

    "},{"location":"glossary/#chronograph_1","title":"Chronograph","text":"

    A timepiece with both timekeeping and stopwatch capabilities.

    "},{"location":"glossary/#color-depth_1","title":"Color Depth","text":"

    The number of bits used to represent colors in a display.

    Example: Using 16 bits per pixel to show 65,536 different colors.

    "},{"location":"glossary/#concurrency_1","title":"Concurrency","text":"

    The ability to handle multiple tasks or events simultaneously in a program.

    Example: Updating the display while checking for button presses.

    "},{"location":"glossary/#conditionals_1","title":"Conditionals","text":"

    Programming statements that perform different actions based on whether a condition is true or false.

    Example: Switching between 12-hour and 24-hour time formats.

    "},{"location":"glossary/#custom-font_1","title":"Custom Font","text":"

    A specialized set of character designs loaded into memory for display purposes.

    Example: Loading compact number fonts using the micropython-ufont library.

    "},{"location":"glossary/#daylight-saving-time_1","title":"Daylight Saving Time","text":"

    A seasonal time adjustment typically involving a one-hour shift.

    Example: Automatically adjusting clock time based on DST rules.

    "},{"location":"glossary/#deep-sleep_1","title":"Deep Sleep","text":"

    A low-power mode that disables most system functions to conserve energy.

    Example: Entering sleep mode when the watch face isn't being viewed.

    "},{"location":"glossary/#display-driver_1","title":"Display Driver","text":"

    Software that controls how information is shown on a specific type of display.

    Example: Using the ST7735 driver for TFT LCD screens.

    "},{"location":"glossary/#double-buffering_1","title":"Double Buffering","text":"

    A technique using two memory areas to prepare the next frame while displaying the current one.

    Example: Creating smooth animations without visible drawing operations.

    "},{"location":"glossary/#e-paper-display_1","title":"E-Paper Display","text":"

    A low-power screen technology that maintains its image without constant power.

    Example: Using partial updates to change only modified portions of the display.

    "},{"location":"glossary/#external-rtc_1","title":"External RTC","text":"

    A separate timekeeping chip that maintains accurate time independent of the main processor.

    Example: Using a DS3231 module for precise timekeeping.

    "},{"location":"glossary/#filesystem_1","title":"Filesystem","text":"

    A system for storing and organizing files on the microcontroller.

    Example: Saving configuration settings and logs to internal storage.

    "},{"location":"glossary/#framebuffer_1","title":"Framebuffer","text":"

    A region of memory that holds the complete contents of a display.

    Example: Modifying pixel data before updating the screen.

    "},{"location":"glossary/#functions_1","title":"Functions","text":"

    Reusable blocks of code that perform specific tasks.

    Example: Creating a function to convert between 12-hour and 24-hour formats.

    "},{"location":"glossary/#ghosting_1","title":"Ghosting","text":"

    A visual artifact where previous images remain partially visible on certain display types.

    Example: Using display clearing techniques on e-paper screens.

    "},{"location":"glossary/#i2c-sensors_1","title":"I2C Sensors","text":"

    Digital components that communicate using the I2C protocol to provide measurements.

    Example: Reading temperature and humidity data for weather display.

    "},{"location":"glossary/#interrupt_2","title":"Interrupt","text":"

    A signal that temporarily pauses normal program execution to handle important events.

    Example: Responding immediately to button presses.

    "},{"location":"glossary/#json_1","title":"JSON","text":"

    A text-based data format commonly used for exchanging information with web services.

    Example: Parsing weather data from online APIs.

    "},{"location":"glossary/#libraries_1","title":"Libraries","text":"

    Collections of pre-written code that provide useful functions and features.

    Example: Using the math module for trigonometric calculations.

    "},{"location":"glossary/#lipo-charging_1","title":"LiPo Charging","text":"

    The process of safely recharging Lithium Polymer batteries.

    Example: Implementing USB charging circuits with protection features.

    "},{"location":"glossary/#logging_1","title":"Logging","text":"

    The practice of recording program events and data for debugging or analysis.

    Example: Saving timing discrepancies to investigate accuracy issues.

    "},{"location":"glossary/#loops_1","title":"Loops","text":"

    Programming structures that repeat code blocks multiple times.

    Example: Continuously updating the display every second.

    "},{"location":"glossary/#math-module_1","title":"Math Module","text":"

    A collection of mathematical functions for complex calculations.

    Example: Using trigonometry to position clock hands.

    "},{"location":"glossary/#menu-system_1","title":"Menu System","text":"

    An interface allowing users to navigate options and settings.

    Example: Creating hierarchical settings menus for watch configuration.

    "},{"location":"glossary/#network-time-protocol-ntp_1","title":"Network Time Protocol (NTP)","text":"

    A method for synchronizing time over the internet.

    Example: Updating the RTC from online time servers.

    "},{"location":"glossary/#partial-refresh_1","title":"Partial Refresh","text":"

    Updating only changed portions of a display to improve efficiency.

    Example: Refreshing only the seconds digits each update.

    "},{"location":"glossary/#pedometer_1","title":"Pedometer","text":"

    A feature that counts steps using motion sensor data.

    Example: Calculating daily step counts from accelerometer readings.

    "},{"location":"glossary/#power-management_1","title":"Power Management","text":"

    Techniques for minimizing and controlling energy consumption.

    Example: Using sleep modes and efficient display updates.

    "},{"location":"glossary/#pwm-audio_1","title":"PWM Audio","text":"

    Using Pulse Width Modulation to generate sounds and tones.

    Example: Creating alarm beeps and hourly chimes.

    "},{"location":"glossary/#rotary-encoder_1","title":"Rotary Encoder","text":"

    A input device that converts rotational movement into digital signals.

    Example: Using encoder rotation to adjust time settings.

    "},{"location":"glossary/#screen-update_1","title":"Screen Update","text":"

    The process of refreshing display contents to show new information.

    Example: Efficiently updating only changed portions of the time display.

    "},{"location":"glossary/#servo-motor_1","title":"Servo Motor","text":"

    An actuator that can rotate to precise positions.

    Example: Moving physical clock hands on a hybrid display.

    "},{"location":"glossary/#sleep-mode_1","title":"Sleep Mode","text":"

    A low-power state that reduces energy consumption.

    Example: Entering deep sleep between display updates.

    "},{"location":"glossary/#spi-interface_1","title":"SPI Interface","text":"

    A high-speed serial communication protocol for connecting displays and sensors.

    Example: Transferring data to TFT displays efficiently.

    "},{"location":"glossary/#temperature-sensor_1","title":"Temperature Sensor","text":"

    A component that measures ambient temperature.

    Example: Displaying current temperature alongside time.

    "},{"location":"glossary/#thonny-ide_1","title":"Thonny IDE","text":"

    An integrated development environment optimized for MicroPython programming.

    Example: Using Thonny to upload code and debug timing issues.

    "},{"location":"glossary/#time-zone_1","title":"Time Zone","text":"

    A region that observes a uniform standard time.

    Example: Converting between local time and UTC.

    "},{"location":"glossary/#timer_1","title":"Timer","text":"

    A system resource that generates regular time-based events.

    Example: Creating precise one-second update intervals.

    "},{"location":"glossary/#utc_1","title":"UTC","text":"

    Coordinated Universal Time, the primary time standard for global time coordination.

    Example: Converting local time to UTC for synchronization.

    "},{"location":"glossary/#watchdog-timer_1","title":"Watchdog Timer","text":"

    A hardware feature that resets the system if the program stops responding.

    Example: Ensuring reliability in long-running clock applications.

    "},{"location":"glossary/#weather-updates_1","title":"Weather Updates","text":"

    Real-time weather information obtained through internet services.

    Example: Displaying temperature and forecast alongside time.

    "},{"location":"glossary/#wi-fi-module_1","title":"Wi-Fi Module","text":"

    Hardware that enables wireless network connectivity.

    Example: Connecting to the internet for time synchronization.

    "},{"location":"glossary/#world-clock_1","title":"World Clock","text":"

    A timepiece that displays times for multiple time zones simultaneously.

    Example: Showing local time alongside other major cities' times.

    "},{"location":"glossary/#battery-drain-calculation","title":"Battery Drain Calculation","text":"

    The process of measuring and estimating power consumption to determine battery life.

    Example: Measuring current draw during different display update modes.

    "},{"location":"glossary/#changing-fonts","title":"Changing Fonts","text":"

    The process of modifying text appearance by loading and applying different typefaces.

    Example: Using the micropython-ufont library to load compact digital number styles.

    "},{"location":"glossary/#color-animations","title":"Color Animations","text":"

    Dynamic changes in display colors to create visual effects or indicate status.

    Example: Gradually shifting background colors throughout the day.

    "},{"location":"glossary/#color-conversion","title":"Color Conversion","text":"

    The process of transforming between different color representation systems.

    Example: Converting RGB colors to 16-bit format for TFT displays.

    "},{"location":"glossary/#console-output","title":"Console Output","text":"

    Text-based information displayed in the development environment for debugging.

    Example: print(\"Current time:\", hours, \":\", minutes)

    "},{"location":"glossary/#cuckoo-clock","title":"Cuckoo Clock","text":"

    A timepiece that marks specific hours with sound and optional mechanical movement.

    Example: Playing bird sounds and activating a servo at the top of each hour.

    "},{"location":"glossary/#datetime-objects","title":"datetime Objects","text":"

    Programming structures that store date and time information together.

    Example: Converting between timestamp integers and datetime format.

    "},{"location":"glossary/#drawing-libraries","title":"Drawing Libraries","text":"

    Software collections that provide functions for creating visual elements.

    Example: Using built-in graphics functions to draw clock hands and numbers.

    "},{"location":"glossary/#drawing-primitives","title":"Drawing Primitives","text":"

    Basic shapes and elements used to create more complex visual displays.

    Example: Using lines and arcs to create clock hands.

    "},{"location":"glossary/#fast-redraw","title":"Fast Redraw","text":"

    Techniques for updating displays quickly to maintain smooth animation.

    Example: Using hardware acceleration for screen updates.

    "},{"location":"glossary/#flicker-reduction","title":"Flicker Reduction","text":"

    Methods to minimize visible display instability during updates.

    Example: Using double buffering to prevent partial frame displays.

    "},{"location":"glossary/#hardware-documentation","title":"Hardware Documentation","text":"

    Technical specifications and usage instructions for electronic components.

    Example: Consulting pinout diagrams for display connections.

    "},{"location":"glossary/#incremental-drawing","title":"Incremental Drawing","text":"

    Updating only the necessary portions of a display to improve efficiency.

    Example: Refreshing only the seconds indicator rather than the full screen.

    "},{"location":"glossary/#loading-drivers","title":"Loading Drivers","text":"

    Installing and initializing software that controls specific hardware components.

    Example: Importing and configuring TFT display drivers.

    "},{"location":"glossary/#localtime-function","title":"localtime() Function","text":"

    A MicroPython function that returns the current time as a tuple of values.

    Example: year, month, day, hour, minute, second = localtime()

    "},{"location":"glossary/#mathsin-and-mathcos","title":"math.sin() and math.cos()","text":"

    Trigonometric functions used for calculating positions on circular displays.

    Example: Computing analog clock hand coordinates.

    "},{"location":"glossary/#micropython-drawing","title":"MicroPython Drawing","text":"

    Built-in functions for creating visual elements on displays.

    Example: Using framebuf methods to draw shapes and text.

    "},{"location":"glossary/#micropython-network","title":"MicroPython network","text":"

    A module providing Wi-Fi and network connectivity functions.

    Example: Connecting to wireless networks for time synchronization.

    "},{"location":"glossary/#micropython-syntax","title":"MicroPython Syntax","text":"

    The specific programming language rules and structure for MicroPython code.

    Example: Using Python-style indentation for code blocks.

    "},{"location":"glossary/#screen-via-spi","title":"Screen Via SPI","text":"

    High-speed serial communication method for updating displays.

    Example: Sending framebuffer data to TFT screens efficiently.

    "},{"location":"glossary/#setting-system-clock","title":"Setting System Clock","text":"

    Configuring the internal timekeeping system with accurate time.

    Example: Updating RTC time from an external time source.

    "},{"location":"glossary/#sleep-scheduling","title":"Sleep Scheduling","text":"

    Managing when the device enters and exits low-power states.

    Example: Programming wake-up times for hourly updates.

    "},{"location":"glossary/#sound-encoding","title":"Sound Encoding","text":"

    Methods for storing and playing audio data for alarms and notifications.

    Example: Converting WAV files to suitable format for playback.

    "},{"location":"glossary/#tft-displays","title":"TFT Displays","text":"

    Thin-film-transistor liquid crystal displays for showing color graphics.

    Example: Using ST7735 or ILI9341 displays for watch faces.

    "},{"location":"glossary/#timer-based-events","title":"Timer-Based Events","text":"

    Actions triggered by internal timing mechanisms.

    Example: Updating display elements at specific intervals.

    "},{"location":"glossary/#ultra-low-power","title":"Ultra-Low Power","text":"

    Operating modes and techniques that minimize energy consumption.

    Example: Using sleep modes and efficient screen updates.

    "},{"location":"glossary/#battery-tools","title":"Battery Tools","text":"

    Instruments and methods for measuring power consumption and battery health.

    Example: Using multimeters to measure current draw in different modes.

    "},{"location":"glossary/#button-input-handling","title":"Button Input Handling","text":"

    Software techniques for detecting and responding to button presses.

    Example: Using interrupts and debouncing for reliable input detection.

    "},{"location":"glossary/#custom-segment-display","title":"Custom Segment Display","text":"

    A specialized arrangement of LED segments for showing numbers or characters.

    Example: Creating unique digit patterns using individual LED segments.

    "},{"location":"glossary/#display-technology-comparison","title":"Display Technology Comparison","text":"

    Analysis of different screen types' advantages and limitations.

    Example: Evaluating power consumption versus update speed for various displays.

    "},{"location":"glossary/#drawing-arcs","title":"Drawing Arcs","text":"

    Creating curved lines as portions of circles on displays.

    Example: Drawing round clock face elements and decorative features.

    "},{"location":"glossary/#drawing-circles","title":"Drawing Circles","text":"

    Creating perfect circular shapes on displays.

    Example: Drawing clock face outlines and hour markers.

    "},{"location":"glossary/#drawing-ellipses","title":"Drawing Ellipses","text":"

    Creating oval shapes on displays.

    Example: Designing stylized clock faces and decorative elements.

    "},{"location":"glossary/#drawing-hands","title":"Drawing Hands","text":"

    Creating moving indicators for hours, minutes, and seconds.

    Example: Using line drawing functions to show analog time.

    "},{"location":"glossary/#drawing-lines","title":"Drawing Lines","text":"

    Creating straight line segments on displays.

    Example: Drawing clock hand indicators and markings.

    "},{"location":"glossary/#drawing-numbers","title":"Drawing Numbers","text":"

    Displaying numerical values on screen.

    Example: Showing digital time values and markers.

    "},{"location":"glossary/#drawing-pixels","title":"Drawing Pixels","text":"

    Setting individual display points for custom graphics.

    Example: Creating fine details in watch face designs.

    "},{"location":"glossary/#drawing-polygons","title":"Drawing Polygons","text":"

    Creating shapes with multiple straight sides.

    Example: Making custom hour markers and decorative elements.

    "},{"location":"glossary/#drawing-rectangles","title":"Drawing Rectangles","text":"

    Creating four-sided shapes with right angles.

    Example: Drawing display borders and menu backgrounds.

    "},{"location":"glossary/#drawing-text","title":"Drawing Text","text":"

    Displaying characters and strings on screen.

    Example: Showing time, date, and menu options.

    "},{"location":"glossary/#drawing-tick-marks","title":"Drawing Tick Marks","text":"

    Creating small indicators around a clock face.

    Example: Marking hours and minutes on an analog display.

    "},{"location":"glossary/#external-sensors","title":"External Sensors","text":"

    Additional hardware components that measure environmental conditions.

    Example: Reading temperature and humidity for weather display.

    "},{"location":"glossary/#time-module","title":"Time Module","text":"

    MicroPython library for handling time-related operations.

    Example: Using scheduling functions for regular updates.

    "},{"location":"glossary/#time-synchronization","title":"Time Synchronization","text":"

    Process of updating device time from an accurate external source.

    Example: Getting current time from network time servers.

    "},{"location":"glossary/#wake-on-alarm","title":"Wake on Alarm","text":"

    Feature that activates the device from sleep mode at specific times.

    Example: Waking the display for scheduled notifications.

    "},{"location":"glossary/#weather-updates_2","title":"Weather Updates","text":"

    Real-time environmental data obtained through internet services.

    Example: Displaying current conditions alongside time.

    "},{"location":"references/","title":"References","text":"
    1. watchmaker - custom watch faces
    2. Makerfabs GC9A01 1.28 Inch Round LCD Module
    3. Dronebotworkshop Using GC9A01 Round LCD Modules
    4. DroneBot Workshop YouTube Video
    5. Mr. Volt YouTube Exotic Round Displays and How to Use Them - this videos demonstrates some very new round displays up to 5 inches. These would be ideal for robot faces but they cost up to $200 for the larger displays.
    6. NTP Pool Project - sites that run the network time protocol
    7. Pico Displays and Fonts
    8. Analog Clock Face Generator - a wonderful way to try out different designs. This web app allows you to change the format of the markers, digits and hands.
    9. Blocklayer Clock Face
    10. Mick Make's YouTube Video: Build a talking Alarm Clock synced to Google calendars - great example of how to use the Google API to access your personal calendar.
    "},{"location":"references/#inspirational-electronic-clocks","title":"Inspirational Electronic Clocks","text":"

    \"The Clock\" using 1,916 parts by Gislain Benoit

    Divoom Times Gate Clock - Five 128x128 color LCD displays.

    ClocTech Tube Shaped Nixie Clock available for $49 at WalMart. This clock shines an LED into a Plexiglass plate to give the appearance of a 3D Nixie Tube.

    "},{"location":"kits/","title":"Introduction to Clock and Watch Kits","text":""},{"location":"kits/#standard-oled","title":"Standard OLED","text":""},{"location":"kits/#raspberry-pi-and-monchorme-oled","title":"Raspberry Pi and Monchorme OLED","text":""},{"location":"kits/#raspberry-pi-w-and-monchorme-oled","title":"Raspberry Pi W and Monchorme OLED","text":""},{"location":"kits/#lilygo-rp240","title":"LilyGo RP240","text":""},{"location":"kits/e-ink/","title":"E-Ink Displays","text":"

    Prompt

    Please suggest a low-cost e-ink display that has strong support for a microPython driver.

    ChatGPT

    Thought about e-ink display and MicroPython for 5 seconds

    If you're looking for a budget-friendly e-ink module that's well-documented and easy to use in MicroPython projects, a great place to start is with the smaller Waveshare e-Paper displays. Specifically, the Waveshare 1.54-inch e-Paper module is often cited for its low cost and good MicroPython support. Here are some details:

    "},{"location":"kits/e-ink/#chatgpt-response","title":"ChatGPT Response","text":"

    1) Waveshare 1.54-inch e-Paper Module

    Why it's a good pick

    • Affordability: Often in the \\(15--\\)25 range, depending on where you purchase.
    • MicroPython libraries: Strong community support and official Waveshare repositories on GitHub. There are also third-party MicroPython drivers floating around that make it easier to integrate.
    • Multiple variants: You can find \"red/black/white\" or \"black/white\" only variants. The simpler (black/white) ones tend to be cheaper.
    • Low power consumption: Typical for e-ink, so it's great for battery-powered projects.

    Where to find drivers

    • Waveshare's official GitHub has examples in C, Arduino, and sometimes MicroPython.
    • Look for community forks or repos titled similarly to micropython-waveshare-epaper (there are a few) for more up-to-date drivers.

    Key specs

    • Resolution: ~200 \u00d7 200 pixels (for the 1.54\" black/white version)
    • Interfaces: SPI, typically 3.3 V (works well with ESP8266, ESP32, etc.)
    • Refresh time: ~2 seconds for a full refresh; partial refresh also possible on some models.
    "},{"location":"kits/e-ink/#2-waveshare-213-inch-e-paper-slightly-larger-option","title":"2) Waveshare 2.13-inch e-Paper (Slightly Larger Option)","text":"

    If you need a bit more display real estate, the 2.13-inch Waveshare e-Paper module is another solid choice. It's still relatively low cost (somewhere around \\(25--\\)30) but gives you higher resolution (around 250 \u00d7 122 or 212 \u00d7 104, depending on the version) for more text or small graphics.

    • Strong MicroPython support (similarly to the 1.54-inch).
    • Typically uses the same library approach from Waveshare, so upgrading the size is straightforward.
    "},{"location":"kits/e-ink/#3-lilygo-t5-series-all-in-one-board","title":"3) LilyGo T5 Series (All-in-One Board)","text":"

    Another cost-effective route (if you don't mind an all-in-one solution rather than a separate module) is the LilyGo T5 board series. These boards come with an ESP32 already integrated and a small e-ink display (like 1.54\", 2.13\", 2.7\", 4.7\" versions).

    • Pros:
      • ESP32 + e-ink combined in one board
      • Some have built-in battery circuitry
      • Often includes MicroPython support or ready-to-flash firmware
    • Cons:
      • Slightly more expensive than just a raw display
      • Tied to LilyGo's board layout and pins

    If you already have a microcontroller board and want to keep costs low, a stand-alone Waveshare display will likely be cheaper. However, if you're starting from scratch, the LilyGo T5 might save you some setup time (fewer wiring hassles, etc.).

    "},{"location":"kits/e-ink/#summary","title":"Summary","text":"
    • Best Overall Low-Cost: Waveshare 1.54-inch e-Paper module. It's consistently among the cheapest e-ink modules, with decent resolution for text/graphics and ample MicroPython support from both the official Waveshare examples and the community.

    • Slightly Larger Screen: Waveshare 2.13-inch e-Paper offers more room but at a slightly higher price.

    • All-in-One Alternative: LilyGo T5 boards combine an ESP32 and e-ink, and often come with MicroPython pre-installed or easily flashed.

    All of these displays have active communities, plenty of tutorials, and code examples you can adapt for MicroPython, making them a great fit if you're just getting started with e-ink in your microcontroller projects.

    o1

    "},{"location":"kits/gc9a01/","title":"GC9A01 Display","text":"

    The gc9a01 is a chip that drives a 240x240 round display that is connected to a microcontroller by an SPI display.

    The current gc9a01 drivers are not compatable with the current release of framebuf in the standard MicroPython runtime. Therefore the standard framebuf functions such as ellipse() and poly() functions do not work. This limits the portability of many of or clock and watch example.

    The good news is that you can do some drawing operations faster and your code does not have to run the show() command. Functions such as line() will draw directly to the display.

    To connect we need to either use a firmware version or load the driver into the /lib directory and we can then use the following code:

    from machine import Pin, SPI\nimport gc9a01 as gc9a01\n\n# hardware config\nSCL_PIN = 2\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\nRST_PIN = 6\nspi = SPI(0, baudrate=60000000, sck=Pin(SCL_PIN), mosi=Pin(SDA_PIN))\n\n# initialize the display\ntft = gc9a01.GC9A01(\n    spi,\n    dc=Pin(DC_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT),\n    reset=Pin(RST_PIN, Pin.OUT),\n    rotation=0)\n\ntft.fill(gc9a01.BLACK)\n\n# x, y, width, height\n# red\ntft.fill_rect(50,  75, 50, 60, gc9a01.color565(255,0,0))\n# green\ntft.fill_rect(100, 75, 50, 60, gc9a01.color565(0,255,0))\n# blue\ntft.fill_rect(150, 75, 50, 60, gc9a01.color565(0,0,255))\n
    "},{"location":"kits/gc9a01/#rotation","title":"Rotation","text":"

    The driver supports 8 different types of rotations:

    • 0 - PORTRAIT
    • 1 - LANDSCAPE
    • 2 - INVERTED PORTRAIT
    • 3 - INVERTED LANDSCAPE
    • 4 - PORTRAIT MIRRORED
    • 5 - LANDSCAPE MIRRORED
    • 6 - INVERTED PORTRAIT MIRRORED
    • 7 - INVERTED LANDSCAPE MIRRORED

    In our labs we have the connector at the bottom so we use the Portrait rotation of 0 which is the default rotation.

    "},{"location":"kits/gc9a01/#references","title":"References","text":"
    1. Russ Hughes - Russ provides firmware images that you can use for both the Pico and Pico W.
      1. Raspberry Pi Pico
      2. Raspberry Pi Pico W
    "},{"location":"kits/gc9a01/01-hello-world/","title":"Hello World Test","text":"

    We begin by carefully setting up the 7 wires that connect from the gc9a01 graphics controller to the breadboard that we have our Raspberry Pi Pico W connected.

    # 01-hello-world-firmware.py\n# \nfrom machine import Pin, SPI\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\ntft.init()\ntft.fill(0) # fill the screen with black\ntft.text(font, \"Hello world!\", 20, 100, gc9a01.color565(255,0,0), gc9a01.color565(0,0,255))\n
    "},{"location":"kits/gc9a01/02-display-time/","title":"Display Time and Date","text":"

    Here is a program that will display the time and date including the day-of-the-week and the name of the month.

    We use the ``localtime()``` function to get the current time in an array of integers that looks like this:

    (2023, 9, 30, 13, 18, 9, 5, 273)\n

    The fields are:

    1. Year
    2. Month
    3. Day of Month
    4. Hour in 24-hour format
    5. Minutes
    6. Seconds
    7. Day of Week (Monday = 0, Sunday = 6)
    8. Day of the Year

    We could convert each of these numbers to strings and display them. However, most people like to do a bit of formatting such as displaing a 12-hour am/pm format and returning the name of the month and day of the week. Here is the complete progam with the formatting.

    # 02-display-time.py\n# \nfrom machine import Pin, SPI\nfrom utime import sleep, localtime\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\ntft.init()\ntft.fill(0) # fill the screen with black\n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\n# I limit the month names to 5 characters max\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\ndef format_time(now):\n    hour_number = now[3]\n    if hour_number < 13:\n        hour_12 = hour_number\n        am_pm = 'am'\n    else:\n        hour_12 = hour_number - 12\n        am_pm = 'pm'\n    minutes_num = now[4]\n    if minutes_num < 10:\n        min_leading_zero = '0'\n    else:\n        min_leading_zero = ''\n    seconds_num = now[5]\n    if seconds_num < 10:\n        sec_leading_zero = '0'\n    else:\n        sec_leading_zero = ''\n    return \"{}:{}{}:{}{} {}\".format(hour_12, min_leading_zero, minutes_num, sec_leading_zero, seconds_num, am_pm)\n\ndef day_of_week(now):\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    return day_name\n\ndef format_date(now):\n    month_number = now[1]\n    month_name = months[month_number - 1]\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    hour_number = now[3]\n    return \"{} {}, {}\".format(month_name, now[2], now[0])\n\ntft.fill(0) # erase the screen to black\nwhite = gc9a01.color565(255, 255, 255)\nwhile(True):\n    # get the time from the local real-time clock\n    now = localtime()\n    print(now)    \n    tft.text(font, format_time(now), 35, 50, white)\n    tft.text(font, day_of_week(now), 50, 80, white)\n    tft.text(font, format_date(now), 5, 110, white)\n    #tft.show()\n    sleep(1)\n
    "},{"location":"kits/gc9a01/03-display-hand/","title":"Display Second Hand","text":"

    In this lesson we will use a bit of trigonometry to display a second hand that ticks every second.

    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nHAND_LENGTH = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nwhite = gc9a01.color565(255, 255, 255)\n\nwhile True:\n    radians = (counter/60)*TWO_PI\n    x = int(math.sin(radians)*HAND_LENGTH)\n    y = -int(math.cos(radians)*HAND_LENGTH)\n    print(radians, x, y)\n    tft.fill(0)\n    tft.line(CENTER, CENTER, CENTER+x,CENTER+y, white)\n    sleep(1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0\n
    "},{"location":"kits/gc9a01/04-cycle-fonts/","title":"Cycle Through the Builtin Fonts","text":"

    This program will cycle through the built-in fonts showing greetings in different fonts, langauges and colors.

    # Adapted from the hersey.py program\nfrom machine import Pin, SPI\nfrom utime import sleep, localtime\nimport random\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0)\n\n# Load several frozen fonts from flash\n\nimport greeks\nimport italicc\nimport italiccs\nimport meteo\nimport romanc\nimport romancs\nimport romand\nimport romanp\nimport romans\nimport scriptc\nimport scripts\n\n\ndef cycle(p):\n    '''\n    return the next item in a list\n    '''\n    try:\n        len(p)\n    except TypeError:\n        cache = []\n        for i in p:\n            yield i\n            cache.append(i)\n        p = cache\n    while p:\n        yield from p\n\n\nCOLORS = cycle([0xe000, 0xece0, 0xe7e0, 0x5e0, 0x00d3, 0x7030])\n\nFONTS = cycle([\n    greeks, italicc, italiccs, meteo, romanc, romancs,\n    romand, romanp, romans, scriptc, scripts])\n\nGREETINGS = cycle([\n    \"bonjour\", \"buenas noches\", \"buenos dias\",\n    \"good day\", \"good morning\", \"hey\",\n    \"hi-ya\", \"hi\", \"how are you\", \"how goes it\",\n    \"howdy-do\", \"howdy\", \"shalom\", \"welcome\",\n    \"what's happening\", \"what's up\"])\n\ntft.init()\nrow = 120\n\nwhile True:\n    color = next(COLORS)\n    tft.fill(gc9a01.BLACK)\n    tft.draw(next(FONTS), next(GREETINGS), 0, row, color)\n    sleep(0.5)\n
    "},{"location":"kits/gc9a01/04-cycle-fonts/#references","title":"References","text":"
    1. Russ Hughes Example
    "},{"location":"kits/gc9a01/05-draw-ticks/","title":"Draw Clock Face Ticks","text":"

    This program draws 12 short white radial lines around a watch face.

    We use the same math we used to draw a single hand. However, in this example we just need to iterate through a range of 0 to 12.

    for i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, WHITE)\n

    Instead of just drawing from the center to a point at (x,y), we need to calculate four numbers. These are the start and ending points of each tick.

    "},{"location":"kits/gc9a01/05-draw-ticks/#full-program","title":"Full Program","text":"
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nTICK_START = 80\nTICK_END = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nWHITE = gc9a01.color565(255, 255, 255)\nBLACK = gc9a01.color565(0, 0, 0)\ntft.fill(BLACK)\nfor i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    print(i, radians, x1, y1, x2, y2)  \n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, WHITE)\n
    "},{"location":"kits/gc9a01/07-draw-12-digits/","title":"Draw Clock Dial Digits","text":"

    This program builds on the previous progam that draws the ticks. It also draws a ditit at the end of each tick.

    We use the same math we used to draw a single hand. However, in this example we just need to iterate through a range of 0 to 12.

    We have to remember to load our 16x32 fonts. Although this is a bit large for most watch faces, they are easy to read.

    Here is the line we added:

    import vga1_bold_16x32 as font\n

    Note that there are other sizes we can use. A list of the other fonts is here:

    GitHub Site for Russ Hughes for GC9a01 bitmap fonts

    These fonts include the following sizes:

    1. 8x8
    2. 8x16
    3. 16x16
    4. 16x32

    Here is the appropriate line for the normal 16x16:

    import vga1_16x16 as font\n

    if i == 0:\n    num_str = \"12\"\nelse:\n    num_str = str(i)\ntft.text(font, num_str, CENTER+x3-8, CENTER+y3-16, WHITE)\n
    Note because the fonts are 16 wide and 32 high we move 8 to the left and 16 up.

    "},{"location":"kits/gc9a01/07-draw-12-digits/#full-program","title":"Full Program","text":"
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nTICK_START = 50\nTICK_END = 80\nNUM_POS = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nWHITE = gc9a01.color565(255, 255, 255)\nBLACK = gc9a01.color565(0, 0, 0)\nBLUE = gc9a01.color565(0, 0, 255)\ntft.fill(BLACK)\nfor i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    x3 = int(math.sin(radians)*NUM_POS)\n    y3 = -int(math.cos(radians)*NUM_POS)\n    print(i, radians, x1, y1, x2, y2)  \n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, BLUE)\n    if i == 0:\n        num_str = \"12\"\n    else:\n        num_str = str(i)\n    tft.text(font, num_str, CENTER+x3-8, CENTER+y3-16, WHITE)\n

    If you use the 16x16 font the offset in the last line are:

        if i == 0:\n        num_str = \"12\"\n        xOffest = 16\n    else:\n        num_str = str(i)\n        xOffest = 8\n    tft.text(font, num_str, CENTER+x3-xOffest, CENTER+y3-8, WHITE)\n

    The exception is for the \"12\" at the top of the dial. The \"12\" needed to be exactly centered above the top tick mark.

    "},{"location":"kits/gc9a01/07-draw-12-digits/#full-code-for-16x16-clock-face-digits","title":"Full Code for 16x16 Clock Face Digits","text":"
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\nimport vga1_16x16 as font\n\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nTICK_START = 70\nTICK_END = 100\nNUM_POS = 111\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nWHITE = gc9a01.color565(255, 255, 255)\nBLACK = gc9a01.color565(0, 0, 0)\nBLUE = gc9a01.color565(0, 0, 255)\ntft.fill(BLACK)\nfor i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    x3 = int(math.sin(radians)*NUM_POS)\n    y3 = -int(math.cos(radians)*NUM_POS)\n    print(i, radians, x1, y1, x2, y2)  \n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, BLUE)\n    if i == 0:\n        num_str = \"12\"\n        xOffest = 16\n    else:\n        num_str = str(i)\n        xOffest = 8\n    tft.text(font, num_str, CENTER+x3-xOffest, CENTER+y3-8, WHITE)\n
    "},{"location":"kits/gc9a01/08-draw-filled-triangle/","title":"Draw a Filled Triangle","text":"

    Analog clock hands can be draw with simple lines. But the display will be more pleasing if we use clock hands that are made of triangles.

    If the framebuf functions were supported in the driver drawing a filled triangle would be easy. We would just put the three points in an array and call the poly() with a fill option.

    However, the current driver does not support the framebuf functions. To overcome this limiation we will need to write our own function that will fill all the points in a triangle.

    Our founction must take in the three points and a color and draw the traingle.

    "},{"location":"kits/gc9a01/08-draw-filled-triangle/#draw-filled-triangle","title":"Draw Filled Triangle","text":"

    Without going into too much detail, here is the algorithm we will use dto draw a filled triangle. Note that only the last line does drawing using the line() function. You will note that it must get the points in order before the main loops run. This version also checks for divide by zero errors.

    def drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n\n    # get our points in order\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n\n        for x in range(xa, xb+1):\n            # sleep(.1)\n            tft.line(x, y, x, y, color)\n
    "},{"location":"kits/gc9a01/08-draw-filled-triangle/#full-test-program","title":"Full Test Program","text":"

    To test our alforithm we can genrate three random points near the center of the display and then call the traingle fill on these points. If you would like to see how the algorithm does the drawing, you can uncomment the sleep function just before the tft.line() above.

    # 01-display-test.py\n# \nfrom machine import Pin, SPI\nimport random\nimport gc9a01\nimport vga1_16x16 as font\nfrom utime import sleep\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\nWHITE = gc9a01.color565(255,255,255)\nBLUE = gc9a01.color565(0,0,255)\nBLACK = gc9a01.color565(0,0,0)\n\ntft.init()\ntft.fill(0) # fill the screen with black\ntft.text(font, \"Draw Filled Triangle Test\", 20, 10, BLUE, BLACK)\n\n\n\ndef drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n\n        for x in range(xa, xb+1):\n            tft.line(x, y, x, y, color)\n\n\nmin = 50\nmax = 150\nwhile True:\n    tft.fill(BLACK)\n    x1 = random.randint(min, max)\n    y1 = random.randint(min, max)\n    x2 = random.randint(min, max)\n    y2 = random.randint(min, max)\n    x3 = random.randint(min, max)\n    y3 = random.randint(min, max)\n    drawFilledTriangle(x1, y1, x2, y2, x3, y3, WHITE)\n    sleep(.1)\n
    "},{"location":"kits/gc9a01/08-draw-filled-triangle/#crazy-triangles","title":"Crazy Triangles","text":"
    # lab 15: Filled Triangles\n# \nfrom machine import Pin, SPI\nimport random\nimport gc9a01\nimport vga1_16x16 as font\nfrom utime import sleep\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\nWHITE = gc9a01.color565(255,255,255)\nBLUE = gc9a01.color565(0,0,255)\nBLACK = gc9a01.color565(0,0,0)\n\ntft.init()\ntft.fill(0) # fill the screen with black\ntft.text(font, \"Triangles\", 57, 22, BLUE, BLACK)\n\ndef drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n\n        for x in range(xa, xb+1):\n            # for wathing the drawing\n            # sleep(.001)\n            tft.line(x, y, x, y, color)\n\nmin = 40\nmax = 220\nwhile True:\n    # tft.fill(BLACK)\n    x1 = random.randint(min, max)\n    y1 = random.randint(min, max)\n    x2 = random.randint(min, max)\n    y2 = random.randint(min, max)\n    x3 = random.randint(min, max)\n    y3 = random.randint(min, max)\n    red = random.randint(0, 255)\n    green = random.randint(0, 255)\n    blue = random.randint(0, 255)\n    color = gc9a01.color565(red,green,blue)\n    drawFilledTriangle(x1, y1, x2, y2, x3, y3, color)\n    # slow down the drawing here\n    sleep(.1)\n
    "},{"location":"kits/gc9a01/09-watch-face/","title":"Watch Face","text":"
    1. Ticks
    2. Second hand
    3. Minute hand
    4. Hour hand
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n# A full circle is 2*Pi radians\nTWO_PI = 3.1415926*2\nWHITE = gc9a01.color565(255, 255, 255)\nBLUE = gc9a01.color565(0, 0, 255)\nGREEN = gc9a01.color565(0, 255, 0)\nPURPLE = gc9a01.color565(255, 0, 255)\nBLACK = gc9a01.color565(0, 0, 0)\ntft.fill(BLACK)\nCENTER = 120\nMIN_TICK_START = 80\nMIN_TICK_END = 98\nSEC_TICK_START = 100\nSEC_TICK_END = 120\n\ndef drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n        for x in range(xa, xb+1):\n            tft.line(x, y, x, y, color)\n\ndef drawTicks():\n    for i in range(0,60):\n        radians = (i/60)*TWO_PI\n        x1 = int(math.sin(radians)*SEC_TICK_START)\n        y1 = -int(math.cos(radians)*SEC_TICK_START)\n        x2 = int(math.sin(radians)*SEC_TICK_END)\n        y2 = -int(math.cos(radians)*SEC_TICK_END)\n        # print(i, radians, x1, y1, x2, y2)  \n        tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, BLUE)\n\n    for i in range(0,12):\n        radians = (i/12)*TWO_PI\n        x1 = int(math.sin(radians)*MIN_TICK_START)\n        y1 = -int(math.cos(radians)*MIN_TICK_START)\n        x2 = int(math.sin(radians)*MIN_TICK_END)\n        y2 = -int(math.cos(radians)*MIN_TICK_END)\n        # print(i, radians, x1, y1, x2, y2)  \n        tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, GREEN)\n\nCENTER = 120\nSEC_HAND_LENGTH = 118\ndef drawSecondHand(sec):\n    # print('sec=', sec)\n    if sec ==0:\n        radians = 0\n    else: radians = (sec/60)*TWO_PI\n    x = int(math.sin(radians)*SEC_HAND_LENGTH)\n    y = -int(math.cos(radians)*SEC_HAND_LENGTH)\n    # print(radians, x, y)\n    tft.line(CENTER, CENTER, CENTER+x,CENTER+y, WHITE)\n    sleep(.1)\n    tft.line(CENTER, CENTER, CENTER+x,CENTER+y, BLACK)\n\n\nMIN_HAND_LENGTH = 90\nMIN_HAND_WIDTH = 5\ndef drawMinuteHand(min, color):\n    radians = (min/60)*TWO_PI\n    x1 = -int(math.cos(radians)*MIN_HAND_WIDTH)\n    y1 = -int(math.sin(radians)*MIN_HAND_WIDTH)\n    x2 = int(math.sin(radians)*MIN_HAND_LENGTH)\n    y2 = -int(math.cos(radians)*MIN_HAND_LENGTH)\n    x3 = int(math.cos(radians)*MIN_HAND_WIDTH)\n    y3 = int(math.sin(radians)*MIN_HAND_WIDTH)\n    # print('min:', x1, y1, x2, y2, x3, y3)\n    drawFilledTriangle(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, CENTER+x3, CENTER+y3, color)\n\nHOUR_HAND_LENGTH = 60\nHOUR_HAND_WIDTH = 6\ndef drawHourHand(hour, color):\n    radians = (hour/12)*TWO_PI\n    x1 = -int(math.cos(radians)*HOUR_HAND_WIDTH)\n    y1 = -int(math.sin(radians)*HOUR_HAND_WIDTH)\n    x2 = int(math.sin(radians)*HOUR_HAND_LENGTH)\n    y2 = -int(math.cos(radians)*HOUR_HAND_LENGTH)\n    x3 = int(math.cos(radians)*HOUR_HAND_WIDTH)\n    y3 = int(math.sin(radians)*HOUR_HAND_WIDTH)\n    # print('hour:', x1, y1, x2, y2, x3, y3)\n    drawFilledTriangle(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, CENTER+x3, CENTER+y3, color)\n\ncounter = 0\nmin = 58\nhour = 6\ndrawMinuteHand(min, GREEN)\ndrawHourHand(hour, PURPLE)\nhour = 6\nwhile True:\n    # this is the flicker\n    # tft.fill(BLACK)\n    drawTicks()\n\n    drawSecondHand(counter)\n    # if we are at 60 we start over\n    if counter > 59:\n        drawMinuteHand(min, BLACK)\n        counter = 0\n        min += 1\n        drawMinuteHand(min, GREEN)\n        if min > 59:\n            min=0\n            drawHourHand(hour, BLACK)\n            hour += 1\n            drawHourHand(hour, PURPLE)\n            if hour > 11:\n                hour = 0\n    counter += 1\n    # sleep(.5)\n
    "},{"location":"kits/ili9341/","title":"ILI9341 Display","text":"

    The ILI9341 is a low-cost color single-chip driver for a TFT liquid crystal display with a resolution of 240x320.

    The board for the ILI9341 with a display costs around $9.00. Although these displays are not a high contrast as OLED displays, they are still adequate for many clock projects that would like to draw smooth circles on a clock face.

    "},{"location":"kits/ili9341/#driver","title":"Driver","text":"

    dagger GitHub Repo

    "},{"location":"kits/ili9341/#characteristics","title":"Characteristics","text":"

    Direct write No support for standard micropython framebuf

    "},{"location":"kits/ili9341/#sample-lesson-plan","title":"Sample Lesson Plan","text":"

    GPT-4 Generated Lesson Plan

    "},{"location":"kits/ili9341/#source-code","title":"Source Code","text":"

    Source Code

    "},{"location":"kits/ili9341/01-rainbow-test/","title":"Rainbow Test","text":"
    from ili9341 import Display, color565\nfrom machine import Pin, SPI\n\n# Use these PIN definitions.  SCK must be on 2 and data (SDL) on 3 for SPI bus 0\nSCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\n\nspi = SPI(0, baudrate=40000000, sck=Pin(SCK_PIN), mosi=Pin(MISO_PIN))\ndisplay = Display(spi, dc=Pin(DC_PIN), cs=Pin(CS_PIN), rst=Pin(RESET_PIN), width=WIDTH, height=HEIGHT, rotation=ROTATION)\n\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nPURPLE = color565(255,0,255)\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\n\ndisplay.fill_rectangle(0,0, 50,HEIGHT, RED)\ndisplay.fill_rectangle(50,0, 50,HEIGHT, ORANGE)\ndisplay.fill_rectangle(100,0, 50,HEIGHT, YELLOW)\ndisplay.fill_rectangle(150,0, 50,HEIGHT, GREEN)\ndisplay.fill_rectangle(200,0, 50,HEIGHT, BLUE)\ndisplay.fill_rectangle(250,0, 50,HEIGHT, PURPLE)\ndisplay.fill_rectangle(300,0, 20,HEIGHT, WHITE)\n\nprint('Done')\n
    "},{"location":"kits/ili9341/01-rainbow-test/#color-definitions","title":"Color Definitions","text":"

    We can also use this same process for storing all of the common constants that we duplicate in our examples. For example all the named color defintions can be moved into a serate color-defs.py file like this:

    Sample colors.py

    from ili9341 import color565\n\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nCYAN = color565(0,255,255)\nPURPLE = color565(255,0,255)\n

    This sample program imports both the config and the colors file:

    from ili9341 import Display, color565\nfrom machine import Pin, SPI\nimport config\nimport colors\n\n# Use these PIN definitions.  SCK must be on 2 and data (SDL) on 3\nSCK_PIN = config.SCK_PIN\nMISO_PIN = config.MISO_PIN # labeled SDI(MOSI) on the back of the display\nDC_PIN = config.DC_PIN\nRESET_PIN = config.RESET_PIN\nCS_PIN = config.CS_PIN\n\nWIDTH=config.WIDTH\nHEIGHT=config.HEIGHT\nROTATION=config.ROTATION\n\n# mosi=Pin(23)\n# miso=Pin(MISO_PIN)\nspi = SPI(0, baudrate=40000000, sck=Pin(SCK_PIN), mosi=Pin(MISO_PIN))\ndisplay = Display(spi, dc=Pin(DC_PIN), cs=Pin(CS_PIN), rst=Pin(RESET_PIN), width=WIDTH, height=HEIGHT, rotation=ROTATION)\n\ndisplay.fill_rectangle(0,0, 50,HEIGHT, colors.RED)\ndisplay.fill_rectangle(50,0, 50,HEIGHT, colors.ORANGE)\ndisplay.fill_rectangle(100,0, 50,HEIGHT, colors.YELLOW)\ndisplay.fill_rectangle(150,0, 50,HEIGHT, colors.GREEN)\ndisplay.fill_rectangle(200,0, 50,HEIGHT, colors.BLUE)\ndisplay.fill_rectangle(250,0, 50,HEIGHT, colors.PURPLE)\ndisplay.fill_rectangle(300,0, 20,HEIGHT, colors.WHITE)\n\nprint('Done')\n

    Note that the string colors. must appear before each color name. You can shorten this to be just c. if you want to keep your code smaller and easier to read.

    "},{"location":"kits/ili9341/01-rainbow-test/#hiding-hardware-initialization","title":"Hiding Hardware Initialization","text":"

    We could take this one step further and put the lines that setup the SPI and the Display into a separate function. However, in our labs we want to keep some of this code explicit so we will leave the SPI and Display initialization in our examples.

    "},{"location":"kits/ili9341/02-config/","title":"Creating a Hardware Configuration File","text":"

    Rather than hard-coding the pin numbers in every example, let's put all our hardware configuration data in a single file. All the examples from here on can use that configuration data.

    "},{"location":"kits/ili9341/02-config/#hardware-configuration-file","title":"Hardware Configuration File","text":"
    # Dan's Robot Labs configuration file for ILI9341 clock project\n# The colors on the SPI bus cable are:\n# 3.3v power - red\n# SCK - orange\n# MISO/Data - yellow\n# DC - green\n# RESET - blue\n# GND - black\n# CS - purple\nSCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\n
    "},{"location":"kits/ili9341/02-config/#sample-use-of-haredwre-configuration-file","title":"Sample Use of Haredwre Configuration File","text":"
    # print out \"Hello World!\" using the rotation=3 using 32-bit high font\n# the default is white text on a black background\nfrom ili9341 import Display, color565\nfrom machine import Pin, SPI\nimport config\n\n# Use these PIN definitions.  SCK must be on 2 and data (SDL) on 3\nSCK_PIN = config.SCK_PIN\nMISO_PIN = config.MISO_PIN # labeled SDI(MOSI) on the back of the display\nDC_PIN = config.DC_PIN\nRESET_PIN = config.RESET_PIN\nCS_PIN = config.CS_PIN\n\nWIDTH=config.WIDTH\nHEIGHT=config.HEIGHT\nROTATION=config.ROTATION\n\n# mosi=Pin(23)\n# miso=Pin(MISO_PIN)\nspi = SPI(0, baudrate=40000000, sck=Pin(SCK_PIN), mosi=Pin(MISO_PIN))\ndisplay = Display(spi, dc=Pin(DC_PIN), cs=Pin(CS_PIN), rst=Pin(RESET_PIN), width=WIDTH, height=HEIGHT, rotation=ROTATION)\n\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nPURPLE = color565(255,0,255)\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\n\ndisplay.fill_rectangle(0,0, 50,HEIGHT, RED)\ndisplay.fill_rectangle(50,0, 50,HEIGHT, ORANGE)\ndisplay.fill_rectangle(100,0, 50,HEIGHT, YELLOW)\ndisplay.fill_rectangle(150,0, 50,HEIGHT, GREEN)\ndisplay.fill_rectangle(200,0, 50,HEIGHT, BLUE)\ndisplay.fill_rectangle(250,0, 50,HEIGHT, PURPLE)\ndisplay.fill_rectangle(300,0, 20,HEIGHT, WHITE)\n\nprint('Done')\n
    "},{"location":"kits/led-displays/","title":"LED Display Clock","text":""},{"location":"kits/led-displays/#simple-tm1637","title":"Simple TM1637","text":"

    Simple TM1637

    "},{"location":"kits/led-displays/#shift-register-displays","title":"Shift Register Displays","text":"

    Shift Register Displays

    We can use the TM1637 4-Digit LED Display Module which can be purchased on e-Bay for a few dollars. This means that your clock will cost under $10 total.

    Sample Listing on EBay

    "},{"location":"kits/led-displays/#hookup-instructions","title":"Hookup Instructions","text":"

    We can hook this up to the Raspberry Pi.

    |Name|Pin|| |5 Volts|VBUS or VSYS| |GND|Any GND Pin| |CLK|Pins 4| |Data|Pin 5 |

    "},{"location":"kits/led-displays/#micropython-driver","title":"MicroPython Driver","text":"

    Mike Causer's TM1637 GitHub Driver

    "},{"location":"kits/led-displays/#sample-code","title":"Sample Code","text":""},{"location":"kits/led-displays/#python-imports","title":"Python Imports","text":"
    import tm1637\nfrom machine import Pin\nfrom utime import sleep\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n
    "},{"location":"kits/led-displays/#test-program","title":"Test Program","text":"
    import tm1637\nfrom machine import Pin\nfrom utime import sleep\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n\nwhile True:\n    # all LEDS on \"88:88\"\n    tm.write([127, 255, 127, 127])\n    sleep(1)\n\n    # all LEDS off\n    tm.write([0, 0, 0, 0])\n    sleep(1)\n\n    # show \"0123\"\n    tm.write([63, 6, 91, 79])\n    sleep(1)\n\n    # show \"COOL\"\n    tm.write([0b00111001, 0b00111111, 0b00111111, 0b00111000])\n    sleep(1)\n\n    # show \"HELP\"\n    tm.show('help')\n    sleep(1)\n\n    # display \"dEAd\", \"bEEF\"\n    tm.hex(0xdead)\n    sleep(1)\n\n    tm.hex(0xbeef)\n    sleep(1)\n\n    # show \"12:59\"\n    tm.numbers(12, 59)\n    sleep(1)\n\n    # show \"-123\"\n    tm.number(-123)\n    sleep(1)\n\n    # show temperature '24*C'\n    tm.temperature(24)\n    sleep(1)\n

    Next, will will use the localtime() function to build a simple clock.

    Simple Clock

    "},{"location":"kits/led-displays/#references","title":"References","text":"
    • Mike Causer TM1637 Driver GitHub Repo
    • YouTube Video by NerdCave
    "},{"location":"kits/led-displays/clock-simple/","title":"A Simple Clock with the TM1637 LED Display","text":"

    Here is a simple clock program that will display the hours and minutes from the localtime() function. It will also turn the colon LEDs on and off every second using the modulo function to test for the even/odd property of the second.

    "},{"location":"kits/led-displays/clock-simple/#the-localtime-function","title":"The Localtime function","text":"
    # display hours and minutes on the TM1637 LED display\n# make the colon go on and off every second\nimport tm1637\nfrom machine import Pin\nfrom utime import sleep, localtime\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n\nwhile True:\n    now = localtime() # returns 8 inits for date and time\n    hours = now[3]\n    minutes = now[4]\n    seconds = now[5]\n    print(hours, \":\", minutes, ' ', seconds)\n    # flash the colon on and off every second\n    if (seconds % 2): # modulo 2 will be true for odd numbers\n        tm.numbers(hours, minutes, True)\n    else:\n        tm.numbers(hours, minutes, False)\n    sleep(1)\n

    That is it! Pretty cool that you can write an entire clock program in that few lines of code. But it is not perfect. Let's find some ways to make the clock work a little better.

    Note that the hours is always in 24 hour time. If you want to use 12 hour time you will need to subtract 12 from the hours if the hours is greater than 12.

    We can add the following lines of code to make the display better for people that use a 12-hour clock.

    if hours > 12:\n    hours = now[3]\n    hours = hours - 12\n

    This will work, but it has the disadvantage of displaying the leading zero before the ones digit. Unfortunately, this is the way that the numbers() function was written in the TM1637 module. Let's take a look at how we can clean this up a bit.

    "},{"location":"kits/led-displays/clock-simple/#removing-leading-zeros","title":"Removing Leading Zeros","text":"

    In order to fix the leading zeros problem in the hours place, we need to write our own version of the numbers() function that changes '0' to be a space (all 7 segments off) if the hours is less than 10.

    Here is the original numbers() function taken directly from the driver:

    def numbers(self, num1, num2, colon=True):\n    \"\"\"Display two numeric values -9 through 99, with leading zeros\n    and separated by a colon.\"\"\"\n    num1 = max(-9, min(num1, 99))\n    num2 = max(-9, min(num2, 99))\n    segments = self.encode_string('{0:0>2d}{1:0>2d}'.format(num1, num2))\n    if colon:\n        segments[1] |= 0x80 # colon on\n    self.write(segments)\n

    You can see that the author used the Python .format function to display the first number using a leading zero. This is fine for our minutes, but not a standard for the hours.

    We will need to modify this code to put in a space character in if the hours is less than 10 and to only display the hours number without a leading zero. The format {0:0>2d} will be changed to be: {prefix}{num1:d} where:

    prefix = ' ' if num1 < 10 else ''\n
    def numbers_nlz(num1, num2, colon=True):\n    \"\"\"Display two numeric values -9 through 99, with a leading space before\n    single-digit first numbers and separated by a colon.\"\"\"\n    num1 = max(-9, min(num1, 99))\n    num2 = max(-9, min(num2, 99))\n    prefix = ' ' if num1 < 10 else ''\n    print(f'\"{prefix}{num1:d}{num2:0>2d}\"')\n    segments = tm.encode_string(f'{prefix}{num1:d}{num2:0>2d}')\n    if colon:\n        segments[1] |= 0x80  # colon on\n    tm.write(segments)\n

    Now the display will work as most normal digital clocks.

    So as long as the localtime() function is working, this clock should work fine. An as long as your device is connected to your computer via an USB cable it will be fine.

    What if you would like your clock to work without being connected to a computer. We have two options:

    1. Used a Raspberry Pi Pico W to get time from a central time service over Wifi
    2. or use a local clock and set the time manually
    "},{"location":"kits/led-displays/reference/","title":"Programming Reference for the TM1637 Clock LED Driver","text":""},{"location":"kits/led-displays/reference/#seven-segment-font","title":"Seven Segment Font","text":"

    They are called 7-segment displays as there are 7 LEDs for each digit (segment). One byte (7 lower bits) for each segment. The 8th bit (MSB) is for the colon and only on the 2nd segment.

          A\n     ---\n  F |   | B   *\n     -G-      H (on 2nd segment)\n  E |   | C   *\n     ---\n      D\n\n  HGFEDCBA\n0b01101101 = 0x6D = 109 = show \"5\"\n
    Display Bin Hex Dec 0 0b00111111 0x3F 63 1 0b00000110 0x06 6 2 0b01011011 0x5B 91 3 0b01001111 0x4F 79 4 0b01100110 0x66 102 5 0b01101101 0x6D 109 6 0b01111101 0x7D 125 7 0b00000111 0x07 7 8 0b01111111 0x7F 127 9 0b01101111 0x6F 111 A 0b01110111 0x77 119 b 0b01111100 0x7C 124 C 0b00111001 0x39 57 d 0b01011110 0x5E 94 E 0b01111001 0x79 121 F 0b01110001 0x71 113 G 0b00111101 0x3D 61 H 0b01110110 0x76 118 I 0b00000110 0x06 6 J 0b00011110 0x1E 30 K 0b01110110 0x76 118 L 0b00111000 0x38 56 M 0b01010101 0x55 85 n 0b01010100 0x54 84 O 0b00111111 0x3F 63 P 0b01110011 0x73 115 q 0b01100111 0x67 103 r 0b01010000 0x50 80 S 0b01101101 0x6D 109 t 0b01111000 0x78 120 U 0b00111110 0x3E 62 v 0b00011100 0x1C 28 W 0b00101010 0x2A 42 X 0b01110110 0x76 118 y 0b01101110 0x6E 110 Z 0b01011011 0x5B 91 blank 0b00000000 0x00 0 - 0b01000000 0x40 64 * 0b01100011 0x63 99"},{"location":"kits/led-displays/reference/#methods","title":"Methods","text":""},{"location":"kits/led-displays/reference/#set-brightneww","title":"Set Brightneww","text":"

    Get or set brightness.

    brightness(val=None)\n

    "},{"location":"kits/led-displays/reference/#write-segments","title":"Write Segments","text":"

    Write one or more segments at a given offset.

    write(segments, pos=0)\n

    "},{"location":"kits/led-displays/reference/#write-two-numbers-and-colon","title":"Write Two Numbers and Colon","text":"

    Write Two Numbers and Colon

    numbers(num1, num2, colon=True):\n
    "},{"location":"kits/led-displays/shift-register-displays/","title":"Shift Register Displays","text":"

    The 74hc595 is a chip that takes a clock and data stream in and turns many LEDs on or off. 74hc595 chips can be connected in series to control 7 segments on 4 digits.

    I'll create a detailed walkthrough of the clock-driver.py program, breaking it down into digestible sections with accompanying labs. This will help students understand both the code and the underlying concepts.

    "},{"location":"kits/led-displays/shift-register-displays/#1-core-components-and-imports","title":"1. Core Components and Imports","text":"
    from machine import Pin, RTC \nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep, localtime, ticks_ms\n

    This section imports the necessary libraries. The program uses: - machine.Pin: Controls individual GPIO pins on the Pico - RTC: Real-Time Clock for keeping time - sr74hc595: Manages the shift register that controls the display - utime: Provides timing functions

    "},{"location":"kits/led-displays/shift-register-displays/#lab-1-understanding-gpio-pins","title":"Lab 1: Understanding GPIO Pins","text":"

    Have students create a simple LED blink program:

    from machine import Pin\nfrom utime import sleep\n\nled = Pin(25, Pin.OUT)  # Built-in LED on Pico\nwhile True:\n    led.value(1)  # Turn on\n    sleep(1)\n    led.value(0)  # Turn off\n    sleep(1)\n
    "},{"location":"kits/led-displays/shift-register-displays/#2-rtc-initialization","title":"2. RTC Initialization","text":"
    def wait_for_rtc():\n    print(\"Waiting for RTC to be ready...\")\n    rtc = RTC()\n    while True:\n        current_time = rtc.datetime()\n        if current_time[0] != 2021 or current_time[1] != 1 or current_time[2] != 1:\n            print(\"RTC is ready!\")\n            return\n        print(\"RTC not ready yet...\")\n        sleep(1)\n

    This function ensures the RTC has been set to a valid time before proceeding.

    "},{"location":"kits/led-displays/shift-register-displays/#lab-2-rtc-basics","title":"Lab 2: RTC Basics","text":"

    Have students experiment with reading and setting the RTC:

    from machine import RTC\nfrom utime import sleep\n\nrtc = RTC()\n# Set the time (year, month, day, weekday, hour, minute, second, subsecond)\nrtc.datetime((2024, 12, 27, 5, 14, 30, 0, 0))\n\nwhile True:\n    current_time = rtc.datetime()\n    print(f\"Current time: {current_time[4]:02d}:{current_time[5]:02d}:{current_time[6]:02d}\")\n    sleep(1)\n
    "},{"location":"kits/led-displays/shift-register-displays/#3-seven-segment-display-setup","title":"3. Seven-Segment Display Setup","text":"

    class FourDigitClock:\n    ALL_OFF = 0xFF  # All segments off (inverted logic)\n\n    def __init__(self, ser_pin, srclk_pin, rclk_pin):\n        self.ser = Pin(ser_pin, Pin.OUT)\n        self.srclk = Pin(srclk_pin, Pin.OUT) \n        self.rclk = Pin(rclk_pin, Pin.OUT)\n
    This class manages the four-digit display. It uses three pins to control the shift register.

    "},{"location":"kits/led-displays/shift-register-displays/#lab-3-seven-segment-pattern-display","title":"Lab 3: Seven-Segment Pattern Display","text":"

    Have students create a simple program to display a single digit:

    from machine import Pin\nfrom utime import sleep\n\n# Create a simple version that lights up segments manually\nsegments = {\n    'a': Pin(2, Pin.OUT),\n    'b': Pin(3, Pin.OUT),\n    'c': Pin(4, Pin.OUT),\n    # ... add more segments\n}\n\ndef display_number(number):\n    # Pattern for number 1\n    if number == 1:\n        segments['b'].value(1)\n        segments['c'].value(1)\n    # Add more numbers...\n

    "},{"location":"kits/led-displays/shift-register-displays/#4-digit-patterns","title":"4. Digit Patterns","text":"

    self.SEGMENTS = {\n    'a': 4, 'b': 3, 'c': 2, \n    'd': 7, 'e': 6, 'f': 5, 'g': 1\n}\nself.DIGIT_SEGMENTS = {\n    0: 'abcdef', 1: 'bc', 2: 'abged', 3: 'abgcd',\n    4: 'fbcg', 5: 'afgcd', 6: 'afedcg', \n    7: 'abc', 8: 'abcdefg', 9: 'abfgcd'\n}\n
    This section defines which segments should be lit for each number.

    "},{"location":"kits/led-displays/shift-register-displays/#lab-4-pattern-design","title":"Lab 4: Pattern Design","text":"

    Have students draw and design their own custom characters using the seven segments. They can create: - Letters (A, b, C, d, E, F) - Custom symbols - Animated patterns

    "},{"location":"kits/led-displays/shift-register-displays/#5-time-display-logic","title":"5. Time Display Logic","text":"
    def display_time(self, hour, minute, colon_state):\n    # Convert to 12-hour format\n    if hour > 12:\n        hour -= 12\n    elif hour == 0:  \n        hour = 12\n
    "},{"location":"kits/led-displays/shift-register-displays/#lab-5-time-format-conversion","title":"Lab 5: Time Format Conversion","text":"

    Have students write a program that converts between 24-hour and 12-hour time formats:

    def convert_time(hour24):\n    if hour24 > 12:\n        return hour24 - 12, \"PM\"\n    elif hour24 == 0:\n        return 12, \"AM\"\n    elif hour24 == 12:\n        return 12, \"PM\"\n    else:\n        return hour24, \"AM\"\n
    "},{"location":"kits/led-displays/shift-register-displays/#advanced-labs-and-extensions","title":"Advanced Labs and Extensions:","text":""},{"location":"kits/led-displays/shift-register-displays/#1-alarm-clock-lab","title":"1. Alarm Clock Lab","text":"

    Modify the clock to add alarm functionality: - Add a button to set alarm time - Add a buzzer for the alarm - Implement snooze functionality

    "},{"location":"kits/led-displays/shift-register-displays/#2-temperature-display-lab","title":"2. Temperature Display Lab","text":"

    Alternate between showing time and temperature: - Add a temperature sensor - Display temperature for 3 seconds every minute - Add a button to toggle between time and temperature

    "},{"location":"kits/led-displays/shift-register-displays/#3-custom-animation-lab","title":"3. Custom Animation Lab","text":"

    Create animations for the display: - Make digits spin when changing - Create a \"snake\" animation for the top of each hour - Design transitions between numbers

    "},{"location":"kits/led-displays/shift-register-displays/#4-world-clock-lab","title":"4. World Clock Lab","text":"

    Modify the clock to show multiple time zones: - Add buttons to cycle through different time zones - Show timezone abbreviation - Store favorite time zones

    "},{"location":"kits/led-displays/shift-register-displays/#5-stopwatch-lab","title":"5. Stopwatch Lab","text":"

    Add stopwatch functionality: - Use buttons to start/stop/reset - Display tenths of seconds - Store lap times

    "},{"location":"kits/led-displays/shift-register-displays/#summary","title":"Summary","text":"

    These labs progressively build upon the base code while introducing new concepts and challenges. Each lab reinforces different programming concepts:

    • Variables and data types
    • Control structures (if/else, loops)
    • Functions and methods
    • Object-oriented programming
    • Hardware interaction
    • Time and date handling
    • User input processing

    This allows students to learn both programming and hardware concepts in a hands-on, engaging way while creating something practical and visible.

    "},{"location":"kits/led-strips/","title":"LED Strip Clocks","text":"

    In this section we will present two clocks that use and LED strip.

    1. The first kit displays binary numbers. Hard to read but very geeky.
    2. The second requires building four seven-segment displays from the LED strip (or LED string)
    "},{"location":"kits/led-strips/01-binary-clock/","title":"Binary Clock","text":"

    This kit just needs a Pico and a short segment of an LED strip - about 14 pixels.

    We can create a very simple binary clock using a single LED strip.

    The strip will have three color bands:

    1. One binary number will be the hour (0 to 12) (4 red pixels)
    2. One binary number will be the minutes (0 to 59) (6 green pixels)
    3. One binary number will be the seconds (0 to 59) (6 blue pixels)

    We can also put spaces between the bands

    We can optionally also have the seconds displayed by:

    1. A single LED that blinks on and off
    2. Two decimal digits
    3. A single binary from (0 to 60)
    "},{"location":"kits/led-strips/01-binary-clock/#sample-code","title":"Sample Code","text":"
    from machine import Pin\nfrom neopixel import NeoPixel\nfrom utime import sleep, localtime\n# get the configuration information\nimport config\n\nnp = config.NUMBER_PIXELS\nstrip = NeoPixel(Pin(config.NEOPIXEL_PIN), np)\n\nsec_bits = [0,0,0,0,0,0]\nmin_bits = [0,0,0,0,0,0]\nhr_bits = [0,0,0,0,0,0]\n\ndef decimal_to_binary(n, a):\n    global sec_bits\n    for i in range(0,6):\n        if n % 2:\n            a[i] = 1\n        else:\n            a[i] = 0\n        ## n halfed\n        n //= 2\n\ndef display_binary(binary, index, color):\n    for i in range(0, 6):\n        # print(i, ' ', end='')\n        if binary[i] == 1:\n            strip[index+i] = color\n        else:\n            strip[index+i] = (0,0,0)\n    strip.write()\n\n# light mark and write\ndef display_mark(loc):\n    strip[loc] = (5,5,5)\n    strip.write()\n\n# update from the first time\n# sec\ndisplay_mark(0)\ndisplay_mark(7)\n\n# min\ndisplay_mark(9)\ndisplay_mark(16)\n\n# min\ndisplay_mark(19)\ndisplay_mark(26)\n\nnow = localtime()\nhour = now[3]\n# use AM/PM 12 hour time\nif hour > 12:\n    hour = hour - 12\nminute = now[4]\n\n# this is not working\ndecimal_to_binary(minute, min_bits)\nprint('initial min:', minute, min_bits)\ndisplay_binary(min_bits, 10, (0,10,0))\n\ndecimal_to_binary(hour, hr_bits)\nprint('initial hour:', hour, hr_bits)\ndisplay_binary(hr_bits, 20, (0,0,10))\n\nwhile True:\n    now = localtime()\n    hour = now[3]\n    # use AM/PM 12 hour time\n    if hour > 12:\n        hour = hour - 12\n    minute = now[4]\n    sec = now[5]\n    print(hour, ':', minute, ' ', sec, sep='')\n    strip.write()\n    decimal_to_binary(sec, sec_bits)\n    print('sec:', sec, sec_bits)\n    display_binary(sec_bits, 1, (10,0,0))\n    if sec == 60:\n        minute = minute + 1\n        sec = 0\n        decimal_to_binary(minute, min_bits)\n        print('min:', minute, min_bits)\n        display_binary(min_bits, 10, (0,10,0))\n        if minute == 60:\n            decimal_to_binary(hour, hr_bits)\n            print('hour:', hour, hr_bits)\n            display_binary(hr_bits, 20, (0,0,10))\n            hour = hour + 1\n            minute = 0\n            if hour == 24:\n                hour = 0\n    sleep(1)\n
    "},{"location":"kits/led-strips/01-binary-clock/#references","title":"References","text":"
    • Moving Rainbow Clock
    "},{"location":"kits/led-strips/02-seven-segment-clock/","title":"Seven Segment Clock","text":"

    We can create a large, bright clock visible in a large classroom by lighting up selective pixels of an LED strip and arranging the pixels in the shape of seven segment displays. We can use three pixels per segment.

    • We can use three pixels per segment.
    • 21 pixels per digit
    • 63 pixels + 6 for the \"1\" + two for the colon = 70 pixels

    eBay 50 for $12

    Drawing Digits

    Lessons

    We can create an array of the segments like this:

    segmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n
    "},{"location":"kits/led-strips/02-seven-segment-clock/#digit-pixel-map","title":"Digit Pixel Map","text":"

    TBD

    • a: n, n+1, n+2
    • b: n+3, n+4, n+5

    def set_pixels(digit, value, color):\n    # look up start pixel for digit\n    # for value turn on pixels\n    n = startVals[digit]\n\n    segmentOn = segmentMapping[value];\n    for i in range(0, 9):\n        if (segmentOn[i]):\n            o = i*3 // offset\n            strip(n+o) = color\n            strip(n+o+1) = color\n            strip(n+o+2) = color\n
    ```

    7-Segment Display Demo with P5.js

    Moving Rainbow Arduino Sign

    "},{"location":"kits/lilygo/","title":"LILYGO T-Display RP2040","text":"

    LILYGO makes low-cost and high-quality microcontroller development boards that include small displays. Although most of their boards run on C programs on ESP-32 processors, they do have one that runs MicroPython on an RP2040. This \"kit\" is really just that development board placed on a breadboard. The device has two buttons on it which can be used to adjust the time.

    This is a color 1.14 inch LCD display PS with 240*135 resolution. It uses the ST7789V chip that has an extreamly high quality driver created by Russ Hughes that allows for flicker-free drawing.

    I purchased mine on Ebay for $10.66 and three dollars for shipping.

    Although the display is too small for most robotic applications where the robot is on the floor and we are standing, it is a good example of how we can get both clocks and watches to look great. My hope is that LILYGO comes out with a larger display in the future.

    Lilygo also sells their own \"wearable\" watch kits] for $35 to $45. However, I have not purchased any of these that can be programmed with an RP2040 and MicroPython yet. Here is a GitHub Page for the T-Watch that implies it might be on the way. Note that using this requires extensive knowledge of the ESP32 development system.

    "},{"location":"kits/lilygo/#getting-started","title":"Getting Started","text":"

    To use the ST7789V driver we MUST use a custom image provide by Rull Hughes. This is because the driver is written in low-level C code and the python driver requires it to be combiled into the firmware image.

    I downloaded the custom image here:

    T-DISPLAY RP2040 Firmware

    I then held the Boot button down while I powered up the device.

    I soldered my own header pins on the LILYGO and placed it on a breadboard. Unfortunatly this makes it impossible to hold down the boot button with the device on the breadboard.

    "},{"location":"kits/lilygo/#pinouts","title":"Pinouts","text":"

    The pinouts are very different from the Raspberry Pi Pico.

    "},{"location":"kits/lilygo/#config-file","title":"Config File","text":"

    This implementation puts the driver in a hidden C program, but it does have a configuration file that we must upload and place in the /lib directory.

    Here is a Link to the File for the T-Display RP2040

    \"\"\"TTGO T-Display RP2040 display\"\"\"\n\nfrom machine import Pin, SPI\nfrom time import sleep\nimport st7789\n\nTFA = 40    # top free area when scrolling\nBFA = 40    # bottom free area when scrolling\n\ndef config(rotation=0, buffer_size=0, options=0):\n\n    Pin(22, Pin.OUT, value=1)\n\n    spi = SPI(0,\n        baudrate=62500000,\n        polarity=1,\n        phase=0,\n        sck=Pin(2, Pin.OUT),\n        mosi=Pin(3, Pin.OUT),\n        miso=None)\n\n    return st7789.ST7789(\n        spi,\n        135,\n        240,\n        cs=Pin(5, Pin.OUT),\n        dc=Pin(1, Pin.OUT),\n        backlight=Pin(4, Pin.OUT),\n        rotation=rotation,\n        options=options,\n        buffer_size=buffer_size)\n
    "},{"location":"kits/lilygo/#blink-the-onboard-led","title":"Blink The Onboard LED","text":"

    This red LED is on the bottom of the board.

    Blink Timer example:

    from machine import Pin, Timer\nled = Pin(25,Pin.OUT)\ntim = Timer()\ndef tick(timer):\n    global led\n    led.toggle()\ntim.init(freq=2.5, mode=Timer.PERIODIC, callback=tick)\n
    "},{"location":"kits/lilygo/#display-example","title":"Display Example","text":"
    \"\"\"\ndisplay-test.py\nFills the screen with red, green and blue\n\"\"\"\n\nfrom utime import sleep\nimport st7789\nimport tft_config\ntft = tft_config.config(1)\ntft.init()\n\nwhile True:\n    tft.fill(st7789.RED)\n    sleep(1)\n    tft.fill(st7789.GREEN)\n    sleep(1)\n    tft.fill(st7789.BLUE)\n    sleep(1)\n
    "},{"location":"kits/lilygo/#drawing-text","title":"Drawing Text","text":"

    For this example to work, you will need to load a font library into the /lib directory.

    import random\nimport utime\nimport st7789\nimport tft_config\nimport vga2_bold_16x32 as font\n\ntft = tft_config.config(1)\ntft.init()\n\n# draw text using a 16X32 font using blue text on a white background\ntft.text(\n        font,\n        'Hello World!',\n        tft.width()//2-100, # x position to start writing\n        tft.height()//2-50, # y position\n        st7789.BLUE, # font in blue\n        st7789.WHITE # background in white\n)\n
    "},{"location":"kits/lilygo/#referneces","title":"Referneces","text":"

    Item on Aliexpress Sample GitHub repo: https://github.com/Xinyuan-LilyGO/LILYGO-T-display-RP2040

    ST7789V Submodule: Russ Hughes GitHub Repo

    Config: Sample Config File

    "},{"location":"kits/max7219/","title":"MAX7219 Clocks","text":"

    The Analog Devices MAX7219 is a low-cost chip that communicates with a row of seven-segment displays using a single serial interface.

    eBay search for MAX7219

    "},{"location":"kits/max7219/#lesson-plan-building-a-clock-with-the-max7219-chip-using-micropython-and-raspberry-pi-pico","title":"Lesson Plan: Building a Clock with the MAX7219 Chip using MicroPython and Raspberry Pi Pico","text":""},{"location":"kits/max7219/#objective","title":"Objective:","text":"

    Students will learn about basic electronics and programming by building a digital clock using the MAX7219 LED driver chip with a Raspberry Pi Pico programmed in MicroPython.

    "},{"location":"kits/max7219/#materials","title":"Materials:","text":"
    • MAX7219 LED dot matrix modules
    • Raspberry Pi Pico
    • Jumper wires
    • Breadboard
    • USB cable for the Raspberry Pi Pico
    • Computers with Thonny Python IDE installed
    • Basic electronic components (resistors, capacitors, etc.)
    • Reference materials on MAX7219 and MicroPython programming
    "},{"location":"kits/max7219/#duration","title":"Duration:","text":"

    5 classes (45 minutes each)

    "},{"location":"kits/max7219/#class-1-introduction-to-the-max7219-and-raspberry-pi-pico","title":"Class 1: Introduction to the MAX7219 and Raspberry Pi Pico","text":"
    • Lecture Topic: Overview of the MAX7219 chip and its applications in digital displays.
    • Activity: Demonstration of a simple LED matrix setup using the MAX7219 and Raspberry Pi Pico.
    • Homework: Read provided material about MAX7219 and basics of MicroPython.
    "},{"location":"kits/max7219/#class-2-basic-electronics-and-circuit-design","title":"Class 2: Basic Electronics and Circuit Design","text":"
    • Lecture Topic: Fundamentals of electronics, introduction to using a breadboard, and designing circuits.
    • Activity: Students practice creating basic circuits on the breadboard using Raspberry Pi Pico.
    • Homework: Sketch a basic circuit diagram for connecting the MAX7219 to the Raspberry Pi Pico.
    "},{"location":"kits/max7219/#class-3-introduction-to-micropython","title":"Class 3: Introduction to MicroPython","text":"
    • Lecture Topic: Basics of MicroPython programming and its application in controlling electronic components.
    • Activity: Simple programming exercises in Thonny Python IDE to

    understand MicroPython syntax and basic commands.

    • Homework: Write a simple program in MicroPython to blink an LED.
    "},{"location":"kits/max7219/#class-4-programming-the-max7219-with-micropython","title":"Class 4: Programming the MAX7219 with MicroPython","text":"
    • Lecture Topic: Detailed instruction on programming the MAX7219 using MicroPython.
    • Activity: Students will write and upload a MicroPython script to the Raspberry Pi Pico to control the MAX7219 module, starting with displaying static numbers.
    • Homework: Modify the script to create a simple animation or pattern on the LED matrix.
    "},{"location":"kits/max7219/#class-5-building-and-programming-the-clock","title":"Class 5: Building and Programming the Clock","text":"
    • Lecture Topic: Integrating the knowledge gained to build a digital clock.
    • Activity: Students will complete the assembly of their digital clocks and program them to display the current time. This will involve fetching the time from the Raspberry Pi Pico and displaying it on the MAX7219 LED matrix.
    • Assessment: Evaluate the students' projects based on functionality, creativity, and understanding of the concepts taught.
    "},{"location":"kits/max7219/#additional-notes","title":"Additional Notes:","text":"
    • Ensure that each student or group has access to all the necessary materials.
    • Supplement the course with online resources and forums for additional support.
    • Encourage students to document their progress and challenges for a reflective learning experience.
    • Consider having a session for students to present their finished clocks and share their learning experiences with the class.
    "},{"location":"kits/max7219/#references","title":"References","text":"

    DIY clock | Homemade 7 segments \"nixie\" tubes

    "},{"location":"kits/pico-oled/","title":"Pico OLED Kits","text":"

    These are our most popular kits. They use a bright monochrome 128x64 OLED with either the Raspberry Pi Pico or the Raspberry Pi Pico W.

    The OLEDs are mounted on a piece of plastic with a half-size breaboard.

    Each board has two buttons so you can adjust the time and alarm clock settings.

    "},{"location":"kits/pico-oled/#individual-exercises","title":"Individual Exercises","text":""},{"location":"kits/pico-oled/#hello-world","title":"Hello World","text":"

    Go to Hello World lab

    "},{"location":"kits/pico-oled/01-hello-world/","title":"Hello World","text":"

    To get started, let's just draw the string \"Hello world!\" on the display.

    Here is the code:

    import machine\nimport ssd1306\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\n\nRES = machine.Pin(4) # Reset\nDC = machine.Pin(5) # Data/command\nCS = machine.Pin(6) # Chip Select\n\nspi=machine.SPI(0, sck=SCL, mosi=SDA)\noled = ssd1306.SSD1306_SPI(128, 64, spi, DC, RES, CS)\n\n# erase the entire screen with black\noled.fill(0)\n\n# place a hello message at point (0,0) in white\noled.text(\"Hello world!\", 0, 0, 1)\n\n# send the entire frame buffer to the display via the SPI bus\noled.show()\n

    Challenges

    1. Can you change the message from \"Hello world!\" to have your name in it?
    2. Can you change the location of the text on the screen by changing the location point from (0,0) to another place on the screen? The screen is 128 pixels wide by 64 pixels high.
    3. How far down can you display the message without going off the screen?
    4. How many characters wide can a message be before it goes off the right edge of the dipsplay?
    5. Can you display multiple messages on different lines?
    "},{"location":"kits/pico-oled/02-display-time/","title":"Display Time","text":""},{"location":"kits/pico-oled/02-display-time/#the-localtime-function","title":"The Localtime function","text":"
    from time import localtime\n\nprint(localtime())\n
    import machine\nimport ssd1306\nimport config\nfrom time import localtime\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\n\nyear = localtime()[0]\nmonth = localtime()[1]\nday = localtime()[2]\nhour = localtime()[3]\nminute = localtime()[4]\n\n# display the time in hour and minute on the first line\noled.text(str(hour) + \":\" + str(minute), 0, 0, 1)\n\n# display the date on the second line\noled.text(str(month) + \"/\" + str(day) + \"/\" + str(year), 0, 10, 1)\noled.show()\n
    "},{"location":"kits/pico-oled/02-hello-config/","title":"Hello Configuraiton","text":""},{"location":"kits/pico-oled/03-display-localtime/","title":"Display Localtime","text":"
    import machine\nimport ssd1306\nimport config\nfrom time import localtime\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\n\nyear = localtime()[0]\nmonth = localtime()[1]\nday = localtime()[2]\nhour = localtime()[3]\nminute = localtime()[4]\n\n# display the time in hour and minute on the first line\noled.text(str(hour) + \":\" + str(minute), 0, 0, 1)\n\n# display the date on the second line\noled.text(str(month) + \"/\" + str(day) + \"/\" + str(year), 0, 10, 1)\noled.show()\n

    Challenges

    1. Change the display format of the date and time. Place the date and time in the center of the display.
    2. Add code to add a \"AM\" or \"PM\" string if the hour is greater than 12 noon
    3. Adding additional text to display if it is morning or evening
    "},{"location":"kits/pico-oled/04-display-localtime-updates/","title":"Display Local Time with Updates","text":"

    Now let's update the display every second.

    import machine\nimport ssd1306\nimport config\nfrom time import localtime\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\n\nwhile True:\n    # clear the entire screen\n\n    oled.fill(0)\n    year = localtime()[0]\n    month = localtime()[1]\n    day = localtime()[2]\n    hour = localtime()[3]\n    minute = localtime()[4]\n    second = localtime()[5]\n\n    # display the time in hour and minute on the first line\n    oled.text(str(hour) + \":\" + str(minute) + \":\" + str(second) , 0, 0, 1)\n\n    # display the date on the second line\n    oled.text(str(month) + \"/\" + str(day) + \"/\" + str(year), 0, 10, 1)\n    # send the entire screen to the display via SPI\n    oled.show()\n
    "},{"location":"kits/pico-oled/05-clock-hands/","title":"Clock Hands","text":"

    Now lets display the hands on a clock. We will need to do a little math to calculate were on the clock face to draw the hands to from the center.

    import machine\nimport ssd1306\nimport config\nfrom time import sleep, localtime\nimport math\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\nTWO_PI = 3.14159 * 2\n\nLENGTH = config.HEIGHT // 2\nCENTER_X = config.WIDTH // 2\nCENTER_Y = config.HEIGHT // 2\n\noled.fill(0)\n\nfor i in range(0,61):\n    radians = (i/60)*TWO_PI\n    x = int(math.sin(radians)*LENGTH)\n    y = -int(math.cos(radians)*LENGTH)\n    # print(i, radians, x, y, x, y)  \n    oled.line(CENTER_X, CENTER_Y, CENTER_X + x, CENTER_Y + y, 1)\n    oled.show()\n    sleep(.1)\n    oled.line(CENTER_X, CENTER_Y, CENTER_X + x, CENTER_Y + y, 0)\n
    "},{"location":"kits/pico-oled/10-draw-seven-segments/","title":"Draw Seven Segments","text":""},{"location":"kits/pico-oled/10-draw-seven-segments/#dight-to-segment-data","title":"Dight to Segment Data","text":"
    segmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n
    "},{"location":"kits/pico-oled/10-draw-seven-segments/#draw-segment-function","title":"Draw Segment Function","text":"

    Parameters:

    1. The digit to display - an integer in the range 0-9
    2. x of the upper left corner
    3. y of the upper left corner
    4. the width of the digit (about 20 is a good value)
    5. the height of the digit
    6. the thickness of each segment (3 or 4 are good values)
    7. the color (0=black, 1=white)
    # x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottem, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top row\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottem element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottum\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n
    "},{"location":"kits/pico-oled/10-draw-seven-segments/#full-program","title":"Full Program","text":"
    # Clock Lab 20: Draw Seven Segments\n# this lab uses the fill_rect function to draw the segments\nimport machine\nimport utime\nimport ssd1306\nfrom utime import sleep, localtime\nled = machine.Pin(25, machine.Pin.OUT)\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\nspi=machine.SPI(0, sck=SCL, mosi=SDA, baudrate=100000)\n\nRES = machine.Pin(4)\nDC = machine.Pin(5)\nCS = machine.Pin(6)\n\noled = ssd1306.SSD1306_SPI(128, 64, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottem, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottem element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottum\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n\noled.fill(0)\noled.text('Lab 12: rect', 0, 0, 1)\nx = 10 # upper left corner x\ny = 10 # upper left corner y\nw = 20 # digit width\nh = 30 # digit height\nt = 3\n\nwhile True:\n    for i in range(0, 10):\n\n        print(i)\n        # create an outline on px away from the drawing region\n        oled.rect(x-2, y-2, w+4, h+4, 1)\n        # draw one digit\n        drawDigit(i, x, y, w, h, t, 1)\n        # draw a second digit\n        #drawDigit(i, x + w + 4, w, h, t, 1)\n        oled.text(str(i), 0, 54, 1)\n        oled.show()\n        sleep(2)\n        oled.fill(0)\n
    "},{"location":"kits/pico-oled/11-draw-thickness/","title":"Draw Seven Segments with Thickness","text":""},{"location":"kits/pico-oled/15-digital-clock/","title":"OLED Digital Clock Display","text":""},{"location":"kits/shift-register-clock/","title":"74HC595 Shift Register Clock","text":"

    The display has five wires. In addition to power and ground we have:

    ser_pin=2,    # DIO\nsrclk_pin=1,  # SCLK\nrclk_pin=0    # RCLK\n

    The shift register takes in a set of 16 bit commands. The first byte is the segment information with one bit for each of the 7 segments and one bit for the colon. The second bit indicates what digit should be turned on.

    Note that for a segment to be on, the bit must be \"0\".

    Here are the letters associated with each of the 7 segments:

     aaaa\nf    b\nf    b\n gggg\ne    c\ne    c\n dddd\n
    # bit 0 is the right-most significant bit and is used to turn on the colon.\nself.SEGMENTS = {\n    'a': 4,  # bit 4\n    'b': 3,  # bit 3\n    'c': 2,  # bit 2\n    'd': 7,  # bit 7\n    'e': 6,  # bit 6\n    'f': 5,  # bit 5\n    'g': 1   # bit 1\n}\n

    \"d\" First byte: 00110000 Second byte: 00010000

    This is where \"a\" is missing. a is the fourth bit. First byte: 00010000

    This is where all the segments are on except f. \"f\" is the 3rd bit First byte: 00100000 \"A\" is First byte: 10000000

    "},{"location":"kits/shift-register-clock/#sample-test","title":"Sample Test","text":"

    The following program will cycle through the digits 0 to 9 on the right most digit to the left most digit.

    from machine import Pin\nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep, localtime\n\nclass FourDigitClock:\n    # Class constants\n    ALL_OFF = 0xFF            # All segments off (inverted logic)\n    SECOND_BYTE = 0b00010000  # Keep bit 4 set in second byte\n\n    def __init__(self, ser_pin, srclk_pin, rclk_pin):\n        # Initialize pins\n        self.ser = Pin(ser_pin, Pin.OUT)      # Serial data\n        self.srclk = Pin(srclk_pin, Pin.OUT)  # Shift register clock\n        self.rclk = Pin(rclk_pin, Pin.OUT)    # Storage register clock\n\n        self.sr = SR74HC595_BITBANG(self.ser, self.srclk, self.rclk)\n\n        # Segment bit positions (0 turns segment on)\n        # a is the top, b in the upper right, c is the lower right\n        # d is the bottom, e is the lower left, f is the upper right\n        # g is the middle segment\n        self.SEGMENTS = {\n            'a': 4,  # bit 4\n            'b': 3,  # bit 3\n            'c': 2,  # bit 2\n            'd': 7,  # bit 7\n            'e': 6,  # bit 6\n            'f': 5,  # bit 5\n            'g': 1   # bit 1\n        }\n\n        # Define segments needed for each digit\n        self.DIGIT_SEGMENTS = {\n            0: 'abcdef',   # 0 needs all but g\n            1: 'bc',       # 1 needs just b and c\n            2: 'abged',    # 2 needs all but c and f\n            3: 'abgcd',    # 3 needs all but e and f\n            4: 'fbcg',     # 4 needs these four\n            5: 'afgcd',    # 5 needs all but e and b\n            6: 'afedcg',   # 6 needs all but b\n            7: 'abc',      # 7 needs just these three\n            8: 'abcdefg',  # 8 needs all segments\n            9: 'abfgcd'    # 9 needs all but e\n        }\n\n        # Pre-calculate patterns for all digits\n        self.DIGIT_PATTERNS = {\n            digit: self.create_pattern(segments) \n            for digit, segments in self.DIGIT_SEGMENTS.items()\n        }\n\n    def create_pattern(self, segments):\n        \"\"\"Create bit pattern from segment letters with inverted logic\"\"\"\n        pattern = self.ALL_OFF\n        for segment in segments:\n            if segment in self.SEGMENTS:\n                pattern &= ~(1 << self.SEGMENTS[segment])\n        return pattern\n\n    def display_pattern(self, first_byte, digit_select_byte):\n        \"\"\"Display a pattern with specified digit selection\"\"\"\n        self.sr.bits(first_byte, 8)\n        self.sr.bits(digit_select_byte, 8)\n        self.sr.latch()\n\n    def test_all_positions(self):\n        \"\"\"Test counting 0-9 on all digit positions\"\"\"\n        print(\"Testing all digit positions...\")\n\n        # Digit selection patterns to try\n        digit_patterns = [\n            (0, 0b00010000, \"Rightmost digit\"),\n            (1, 0b00100000, \"Second digit\"),\n            (2, 0b01000000, \"Third digit\"),\n            (3, 0b10000000, \"Leftmost digit\")\n        ]\n\n        # Test each digit position\n        for position, digit_select, position_name in digit_patterns:\n            print(f\"\\nTesting {position_name}\")\n\n            # Count 0-9 on this position\n            for number in range(10):\n                print(f\"Displaying {number} on {position_name}\")\n\n                # Display the number\n                self.display_pattern(self.DIGIT_PATTERNS[number], digit_select)\n                sleep(.25)\n\n                # Clear display between numbers\n                self.display_pattern(self.ALL_OFF, self.ALL_OFF)\n                sleep(0.05)\n\n            # Wait for user input before moving to next position\n            #input(f\"Press Enter to test next position...\")\n\ndef run_position_test():\n    \"\"\"Run position testing\"\"\"\n    clock = FourDigitClock(\n        ser_pin=2,    # DIO\n        srclk_pin=1,  # SCLK\n        rclk_pin=0    # RCLK\n    )\n\n    print(\"Starting position tests...\")\n    clock.test_all_positions()\n\n# Run the position test\nif __name__ == '__main__':\n    run_position_test()\n
    "},{"location":"kits/shift-register-clock/#references","title":"References","text":"

    74HC595 Shift Register

    "},{"location":"kits/shift-register-clock/clock-main/","title":"Clock Main","text":""},{"location":"kits/shift-register-clock/clock-main/#details","title":"Details","text":"

    This program use 12 hour time and also flashes the colon ever 1/2 second. It also is designed to work with a real-time clock that might take a bit of time to startup with the Pico first powers up.

    from machine import Pin, RTC \nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep, localtime, ticks_ms\n\ndef wait_for_rtc():\n    print(\"Waiting for RTC to be ready...\")\n    rtc = RTC()\n    while True:\n        current_time = rtc.datetime()\n        # On Pico, default RTC starts at (2021, 1, 1, 0, 0, 0, 0, 0)\n        # So we check if it's been set to something else\n        if current_time[0] != 2021 or current_time[1] != 1 or current_time[2] != 1:\n            print(\"RTC is ready!\")\n            return\n        print(\"RTC not ready yet...\")\n        sleep(1)  # Check every second\n\nclass FourDigitClock:\n    ALL_OFF = 0xFF  # All segments off (inverted logic)\n\n    def __init__(self, ser_pin, srclk_pin, rclk_pin):\n        self.ser = Pin(ser_pin, Pin.OUT)\n        self.srclk = Pin(srclk_pin, Pin.OUT) \n        self.rclk = Pin(rclk_pin, Pin.OUT)\n        self.sr = SR74HC595_BITBANG(self.ser, self.srclk, self.rclk)\n\n        self.SEGMENTS = {\n            'a': 4, 'b': 3, 'c': 2, \n            'd': 7, 'e': 6, 'f': 5, 'g': 1\n        }\n        self.DIGIT_SEGMENTS = {\n            0: 'abcdef', 1: 'bc', 2: 'abged', 3: 'abgcd',\n            4: 'fbcg', 5: 'afgcd', 6: 'afedcg', \n            7: 'abc', 8: 'abcdefg', 9: 'abfgcd'\n        }\n        self.DIGIT_PATTERNS = {\n            digit: self.create_pattern(segments)\n            for digit, segments in self.DIGIT_SEGMENTS.items()\n        }\n        self.DIGIT_SELECT = [\n            0b00010000,  # Rightmost digit\n            0b00100000,  # Second digit \n            0b01000000,  # Third digit\n            0b10000000   # Leftmost digit  \n        ]\n\n    def create_pattern(self, segments):\n        pattern = self.ALL_OFF\n        for segment in segments:\n            if segment in self.SEGMENTS:\n                pattern &= ~(1 << self.SEGMENTS[segment]) \n        return pattern\n\n    def display_digit(self, digit, position, dp=False):\n        pattern = self.DIGIT_PATTERNS[digit]\n        if dp:\n            pattern &= ~(1 << 0)  # Turn on decimal point\n        self.sr.bits(pattern, 8)\n        self.sr.bits(self.DIGIT_SELECT[position], 8)\n        self.sr.latch()\n\n    def display_time(self, hour, minute, colon_state):\n        # Convert to 12-hour format\n        if hour > 12:\n            hour -= 12\n        elif hour == 0:  \n            hour = 12\n\n        digits = [hour // 10, hour % 10, minute // 10, minute % 10]\n\n        for position, digit in enumerate(reversed(digits)):\n            self.display_digit(digit, position, dp=(position == 1 and colon_state))\n            sleep(0.002)  # Reduced persistence timing\n\n\ndef run_clock():\n    # wait for a good time to come from localtime()\n    wait_for_rtc()\n\n    clock = FourDigitClock(ser_pin=2, srclk_pin=1, rclk_pin=0)\n    print(\"Starting clock...\")\n\n    last_second = -1\n    colon_state = True\n    last_toggle = ticks_ms()\n\n    while True:\n        current_time = localtime()\n        hour = current_time[3]\n        minute = current_time[4]\n        current_second = current_time[5]\n\n        if ticks_ms() - last_toggle >= 500:\n            colon_state = not colon_state\n            last_toggle = ticks_ms()\n\n        clock.display_time(hour, minute, colon_state)\n\n\nif __name__ == '__main__':\n    run_clock()\n
    "},{"location":"kits/shift-register-clock/sample-prompt/","title":"Sample ChatGPT Prompt","text":"

    Prompt

    Please help me write a micropython program for a 4-digit clock. I have a digital clock display with 4 digits I purchased on eBay. Each of the 4 digits has 7 segments and there is also a colon between the 2nd and 3rd digits. The part says they use 74hc595 shift registers. The names of the connectors are:

    1. GND
    2. VCC
    3. RCLK
    4. SCLK
    5. DIO

    I found a micropython driver called: sr74hc595. When I run a test program the various segments do light up, but I don't see a pattern. Can you give me some suggestions on how to write a driver that writes the correct time like 12:34?

    Here is the code that is working:

    # SPDX-FileCopyrightText: 2021 Mike Causer <https://github.com/mcauser>\n# SPDX-License-Identifier: MIT\n\n\"\"\"\nMicroPython 74HC595 8-Bit Shift Register\nhttps://github.com/mcauser/micropython-74hc595\n\"\"\"\n\nfrom machine import Pin\n# from sr74hc595 import SR74HC595_BITBANG\nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep\n\nser = Pin(2, Pin.OUT)\nrclk = Pin(0, Pin.OUT)\nsrclk = Pin(1, Pin.OUT)\n\n# construct without optional pins\nsr = SR74HC595_BITBANG(ser, srclk, rclk)\n\n#sr.clear()  # raises RuntimeError because you haven't provide srclr pin\n#sr.enable()  # raises RuntimeError because you haven't provide oe pin\n\n# reconstruct with all pins\noe = Pin(3, Pin.OUT, value=0)  # low enables output\nsrclr = Pin(3, Pin.OUT, value=1)  # pulsing low clears data\n\nsr = SR74HC595_BITBANG(ser, srclk, rclk, srclr, oe)\n\nwhile True:\n\n    sr.bit(1)  # send high bit, do not latch yet\n    sr.bit(0)  # send low bit, do not latch yet\n    sr.latch()  # latch outputs, outputs=0000_0010\n\n    sr.bit(1, 1)  # send high bit and latch, outputs=0000_0101\n    sr.bit(0, 1)  # send low bit and latch, outputs=0000_1010\n\n    sr.bits(0xFF, 4)  # send 4 lowest bits of 0xff (sends 0x0f), outputs=1010_1111\n    sr.clear(0)  # clear the memory but don't latch yet\n    sr.latch()  # next latch shows the outputs have been reset\n    sr.bits(0b1010_1010, 8)  # write some bits\n    sr.clear()  # clear the memory and latch, outputs have been reset\n\n    sr.enable()  # outputs enabled\n    sr.enable(0)  # outputs disabled\n\n    sleep(1)\n\n    sr.bits(0b1111_1111, 8)  # write some bits\n    sr.clear()  # clear the memory and latch, outputs have been reset\n\n    sr.enable()  # outputs enabled\n    sr.enable(0)  # outputs disabled\n\n    sleep(1)\n\n    sr.bits(0b0000_0011, 8)  # write some bits\n    sr.clear()  # clear the memory and latch, outputs have been reset\n\n    sr.enable()  # outputs enabled\n    sr.enable(0)  # outputs disabled\n    sleep(1)\n
    "},{"location":"kits/tm1637/","title":"TM1637 LED Display","text":"

    Setting the Time

    The TM1637 LED digital display is an incredibly popular and cost-effective 4-digit 7-segment display module widely used in hobbyist electronics and educational projects. At around 30 cents per unit when purchased in bulk, it offers exceptional value for clock projects, counters, and basic numeric displays.

    Key features: - 4 digits with decimal points - Built-in controller chip that handles multiplexing - Simple 2-wire interface (clock and data) - 3.3V or 5V compatible - Brightness control - Colon indicator for clock displays

    What makes the TM1637 particularly appealing for MicroPython projects is its straightforward programming interface. Using just two pins (clock and data), you can control all segments and digits through a simple serial protocol. The module handles all the multiplexing internally, making it much easier to use than raw 7-segment displays.

    The TM1637 LED Clock is a low-cost way to get started. It is simple to setup and use and only requires the user to make 4 connections.

    "},{"location":"kits/tm1637/#parts-list","title":"Parts List","text":"
    1. 1/2 Size 400 tie solderless Breadboard
    2. 4 Male-Female 20cm jumper wires (Dupont Cables)
    3. Raspberry Pi Pico (or Pico W)
    4. TM1637 LED Clock display
    "},{"location":"kits/tm1637/#connection-diagram","title":"Connection Diagram","text":""},{"location":"kits/tm1637/#the-micropython-preamble","title":"The MicroPython Preamble","text":"
    import tm1637\nfrom machine import Pin, RTC\nfrom utime import sleep, localtime, ticks_ms\n\n# Initialize display\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n

    Here's some example MicroPython code to test various display features using your preamble:

    # Basic number display\ntm.numbers(12, 59)  # Display 12:59\nsleep(1)\n\n# Show temperature with decimal\ntm.temperature(23.4)  # Display 23.4\nsleep(1)\n\n# Control brightness (0-7)\ntm.brightness(2)  # Set to medium brightness\n\n# Blank the display\ntm.show('    ')\nsleep(1)\n\n# Show individual digits\ntm.write([0, 1, 2, 3])  # Display 0123\nsleep(1)\n\n# Toggle colon\ntm.show('1234', True)  # Show 12:34 with colon\nsleep(1)\ntm.show('1234', False)  # Show 1234 without colon\nsleep(1)\n\n# Scroll some numbers\nfor i in range(10):\n    tm.number(i * 111)\n    sleep(0.5)\n\n# Test all segments\ntm.write([0x7f, 0x7f, 0x7f, 0x7f])  # All segments on\nsleep(1)\n

    Given its popularity, there are several MicroPython libraries available for the TM1637. The example above uses one of the most common libraries. The display's simplicity and reliability have made it a staple in DIY electronics, particularly for clock projects, temperature displays, and basic counters. You'll find it used in countless Arduino and Raspberry Pi Pico projects, making it one of the most recognizable LED display modules in the maker community.

    "},{"location":"kits/tm1637/manual-time-setting/","title":"Manually Setting the Time","text":"

    Setting the Time

    Next, we will create a complete program that implements a clock with manual time setting using the three buttons. This is a great practical example that teaches state management and user input handling.

    import tm1637\nfrom machine import Pin, RTC\nfrom utime import sleep, localtime, ticks_ms\n\n# Initialize display and RTC\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\nrtc = RTC()\n\n# Initialize buttons with pull-up resistors\nmode_btn = Pin(2, Pin.IN, Pin.PULL_UP)\nnext_btn = Pin(3, Pin.IN, Pin.PULL_UP)\nprev_btn = Pin(4, Pin.IN, Pin.PULL_UP)\n\n# Clock modes\nRUNNING = 0\nSET_HOUR = 1\nSET_MINUTE = 2\nSET_AMPM = 3\n\nclass Clock:\n    def __init__(self):\n        self.mode = RUNNING\n        self.hours = 12\n        self.minutes = 0\n        self.is_pm = False\n        self.colon_on = True\n        self.last_button_time = ticks_ms()\n        self.button_debounce = 200  # milliseconds\n        self.load_time_from_rtc()\n\n    def load_time_from_rtc(self):\n        \"\"\"Get current time from RTC\"\"\"\n        _, _, _, _, hours, minutes, _, _ = rtc.datetime()\n        self.hours = hours % 12\n        if self.hours == 0:\n            self.hours = 12\n        self.is_pm = hours >= 12\n        self.minutes = minutes\n\n    def save_time_to_rtc(self):\n        \"\"\"Save current time to RTC\"\"\"\n        current_time = list(rtc.datetime())\n        hours = self.hours\n        if self.is_pm and hours != 12:\n            hours += 12\n        elif not self.is_pm and hours == 12:\n            hours = 0\n        current_time[4] = hours  # Set hours\n        current_time[5] = self.minutes  # Set minutes\n        rtc.datetime(tuple(current_time))\n\n    def debounce(self):\n        \"\"\"Handle button debouncing\"\"\"\n        current_time = ticks_ms()\n        if current_time - self.last_button_time < self.button_debounce:\n            return False\n        self.last_button_time = current_time\n        return True\n\n    def handle_buttons(self):\n        \"\"\"Process button inputs\"\"\"\n        if not self.debounce():\n            return\n\n        # Mode button cycles through modes\n        if mode_btn.value() == 0:  # Button pressed (active low)\n            self.mode = (self.mode + 1) % 4\n            if self.mode == RUNNING:\n                self.save_time_to_rtc()\n\n        # Next/Previous buttons modify current setting\n        elif next_btn.value() == 0 or prev_btn.value() == 0:\n            increment = -1 if prev_btn.value() == 0 else 1\n\n            if self.mode == SET_HOUR:\n                self.hours = ((self.hours + increment - 1) % 12) + 1\n            elif self.mode == SET_MINUTE:\n                self.minutes = (self.minutes + increment) % 60\n            elif self.mode == SET_AMPM:\n                self.is_pm = not self.is_pm\n\n    def update_display(self):\n        \"\"\"Update the TM1637 display based on current mode and time\"\"\"\n        if self.mode == RUNNING:\n            # Normal time display with blinking colon\n            self.colon_on = not self.colon_on\n        else:\n            # Setting mode - flash the active component\n            flash_on = (ticks_ms() // 500) % 2 == 0\n\n            if self.mode == SET_HOUR:\n                if not flash_on:\n                    tm.show('    ')\n                    return\n            elif self.mode == SET_MINUTE:\n                if not flash_on:\n                    tm.numbers(self.hours, 0)\n                    return\n            elif self.mode == SET_AMPM:\n                if flash_on:\n                    tm.show(' ' + ('P' if self.is_pm else 'A') + ' ')\n                    return\n\n        # Update display\n        tm.numbers(self.hours, self.minutes, colon=self.colon_on)\n\n    def run(self):\n        \"\"\"Main clock loop\"\"\"\n        tm.brightness(2)  # Set initial brightness\n\n        while True:\n            self.handle_buttons()\n\n            if self.mode == RUNNING:\n                self.load_time_from_rtc()\n\n            self.update_display()\n            sleep(0.1)  # Small delay to prevent display flicker\n\n# Create and run the clock\nif __name__ == '__main__':\n    clock = Clock()\n    print(\"Starting clock... Use buttons to set time:\")\n    print(\"Mode: Switch between run/set hour/set minute/set AM,PM\")\n    print(\"Next/Prev: Adjust current setting\")\n    clock.run()\n

    Key concepts and features of this implementation:

    1. Button Handling
    2. Uses pull-up resistors (buttons connect to ground when pressed)
    3. Implements debouncing to prevent multiple triggers
    4. Buttons are active-low (0 when pressed, 1 when released)

    5. Mode System

    6. RUNNING: Normal clock operation
    7. SET_HOUR: Adjust hours (1-12)
    8. SET_MINUTE: Adjust minutes (0-59)
    9. SET_AMPM: Toggle between AM and PM

    10. Visual Feedback

    11. Selected component flashes when being set
    12. Colon blinks in running mode
    13. Special AM/PM display during setting

    14. Time Management

    15. Maintains time in 12-hour format internally
    16. Converts to/from 24-hour format for RTC
    17. Handles midnight/noon edge cases

    18. State Management

    19. Uses a class to organize state and behavior
    20. Separates display, button handling, and time management

    Common challenges students might encounter:

    1. Button Debouncing
    2. Understanding why debouncing is necessary
    3. Adjusting debounce timing for reliable operation

    4. Time Format Conversion

    5. Converting between 12/24 hour formats
    6. Handling edge cases (12 AM/PM)

    7. Display Updates

    8. Managing display refresh rate
    9. Creating smooth visual feedback

    Suggested exercises for students:

    1. Add a temperature display mode
    2. Implement a brightness adjustment feature
    3. Add an alarm setting mode
    4. Save settings to flash memory
    5. Add a battery backup indicator

    Would you like me to explain any part in more detail or provide examples of these extensions?

    "},{"location":"kits/tm1637/running-clock/","title":"Full Running Clock Using the TM1637","text":"

    I'll create a detailed example of a running clock using the TM1637 display. This builds on some of the concepts shown in the clock-driver.py file you shared, but simplified for the TM1637.

    import tm1637\nfrom machine import Pin, RTC\nfrom utime import sleep, localtime\n\n# Initialize the display\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n\n# Initialize the RTC (Real Time Clock)\nrtc = RTC()\n\ndef set_initial_time():\n    \"\"\"\n    Set an initial time if RTC isn't configured.\n    In a real project, you'd sync this with a time server or user input.\n    \"\"\"\n    # Format: (year, month, day, weekday, hours, minutes, seconds, subseconds)\n    rtc.datetime((2024, 12, 28, 5, 12, 0, 0, 0))\n\ndef format_time(hours, minutes):\n    \"\"\"\n    Convert 24-hour time to 12-hour format\n    Returns hours and whether it's PM\n    \"\"\"\n    is_pm = hours >= 12\n    if hours > 12:\n        hours -= 12\n    elif hours == 0:\n        hours = 12\n    return hours, is_pm\n\ndef run_clock():\n    # Set initial brightness (0-7)\n    tm.brightness(2)\n\n    # Track colon state for blinking\n    colon_on = True\n\n    while True:\n        # Get current time from RTC\n        year, month, day, weekday, hours, minutes, seconds, _ = rtc.datetime()\n\n        # Convert to 12-hour format\n        display_hours, is_pm = format_time(hours, minutes)\n\n        # Toggle colon every second\n        if seconds != prev_seconds:\n            colon_on = not colon_on\n            prev_seconds = seconds\n\n        # Display the time\n        tm.numbers(display_hours, minutes, colon=colon_on)\n\n        # Brief pause to prevent display flicker\n        sleep(0.1)\n\nif __name__ == '__main__':\n    set_initial_time()  # Only needed if RTC isn't set\n    print(\"Starting clock...\")\n    run_clock()\n

    Let's break down the key concepts students need to understand:

    1. Real-Time Clock (RTC)
    2. The RTC is a hardware component that keeps track of time
    3. It continues running even when the microcontroller is reset
    4. Time is stored as a tuple: (year, month, day, weekday, hours, minutes, seconds, subseconds)
    5. Students should understand why RTCs are important for accurate timekeeping

    6. Time Formats

    7. 24-hour vs 12-hour time conversion
    8. Why we need to handle special cases (midnight = 0 hours \u2192 12, noon = 12 stays 12)
    9. The concept of AM/PM

    10. Display Multiplexing

    11. How LED displays show multiple digits (though the TM1637 handles this internally)
    12. Why we need a brief sleep to prevent display flicker
    13. How brightness control works with PWM (Pulse Width Modulation)

    14. State Management

    15. Tracking the colon state for blinking
    16. Maintaining previous second value to detect changes
    17. Why we use global variables in this context

    18. Program Structure

    19. Main loop design
    20. Function organization
    21. Error handling (not shown but important in real applications)

    Common challenges students might encounter:

    1. Time Drift
    2. The RTC might drift slightly over time
    3. In real applications, you'd want to sync with an NTP server periodically

    4. Power Management

    5. Display brightness affects power consumption
    6. Consider dimming display in low light conditions
    7. Think about battery life in portable applications

    8. User Interface

    9. Adding buttons to set the time
    10. Handling time zone changes
    11. Adding features like alarms or timers

    Extensions students could try:

    1. Add a temperature display that alternates with the time
    2. Implement automatic brightness control using a light sensor
    3. Add alarm functionality with a buzzer
    4. Create a menu system for setting the time
    5. Add a battery backup system

    Would you like me to elaborate on any of these concepts or provide example code for any of the extensions?

    For reference, this code builds on the concepts shown in your clock-driver.py file, but simplifies the implementation thanks to the TM1637's built-in controller. The course-description.md suggests this would fit well in the early stages of your course, particularly during the \"Understanding\" phase where students explore how timing functions and hardware work together.

    "},{"location":"kits/waveshare/","title":"Waveshare RP2040","text":"

    The Waveshare RP2040 1.28\" IPS LCD Board is a wonderful developent board with a build in RP2040 processor that currently sells for about $18. The board has a USB-C connector, a place for a LiPo battery connection and built in Accelerometer & Gyroscope. It is a great value and a wonderful way to start to learn Python for smart watches!

    1. Waveshare SKU: 22668
    2. Waveshare Part Number: RP2040-LCD-1.28
    3. Link to Waveshare site

    Note that this watch does not have a real-time clock and has no ability to connect to time syhronization using WiFi. However, it is an ideal development tool for learning to program watch displays and integrate sensors.

    "},{"location":"kits/waveshare/#micropython-version","title":"MicroPython Version","text":"

    To use these lessions you much use MicroPython runtime v1.19.1-854-g35524a6fd released on 2023-02-07 or later. This version supports all the native framebuf drawing libraries (ellipse and polygon)

    See the documentation here: MicroPython Framebuffer Functions

    "},{"location":"kits/waveshare/#lessons","title":"Lessons","text":"
    1. Hello world! Lesson
    2. Color Lab
    3. Drawing Analog Hands
    4. 5x8 Fonts
    "},{"location":"kits/waveshare/#detailed-components","title":"Detailed Components","text":"Component Description USB Type-C connector USB 1.1 with device and host support ETA6096 high efficiency Lithium battery recharge manager Battery Header MX1.25 header, for 3.7V Lithium battery, allows recharging the battery and powering the board at the same time QMI8658C IMU, includes a 3-axis gyroscope and a 3-axis accelerometer 1.27mm pitch headers Adapting all GPIO and Debug pins W25Q16JVUXIQ 2MB NOR-Flash RP2040 Dual-core processor, up to 133MHz operating frequency RESET Button Reset the processor BOOT Button press it when resetting to enter download mode"},{"location":"kits/waveshare/#references","title":"References","text":"

    wiki

    Instructable by Tony Goodhew - note that this version does not leverage the built-in drawing libraries that were made available in version 19 of the MicroPython release. See The MicroPython FrameBuf Library

    Github Gist by Alasdair Allan

    "},{"location":"kits/waveshare/01-hello-world/","title":"Waveshare Hello World","text":""},{"location":"kits/waveshare/01-hello-world/#step-1-load-the-library","title":"Step 1: Load the Library","text":""},{"location":"kits/waveshare/01-hello-world/#step-2-load-a-test-program","title":"Step 2: Load a Test Program","text":"
    from LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \nLCD.set_bl_pwm(65535)\n\nLCD.fill(LCD.black)    \nLCD.text(\"Hello world!\", 50, 100, LCD.white)\nLCD.show()\n

    You should see \"Hello world!\" in a small white font near the center of the screen.

    Challenges

    1. Can you move the text around the screen by changing the x and y starting position of the text?
    2. Can you change the background fill from black to another color?
    3. Can you change the color of the text from white to be another color?
    4. Can you change the font size? (hint: this is not easy!)
    "},{"location":"kits/waveshare/02-color-test/","title":"Color Tests","text":"

    Now let's try to make the background screen change colors:

    from LCD_1inch28 import LCD_1inch28\nfrom utime import sleep\n\nLCD = LCD_1inch28()  \nLCD.set_bl_pwm(65535)\n\nLCD.fill(LCD.black)\nLCD.show()\nsleep(1)\nLCD.fill(LCD.white)\nsleep(1)\nLCD.show()\nLCD.fill(LCD.red)\nLCD.show()\nsleep(1)\nLCD.fill(LCD.green)\nLCD.show()\nsleep(1)\nLCD.fill(LCD.blue)\nLCD.show()\nprint('done')\n

    What happens when you change the color \"red\" to be \"orange\"? You shouild see:

    Traceback (most recent call last):\n  File \"<stdin>\", line 10, in <module>\nAttributeError: 'LCD_1inch28' object has no attribute 'orange'\n

    This shows you that although the driver knows about some basic colors, (black, white, red, green and blue), it has no understanding of other colors.

    To draw these colors we need to add our own color lists.

    "},{"location":"kits/waveshare/02-color-test/#custom-color-lists","title":"Custom Color Lists","text":"

    In order to get more nuanced colors, we need to define them using the binary of their red, green and blue values. With this display, we order the bits, blue, red and green.

    We can use the following binary notation to represent the colors:

    # binary representations of colors B=Blue bits, R=Red bits, G=Green bits\n# color = 0bBBBBBRRRRRGGGGGG\n# Cyan has all the blue and green bits on and the red bits off\ncyan = cyan = 0b1111100000111111\n
    from machine import Pin,I2C,SPI,PWM,ADC\nfrom time import sleep\nfrom LCD_1inch28 import LCD_1inch28, QMI8658\n\nCENTER = 120\nLCD = LCD_1inch28()\nLCD.set_bl_pwm(65535)\n\n# draw readability\nON = 1\nOFF = 0\nNO_FILL = 0\nFILL = 1\n# hex representation of colors\n# note that the bit order is blue, red, green\nblack = 0x0000\nred   = 0x07E0\ngreen = 0x001f\nblue  = 0xf800\nwhite = 0xffff\n\n# binary representations of colors\n# binary representations of colors B=5 Blue bits, R=5 Red bits, G=6 green bits\n# color = 0bBBBBBRRRRRGGGGGG\nyellow = 0b0000011111111111\norange = 0b0000001111000010\ncyan = 0b1111100000111111\nbrown = 0b0000000001000001\ngold = 0b0000001110011110\npurple = 0b1111111111000000\nmagenta = 0b0000001100011000\npink = 0b0000111111000010\nolive = 0b0000000001000010\ngray = 0b00001000010000100\nlightGreen = 0b0000100001111111\ndarkGreen  = 0b0000000000000001\n\nColorList =  (red,    green,   blue,   white,   yellow,  orange,\n              cyan, brown, gold, purple, magenta, pink, olive, gray, lightGreen, darkGreen)\nColorNames = ('red', 'green', 'blue', 'white', 'yellow', 'orange',\n              'cyan', 'brown', 'gold', 'purple', 'magenta', 'pink', 'olive', 'gray', 'lightGreen', 'darkGreen')\n\nradius = 120\nLCD.fill(LCD.black)\n\nfor i in range(0, len(ColorList)):\n    print(ColorNames[i])\n    # LCD.ellipse(CENTER, CENTER, radius, radius, ColorList[i], FILL)\n    LCD.fill(ColorList[i])\n    LCD.text(ColorNames[i], 100, 100, 1)\n    LCD.text(ColorNames[i], 100, 120, white)\n    LCD.show()\n    sleep(1)\n

    Note that we are using the fill function to draw on all the pixels on the screen. We could have used the ellipse funtion to draw into the frame buffer, but the fill function is a bit easier.

    "},{"location":"kits/waveshare/02-color-test/#converting-rgb888-to-brg556","title":"Converting RGB888 to BRG556","text":"
    def convert_color_RGB888_RGB565(R,G,B): # Convert RGB888 to RGB565\n    return (((G&0b00011100)<<3) +((B&0b11111000)>>3)<<8) + (R&0b11111000)+((G&0b11100000)>>5)\n
    "},{"location":"kits/waveshare/02-display-text/","title":"Display Time and Date in Text","text":"
    from utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\ndef format_time(now):\n    hour_number = now[3]\n    if hour_number < 13:\n        hour_12 = hour_number\n        am_pm = 'am'\n    else:\n        hour_12 = hour_number - 12\n        am_pm = 'pm'\n    minutes_num = now[4]\n    if minutes_num < 10:\n        min_leading_zero = '0'\n    else:\n        min_leading_zero = ''\n    seconds_num = now[5]\n    if seconds_num < 10:\n        sec_leading_zero = '0'\n    else:\n        sec_leading_zero = ''\n    return \"{}:{}{}:{}{} {}\".format(hour_12, min_leading_zero, minutes_num, sec_leading_zero, seconds_num, am_pm)\n\ndef format_date(now):\n    month_number = now[1]\n    month_name = months[month_number - 1]\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    hour_number = now[3]\n    return \"{} {} {}, {}\".format(day_name, month_name, now[2], now[0])\n\nwhile(True):\n    now = localtime()\n    # print(now)\n    LCD.fill(LCD.black)    \n    LCD.text(format_time(now), 77, 50, LCD.white)\n    LCD.text(format_date(now), 40, 80, LCD.white)\n    LCD.show()\n    sleep(1)\n
    "},{"location":"kits/waveshare/03-drawing-hands/","title":"Drawing Analog Hands","text":"

    Drawing a analog hand requirs drawing a line from the center of the screen to a point on the edge of the circle. The point positon varies periodically, just like the sine and cosine functions vary. We can demonstrate this will a counter that goes from 0 to 360 degrees.

    Consider the following:

    1. Since the sine(0) = 0 we can use that function for the displacement from the center on the x-axis.
    2. Since the cosine(0) = 1, we can use that as the negative Y displacement from the center. Remember in drawing pixels, (0,0) is in the upper-left corner of the screen.

    There is one other bit of math we need to review. The sine() and cosine() function take in a number called radians which is usually a number between 0 and two times Pi. They then return a value between 0 and 1. We need multiple both of these values by the length of the watch hand to get to the right part of the watch face.

    from utime import sleep\nfrom LCD_1inch28 import LCD_1inch28\nimport math\n\nLCD = LCD_1inch28()\n\nCENTER = 120\nHAND_LENGTH = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nwhile True:\n    radians = (counter/60)*TWO_PI\n    x = int(math.sin(radians)*HAND_LENGTH)\n    y = -int(math.cos(radians)*HAND_LENGTH)\n    print(radians, x, y)\n    LCD.fill(LCD.black)\n    LCD.line(CENTER, CENTER, CENTER+x,CENTER+y, LCD.white)\n    LCD.show()\n    sleep(1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0\n

    You should now see a narrow white line moving much like a second hand on a watch!

    "},{"location":"kits/waveshare/03-drawing-hands/#adding-bling-to-your-hands","title":"Adding bling to your hands","text":"

    Although drawing a single white line is a clean efficent design, many people like to add other features such as an arrow head at the tip of the hand. To do this we can use the poly function to draw the arrow. To get this right, we also need to orient the arrow in the right direction.

    "},{"location":"kits/waveshare/03-drawing-hands/#drawing-a-triangle","title":"Drawing a Triangle","text":"

    We can use the MicroPython standard poly function to draw a triangle. The poly

    `FrameBuffer.poly(x, y, coords, c[, f])

    This will draw an arbitrary polygon at the given x, y location using the given color (c).

    The coords must be specified as a array of integers, e.g. array('h', [x0, y0, x1, y1, ... xn, yn]).

    The optional f parameter can be set to True to fill the polygon. Otherwise just a one pixel outline is drawn.

    Let's start with drawing a basic triangle in the center of the screen like this:

    LCD.

    # draw a triangle on a blue background\nfrom utime import sleep\nfrom LCD_1inch28 import LCD_1inch28\nimport math\nfrom array import array\nLCD = LCD_1inch28()\n\nCENTER = 120\nNO_FILL = 0 # just the border is drawn\nFILL = 1 # all pixels within the polygon are drawn\n# draw a blue background\nLCD.fill(LCD.blue)\n\n# distance from the center to the tip of the traiangle\nd = 50\nmy_array = array('B', [CENTER-d,CENTER+d, CENTER,CENTER-d, CENTER+d,CENTER+d])\nLCD.poly(0,0, my_array, LCD.white, FILL)\nLCD.show()\nprint('done')\n
    "},{"location":"kits/waveshare/03-drawing-hands/#drawing-a-triangle-rotating","title":"Drawing a Triangle Rotating","text":"

    Now we will modify the draw triangle program to rotate each of the three points. We do this by passing the CENTER and either a positve or negative value of the x and y which varies as we move around the circle.

    Here is the line that is the most difficult to understand:

    my_array = array('B', [CENTER-x,CENTER-y, CENTER+y,CENTER-x, CENTER+x,CENTER+y])\n

    Note that the first point is in the lower left corner:

    (CENTER-x, CENTER-y)\n

    The second point is at the top of the trainagle and the X is initially zero (sine(0) = y)

    (CENTER+y, CENTER-x)\n

    The third point is to the lower right where we need to add to both the X and Y:

    (CENTER+x, CENTER-y)\n

    Here is the full program:

    # draw rotating triangle\nfrom utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\nfrom array import array\nimport math\nTWO_PI = 3.145175*2\n\nLCD = LCD_1inch28()\n\nCENTER = 120\nNO_FILL = 0 # just the border is drawn\nFILL = 1 # all pixels within the polygon are drawn\n\n# distance from the center to the tip of the traiangle\nd = 50\n\ncounter = 0\nwhile True:\n    LCD.fill(LCD.blue)\n    radians = (counter/60)*TWO_PI\n    x = int(math.cos(radians)*d)\n    y = int(math.sin(radians)*d)\n\n    # the three points of the triangle are rotated in a circle\n    my_array = array('B', [CENTER-x,CENTER-y, CENTER+y,CENTER-x, CENTER+x,CENTER+y])\n    print(CENTER-x, CENTER+y)\n\n    LCD.poly(0,0, my_array, LCD.white, FILL)\n    LCD.show()\n    sleep(.1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0\n

    You might have to stare at the code and the drawing for a while to get this figured out.

    "},{"location":"kits/waveshare/03-drawing-hands/#create-a-draw-triangle-function","title":"Create a Draw Triangle Function","text":"

    Now we are ready to package our triangle drawing experiment into a single function to make it easier to use. We will pass in four parameters:

    1. The center of the triangle's X and Y coordinates
    2. The size of the triangle measured from the center to the tip
    3. The number of seconds on the clock (0 to 59) which we will convert to radians. This becomes the agle of the triangle.
    def drawTriangle(x, y, size, seconds):\n    radians = (seconds/60)*TWO_PI\n    # calculate the offsets\n    xo = int(math.cos(radians)*size)\n    yo = int(math.sin(radians)*size)\n    # build the array - use B if we have under 255 and h if over 255\n    arr = array('B', [x-xo,y-yo,  x+yo,y-xo,  x+xo,y+yo])\n    LCD.poly(0,0, arr, LCD.white, FILL)\n
    "},{"location":"kits/waveshare/03-drawing-hands/#full-program","title":"Full Program","text":"
    from utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\nfrom array import array\nimport math\nTWO_PI = 3.145175*2\n\nLCD = LCD_1inch28()\n\nCENTER = 120\nNO_FILL = 0 # just the border is drawn\nFILL = 1 # all pixels within the polygon are drawn\nHAND_LENGTH = 100\nTRIANGLE_SIZE = 10\n\ndef drawTriangle(x, y, size, seconds):\n    radians = (seconds/60)*TWO_PI\n    # calculate the offsets\n    xo = int(math.cos(radians)*size)\n    yo = int(math.sin(radians)*size)\n    # build the array - use B if we have under 255 and h if over 255\n    arr = array('B', [x-xo,y-yo,  x+yo,y-xo,  x+xo,y+yo])\n    LCD.poly(0,0, arr, LCD.white, FILL)\n\ncounter = 0\nwhile True:\n    LCD.fill(LCD.blue)\n    radians = (counter/60)*TWO_PI\n    x = int(math.sin(radians)*HAND_LENGTH)\n    y = -int(math.cos(radians)*HAND_LENGTH)\n    LCD.line(CENTER, CENTER, CENTER+x,CENTER+y, LCD.white)\n    drawTriangle(CENTER+x, CENTER+y, TRIANGLE_SIZE, counter)\n    LCD.show()\n    sleep(.1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0```\n
    "},{"location":"kits/waveshare/03-drawing-hands/#drawing-x-and-y-axis","title":"Drawing X and Y Axis","text":"
    # draw thin blue axis lines through the center\n# vertical line\nLCD.line(CENTER, 0, CENTER, 2*CENTER, blue)\n# horizontal line\nLCD.line(0, CENTER, 2*CENTER, CENTER, blue)\n
    "},{"location":"kits/waveshare/04-5x8-font/","title":"5x8 Font Test","text":"

    We can create custom functions for drawing larger fonts. Here we have a byte array of 5X8 fonts. The function character() draws individual characters one at a time.

    from LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \n\n# Standard ASCII 5x8 font\n# https://gist.github.com/tdicola/229b3eeddc12d58fb0bc724a9062aa05\nFONT_HEIGHT = 8\nFONT_WIDTH = 5\nFONT = bytes([\n    0x00, 0x00, 0x00, 0x00, 0x00, # <space>\n    0x3E, 0x5B, 0x4F, 0x5B, 0x3E,\n    0x3E, 0x6B, 0x4F, 0x6B, 0x3E,\n    0x1C, 0x3E, 0x7C, 0x3E, 0x1C,\n    0x18, 0x3C, 0x7E, 0x3C, 0x18,\n    0x1C, 0x57, 0x7D, 0x57, 0x1C,\n    0x1C, 0x5E, 0x7F, 0x5E, 0x1C,\n    0x00, 0x18, 0x3C, 0x18, 0x00,\n    0xFF, 0xE7, 0xC3, 0xE7, 0xFF,\n    0x00, 0x18, 0x24, 0x18, 0x00,\n    0xFF, 0xE7, 0xDB, 0xE7, 0xFF,\n    0x30, 0x48, 0x3A, 0x06, 0x0E,\n    0x26, 0x29, 0x79, 0x29, 0x26,\n    0x40, 0x7F, 0x05, 0x05, 0x07,\n    0x40, 0x7F, 0x05, 0x25, 0x3F,\n    0x5A, 0x3C, 0xE7, 0x3C, 0x5A,\n    0x7F, 0x3E, 0x1C, 0x1C, 0x08,\n    0x08, 0x1C, 0x1C, 0x3E, 0x7F,\n    0x14, 0x22, 0x7F, 0x22, 0x14,\n    0x5F, 0x5F, 0x00, 0x5F, 0x5F,\n    0x06, 0x09, 0x7F, 0x01, 0x7F,\n    0x00, 0x66, 0x89, 0x95, 0x6A,\n    0x60, 0x60, 0x60, 0x60, 0x60,\n    0x94, 0xA2, 0xFF, 0xA2, 0x94,\n    0x08, 0x04, 0x7E, 0x04, 0x08, # UP\n    0x10, 0x20, 0x7E, 0x20, 0x10, # Down\n    0x08, 0x08, 0x2A, 0x1C, 0x08, # Right\n    0x08, 0x1C, 0x2A, 0x08, 0x08, # Left\n    0x1E, 0x10, 0x10, 0x10, 0x10,\n    0x0C, 0x1E, 0x0C, 0x1E, 0x0C,\n    0x30, 0x38, 0x3E, 0x38, 0x30,\n    0x06, 0x0E, 0x3E, 0x0E, 0x06,\n    0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x5F, 0x00, 0x00,\n    0x00, 0x07, 0x00, 0x07, 0x00,\n    0x14, 0x7F, 0x14, 0x7F, 0x14,\n    0x24, 0x2A, 0x7F, 0x2A, 0x12,\n    0x23, 0x13, 0x08, 0x64, 0x62,\n    0x36, 0x49, 0x56, 0x20, 0x50,\n    0x00, 0x08, 0x07, 0x03, 0x00,\n    0x00, 0x1C, 0x22, 0x41, 0x00,\n    0x00, 0x41, 0x22, 0x1C, 0x00,\n    0x2A, 0x1C, 0x7F, 0x1C, 0x2A,\n    0x08, 0x08, 0x3E, 0x08, 0x08,\n    0x00, 0x80, 0x70, 0x30, 0x00,\n    0x08, 0x08, 0x08, 0x08, 0x08,\n    0x00, 0x00, 0x60, 0x60, 0x00,\n    0x20, 0x10, 0x08, 0x04, 0x02,\n    0x3E, 0x51, 0x49, 0x45, 0x3E,\n    0x00, 0x42, 0x7F, 0x40, 0x00,\n    0x72, 0x49, 0x49, 0x49, 0x46,\n    0x21, 0x41, 0x49, 0x4D, 0x33,\n    0x18, 0x14, 0x12, 0x7F, 0x10,\n    0x27, 0x45, 0x45, 0x45, 0x39,\n    0x3C, 0x4A, 0x49, 0x49, 0x31,\n    0x41, 0x21, 0x11, 0x09, 0x07,\n    0x36, 0x49, 0x49, 0x49, 0x36,\n    0x46, 0x49, 0x49, 0x29, 0x1E,\n    0x00, 0x00, 0x14, 0x00, 0x00,\n    0x00, 0x40, 0x34, 0x00, 0x00,\n    0x00, 0x08, 0x14, 0x22, 0x41,\n    0x14, 0x14, 0x14, 0x14, 0x14,\n    0x00, 0x41, 0x22, 0x14, 0x08,\n    0x02, 0x01, 0x59, 0x09, 0x06,\n    0x3E, 0x41, 0x5D, 0x59, 0x4E,\n    0x7C, 0x12, 0x11, 0x12, 0x7C, # A\n    0x7F, 0x49, 0x49, 0x49, 0x36,\n    0x3E, 0x41, 0x41, 0x41, 0x22,\n    0x7F, 0x41, 0x41, 0x41, 0x3E,\n    0x7F, 0x49, 0x49, 0x49, 0x41,\n    0x7F, 0x09, 0x09, 0x09, 0x01,\n    0x3E, 0x41, 0x41, 0x51, 0x73,\n    0x7F, 0x08, 0x08, 0x08, 0x7F,\n    0x00, 0x41, 0x7F, 0x41, 0x00,\n    0x20, 0x40, 0x41, 0x3F, 0x01,\n    0x7F, 0x08, 0x14, 0x22, 0x41,\n    0x7F, 0x40, 0x40, 0x40, 0x40,\n    0x7F, 0x02, 0x1C, 0x02, 0x7F,\n    0x7F, 0x04, 0x08, 0x10, 0x7F,\n    0x3E, 0x41, 0x41, 0x41, 0x3E,\n    0x7F, 0x09, 0x09, 0x09, 0x06,\n    0x3E, 0x41, 0x51, 0x21, 0x5E,\n    0x7F, 0x09, 0x19, 0x29, 0x46,\n    0x26, 0x49, 0x49, 0x49, 0x32,\n    0x03, 0x01, 0x7F, 0x01, 0x03,\n    0x3F, 0x40, 0x40, 0x40, 0x3F,\n    0x1F, 0x20, 0x40, 0x20, 0x1F,\n    0x3F, 0x40, 0x38, 0x40, 0x3F,\n    0x63, 0x14, 0x08, 0x14, 0x63,\n    0x03, 0x04, 0x78, 0x04, 0x03,\n    0x61, 0x59, 0x49, 0x4D, 0x43,\n    0x00, 0x7F, 0x41, 0x41, 0x41,\n    0x02, 0x04, 0x08, 0x10, 0x20,\n    0x00, 0x41, 0x41, 0x41, 0x7F,\n    0x04, 0x02, 0x01, 0x02, 0x04,\n    0x40, 0x40, 0x40, 0x40, 0x40,\n    0x00, 0x03, 0x07, 0x08, 0x00,\n    0x20, 0x54, 0x54, 0x78, 0x40,\n    0x7F, 0x28, 0x44, 0x44, 0x38,\n    0x38, 0x44, 0x44, 0x44, 0x28,\n    0x38, 0x44, 0x44, 0x28, 0x7F,\n    0x38, 0x54, 0x54, 0x54, 0x18,\n    0x00, 0x08, 0x7E, 0x09, 0x02,\n    0x18, 0xA4, 0xA4, 0x9C, 0x78,\n    0x7F, 0x08, 0x04, 0x04, 0x78,\n    0x00, 0x44, 0x7D, 0x40, 0x00,\n    0x20, 0x40, 0x40, 0x3D, 0x00,\n    0x7F, 0x10, 0x28, 0x44, 0x00,\n    0x00, 0x41, 0x7F, 0x40, 0x00,\n    0x7C, 0x04, 0x78, 0x04, 0x78,\n    0x7C, 0x08, 0x04, 0x04, 0x78,\n    0x38, 0x44, 0x44, 0x44, 0x38,\n    0xFC, 0x18, 0x24, 0x24, 0x18,\n    0x18, 0x24, 0x24, 0x18, 0xFC,\n    0x7C, 0x08, 0x04, 0x04, 0x08,\n    0x48, 0x54, 0x54, 0x54, 0x24,\n    0x04, 0x04, 0x3F, 0x44, 0x24,\n    0x3C, 0x40, 0x40, 0x20, 0x7C,\n    0x1C, 0x20, 0x40, 0x20, 0x1C,\n    0x3C, 0x40, 0x30, 0x40, 0x3C,\n    0x44, 0x28, 0x10, 0x28, 0x44,\n    0x4C, 0x90, 0x90, 0x90, 0x7C,\n    0x44, 0x64, 0x54, 0x4C, 0x44,\n    0x00, 0x08, 0x36, 0x41, 0x00,\n    0x00, 0x00, 0x77, 0x00, 0x00,\n    0x00, 0x41, 0x36, 0x08, 0x00,\n    0x02, 0x01, 0x02, 0x04, 0x02,\n    0x3C, 0x26, 0x23, 0x26, 0x3C,\n    0x1E, 0xA1, 0xA1, 0x61, 0x12, # Extension starts here\n    0x3A, 0x40, 0x40, 0x20, 0x7A,\n    0x38, 0x54, 0x54, 0x55, 0x59,\n    0x21, 0x55, 0x55, 0x79, 0x41,\n    0x22, 0x54, 0x54, 0x78, 0x42, # a-umlaut\n    0x21, 0x55, 0x54, 0x78, 0x40,\n    0x20, 0x54, 0x55, 0x79, 0x40,\n    0x0C, 0x1E, 0x52, 0x72, 0x12,\n    0x39, 0x55, 0x55, 0x55, 0x59,\n    0x39, 0x54, 0x54, 0x54, 0x59,\n    0x39, 0x55, 0x54, 0x54, 0x58,\n    0x00, 0x00, 0x45, 0x7C, 0x41,\n    0x00, 0x02, 0x45, 0x7D, 0x42,\n    0x00, 0x01, 0x45, 0x7C, 0x40,\n    0x7D, 0x12, 0x11, 0x12, 0x7D, # A-umlaut\n    0xF0, 0x28, 0x25, 0x28, 0xF0,\n    0x7C, 0x54, 0x55, 0x45, 0x00,\n    0x20, 0x54, 0x54, 0x7C, 0x54,\n    0x7C, 0x0A, 0x09, 0x7F, 0x49,\n    0x32, 0x49, 0x49, 0x49, 0x32,\n    0x3A, 0x44, 0x44, 0x44, 0x3A, # o-umlaut\n    0x32, 0x4A, 0x48, 0x48, 0x30,\n    0x3A, 0x41, 0x41, 0x21, 0x7A,\n    0x3A, 0x42, 0x40, 0x20, 0x78,\n    0x00, 0x9D, 0xA0, 0xA0, 0x7D,\n    0x3D, 0x42, 0x42, 0x42, 0x3D, # O-umlaut\n    0x3D, 0x40, 0x40, 0x40, 0x3D,\n    0x3C, 0x24, 0xFF, 0x24, 0x24,\n    0x48, 0x7E, 0x49, 0x43, 0x66,\n    0x2B, 0x2F, 0xFC, 0x2F, 0x2B,\n    0xFF, 0x09, 0x29, 0xF6, 0x20,\n    0xC0, 0x88, 0x7E, 0x09, 0x03,\n    0x20, 0x54, 0x54, 0x79, 0x41,\n    0x00, 0x00, 0x44, 0x7D, 0x41,\n    0x30, 0x48, 0x48, 0x4A, 0x32,\n    0x38, 0x40, 0x40, 0x22, 0x7A,\n    0x00, 0x7A, 0x0A, 0x0A, 0x72,\n    0x7D, 0x0D, 0x19, 0x31, 0x7D,\n    0x26, 0x29, 0x29, 0x2F, 0x28,\n    0x26, 0x29, 0x29, 0x29, 0x26,\n    0x30, 0x48, 0x4D, 0x40, 0x20,\n    0x38, 0x08, 0x08, 0x08, 0x08,\n    0x08, 0x08, 0x08, 0x08, 0x38,\n    0x2F, 0x10, 0xC8, 0xAC, 0xBA,\n    0x2F, 0x10, 0x28, 0x34, 0xFA,\n    0x00, 0x00, 0x7B, 0x00, 0x00,\n    0x08, 0x14, 0x2A, 0x14, 0x22,\n    0x22, 0x14, 0x2A, 0x14, 0x08,\n    0x55, 0x00, 0x55, 0x00, 0x55, # 176 (25% block) missing in old code\n    0xAA, 0x55, 0xAA, 0x55, 0xAA, # 50% block\n    0xFF, 0x55, 0xFF, 0x55, 0xFF, # 75% block\n    0x00, 0x00, 0x00, 0xFF, 0x00,\n    0x10, 0x10, 0x10, 0xFF, 0x00,\n    0x14, 0x14, 0x14, 0xFF, 0x00,\n    0x10, 0x10, 0xFF, 0x00, 0xFF,\n    0x10, 0x10, 0xF0, 0x10, 0xF0,\n    0x14, 0x14, 0x14, 0xFC, 0x00,\n    0x14, 0x14, 0xF7, 0x00, 0xFF,\n    0x00, 0x00, 0xFF, 0x00, 0xFF,\n    0x14, 0x14, 0xF4, 0x04, 0xFC,\n    0x14, 0x14, 0x17, 0x10, 0x1F,\n    0x10, 0x10, 0x1F, 0x10, 0x1F,\n    0x14, 0x14, 0x14, 0x1F, 0x00,\n    0x10, 0x10, 0x10, 0xF0, 0x00,\n    0x00, 0x00, 0x00, 0x1F, 0x10,\n    0x10, 0x10, 0x10, 0x1F, 0x10,\n    0x10, 0x10, 0x10, 0xF0, 0x10,\n    0x00, 0x00, 0x00, 0xFF, 0x10,\n    0x10, 0x10, 0x10, 0x10, 0x10,\n    0x10, 0x10, 0x10, 0xFF, 0x10,\n    0x00, 0x00, 0x00, 0xFF, 0x14,\n    0x00, 0x00, 0xFF, 0x00, 0xFF,\n    0x00, 0x00, 0x1F, 0x10, 0x17,\n    0x00, 0x00, 0xFC, 0x04, 0xF4,\n    0x14, 0x14, 0x17, 0x10, 0x17,\n    0x14, 0x14, 0xF4, 0x04, 0xF4,\n    0x00, 0x00, 0xFF, 0x00, 0xF7,\n    0x14, 0x14, 0x14, 0x14, 0x14,\n    0x14, 0x14, 0xF7, 0x00, 0xF7,\n    0x14, 0x14, 0x14, 0x17, 0x14,\n    0x10, 0x10, 0x1F, 0x10, 0x1F,\n    0x14, 0x14, 0x14, 0xF4, 0x14,\n    0x10, 0x10, 0xF0, 0x10, 0xF0, # ok\n    0x00, 0x00, 0x1F, 0x10, 0x1F,\n    0x00, 0x00, 0x00, 0x1F, 0x14,\n#   0x00, 0x00, 0x00, 0xFC, 0x14, # any new after this line breaks\n    0x00, 0x00, 0x00, 0x00, 0x00  # 255 also a <space>\n])\n\ndef convert_color_RGB888_RGB565(R,G,B): # Convert RGB888 to RGB565\n    return (((G&0b00011100)<<3) + ((B&0b11111000)>>3)<<8) + (R&0b11111000) + ((G&0b11100000)>>5)\n\ndef character(asc, xt, yt, sz, r, g, b):  # Single character sz is size: 1 or 2\n    cc = convert_color_RGB888_RGB565(r,g,b)\n    code = asc * 5    # 5 bytes per character\n    for ii in range(5):\n        line = FONT[code + ii]\n        for yy in range(8):\n            if (line >> yy) & 0x1:\n                LCD.pixel(ii*sz+xt,yy*sz+yt,cc) \n                if sz > 1:\n                    LCD.pixel(ii*sz+xt+1,yy*sz+yt,cc)\n                    LCD.pixel(ii*sz+xt,yy*sz+yt+1,cc)\n                    LCD.pixel(ii*sz+xt+1,yy*sz+yt+1,cc)\n                if sz == 3:\n                    LCD.pixel(ii*sz+xt,  yy*sz+yt+2,cc)\n                    LCD.pixel(ii*sz+xt+1,yy*sz+yt+2,cc)\n                    LCD.pixel(ii*sz+xt+2,yy*sz+yt+2,cc)\n                    LCD.pixel(ii*sz+xt+2,yy*sz+yt,cc)\n                    LCD.pixel(ii*sz+xt+2,yy*sz+yt+1,cc)\n\n# Print a string\ndef prnt_st(asci, xx, yy, sz,r,g,b):  # Text string\n    if sz == 1: move = 6\n    if sz == 2: move = 11\n    if sz == 3: move = 17 \n    for letter in(asci):\n        asci = ord(letter)\n        character(asci,xx,yy,sz,r,g,b)\n        xx = xx + move\n\n# Center text string\ndef cntr_st(s,y,sz,r,g,b): # Centres text on line y\n    if sz == 1: w = 6\n    if sz == 2: w = 11\n    if sz == 3: w = 17 \n    gap = int((width - len(s) * w)/2)\n    prnt_st(s,gap,y,sz,r,g,b)\n\nLCD.fill(LCD.black)    \nprnt_st(\"Hello world! Red\", 20, 80, 2, 255, 0, 0)\nprnt_st(\"Hello world! Green\", 20, 100, 2, 0, 255, 0)\nprnt_st(\"Hello world! Blue\", 20, 120, 2, 0, 0, 255)\nprnt_st(\"Hello world! White\", 20, 140, 2, 255, 255, 255)\nLCD.show()\n
    "},{"location":"lessons/","title":"Python Project-Based Learning: Building Clocks and Watches with Smart Watch Displays","text":"

    These lessons are general to all of our kits. We often use the Pico OLED for many examples since that is the kit we have been using for the longest time.

    These lessons focus on using functions like the MicroPython localtime() to get the time in your current timezone.

    They also focus on drawing scalable numbers on different size displays and drawing times on larger color displays.

    Here are some sample lesson plans for a 14-week semimester hich school course on learning computational thining by using MicroPython to write clock and smartwatch application. This course assumes no prior knowledge of programming.

    "},{"location":"lessons/#weeks-1-2-introduction-to-python-and-basic-concepts","title":"Weeks 1-2: Introduction to Python and Basic Concepts","text":""},{"location":"lessons/#lesson-1-introduction-to-python","title":"Lesson 1: Introduction to Python","text":"
    • What is Python?
    • Why learn Python?
    • Data Science
    • Artificial Intellegence
    • Python Installation and Setup
    "},{"location":"lessons/#lesson-2-hello-world","title":"Lesson 2: Hello, World!","text":"
    • Writing the first Python program
    • Drawing a simple rectangle to the screen
    • Making the rectangle bounce around the screen
    • Understanding Python syntax
    • Using the graphics library for your clock or watch
    "},{"location":"lessons/#lesson-3-variables-and-data-types","title":"Lesson 3: Variables and Data Types","text":"
    • Introduction to variables
    • Common data types (integers, floats, strings, booleans)
    • Drawing with pixels, lines and rectangles
    • Chainging color
    "},{"location":"lessons/#lesson-4-basic-operations","title":"Lesson 4: Basic Operations","text":"
    • Arithmetic operations
    • Concatenation and repetition
    • Assignment operators
    • Lists of colors
    "},{"location":"lessons/#weeks-3-4-control-structures-and-functions","title":"Weeks 3-4: Control Structures and Functions","text":""},{"location":"lessons/#lesson-5-conditionals","title":"Lesson 5: Conditionals","text":"
    • if, else, and elif statements
    • Alternating the color of your lines
    • Horizontal and radial lines
    "},{"location":"lessons/#lesson-6-loops","title":"Lesson 6: Loops","text":"
    • for and while loops
    • Loop control with break and continue
    • Draing the tick marks on a watch
    "},{"location":"lessons/#lesson-7-functions","title":"Lesson 7: Functions","text":"
    • Defining and calling functions
    • Arguments and return values
    "},{"location":"lessons/#weeks-5-6-working-with-libraries-and-hardware","title":"Weeks 5-6: Working with Libraries and Hardware","text":""},{"location":"lessons/#lesson-8-importing-libraries","title":"Lesson 8: Importing Libraries","text":"
    • What is a library?
    • Importing and using libraries
    "},{"location":"lessons/#lesson-9-introduction-to-hardware-interaction","title":"Lesson 9: Introduction to Hardware Interaction","text":"
    • Communicating with smart watch displays
    • Sending and receiving data
    "},{"location":"lessons/#weeks-7-8-project-1-basic-digital-clock","title":"Weeks 7-8: Project 1: Basic Digital Clock","text":""},{"location":"lessons/#lesson-10-planning-the-project","title":"Lesson 10: Planning the Project","text":"
    • Project overview
    • Creating a project plan
    "},{"location":"lessons/#lesson-11-building-a-basic-digital-clock","title":"Lesson 11: Building a Basic Digital Clock","text":"
    • Displaying time on the smart watch display
    • Updating the time
    "},{"location":"lessons/#weeks-9-10-intermediate-python-concepts","title":"Weeks 9-10: Intermediate Python Concepts","text":""},{"location":"lessons/#lesson-12-lists-and-dictionaries","title":"Lesson 12: Lists and Dictionaries","text":"
    • Creating and manipulating lists and dictionaries
    "},{"location":"lessons/#lesson-13-error-handling","title":"Lesson 13: Error Handling","text":"
    • try and except blocks
    "},{"location":"lessons/#weeks-11-12-project-2-analog-clock-display","title":"Weeks 11-12: Project 2: Analog Clock Display","text":""},{"location":"lessons/#lesson-14-planning-the-project","title":"Lesson 14: Planning the Project","text":"
    • Project overview
    • Creating a project plan
    "},{"location":"lessons/#lesson-15-building-an-analog-clock-display","title":"Lesson 15: Building an Analog Clock Display","text":"
    • Designing an analog clock
    • Rotating clock hands based on the current time
    "},{"location":"lessons/#weeks-13-14-advanced-python-concepts-and-optimization","title":"Weeks 13-14: Advanced Python Concepts and Optimization","text":""},{"location":"lessons/#lesson-16-more-about-functions","title":"Lesson 16: More About Functions","text":"
    • Lambda functions, higher-order functions
    "},{"location":"lessons/#lesson-17-optimization-techniques","title":"Lesson 17: Optimization Techniques","text":"
    • Improving code efficiency
    "},{"location":"lessons/#weeks-15-16-final-project-customizable-clockwatch","title":"Weeks 15-16: Final Project: Customizable Clock/Watch","text":""},{"location":"lessons/#lesson-18-planning-the-project","title":"Lesson 18: Planning the Project","text":"
    • Project overview
    • Creating a project plan
    "},{"location":"lessons/#lesson-19-building-a-customizable-clockwatch","title":"Lesson 19: Building a Customizable Clock/Watch","text":"
    • Adding customization options (color, style, etc.)
    • Implementing user input for customization
    "},{"location":"lessons/#lesson-20-final-project-presentations","title":"Lesson 20: Final Project Presentations","text":"
    • Students present their final projects
    • Review and feedback session
    "},{"location":"lessons/#ongoing-reflection-and-feedback","title":"Ongoing: Reflection and Feedback","text":"
    • After each project, have students reflect on what went well, what they struggled with, and what they learned.
    • Continuously solicit feedback from students to improve the learning experience.

    This outline provides a balance between teaching Python concepts and applying them to real-world projects, which can keep students engaged and help them to better retain what they've learned. Tailor this outline to meet the specific needs and pace of your students, and ensure to provide plenty of opportunities for students to practice their skills, ask questions, and get feedback.

    "},{"location":"lessons/00-hardware-config/","title":"Hardware Configuration Files","text":"

    All our current displays use the SPI interface. The alternative microcontroller bus, I2C, is about 10x slower than SPI. The SPI intrface interface typically uses 7 wires, which can get a little complex. Just a single wire broken or two wires crossed can will cause the display to not work.

    We have dozens of sample programs for each kit. And the exact connections on our kits vary. Rather than hard-coding the hardware pin numbers in each example, we can move them to a separate config.py file. We can then just import that file into each of our examples.

    Here is a sample config.py file:

    # Dan's Robot Labs configuration file for ILI9341 clock project\n# The colors on the SPI bus cable are:\n# 3.3v power - red\n# SCK - orange\n# MISO/Data - yellow\n# DC - green\n# RESET - blue\n# GND - black\n# CS - purple\n\nSCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\nBUTTON_1_PIN = 14 # one up from lower-left corner\nBUTTON_2_PIN = 15 # lower left corner with USB on top\n

    To use this configuration file you will need to do two things:

    1. import the config file (don't add the .py extension)
    2. Add the prefix config. to each value you would like to reference.
    import config\n\nWIDTH=config.WIDTH\n
    "},{"location":"lessons/01-drawing-coordinates/","title":"Drawing Coordinates","text":"

    Screen Coordinates Lab on Robot Faces

    "},{"location":"lessons/01-get-local-time/","title":"Getting Local Time","text":""},{"location":"lessons/01-get-local-time/#lesson-overview","title":"Lesson Overview","text":"

    In this lesson, we will learn how to get the local date and time from the MicroPython runtime using the standard localtime() function. We will learn about how to use the eight integers returned by the localtime() functions.

    MicroPython provides a very convenient function called localtime() that will get the time from the host computer in your local timezone that you connect to via your USB cable. Your local computer has a clock and knows the time in the local timezone. This information is usually sent to MicroPython runtime when the computer is connected to the USB cable.

    Note

    The gmtime() function returns the time in UTC (Coordinated Universal Time) time. Use this if you want time stamps that are not dependent on time zone and daylight savings rules. For example, log files should use this function.

    "},{"location":"lessons/01-get-local-time/#sample-code","title":"Sample Code","text":"
    import time\n\nprint(time.localtime())\n
    "},{"location":"lessons/01-get-local-time/#result","title":"Result","text":"

    Local time returns a read-only tuple:

    (2023, 2, 28, 18, 54, 7, 1, 59)\n
    "},{"location":"lessons/01-get-local-time/#extracting-specific-datetime-components","title":"Extracting Specific Date/Time Components","text":"
    from time import localtime\n\nnow = localtime()\nprint(now)\n\nprint('year:',    now[0])\nprint('month:',   now[1])\nprint('day:',     now[2])\nprint('hour:',    now[3])\nprint('minute:',  now[4])\nprint('sec:',     now[5])\nprint('weekday:', now[6])\nprint('day of year:', now[7])\n
    "},{"location":"lessons/01-get-local-time/#format-of-the-localtime","title":"Format of the Localtime","text":"

    The format is a \"8-tuple\" of integers in the format (year, month, mday, hour, minute, second, weekday, yearday)

    Most of the values are pretty intuitive to figure out. There are a few notes.

    1. Hour is the hour in 24-hour format. If we want to display the hour in 12-hour format we will need to do some formatting.
    2. Weekday is a numeric code that runs from 0 for Monday to 6 for Sunday.
    3. Yearday is the day of the year. January 1st is the fist day of the year so it is a 1 (not 0).
    "},{"location":"lessons/01-get-local-time/#printing-formatted-dates","title":"Printing Formatted Dates","text":""},{"location":"lessons/01-get-local-time/#sample-code_1","title":"Sample Code","text":"
    import time\n\nnow = time.localtime()\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\nfor i in range(8):\n    print(label[i], ':', now[i])\n\nprint()\nprint(\"Date: {}/{}/{}\".format(now[1], now[2], now[0]))\nprint(\"Time: {}:{}\".format(now[3], now[4]))\n
    "},{"location":"lessons/01-get-local-time/#results","title":"Results","text":"
    year : 2023\nmonth : 2\nmday : 28\nhour : 19\nminute : 20\nsecond : 26\nweekday : 1\nyearday : 59\n\nDate: 2/28/2023\nTime: 19:20\n
    "},{"location":"lessons/01-get-local-time/#label-formatting","title":"Label Formatting","text":"

    We can also add labels to make the date and time easier to read.

    import time\n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\n\nnow = time.localtime()\n\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\nmonth_number = now[1]\nmonth_name = months[month_number]\nweekday_number = now[6]\nday_name = days[weekday_number]\nhour_number = now[3]\nif hour_number < 13:\n    hour_12 = hour_number\n    am_pm = 'am'\nelse:\n    hour_12 = hour_number - 12\n    am_pm = 'pm'\n\nprint()\nprint(\"Date: {} {} {}, {}\".format(day_name, month_name, now[2], now[0]))\nprint(\"Time: {}:{} {}\".format(hour_12, now[4], am_pm))\n
    "},{"location":"lessons/01-get-local-time/#label-formatted-results","title":"Label Formatted Results","text":"
    Date: Tuesday March 28, 2023\nTime: 7:46 pm\n
    "},{"location":"lessons/01-get-local-time/#modifying-the-thonny-parameters","title":"Modifying the Thonny Parameters","text":"

    By default Thonny syncs the host time at power up.

    However, to test that our code is setting the correct local time we will need to disable this in future labs.

    After we do this, the localtime() will return the number of seconds after midnight on January 1st, 2021.

    import time\nprint(time.localtime())\n

    (2021, 1, 1, 0, 0, 22, 4, 1)\n
    This was printed 22 seconds after power up.

    We will used this when we use a RTC and use the Pico \"W\" to sync with the NTP functions.

    from mpython import *\nimport ntptime\nimport secrets\n\n# summary\nmywifi=wifi()\nmywifi.connectWiFi(secrets.wifi_ssid, secrets.wifi_pass)\n\nprint(\"Local time before synchronization\uff1a%s\" %str(time.localtime()))\nntptime.settime()\nprint(\"Local time after synchronization\uff1a%s\" %str(time.localtime()))\n

    Result:

    Local time before synchronization\uff1a(2021, 1, 1, 0, 3, 31, 4, 1)\nLocal time after synchronization\uff1a(2023, 10, 16, 20, 16, 59, 0, 289)\n
    "},{"location":"lessons/01-get-local-time/#references","title":"References","text":"
    • MicroPython Time Documents
    • Bhavesh Kakwani's blog Sync time in MicroPython using NTP - although the blog uses an ESP32, the concepts are the same on other processors such as the Raspberry Pi Pico.
    "},{"location":"lessons/02-display-text/","title":"Display Time and Date in Text","text":"
    from utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\ndef format_time(now):\n    hour_number = now[3]\n    if hour_number < 13:\n        hour_12 = hour_number\n        am_pm = 'am'\n    else:\n        hour_12 = hour_number - 12\n        am_pm = 'pm'\n    minutes_num = now[4]\n    if minutes_num < 10:\n        min_leading_zero = '0'\n    else:\n        min_leading_zero = ''\n    seconds_num = now[5]\n    if seconds_num < 10:\n        sec_leading_zero = '0'\n    else:\n        sec_leading_zero = ''\n    return \"{}:{}{}:{}{} {}\".format(hour_12, min_leading_zero, minutes_num, sec_leading_zero, seconds_num, am_pm)\n\ndef format_date(now):\n    month_number = now[1]\n    month_name = months[month_number - 1]\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    hour_number = now[3]\n    return \"{} {} {}, {}\".format(day_name, month_name, now[2], now[0])\n\nwhile(True):\n    now = localtime()\n    # print(now)\n    LCD.fill(LCD.black)    \n    LCD.text(format_time(now), 77, 50, LCD.white)\n    LCD.text(format_date(now), 40, 80, LCD.white)\n    LCD.show()\n    sleep(1)\n
    "},{"location":"lessons/03-drawing-face/","title":"Drawing Watch Faces","text":"

    An analog watch ususally has hands that are drawn from the center to the edge of the display.

    The lines or marks that indicate the hours are often referred to as \"hour indices\" or \"hour markers.\"

    The smaller lines that indicate the minutes are called \"minute indices\" or \"minute markers.\"

    For simple lines, we can use the line(x1,y1, x2,y2,color) function which draws a sinle pixel line from the starting point at (x1,y1) to the end pint at (x2,y2) using the fifth color parameter. For monochrome clocks the color 1 is whtie and 0 is black.

    For thinker lines we can use the display.rect() function.

    Some watches have more complex hands that are composed of multiple geometries such as triangles.

    For most modern display drivers we can use the MicroPython poly() function to draw polygons on the screen. These are part of the MicroPython framebuf function.

    Some older drivers don't yet support these functions, so we might have to craft our own functions.

    "},{"location":"lessons/03-drawing-face/#references","title":"References","text":"

    Instructables on Filled Circles and Triangles by TonyGo2

    "},{"location":"lessons/04-larger-fonts/","title":"Larger Fonts","text":"

    Many display libraries use the MicroPython framebuf standards that only provide for a single font. This is sometimes fine for simple small displays, but it is sometimes insufficient for some projects where either a smaller or larger font is used.

    The ssd1306 driver is a good example of the default behaviour of text drawing. Only a single font is suppied.

    display.text('Hello, World!', 0, 0, 1)\ndisplay.show()\n

    Some display drivers allow you to change the default font:

    LCD160 Set Font

    Font to Py Command

    Sample Font Files

    "},{"location":"lessons/04-larger-fonts/#references","title":"References","text":"

    Peter Hinch's Font to Python Utility - a utility takes input a font file in ttf or otf form together with a height in pixels and outputs a Python source file containing the font as a bitmap.

    Peter Hinch's Nano GUI

    Les' Lab: Designing your own Pico fonts - Raspberry Pi Pico display fonts in MicroPython: How to design fonts for your Pi Pico project.

    "},{"location":"lessons/05-buttons/","title":"Buttons","text":"

    Our standard watch kit places two buttons on the breadboard. You can use these buttons to set the time.

    The buttons are connected to the lower-left corner of the pico using GPIO 14 and GPIO 15.

    Instructions on how to use these buttons are covered in our MicroPython class:

    Using Buttons in MicroPython

    We suggest using the top blue button to change the mode of operation. As you press this you cycle through various modes of your clock or watch. Here are some sample modes for a clock:

    1. Run mode
    2. Set current time hour
    3. Set current time minute
    4. Set alarm hour
    5. Set alarm minute

    After you are in a given mode, the bottom button can be used to cycle through the options. Remember to get the current value for the cycle for each mode. So if you are adjusting the hour you have to make sure the cycle value starts at the current hour.

    "},{"location":"lessons/05-buttons/#sample-button-mode-code","title":"Sample Button Mode Code","text":"
    from utime import sleep, ticks_ms\nfrom machine import Pin\n\n# Sample Raspberry Pi Pico MicroPython button press example with a debounce delay value of 200ms in the interrupt handler\n\n# Config\nMODE_BUTTON_PIN = 14\nCYCLE_BUTTON_PIN = 15\nmode = 0 # the count of times the button has been pressed\ncycle = 0\nlast_time = 0 # the last time we pressed the button\n\nbuiltin_led = machine.Pin(25, Pin.OUT)\n# The lower left corner of the Pico has a wire that goes through the buttons upper left and the lower right goes to the 3.3 rail\nmode_pin = machine.Pin(MODE_BUTTON_PIN, machine.Pin.IN, machine.Pin.PULL_UP)\ncycle_pin = machine.Pin(CYCLE_BUTTON_PIN, machine.Pin.IN, machine.Pin.PULL_UP)\n\n# This function gets called every time the button is pressed.  The parameter \"pin\" is not used.\ndef button_pressed_handler(pin):\n    global mode, cycle, last_time\n    new_time = ticks_ms()\n    # if it has been more that 1/5 of a second since the last event, we have a new event\n    if (new_time - last_time) > 200:\n        # this should be pin.id but it does not work\n        if '14' in str(pin):\n            mode +=1\n        else:\n            cycle +=1\n        # last, we update the last time we got an ISR here\n        last_time = new_time\n\n\n# now we register the handler function when the button is pressed\nmode_pin.irq(trigger=machine.Pin.IRQ_FALLING, handler = button_pressed_handler)\ncycle_pin.irq(trigger=machine.Pin.IRQ_FALLING, handler = button_pressed_handler)\n\n# This is for only printing when a new button press count value happens\nold_mode = 0\nold_cycle = 0 \n\nwhile True:\n    # only print on change in the button_presses value\n    if mode != old_mode:\n        print('New Mode:', mode)\n        builtin_led.toggle()\n        old_mode = mode\n    if cycle != old_cycle:\n        print('New Cycle:', cycle)\n        builtin_led.toggle()\n        old_cycle = cycle\n    sleep(.1)\n
    "},{"location":"lessons/05-buttons/#three-button-set","title":"Three Button Set","text":"
    from machine import Pin\nimport time\n\n# Pin setup\nmode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n\n# Time state\nhour = 12\nminute = 0\nis_pm = False\nmode = 0\nmode_names = [\"run\", \"set hour\", \"set minute\", \"set AM/PM\"]\nmode_count = len(mode_names)\n\n# Debounce state\nlast_mode_press = 0\nlast_next_press = 0\nlast_prev_press = 0\nDEBOUNCE_MS = 200\n\ndef format_time():\n    return f\"{hour:02d}:{minute:02d} {'PM' if is_pm else 'AM'}\"\n\ndef handle_mode(pin):\n    global mode, last_mode_press\n    current_time = time.ticks_ms()\n    if time.ticks_diff(current_time, last_mode_press) > DEBOUNCE_MS:\n        mode = (mode + 1) % mode_count\n        print(f\"Mode: {mode_names[mode]}\")\n        last_mode_press = current_time\n\ndef handle_next(pin):\n    global hour, minute, is_pm, last_next_press\n    current_time = time.ticks_ms()\n    if time.ticks_diff(current_time, last_next_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = (hour % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute + 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_next_press = current_time\n\ndef handle_previous(pin):\n    global hour, minute, is_pm, last_prev_press\n    current_time = time.ticks_ms()\n    if time.ticks_diff(current_time, last_prev_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = ((hour - 2) % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute - 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_prev_press = current_time\n\n# Set up interrupts\nmode_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_mode)\nnext_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_next)\nprevious_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_previous)\n\n# Main loop\nprint(\"Clock started. Press mode button to change settings.\")\nwhile True:\n    if mode == 0:  # Only update display in run mode\n        print(format_time())\n        time.sleep(1)\n
    "},{"location":"lessons/06-draw-performance/","title":"Drawing Performance","text":"

    One of the challenges we face when updating the watch display is that refreshing an entire screen using a relatively slow SPI interface means that we need to be thoughtful about updating the displays.

    By default, many screen drivers update every pixel of the screen when the user does a show() operation. For small monochrome screens this is not usually a problem. But for larger color screens the draw times can lead to slow updates.

    Let's do a little math to see when drawing performance becomes a problem. Remember that the human eye can's really see screen updates that occur faster than about 30 frames per second. That is why most film movies were filled at 25 frames per second.

    To calculate the full-screen draw time we need to calculate the total number of bits we need to send and then calculate the time it takes to send these bits. We can then check our math by looking at timestamps just before we draw and after we finish the drawing.

    Let's start out with our favorite clock screen: the 128X64 monochrome OLED screen.

    1. Width = 128
    2. Height = 64
    3. Bits per Pixel = 1

    Total bits = 128 * 64 * 1 = 8,192 bits = 1024 bytes

    Now we need to also know the transfer speed of our display interface. Although there are both I2C and SPI versions of these displays, we usually prefer the SPI that should transfer data at about

    Pi Pico SPI LCD using a frame buffer to get 30fps animation - ILI9341 and ST7789 MicroPython drivers

    "},{"location":"lessons/06-draw-performance/#sample-timer-code","title":"Sample Timer Code","text":"

    We can calculate the time to draw the full screen by recording the number of clock ticks in microseconds before and after we do a screen update.

    from utime import ticks_us\n\nstart = ticks_us()\nscreen_update()\nend = ticks_us()\nprint('Execution time in microseconds:', end - start)\n

    On the OLED screen, we get a result that is around 10 milliseconds which is 100 screen updates per second.

    "},{"location":"lessons/06-draw-performance/#references","title":"References","text":"
    1. Notes on the very slow refresh rate for ST7735
    "},{"location":"lessons/06-setting-time/","title":"Manually Setting Time","text":"

    We need a program that will use three buttons to set the time.

    "},{"location":"lessons/06-setting-time/#the-mode-button","title":"The Mode Button","text":"

    The first button is called the \"mode\" button. It will cycle through four internal \"states\" of our clock. Here are the modes:

    1. Mode 0: Clock Running - this is the normal mode of operation
    2. Mode 1: Setting the Hour
    3. Mode 2: Setting the Minute
    4. Mode 3: Setting AM/PM

    Here is a walkthrough of the button-mode-test.py program, breaking it down into clear, digestible concepts for everyone new to MicroPython.

    "},{"location":"lessons/06-setting-time/#code-walkthrough","title":"Code Walkthrough","text":""},{"location":"lessons/06-setting-time/#1-basic-setup-and-imports","title":"1. Basic Setup and Imports","text":"
    from mp_button import Button\nfrom time import localtime, sleep\nfrom machine import Pin\n

    Let's understand what these lines do: - These are import statements that bring in code we need to use - Button is a special module that helps us work with physical buttons - localtime and sleep are time-related functions - Pin lets us work with the physical pins on our Raspberry Pi Pico

    "},{"location":"lessons/06-setting-time/#2-setting-up-the-pins","title":"2. Setting Up the Pins","text":"
    mode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n

    Here's what's happening: - We're setting up three different pins (16, 17, and 18) on the Pico - Each pin is set as an input (Pin.IN) - meaning it receives signals rather than sends them - Pin.PULL_UP means the pin is naturally \"high\" (1) until a button press makes it \"low\" (0) - Think of it like a light switch that's normally on, and pressing the button turns it off

    "},{"location":"lessons/06-setting-time/#3-global-variables","title":"3. Global Variables","text":"
    counter_pressed = 0\ncounter_released = 0\nmode = 0  # default clock running\nmode_names = [\"run\",\"set hour\",\"set minute\",\"set AM/PM\"]\nmode_count = len(mode_names)\nnow = localtime()\nhours = now[3]\nminutes = now[4]\nam_pm = 0\n

    These are our program's variables: - counter_pressed and counter_released keep track of button presses - mode tells us which setting we're currently adjusting (starts at 0) - mode_names is a list of the different modes our clock can be in - mode_count is how many modes we have (4 in this case) - now gets the current time from the Pico - hours and minutes store the current time values - am_pm keeps track of whether it's morning (0) or afternoon (1)

    "},{"location":"lessons/06-setting-time/#4-button-handler-functions","title":"4. Button Handler Functions","text":"
    def button_mode_irq(button, event):\n    global mode, hours, minutes\n    if event == Button.PRESSED:\n        mode += 1\n        mode = mode % mode_count\n        print('new mode:', mode, mode_names[mode])\n

    This is our mode button handler: - global tells Python we want to change variables outside this function - When the button is pressed, we increase the mode by 1 - The % (modulo) operator helps us cycle back to 0 after reaching the last mode - For example: if mode is 3 and we add 1, 4 % 4 = 0, so we go back to the first mode

    "},{"location":"lessons/06-setting-time/#5-next-and-previous-button-handlers","title":"5. Next and Previous Button Handlers","text":"
    def button_next_irq(button, event):\n    global mode, hours, minutes, am_pm\n    if event == Button.PRESSED:\n        if mode == 1:\n            hours += 1\n        if mode == 2:\n            minutes += 1\n        if mode == 3:\n            am_pm = 1 if am_pm == 0 else 0\n

    The next/previous buttons: - They only work when we're in a setting mode (not mode 0) - Mode 1: adjust hours - Mode 2: adjust minutes - Mode 3: toggle between AM and PM - The previous button does the same thing but decreases values

    "},{"location":"lessons/06-setting-time/#6-creating-button-objects","title":"6. Creating Button Objects","text":"
    button_mode = Button(16, False, button_mode_irq, internal_pullup = True, debounce_time = 100)\nbutton_next = Button(17, False, button_next_irq, internal_pullup = True, debounce_time = 100)\nbutton_previous = Button(18, False, button_previous_irq, internal_pullup = True, debounce_time = 100)\n

    Here we create our button objects: - Each button gets a pin number (16, 17, or 18) - We tell it which function to call when pressed (the _irq functions) - debounce_time = 100 prevents multiple triggers from one press - Think of debouncing like waiting a moment to make sure someone really pressed the button once

    "},{"location":"lessons/06-setting-time/#7-main-loop","title":"7. Main Loop","text":"
    while(True):\n    button_mode.update()\n    button_next.update()\n    button_previous.update()\n

    This is our main program loop: - It runs forever (that's what while True means) - Each time through the loop, we check if any buttons were pressed - The update() function handles all the button checking for us

    "},{"location":"lessons/06-setting-time/#full-program-listing","title":"Full Program Listing","text":"
    from mp_button import Button\nfrom time import localtime, sleep\nfrom machine import Pin\n\nmode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n\n# we create a counter to increment as we press\n# and one to increment as we release\ncounter_pressed = 0\ncounter_released = 0\nmode = 0 # default clock running\nmode_names = [\"run\",\"set hour\",\"set minute\",\"set AM/PM\"]\nmode_count = len(mode_names)\nnow = localtime()\nhours = now[3]\nminutes = now[4]\nam_pm = 0\n\n# the following method (function) will be invoked\n# when the button changes state\n# the Button module expects a callback to handle \n# - pin number\n# - event (Button.PRESSED | Button.RELEASED)\n# the event contains a string 'pressed' or 'released'\n# which can be used in your code to act upon\ndef button_mode_irq(button, event):\n    global mode, hours, minutes\n    if event == Button.PRESSED:\n        mode +=1\n        # cycle back to zero if greater than mode_count\n        mode =  mode % mode_count\n        print('new mode:', mode, mode_names[mode])\n\ndef button_next_irq(button, event):\n    global mode, hours, minutes, am_pm\n    if event == Button.PRESSED:\n        if mode == 1:\n            hours += 1\n        if mode == 2:\n            minutes += 1\n        if mode == 3:\n            if am_pm == 0:\n                am_pm = 1\n            else:\n                am_pm = 0\n        print('next button:', hours, minutes, am_pm)\n\ndef button_previous_irq(button, event):\n    global mode, hours, minutes, am_pm\n    if event == Button.PRESSED:\n        if mode == 1:\n            hours -= 1\n        if mode == 2:\n            minutes -= 1\n        if mode == 3:\n            if am_pm == 0:\n                am_pm = 1\n            else:\n                am_pm = 0\n        print('prev button:', hours, minutes, am_pm)\n\nbutton_mode = Button(16, False, button_mode_irq, internal_pullup = True, debounce_time = 100)\nbutton_next = Button(17, False, button_next_irq, internal_pullup = True, debounce_time = 100)\nbutton_previous = Button(18, False, button_previous_irq, internal_pullup = True, debounce_time = 100)\n\nprint(\"year:\", now[0], \"month:\", now[1], \"day-of-month:\", now[2], \"hours\", now[3], \"minutes:\", now[4])\nwhile(True):\n    button_mode.update()\n    button_next.update()\n    button_previous.update()\n
    "},{"location":"lessons/06-setting-time/#the-decrement-time","title":"The Decrement Time","text":"

    The following line need some explanation:

    hour = ((hour - 2) % 12) + 1\n
    Let me break down that line, which handles decrementing hours while staying within the 1-12 range:

    Let's walk through it step by step:

    1. First, we subtract 2 from the current hour: (hour - 2)
    2. We subtract 2 (not 1) because we'll add 1 back at the end
    3. This shift is necessary because we want to work with 0-11 for the modulo operation

    4. Then we take modulo 12: % 12

    5. This ensures our number wraps around within 0-11
    6. For example, if hour was 1, then (1-2) = -1, and -1 % 12 = 11

    7. Finally, we add 1: + 1

    8. This shifts our range from 0-11 back to 1-12

    Here's an example sequence to show how it works: - Starting at hour = 1: - (1 - 2) = -1 - -1 % 12 = 11 - 11 + 1 = 12 - Starting at hour = 12: - (12 - 2) = 10 - 10 % 12 = 10 - 10 + 1 = 11

    This gives us the desired behavior of decrementing through the sequence: 12 \u2192 11 \u2192 10 \u2192 ... \u2192 1 \u2192 12

    "},{"location":"lessons/06-setting-time/#updating-the-display","title":"Updating the Display","text":"
    from machine import Pin\nfrom utime import localtime, sleep, ticks_ms, ticks_diff\nimport tm1637\n\n# Pin setup\nCLK_PIN = 0\nDST_PIN = 1\nPM_PIN = 25\n\nmode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n# LED value 0 indicates AM, value 1 indicates PM\npm_pin = Pin(PM_PIN, Pin.OUT)\n\n# Time state\nnow = localtime()\nhour = now[3]\nminute = now[4]\nsecond = now[5]\n\ntm = tm1637.TM1637(clk=Pin(CLK_PIN), dio=Pin(DST_PIN))\n\nmode = 0\nmode_names = [\"run\", \"set hour\", \"set minute\", \"set AM/PM\"]\nmode_count = len(mode_names)\n\n# Debounce state\nlast_mode_press = 0\nlast_next_press = 0\nlast_prev_press = 0\nDEBOUNCE_MS = 100\n\ndef format_time():\n    return f\"{hour:d}:{minute:02d}:{second:02d} {'PM' if is_pm else 'AM'}\"\n\ndef set_pm():\n    if hour < 12:\n        is_pm = False\n        pm_pin.value(0)\n    else:\n        is_pm = True\n        pm_pin.value(1)\n\ndef handle_mode(pin):\n    global mode, last_mode_press\n    current_time = ticks_ms()\n    if ticks_diff(current_time, last_mode_press) > DEBOUNCE_MS:\n        mode = (mode + 1) % mode_count\n        print(f\"Mode: {mode_names[mode]}\")\n        last_mode_press = current_time\n\ndef handle_next(pin):\n    global hour, minute, is_pm, last_next_press\n    current_time = ticks_ms()\n    if ticks_diff(current_time, last_next_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = (hour % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute + 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_next_press = current_time\n\ndef handle_previous(pin):\n    global hour, minute, is_pm, last_prev_press\n    current_time = ticks_ms()\n    if ticks_diff(current_time, last_prev_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = ((hour - 2) % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute - 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_prev_press = current_time\n\n# numbers modified to not dispaly the leading zero\ndef numbers_nlz(num1, num2, colon=True):\n    \"\"\"Display two numeric values -9 through 99, with a leading space before\n    single-digit first numbers and separated by a colon.\"\"\"\n    num1 = max(-9, min(num1, 99))\n    num2 = max(-9, min(num2, 99))\n    prefix = ' ' if num1 < 10 else ''\n    # print(f'\"{prefix}{num1:d}{num2:0>2d}\"')\n    segments = tm.encode_string(f'{prefix}{num1:d}{num2:0>2d}')\n    if colon:\n        segments[1] |= 0x80  # colon on\n    tm.write(segments)\n\n# Set up interrupts\nmode_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_mode)\nnext_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_next)\nprevious_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_previous)\n\n# Main loop\nprint(\"Clock started. Press mode button to change settings.\")\n\nwhile True:\n    second = localtime()[5]\n    if mode == 0:  # Only update display in run mode\n        print(format_time())\n        # flash the colon on and off every second\n        if (second % 2): # modulo 2 will be true for odd numbers\n            numbers_nlz(hour, minute, True)\n        else:\n            numbers_nlz(hour, minute, False)\n        set_pm()\n        sleep(1)\n
    "},{"location":"lessons/07-drawing-digits/","title":"Drawing Clock Digits","text":""},{"location":"lessons/07-drawing-digits/#the-seven-segments-of-a-numeric-digit","title":"The Seven Segments of a Numeric Digit","text":"

    Since the early history of computing, numeric displays were created using a grouping of seven individual lights to display a single digit. These are called Seven Segment Displays. An example is shown in the image below:

    The segments are labeled \"a\" through \"g\" starting at the top and going around in a clockwise direction. Note that the seventh segment is in the center element is the \"g\" segment.

    Technically, many displays have an 8th segment for the decimal point (DP). To keep things simple we will just focus on the main seven segments in this lesson.

    Clocks also usually have a colon that separates the hours and minutes and an AM/PM indicator for 12-hour displays. We will be treating these and independent drawing components in this lab. Many digital clocks have the colon flash on and off every second.

    "},{"location":"lessons/07-drawing-digits/#the-segment-map","title":"The Segment Map","text":"

    To start out, we need to create a \"digit-to-segment map\" data structure. We use this to help us figure out what segments to turn on for any given digit.

    We will also need to convert the segment letters into integers. These integers will form the index of an array.

    To write our code, we ask, for any given digit, is the segment on or off?

    To do this, we can create an array of segments like this:

    segmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n

    For any given digit like \"2\" we can then just pass the index of \"2\" to a Python list to get a list of the segments to turn on. That line of code looks like this:

    segmentOn = segmentMapping[digit];\n

    This will return the segments that are to be turned on for any given input digit. For example:

    segmentOn = segmentMapping[2];\nprint(segmentOn)\n# returns:\n[1, 1, 0, 1, 1, 0, 1]\n

    We now have the data structure to do the drawing. We will do this in two steps.

    1. Draw the three horizontal lines for a digit if they are on
    2. Draw all vertical lines for a given digit, keeping in mind that we need to only draw half the way down the digit for the upper left and upper right vertical segments (1 and 5)

    We will start out with a simple digit drawing using a single-pixel width line. Later we will add a parameter to change the thickness of the line. But we want to take this one-step-at-a-time.

    "},{"location":"lessons/07-drawing-digits/#drawing-horizontal-segments","title":"Drawing Horizontal Segments","text":"

    This sample code will step through the horizontal lines for segments 0, 3 and 6. It will check using the segmentOn[i] line which will ONLY be true if that segment should be turned on for a given digit.

    Next, we figure out how high to draw the horizontal line. To do this we will need to figure out the vertical offset (yOffset). The top line (segment 0) has no offset and the bottom line has the full height of the digit.

    Unlike the vertical lines, the horizontal lines will span the entire width of the area. That makes our code simple because the line will have a horizontal length of exactly the x plus the width of the digit.

    # reasonable test values for a small display\nx = 10\ny = 10\nwidth = 20\nheight = 30\n# Horizontal segments\n  for i in [0, 3, 6]:\n    # check if this digit has the segment on\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height # bottom element\n      if (i==6):\n          yOffset = height // 2 # bottom\n      # draw a signal thin line\n      oled.line(x, y+yOffset, x + width, y+yOffset, 1)\n
    "},{"location":"lessons/07-drawing-digits/#drawing-the-vertical-segments","title":"Drawing the Vertical Segments","text":"

    Next, we need to create some code to draw the four vertical segments. This is a little more complex because the lines do NOT span the full height of the digit.

    # Draw Vertical segments\nx = 10\ny = 10\nwidth = 20\nheight = 30\n# Draw the vertical segments ur, lr, ll, ul\nfor i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n        # top two segments\n        if (i==1 or i==5):\n            startY = 0\n            endY = height // 2\n        if (i==2 or i==4):\n            startY = height // 2\n            endY = height\n        # left segments\n        if (i==4 or i==5): xOffset = 0\n        # right segments\n        if (i==1 or i==2): xOffset = width\n        oled.line(x+xOffset, y+startY, x+xOffset, y+endY, 1)\n
    "},{"location":"lessons/07-drawing-digits/#testing-our-drawing","title":"Testing Our Drawing","text":"

    We can now wrap the code above in a drawDigit() function, and we will test each of the digits 0-9 in a small test program.

    Our first version of drawDigit is modeled after the rect() function. After we pass in the digit, it takes in the (x,y) and width and height parameters and the color value.

    Draw Digit Function Parameters:

    1. The digit to display - an integer in the range 0-9
    2. x of the upper left corner
    3. y of the upper left corner
    4. the width of the digit (about 20 is a good value)
    5. the height of the digit
    6. the color (0=black, 1=white)

    Here is our testing program that draws digits 0-9 in the center of a standard 128x64 monochrome OLED display:

    # Lab 20: Draw Digits with just the line function\n# this lab uses the line() function to draw the segments\nimport machine\nimport utime\nimport ssd1306\nfrom utime import sleep, localtime\nled = machine.Pin(25, machine.Pin.OUT)\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\nspi=machine.SPI(0, sck=SCL, mosi=SDA, baudrate=100000)\n\nRES = machine.Pin(4)\nDC = machine.Pin(5)\nCS = machine.Pin(6)\nWIDTH = 128\nHEIGHT = 64\n\noled = ssd1306.SSD1306_SPI(WIDTH, HEIGHT, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n\n\n# x and y are the center of the digit, size is the center to edge\ndef drawDigit(digit, x, y, width, height, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottem, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height # bottom element\n      if (i==6):\n          yOffset = height // 2 # middle line\n      oled.line(x, y+yOffset, x + width, y+yOffset, 1)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n        # top two segments\n        if (i==1 or i==5):\n            startY = 0\n            endY = height // 2\n        if (i==2 or i==4):\n            startY = height // 2\n            endY = height\n        # left segments\n        if (i==4 or i==5): xOffset = 0\n        # right segments\n        if (i==1 or i==2): xOffset = width\n        oled.line(x+xOffset, y+startY, x+xOffset, y+endY, 1)\n\n\noled.fill(0)\noled.text('Lab 12: rect', 0, 0, 1)\nx = 10 # upper left corner x\ny = 10 # upper left corner y\nw = 20 # digit width\nh = 30 # digit height\n\nwhile True:\n    for i in range(0, 10):\n\n        print(i)\n        # create an outline one px away from the drawing region\n        oled.rect(x-2, y-2, w+5, h+5, 1)\n        # draw one digit\n        drawDigit(i, x, y, w, h, 1)\n        # draw a second digit\n        #drawDigit(i, x + w + 4, w, h, t, 1)\n        oled.text(str(i), 0, 54, 1)\n        oled.show()\n        sleep(2)\n        oled.fill(0)\n

    This drawDigit() is very handy. We just need to give the function some parameters and it will draw the right digit at a location (x,y) as the upper left corner with the correct width and height!

    But the lines are somewhat thin. A more robust implementation will also allow us the change the thickness of the segments. That will be more complex since we will have to adjust the starting point of where we draw each segment based on the thickness of the segment. We will also need to use a rectangle, not a line. This requires we figure out the exact width and height before we draw.

    We explore that function in the next lesson.

    "},{"location":"lessons/09-digit-functions/","title":"Creating Digit Functions","text":"

    In the last section, we drew a seven-segment digit number using the line function. In this section, we will build a better function that will add a flexible new parameter for the thickness of the digit segments. We will then test the function under a variety of conditions and see how we can make the function easier to use.

    "},{"location":"lessons/09-digit-functions/#new-thickness-parameters","title":"New Thickness Parameters","text":"

    Placing the rectangles correctly within a seven-segment display when we have many drawing parameters requires some precision. We will use a decomposition process and take \"one step at a time\" to work out the details.

    "},{"location":"lessons/09-digit-functions/#draw-segment-function","title":"Draw Segment Function","text":"

    Here is our revised parameters list:

    1. The digit to display - an integer in the range 0-9
    2. x of the upper left corner
    3. y of the upper left corner
    4. the width of the digit (about 20 is a good value)
    5. the height of the digit
    6. (NEW) the thickness of each segment (3 or 4 are good values)
    7. the color (0=black, 1=white)

    Here is our revised function for drawing a single digit with the segment thickness added.

    # digit is the number to display\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottom, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottom element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottom\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n

    Let's now take a look at how we had to modify our code.

    The first item to note is that when we calculate a starting point to draw, we can't just draw at the edge of the region. We need to back off our initial drawing point by the width of the segment.

    Here is an example of subtracting the thickness from y when we draw the bottom segment:

    yOffset = height - thickness # bottom element\n

    "},{"location":"lessons/09-digit-functions/#full-test-program","title":"Full Test Program","text":"
    # Clock Lab 20: Draw Seven Segments\n# this lab uses the fill_rect function to draw the segments\nimport machine\nimport utime\nimport ssd1306\nfrom utime import sleep, localtime\nled = machine.Pin(25, machine.Pin.OUT)\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\nspi=machine.SPI(0, sck=SCL, mosi=SDA, baudrate=100000)\n\nRES = machine.Pin(4)\nDC = machine.Pin(5)\nCS = machine.Pin(6)\n\noled = ssd1306.SSD1306_SPI(128, 64, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n\n# digit is the numer to display\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottom, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottom element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottom\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n\noled.fill(0)\noled.text('Lab 12: rect', 0, 0, 1)\nx = 10 # upper left corner x\ny = 10 # upper left corner y\nw = 20 # digit width\nh = 30 # digit height\nt = 3\n\nwhile True:\n    for i in range(0, 10):\n\n        print(i)\n        # create an outline on px away from the drawing region\n        oled.rect(x-2, y-2, w+4, h+4, 1)\n        # draw one digit\n        drawDigit(i, x, y, w, h, t, 1)\n        # draw a second digit\n        #drawDigit(i, x + w + 4, w, h, t, 1)\n        oled.text(str(i), 0, 54, 1)\n        oled.show()\n        sleep(2)\n        oled.fill(0)\n
    "},{"location":"lessons/12-draw-time-functions/","title":"Draw a Digital Clock Time Function","text":"

    In this section, we will create a new function called drawTime. The input will be the upper left starting point (x,w), width and height, hours and minutes and the format (12-hour or 24-hour) and the color (black or white).

    This lab will build in the prior lab that displayed a single digit.

    Let's first of all create a plan of how we will layout our digital clock display.

    Our goal is to create a function that will be reusable over many types of displays with little or no modification. This will require us to think through the potential ways our users will use this function and anticipate their needs so they are not tempted to rewrite our code on their own.

    "},{"location":"lessons/12-draw-time-functions/#12-hour-display-format","title":"12-Hour Display Format","text":"

    Here is an example of our 12-hour clock layout:

    Note that there are six horizontal x-dimension numbers and three vertical y-dimension numbers that you can adjust to create a pleasant interface.

    "},{"location":"lessons/12-draw-time-functions/#automatically-scaling-the-layout","title":"Automatically Scaling the Layout","text":"

    It would be tempting to just hard-code the layout using a single set of numbers. But what if the user wanted a smaller or larger portion of their display used to display the time?

    As the user selects the height and width of their clock we would like to scale these numbers accordingly. The absolute values of these numbers is not too important now. We just want to get the relative values down. To start the process, I did a layout on an 11-inch wide drawing and I assigned the width of each digit to be 3.0.

    # horizontal\nx1 = .73\nx2 = .73\nx3 = 3.0\nx4 = 1.35\nx5 = .5\nx6 = .35\nx7 = 1.5\nx8 = .35\nx9 = .5\n# Vertical\ny1 = 5.31\ny2 = 1.58\ny3 = .68\ny4 = .68\n

    We need to make the width of the display be x1 + x2 + 3*x3 + x4 + x5 + x6 + x7 which is

    # Scale Test\n\ndef drawTime12h(hour, minute, x, y, width, height):\n    # horizontal\n    x1 = .73\n    x2 = .73\n    x3 = 3.0 # digit width\n    x4 = 1.35\n    x5 = .5\n    x6 = .35\n    x7 = 1.5\n    x8 = .35\n    x9 = .5 # colon width and height\n\n    # vertical\n    y1 = 5.31\n    y2 = 1.58 # to top colon\n    y3 = .68 # between colons\n\n    total_width = x1 + x2 + 3*x3 + x4 + x5 + x6 + x7\n    print(\"total width:\", total_width)\n    total_height = y1\n\n    # calculate the scaling ratios\n    x_scale = width / total_width\n    y_scale = height / total_height \n\n    digit_width = x3 * x_scale\n    digit_height = y1 * y_scale\n    print(\"x scale:\", x_scale, \"y scale:\", y_scale)\n\n    if hour > 12:\n        hour12 = hour - 12\n\n    # hour tens\n    if hour12 > 10:\n        oled.rect(x,y,int(x1*x_scale),int(y1*y_scale))\n\n    # hour ones x,y,w,h\n    drawDigit(hour % 10, int((x + x1 + x2)*x_scale), y, int(x3*x_scale), int(y1*y_scale))\n\n    # minute tens ones digit, x,y,w,h\n    min_tens_x = int((x + x1 + x2 + x3 + x4)*x_scale)\n    drawDigit(minute // 10, min_tens_x, y, int(x3*x_scale), int(y1*y_scale))\n\n    # minute  ones x,y,w,h\n    min_ones_x = int((x + x1 + x2 + 2*x3 + x4 + x5)*x_scale)\n    drawDigit(minute % 10, min_ones_x, y, int(x3*x_scale), int(y1*y_scale))\n\n    # draw colon\n    colon_size = x9\n    # top colon\n    oled.rect(int((x+x1+x2+x3+x8)*x_scale), y+int(y2*y_scale), colon_size, colon_size)\n    # bottom colon\n    oled.rect(int((x+x1+x2+x3+x8)*x_scale), y+int((y2+y3)*y_scale), colon_size, colon_size)\n\n    # AM/PM\n    if hours < 12:\n        am_pm_text = 'am'\n    else:\n        am_pm_text = 'pm'\n    am_pm_x = min_ones_x + int((x3+x6)*x_scale)\n    oled.text(am_pm_text, am_pm_x, y + int(y1*y_scale)) \n\ndrawTime12h(hour, minute, 0, 0, 100, 50)\n
    "},{"location":"lessons/13-testing-the-rtc/","title":"Real Time Clocks","text":"

    Prompt

    You are a friendly and fun science teacher working with a group of high-school students taking a course called \"Programming Clocks and Watches\". Today your lecture is on \"Real time Clocks\" like the old DS1307 and the newer super accurate DS3231. Give the full text of a 15-minute lecture before the hands-on lab and mention where images should be inserted.

    Hello everyone, and welcome to today's exciting lecture on Real Time Clocks! In our \"Programming Clocks and Watches\" course, we're going to dive into the fascinating world of the good old DS1307 used in our classrooms and the new super accurate DS3231.

    First, let's talk about what a Real Time Clock (RTC) is. An RTC is a computer chip that keeps track of the current time, even when the main power is off. It's like a tiny, dedicated clock inside your electronic devices. RTCs are found in computers, smartphones, appliances, and many other gadgets that need to keep accurate time.

    Here is how the DS1307 is typically used in a microcontroller project.

    The DS1307 is one of the most well-known RTCs. We have a LOT of them lying around the lab. This little chip was first introduced in 2005 and has been widely used in various electronic projects. The DS1307 keeps track of seconds, minutes, hours, days, months, and years. It communicates with the main processor using a protocol called I2C (Inter-Integrated Circuit).

    Now, let's take a look at how the DS1307 works. It has a built-in crystal oscillator that vibrates at a specific frequency, acting as a precise clock source. The chip counts these oscillations to keep track of time. The DS1307 also has a small amount of battery-backed memory, allowing it to maintain the time even when the main power is off.

    [Insert image of a coin cell battery]

    Speaking of power, the DS1307 uses a small coin cell battery to keep the clock running when the main power is disconnected. This battery can last for several years, ensuring that your device always has the correct time.

    [Insert image of a DS3231 chip]

    Now, let's move on to the newer and more accurate DS3231. Released in 2011, the DS3231 is known for its incredible precision. It has a temperature-compensated crystal oscillator (TCXO), which means it can maintain accurate timekeeping even when the temperature changes. This is important because temperature fluctuations can affect the frequency of regular crystal oscillators, causing the clock to drift over time.

    [Insert image comparing the accuracy of DS1307 and DS3231]

    How accurate is the DS3231, you might ask? Well, it has a typical accuracy of \u00b12 parts per million (ppm), which translates to a drift of about 1 minute per year! In comparison, the DS1307 has an accuracy of around \u00b120 ppm, which means it can drift by about 10 minutes per year. That's a significant difference!

    [Insert image of I2C communication]

    Just like the DS1307, the DS3231 communicates with the main processor using the I2C protocol. It has a simple register-based interface that allows you to read and set the time easily.

    Now, let's talk about some fun applications of RTCs. One cool project you can build is a digital clock that always displays the correct time, even if it's been unplugged for a while. You can also create a data logger that records temperature, humidity, or other sensor readings along with precise timestamps. The possibilities are endless!

    [Insert image of a digital clock or a data logger project]

    In our hands-on lab today, we'll be working with both the DS1307 and the DS3231. You'll learn how to wire them up, set the time, and read the current time using a microcontroller. We'll also explore some practical examples and discuss how to choose the right RTC for your projects.

    [Insert image of students working on a project]

    So, get ready to have some fun with Real Time Clocks! Remember, whether you're building a simple clock or a complex data logging system, an RTC is an essential component that keeps everything running on time.

    Let's head to the lab and start tinkering with these amazing little chips!

    "},{"location":"lessons/13-testing-the-rtc/#testing-the-ds1307-and-ds3232-real-time-clocks","title":"Testing the DS1307 and DS3232 Real Time Clocks","text":""},{"location":"lessons/13-testing-the-rtc/#hardware-configuration","title":"Hardware Configuration","text":""},{"location":"lessons/13-testing-the-rtc/#ds1307-connections","title":"DS1307 Connections","text":"
    1. CLK - clock
    2. DST - Data (incoming to Pico)
    3. RST - Reset
    4. VCC - must be 5 volts, not 3.2
    5. GND - ground

    We will use the lower right pins on the Pico so that the display can use the pins in the upper-right corner.

    These pin assignments are

    1. GP16 - far lower right - CLK
    2. GP17 - second from the bottom - DST
    3. GP18 - fourth pin up - RST

    Contents of config.py

    CLK_PIN = 16\nDST_PIN = 17\nRST_PIN = 18\n
    "},{"location":"lessons/13-testing-the-rtc/#sample-ds1307-micropython-test-program-for-the-raspberry-pi-pico","title":"Sample DS1307 MicroPython Test Program for the Raspberry Pi Pico","text":"
    from machine import I2C, Pin\nimport config\n\nCLK_PIN = config.CLK_PIN\nDST_PIN = config.DST_PIN\nDS_PIN = config.DS_PIN\n\nprint(\"Clock on pin:\", CLK_PIN)\nprint(\"Data on pin:\", DST_PIN)\nprint(\"Data Select on pin:\", DS_PIN)\n\ni2c = I2C(0, scl=Pin(CLK_PIN), sda=Pin(DST_PIN), freq=100000)\nscan_result = i2c.scan()\nprint(\"I2C addresses found:\", [hex(device_address) for device_address in scan_result])\n\nif 104 in scan_result:\n    print(\"PASS: DS1307 FOUND\")\nelse:\n    print(\"FAIL: DS1307 NOT FOUND\")\n
    "},{"location":"lessons/13-testing-the-rtc/#sample-test-result","title":"Sample Test Result","text":"
    Clock on pin: 17\nData on pin: 16\nData Select on pin: 18\nI2C addresses found: ['0x50', '0x68']\nPASS: DS1307 FOUND\n
    "},{"location":"lessons/13-testing-the-rtc/#full-test-of-ds1307","title":"Full Test of DS1307","text":"
    #!/usr/bin/env python3\n# -*- coding: UTF-8 -*-\n\n\"\"\"I2C DS1307 showcase\"\"\"\n\nfrom ds1307 import DS1307\nfrom machine import I2C, Pin\nfrom utime import gmtime, sleep, time\nimport config\nCLK_PIN = config.CLK_PIN\nDST_PIN = config.DST_PIN\nDS_PIN = config.DS_PIN\n\n# DS1307 on 0x68\nI2C_ADDR = 0x68     # DEC 104, HEX 0x68\n\n# define custom I2C interface, default is 'I2C(0)'\n# check the docs of your device for further details and pin infos\n# this are the pins for the Raspberry Pi Pico adapter board\ni2c = I2C(0, scl=Pin(CLK_PIN), sda=Pin(DST_PIN), freq=800000)\nprint(i2c.scan())\nds1307 = DS1307(addr=I2C_ADDR, i2c=i2c)\n\n# get LCD infos/properties\nprint(\"DS1307 is on I2C address 0x{0:02x}\".format(ds1307.addr))\nprint(\"Weekday start is {}\".format(ds1307.weekday_start))\n\n# get the current RTC time\nprint(\"Current RTC time: {}\".format(ds1307.datetime))\n\n# set the RTC time to the current system time\nnow = gmtime(time())\nds1307.datetime = now\n\n# Print the date and time in ISO8601 format: 2023-04-18T21:14:22\nprint(\"Today is {:04d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}\".format(\n    ds1307.year, ds1307.month, ds1307.day,\n    ds1307.hour, ds1307.minute, ds1307.second))\n\n# check whether this year is a leap year\nprint(\"Is this year a leap year? {}\".format(ds1307.is_leap_year(ds1307.year)))\n\n# get the day of the year\nprint(\"Today is day {} of {}\".format(\n    ds1307.day_of_year(year=ds1307.year, month=ds1307.month, day=ds1307.day),\n    ds1307.year))\n\n# halt the oscillator\nprint(\"The oscillator is currently active at {}? {}\".format(\n    ds1307.datetime, ds1307.halt))\nprint(\"Halt the oscillator and wait for 5 seconds ...\")\nds1307.halt = True\nsleep(5)\n\nprint(\"Current RTC time: {}\".format(ds1307.datetime))\n\nprint(\"Enable the oscillator and wait for 5 seconds ...\")\nds1307.halt = False\nsleep(5)\nprint(\"Current RTC time: {}\".format(ds1307.datetime))\n\n# control the squarewave pin SQ\nprint(\"Set square wave output to 1Hz and wait for 5 seconds ...\")\nds1307.square_wave(sqw=1)\nsleep(5)\n\nprint(\"Set square wave output to 4.096kHz and wait for 5 seconds ...\")\nds1307.square_wave(sqw=4)\nsleep(5)\n\nprint(\"Set square wave output to 8.192kHz and wait for 5 seconds ...\")\nds1307.square_wave(sqw=8)\nsleep(5)\n\nprint(\"Set square wave output to HIGH and wait for 5 seconds ...\")\nds1307.square_wave(out=1)\nsleep(5)\n\nprint(\"Set square wave output to LOW and wait for 5 seconds ...\")\nds1307.square_wave(sqw=0)\nsleep(5)\n
    "},{"location":"lessons/13-testing-the-rtc/#test-result","title":"Test Result","text":"
    [80, 104]\nDS1307 is on I2C address 0x68\nWeekday start is 0\nCurrent RTC time: (2024, 12, 27, 20, 29, 47, 4, 362)\nToday is 2024-12-27T20:29:51\nIs this year a leap year? True\nToday is day 362 of 2024\nThe oscillator is currently active at (2024, 12, 27, 20, 29, 51, 4, 362)? False\nHalt the oscillator and wait for 5 seconds ...\nCurrent RTC time: (2024, 12, 27, 20, 29, 51, 4, 362)\nEnable the oscillator and wait for 5 seconds ...\nCurrent RTC time: (2024, 12, 27, 20, 29, 56, 4, 362)\nSet square wave output to 1Hz and wait for 5 seconds ...\nSet square wave output to 4.096kHz and wait for 5 seconds ...\nSet square wave output to 8.192kHz and wait for 5 seconds ...\nSet square wave output to HIGH and wait for 5 seconds ...\nSet square wave output to LOW and wait for 5 seconds ...\n
    "},{"location":"lessons/13-testing-the-rtc/#localtime-and-gmtimetime","title":"Localtime and gmtime(time())","text":"
    from utime import gmtime, time, localtime\nprint(\"time()\", time())\nprint(\"   localtime()\", localtime())\nprint(\"gmtime(time())\", gmtime(time()))\n

    Result

    time() 1735332067\n   localtime() (2024, 12, 27, 20, 41, 7, 4, 362)\ngmtime(time()) (2024, 12, 27, 20, 41, 7, 4, 362)\n
    This code is running on MicroPython on the Raspberry Pi Pico (RP2040) and demonstrates the usage of time-related functions from the utime module.

    Let's break it down:

    1. from utime import gmtime, time, localtime: This line imports the gmtime, time, and localtime functions from the utime module, which is MicroPython's equivalent of the time module in standard Python.
    2. print(\"time()\", time()): This line prints the label \"time()\" followed by the result of calling the time() function. The time() function returns the number of seconds elapsed since the Unix epoch (January 1, 1970, 00:00:00 UTC) as an integer value. In your output, time() returned 1735332067, which represents the current timestamp.
    3. print(\" localtime()\", localtime()): This line prints the label \"localtime()\" followed by the result of calling the localtime() function. The localtime() function takes no arguments and returns a tuple representing the current local time. The tuple contains the following elements in order: (year, month, day, hour, minute, second, weekday, yearday). In your output, localtime() returned (2024, 12, 27, 20, 41, 7, 4, 362), indicating the current local time on the Raspberry Pi Pico.
    4. print(\"gmtime(time())\", gmtime(time())): This line prints the label \"gmtime(time())\" followed by the result of calling the gmtime() function with the current timestamp obtained from time(). The gmtime() function takes a timestamp as an argument and returns a tuple representing the corresponding UTC time. The tuple has the same format as the one returned by localtime(). In your output, gmtime(time()) returned (2024, 12, 27, 20, 41, 7, 4, 362), which represents the current UTC time.

    What does the number that time() returns represent?

    The number returned by time() represents the number of seconds that have elapsed since the Unix epoch (January 1, 1970, 00:00:00 UTC). This value is commonly known as the Unix timestamp or epoch time. It is a widely used standard for representing points in time and is independent of time zones.

    In our example, time() returned 1735332067. This timestamp corresponds to the date and time shown in the localtime() and gmtime(time()) outputs, which is December 27, 2024, at 20:41:07 UTC.

    The Unix timestamp is a useful representation of time because it allows for easy arithmetic operations on timestamps and can be converted to human-readable formats using functions like localtime() and gmtime(). It is widely used in various programming languages and systems for time-related operations.

    It's important to note that the accuracy and synchronization of the time on the Raspberry Pi Pico depend on its internal clock and any time synchronization mechanisms used. Without external time synchronization, the Pico's internal clock may drift over time, resulting in slight inaccuracies compared to the actual current time.

    "},{"location":"lessons/13-testing-the-rtc/#accuracy-of-the-clock-on-the-raspberry-pi-pico","title":"Accuracy of the Clock on the Raspberry Pi Pico**","text":"

    The Raspberry Pi Pico does not have a real-time clock (RTC) built into its hardware. Its clock is derived from the internal oscillator, which may be subject to drift and is not highly accurate for long-term timekeeping. The accuracy depends on the quality of the oscillator and the environmental conditions, such as temperature.

    • Drift: The internal clock is typically accurate to within 1% under normal conditions.

    • Seconds off per day: For a 1% drift:

    \\[ 1\\% \\text{ of 24 hours} = 0.01 \\times 24 \\times 3600 \\approx 864 \\, \\text{seconds off per day}. \\]

    Thus, the clock on the Pico can drift up to \u00b1864 seconds per day without correction.

    For improved accuracy, you can add an external RTC module to the Pico.

    Accuracy of the Clock on the DS1307

    The DS1307 is a low-cost RTC chip widely used in electronics projects. Its accuracy is based on an external 32.768 kHz quartz crystal oscillator, which is sensitive to factors like temperature and crystal quality. \u2022 Drift: The DS1307 typically drifts by \u00b120 ppm (parts per million) at 25\u00b0C. \u2022 Seconds off per day: With a drift of 20 ppm:

    \\[ 20 \\, \\text{ppm} \\times 24 \\times 3600 \\, \\text{seconds} = 1.728 \\, \\text{seconds off per day}. \\]

    The DS1307 clock may be off by approximately \u00b11.7 seconds per day under ideal conditions.

    For more accurate timekeeping, consider using a higher-quality RTC like the DS3231, which has a drift of \u00b12 ppm (about \u00b10.17 seconds per day) due to its temperature compensation feature.

    "},{"location":"lessons/13-testing-the-rtc/#references","title":"References","text":"
    • DS1307 Data Sheet
    • Reference Manual
    "},{"location":"lessons/15-scale-testing/","title":"Digital Clock Display Scale Testing","text":"

    We would like to test our digital clock display at a large range of different sizes to make sure our scale functions work. For example, the function should work over a range of sizes from 20 to 110 pixels wide.

    Here is a test driver for the drawTime12 function:

    # test times\ntt = [[00,00], [12,59], [12,00], [8,33], [13,59], [23,59]]\n\nwhile True:\n    ## tti is the test time index\n    for tti in range(0,len(tt)):\n        for size in range(20, 110):\n            oled.fill(0) # clear screen\n            # bounding box for the entire screen\n            # oled.rect(0,0, WIDTH-1, HEIGHT-1, 1)\n\n            # bounding box for the time region\n            height = int(size*.5)\n            oled.rect(0, 0, size+20, height+5, 1)\n            # print(\"h=\", tt[tti][0], \"min:\", tt[tti][1])\n            drawTime12h(tt[tti][0], tt[tti][1], 2, 2, size, height, 1)\n            oled.text(str(tt[tti][0]) + ':' + str(tt[tti][1]), 0, 54, 1)\n            oled.show()\n            sleep(.1)\n
    "},{"location":"lessons/15-scale-testing/#sample-code","title":"Sample Code","text":"
    # Lab 42: Scale Test test v2\n\nfrom machine import Pin\nfrom time import sleep\nimport ssd1306\nimport config\n\nSCL=Pin(config.SCL_PIN) # SPI CLock\nSDA=Pin(config.SDA_PIN) # SPI Data\n\nRES = Pin(config.RESET_PIN) # Reset\nDC = Pin(config.DC_PIN) # Data/command\nCS = Pin(config.CS_PIN) # Chip Select\nWIDTH = config.WIDTH\nHEIGHT = config.HEIGHT\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(WIDTH, HEIGHT, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n# digit is the numer to display\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  if digit > 9 or digit < 0:\n      print('Error: digit out of range:', digit)\n      return -1\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottom, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottom element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottom\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + (height // 2)\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n\ndef drawTime12h(hour, minute, x, y, width, height, color):\n\n    # this does not scale\n    am_pm_font_height = 8\n\n    # horizontal spacing\n    x1 = .73 # width of the hour tens digit (1 or off)\n    x2 = .25 # space between hour tens and hour ones\n    x3 = 3.0 # digit width\n    x4 = 1.35 # space beteen hour ones and minute tens\n    x5 = .5 # space between minute tens and minute ones\n    x6 = .35 # space between minute ones and am/pm text\n    x7 = 1.5 # an/pm text width\n\n    # colon x positioning\n    x8 = .35 # space between hour ones and colon\n    x9 = .5 # colon width and height\n\n    # vertical\n    y1 = 5.31 # digit height\n    y2 = (y1 // 2) - .1 # to top colon\n    y3 = 1.5 # space between colons\n\n    total_width = x1 + x2 + 3*x3 + x4 + x5 + x6 + x7\n    # print(\"total width:\", total_width)\n    total_height = y1\n\n    # calculate the scaling ratios\n    x_scale = width / total_width\n    y_scale = height / total_height \n\n    digit_width = x3 * x_scale\n    digit_height = y1 * y_scale\n    # print(\"x scale:\", x_scale, \"y scale:\", y_scale)\n\n\n    time_width = total_width * x_scale\n    # print(\"time_width:\", time_width)\n\n    # thickness calculation based on a fraction of the width\n    thickness = int(.25 * digit_width)\n\n    if hour > 12:\n        hour12 = hour - 12\n    else: hour12 = hour\n\n    hour_minute = hour % 10\n    if hour_minute == 0:\n        hour_minute = 2\n\n    # hour tens display \n    if hour12 == 0 or hour12 > 9:\n        oled.fill_rect(x,y,int(x1*x_scale),int(y1*y_scale), color)\n\n    # hour ones for the d, x,y,w,h, t,c\n    if hour12 == 0:\n        hour12 = 12\n    hour_ones_x = int((x + x1 + x2)*x_scale)\n    drawDigit(hour12 % 10, hour_ones_x, y, int(x3*x_scale), int(y1*y_scale), thickness, color)\n\n    # minute tens ones digit, x,y,w,h\n    min_tens_x = int((x + x1 + x2 + x3 + x4)*x_scale)\n    drawDigit(minute // 10, min_tens_x, y, int(x3*x_scale), int(y1*y_scale), thickness, color)\n\n    # minute ones digit d, x,y,w,h, t, c\n    min_ones_x = int((x + x1 + x2 + 2*x3 + x4 + x5)*x_scale)\n    drawDigit(minute % 10, min_ones_x, y, int(x3*x_scale), int(y1*y_scale), thickness, color)\n\n    # draw colon\n    colon_size = int(x9*x_scale)\n    # top colon\n    oled.fill_rect(int((x+x1+x2+x3+x8)*x_scale), y+int(y2*y_scale), colon_size, colon_size, color)\n    # bottom colon\n    oled.fill_rect(int((x+x1+x2+x3+x8)*x_scale), y+int((y2+y3)*y_scale), colon_size, colon_size, color)\n\n    # AM/PM\n    if hour < 12:\n        am_pm_text = 'am'\n    else:\n        am_pm_text = 'pm'\n    # but here.  It displays outside the width\n    am_pm_x = min_ones_x + int((x3+x6)*x_scale)\n    # print('am/pm x:', am_pm_x)\n    oled.text(am_pm_text, am_pm_x, y + int(y1*y_scale) - am_pm_font_height, color)\n\n    oled.show()\n\n# test times\ntt = [[00,00], [12,59], [12,00], [8,33], [13,59], [23,59]]\n\nwhile True:\n    ## tti is the test time index\n    for tti in range(0,len(tt)):\n        for size in range(20, 110):\n            oled.fill(0) # clear screen\n            # bounding box for the entire screen\n            # oled.rect(0,0, WIDTH-1, HEIGHT-1, 1)\n\n            # bounding box for the time region\n            height = int(size*.5)\n            oled.rect(0, 0, size+20, height+5, 1)\n            # print(\"h=\", tt[tti][0], \"min:\", tt[tti][1])\n            drawTime12h(tt[tti][0], tt[tti][1], 2, 2, size, height, 1)\n            oled.text(str(tt[tti][0]) + ':' + str(tt[tti][1]), 0, 54, 1)\n            oled.show()\n            sleep(.1)\n
    "},{"location":"lessons/30-ili9341/","title":"ILI9341 Drawing","text":"

    The ILI9341 chip is a 262144-color single-chip SOC driver for a TFT liquid crystal display with a resolution of 240x320 dots (RGB).

    Source Code

    "},{"location":"lessons/30-ili9341/#configuration-file","title":"Configuration file","text":"

    These examples will all use the following config file:

    config.py

    SCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\n

    We also put the color names in a colors.py file that calculates the colors using a name.

    from ili9341 import color565\n\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nCYAN = color565(0,255,255)\nPURPLE = color565(255,0,255)\n
    "},{"location":"lessons/30-ili9341/#simple-drawing","title":"Simple Drawing","text":""},{"location":"lessons/40-machine-info/","title":"Machine Info","text":""},{"location":"lessons/40-machine-info/#modules","title":"Modules","text":"
    help('modules')\n
    "},{"location":"lessons/40-machine-info/#clock-frequency","title":"Clock Frequency","text":"
    import machine\nprint('freq:', machine.freq())\n
    "},{"location":"lessons/40-machine-info/#operating-system","title":"Operating System","text":"
    os.uname()\n
    os.statvfs(path)\n
    "},{"location":"lessons/40-machine-info/#platform","title":"Platform","text":"
    platform.platform()\n
    "},{"location":"lessons/50-ds1307-breadboard/","title":"Using the DS1307 IC On A Breadboard","text":"

    You can use the DS1307 IC directly on a breadboard without a development board. Here's what you'll need:

    1. DS1307 IC (8-pin DIP package)
    2. 32.768 kHz crystal oscillator
    3. CR2032 battery holder and battery (for backup power)
    4. Two 4.7k\u03a9 pull-up resistors (for I2C)
    5. 0.1\u00b5F decoupling capacitor
    6. Standard through-hole breadboard

    The basic connections are:

    DS1307 Pinout:\nPin 1 (X1) -> Crystal\nPin 2 (X2) -> Crystal\nPin 3 (VBAT) -> Battery positive\nPin 4 (GND) -> Ground\nPin 5 (SDA) -> I2C Data (needs pull-up)\nPin 6 (SCL) -> I2C Clock (needs pull-up)\nPin 7 (SQW) -> Optional square wave output\nPin 8 (VCC) -> 5V power`\n

    The biggest advantages of using the raw IC are:

    • Lower cost than module boards
    • Smaller footprint
    • More control over the circuit design
    • Better understanding of the RTC system

    Just remember that the DS1307 requires 5V power (unlike its successor DS3231 which can work with 3.3V), so make sure your microcontroller's I2C lines can handle 5V or use a level shifter if necessary.

    "},{"location":"prompts/","title":"Prompts","text":"
    • Course Description
    • Concept Enumeration
    • Concept Dependency
    • Concept Taxonomy
    • Taxonomy Assignments
    • Banner Image
    "},{"location":"prompts/01-course-description/","title":"Generating a Course Description for the Clocks and Watches with MicroPython Course","text":"

    Prompt

    Please generate a course description for a 14-week course for high-school students called \"Building Clocks and Watches with MicroPython\".

    The course is a hands on-course that uses the Raspberry Pi Pico W and low-cost displays to create a fun collection of projects for kids learning how to program.

    We start with a simple clock that uses a LED clock display and then progress to using a web service and an 128x64 OLED display. We also have demonstrations of building stopwatches and timers by integrating buttons and knobs to adjust settings.

    An underlying theme is to promote computational thinking including abstraction, decomposition, algorithms and pattern matching.

    The course provides students with a breadboard, Raspberry Pi Pico Ws, LEDs and OLED graphical displays.

    Use the 2001 Bloom Taxonomy to guild the course description.

    "},{"location":"prompts/01-course-description/#response","title":"Response","text":"

    Course Title: Building Clocks and Watches with MicroPython Duration: 14 Weeks Appropriate for: High School Students

    Course Description: In this 14-week, hands-on course, high school students will learn to design and program functional timekeeping devices---from simple LED clocks to sophisticated stopwatches and web-connected displays---using MicroPython on the Raspberry Pi Pico W. Throughout the course, students will be guided by the 2001 revision of Bloom's Taxonomy, moving from foundational knowledge to creative invention.

    1. Remember: Students begin by identifying essential electronic components---breadboards, microcontrollers, buttons, knobs, and displays---and recalling the fundamental concepts of MicroPython programming.
    2. Understand: Through teacher-led demonstrations, students explore how timing functions, input/output operations, and hardware connections work together to create a basic LED clock. They deepen their grasp of computational thinking by examining concepts like abstraction (focusing on relevant details) and decomposition (breaking large problems into smaller parts).
    3. Apply: As their skills grow, students practice wiring and programming a 128\u00d764 OLED display, interfacing with web services to fetch real-time data. They also implement stopwatches and timers, applying algorithms and pattern-matching techniques to manage user inputs and display outputs accurately.
    4. Analyze: Learners diagnose and troubleshoot various clock behaviors, studying how code efficiency and hardware choices influence device performance. They dissect timing errors, lag issues, and integration problems, refining both their programming and problem-solving skills.
    5. Evaluate: Working in teams, students test multiple clock designs to compare accuracy, power consumption, and user experience. They assess trade-offs---such as display readability vs. complexity---and refine solutions based on feedback, cost, and practicality.
    6. Create: Ultimately, students design and assemble their own custom timekeeping projects, combining LEDs, OLED displays, push buttons, and encoders. This final challenge showcases their ability to unify hardware and code into a polished, functioning prototype.

    By the end of the course, students will have built a diverse collection of digital clocks, stopwatches, and timers while gaining a rich understanding of electronics, computational thinking, and MicroPython. They will leave empowered to continue exploring the world of embedded systems and creative hardware projects.

    "},{"location":"prompts/02-concept-enumeration/","title":"Concept Enumeration","text":"
    1. MicroPython
    2. Raspberry Pi Pico W
    3. Breadboard
    4. Powering Your Clocks and Watches
    5. USB Power
    6. Battery Power
    7. Battery Backup
    8. Battery Drain Calculation
    9. LED Clock Displays
    10. Real-time Clock
    11. The Thoney IDE
    12. Synchronizing time from the PC
    13. the localtime function
    14. MicroPython Syntax
    15. Loops
    16. Conditionals
    17. Functions
    18. Libraries
    19. Loading MicroPython Drivers
    20. Printing time to the console
    21. MicroPython Drawing Libraries
    22. Drawing Lines
    23. Drawing Text
    24. Drawing Pixels
    25. Drawing Rectangles
    26. Seven Segment Digits
    27. Drawing Circles
    28. Drawing Ellipses
    29. Drawing Arcs
    30. Drawing Polygons
    31. Changing Fonts
    32. Using MicroPython Drivers
    33. OLED Displays
    34. The Draw_Digit Function
    35. SmartWatch Displays
    36. Using 16 bits to represent color
    37. Framebuffer
    38. SPI interfaces
    39. Updating the entire screen with SPI
    40. Incremental screen drawing
    41. Drawing hands on an analog clock
    42. Using the sine and cosine functions
    43. Drawing tic marks on a watch face
    44. Drawing numbers on a watch face
    45. Loading Custom fonts
    "},{"location":"prompts/02-concept-enumeration/#response","title":"Response","text":"

    MicroPython Raspberry Pi Pico W Breadboard Powering Your Clocks and Watches USB Power Battery Power Battery Backup Battery Drain Calculation LED Clock Displays Real-time Clock (RTC) Overview The Thonny IDE Synchronizing Time from the PC The localtime() Function MicroPython Syntax Loops Conditionals Functions Libraries Loading MicroPython Drivers Printing Time to the Console MicroPython Drawing Libraries Drawing Lines Drawing Text Drawing Pixels Drawing Rectangles Drawing Circles Drawing Ellipses Drawing Arcs Drawing Polygons Changing Fonts Using MicroPython Drivers OLED Displays Smartwatch Displays Using 16 Bits to Represent Color Framebuffer in MicroPython SPI Interfaces Updating the Entire Screen via SPI Incremental Screen Drawing Drawing Hands on an Analog Clock Using math.sin() and math.cos() Drawing Tick Marks on a Watch Face Drawing Numbers on a Watch Face Loading Custom Fonts Using the time Module for Scheduling Using Internal Timers on the Raspberry Pi Pico External RTC Modules (e.g., DS1307, DS3231) Setting the System Clock from an External RTC Network Time Synchronization (NTP) Setting Up Wi\u2011Fi on the Pico W Working with MicroPython\u2019s network Module Parsing JSON (or Other) Time Data from APIs Displaying Date and Day of Week Creating a 7-Segment Style Digital Display Custom Segment-Based Displays Minimizing Power Consumption (Sleep Modes) Waking from Deep Sleep on RTC Alarm Setting Time with Buttons Using Interrupts for Button Input Button Debouncing Techniques Using A Rotary Encoder Setting Alarms with the RTC Connecting Speakers Playing a Sound Sound Encoding Timer-Based Events Playing Chimes Cuckoo Clocks Generating Beep or Alarm Tones Integrating External Sensors Temperature and Humidity Displaying Sensor Data Accelerometers for Orientation Tilt-Based Wake for Watch Display Ultra-Low Power Using E-Paper Displays Partial Refresh on E-Paper Techniques to Minimize Ghosting on E-Paper Using TFT Displays (e.g., ST7735, ILI9341) Comparing Display Technologies Color Animations on Watch Faces Flicker Reduction Techniques Double Buffering for Smooth Animations Using the micropython-ufont Library Asynchronous Code with uasyncio Time-Based Tasks with uasyncio Handling Concurrency of Time Updates & UI Using a Watchdog Timer for Reliability Logging & Debugging Time Issues Sleep Scheduling Tools for Measuring Battery Usage Hardware Documentation 3D Printing Watch Enclosures Using math Module for Geometry Time Zones & UTC Offsets Daylight Saving Time Using the Built-In Filesystem on Pico Logging Time Data to an SD Card Using I\u00b2C Sensors & Modules Menu Systems for Watch Settings Servo Motors for Mechanical Pointers Converting Between datetime Objects and Timestamps Generating Waveforms for Audio Implementing Clock Themes Fast Redraw Techniques (Blitting) Partial Screen Updates for Watch Faces Color Conversion & Palettes in MicroPython Handling 12-Hour vs. 24-Hour Formats Wi\u2011Fi\u2013Based Weather & Forecast Updates Using Sensors for Step Counting (Pedometer) Adding a LiPo Charging Circuit Chronograph Functionality Timer Stopwatch World Clocks

    "},{"location":"prompts/03-concept-dependency/","title":"Concept Dependency","text":"

    ``` prompt I am creating a course on \"Building Clock and Watches with MicroPython\".

    The goal of this course is to provide high-school students a fun way to learn computational thinking.\n\nI have listed below about 150 concepts taught in this course in a CSV file.  The first column is the ConceptID and the second column is the ConceptLabel.\n\nPlease create a fully connected concept dependency graph\nfor the concepts in this course.\n\nIn this step, for each Concept on this list below, create a new\nlist of other concepts on which it depends.  If a concept\ndepends on a specific concept that is not listed,\nthen we will need to add it as a new concept.\nThis will help us determine the teaching order of the Concepts.\n\nReturn the new list as a CSV file using the following format:\n\n1. The first column in the CSV file is a numeric concept\nID you assigned in the list above.\n2. The second column is the concept name.\n3. The third column is a pipe-delimited list of the Concept IDs that the concept depends upon.\n\nCheck your results to make sure that all concepts are connected to at least one other concept.\n\nFoundation Concepts are concepts that have no dependant concepts in this set.  \nFoundation Concepts have an empty third column.\n
    "},{"location":"prompts/04-concept-taxonomy/","title":"Concept Taxonomy","text":"

    Prompt

    Given the concepts below, our next step is to create a 10-element taxonomy of these concepts for the book \"Building Clocks and Watches with MicroPython\".

    Your task is to organize these concepts into a taxonomy by grouping similar Concepts into one of ten categories. Each category should include concepts that share similar characteristics, functions, or applications.

    Please suggest 10 categories for the taxonomy. Attempt to create categories that evenly distribute the concepts so that each category has a similar number of concepts in it.

    Ensure that the categories cover a range of concept types, including abstract ideas, practical applications, common misunderstandings, and real-world examples. Avoid redundancy and ensure that each category is distinct.

    You can use \"Foundational Concepts\" as your first category. You can use \"Terms and Definitions\" as a second category. You can use \"Example Projects\" as a 10th category.

    "},{"location":"prompts/04-concept-taxonomy/#chatgpt-o1-response","title":"ChatGPT o1 Response","text":"

    Thought about taxonomy for course concepts for 2m 17s

    Below is one possible 10\u2011category taxonomy that groups these 115 concepts into roughly even clusters. Each category highlights a distinct thematic area, from foundational ideas through advanced techniques and ending with example \"capstone\u2011style\" projects. Feel free to adjust or rename categories as needed for your curriculum goals.

    "},{"location":"prompts/04-concept-taxonomy/#category-1-foundational-concepts","title":"Category 1: Foundational Concepts","text":"

    These are the most basic building blocks and hardware essentials on which everything else depends.

    1. (0) Timekeeping Components
    2. (1) MicroPython
    3. (2) Raspberry Pi Pico W
    4. (3) Breadboard
    5. (4) Power
    6. (5) USB Power
    7. (6) Battery Power
    8. (7) Battery Backup
    9. (8) Battery Drain Calculation
    10. (10) Real-time Clocks
    11. (11) The Thonny IDE
    12. (91) Hardware Documentation
    "},{"location":"prompts/04-concept-taxonomy/#category-2-terms-definitions","title":"Category 2: Terms & Definitions","text":"

    Core programming syntax and \"must-know\" terminology used throughout the course.

    1. (13) The localtime() Function
    2. (14) MicroPython Syntax
    3. (15) Loops
    4. (16) Conditionals
    5. (17) Functions
    6. (18) Libraries
    7. (20) Printing Time to the Console
    8. (34) Using 16 Bits to Represent Color
    9. (93) Using math Module for Geometry
    10. (94) Time Zones & UTC Offsets
    11. (95) Daylight Saving Time
    12. (101) Converting Between datetime Objects and Timestamps
    "},{"location":"prompts/04-concept-taxonomy/#category-3-displays","title":"Category 3: Displays","text":"

    An overview of the different display types you might use in clocks/watches.

    1. (9) LED Clock Displays
    2. (21) Displays
    3. (32) OLED Displays
    4. (33) Smartwatch Displays
    5. (53) Creating a 7-Segment Style Digital Display
    6. (54) Custom Segment-Based Displays
    7. (75) Using E-Paper Displays
    8. (76) Partial Refresh on E-Paper
    9. (77) Techniques to Minimize Ghosting on E-Paper
    10. (78) Using TFT Displays (e.g., ST7735, ILI9341)
    11. (79) Comparing Display Technologies
    12. (103) Implementing Clock Themes
    "},{"location":"prompts/04-concept-taxonomy/#category-4-basic-drawing-font-tools","title":"Category 4: Basic Drawing & Font Tools","text":"

    Fundamental graphics APIs and driver-loading concepts.

    1. (19) Loading MicroPython Drivers
    2. (22) Drawing Lines
    3. (23) Drawing Text
    4. (24) Drawing Pixels
    5. (25) Drawing Rectangles
    6. (26) Drawing Circles
    7. (27) Drawing Ellipses
    8. (28) Drawing Arcs
    9. (29) Drawing Polygons
    10. (30) Changing Fonts
    11. (31) Using MicroPython Drivers
    12. (43) Loading Custom Fonts
    "},{"location":"prompts/04-concept-taxonomy/#category-5-advanced-graphics-animations","title":"Category 5: Advanced Graphics & Animations","text":"

    More complex graphics techniques and math-based rendering.

    1. (35) Framebuffer in MicroPython
    2. (39) Drawing Hands on an Analog Clock
    3. (40) Using math.sin() and math.cos()
    4. (41) Drawing Tick Marks on a Watch Face
    5. (42) Drawing Numbers on a Watch Face
    6. (80) Color Animations on Watch Faces
    7. (81) Flicker Reduction Techniques
    8. (82) Double Buffering for Smooth Animations
    9. (104) Fast Redraw Techniques (Blitting)
    10. (105) Partial Screen Updates for Watch Faces
    11. (106) Color Conversion & Palettes in MicroPython
    12. (83) Using the micropython-ufont Library
    "},{"location":"prompts/04-concept-taxonomy/#category-6-graphics-asynchronous-concurrency","title":"Category 6: Graphics, Asynchronous, & Concurrency","text":"

    All about getting time from the internet, using Wi-Fi, and handling multiple tasks.

    1. (12) Synchronizing Time from the PC
    2. (45) Using Internal Timers on the Raspberry Pi Pico
    3. (48) Network Time Synchronization (NTP)
    4. (49) Setting Up WiFi on the Pico W
    5. (50) Working the network module
    6. (51) Parsing JSON
    7. (65) Timer-Based Events
    8. (84) Asynchronous Code with uasyncio
    9. (85) Time-Based Tasks with uasyncio
    10. (86) Handling Concurrency of Time Updates & UI
    11. (108) WiFi-Based Weather & Forecast Updates
    12. (114) World Clocks
    "},{"location":"prompts/04-concept-taxonomy/#category-7-sensors-modules","title":"Category 7: Sensors & Modules","text":"

    External hardware modules, from RTC chips to accelerometers and I\u00b2C sensors.

    1. (46) External RTC Modules (DS1307, DS3231)
    2. (47) Setting the System Clock from an External RTC
    3. (69) Integrating External Sensors
    4. (70) Temperature and Humidity
    5. (71) Displaying Sensor Data
    6. (72) Accelerometers for Orientation
    7. (73) Tilt-Based Wake for Watch Display
    8. (98) Using I\u00b2C Sensors & Modules
    9. (109) Using Sensors for Step Counting (Pedometer)
    10. (110) Adding a LiPo Charging Circuit
    11. (90) Tools for Measuring Battery Usage
    12. (100) Servo Motors for Mechanical Pointers
    "},{"location":"prompts/04-concept-taxonomy/#category-8-user-input-time-functions","title":"Category 8: User Input & Time Functions","text":"

    Handling buttons, debouncing, rotary encoders, and time-related features.

    1. (52) Displaying Date and Day of Week
    2. (57) Setting Time with Buttons
    3. (58) Using Interrupts for Button Input
    4. (59) Button Debouncing Techniques
    5. (60) Using A Rotary Encoder
    6. (61) Setting Alarms with the RTC
    7. (96) Using the Built-In Filesystem on Pico
    8. (97) Logging Time Data to an SD Card
    9. (74) Ultra-Low Power
    10. (99) Menu Systems for Watch Settings
    11. (107) Handling 12-Hour vs. 24-Hour Formats
    12. (111) Chronograph Functionality
    "},{"location":"prompts/04-concept-taxonomy/#category-9-audio-power-management","title":"Category 9: Audio & Power Management","text":"

    Generating sounds, mechanical movements, and minimizing power consumption.

    1. (62) Connecting Speakers
    2. (63) Playing a Sound
    3. (64) Sound Encoding
    4. (66) Playing Chimes
    5. (67) Cuckoo Clocks
    6. (68) Generating Beep or Alarm Tones
    7. (102) Generating Waveforms for Audio
    8. (55) Minimizing Power Consumption (Sleep Modes)
    9. (56) Waking from Deep Sleep on RTC Alarm
    10. (89) Sleep Scheduling
    11. (87) Using a Watchdog Timer for Reliability
    12. (88) Logging & Debugging Time Issues
    "},{"location":"prompts/04-concept-taxonomy/#category-10-example-projects","title":"Category 10: Example Projects","text":"

    A set of \"capstone\" or real-world style projects/enhancements.

    1. (92) 3D Printing Watch Enclosures
    2. (100) [If not placed elsewhere --- but here we used 100 in Category 7, so you can swap if you prefer]
    3. (103) [If not used in Displays]
    4. (112) Timer Project
    5. (113) Stopwatch Project
    6. (109) [If not in Sensors]
    7. (99) [If not in User Input]
    8. ( ... )

    Depending on how you ultimately shuffle things around, you can populate this \"Example Projects\" category with any concepts that serve well as culminating projects---for example, \"Cuckoo Clocks,\" \"Playing Chimes,\" \"Implementing Clock Themes,\" \"Using Sensors for Step Counting,\" or \"Servo Motors for Mechanical Pointers.\"

    "},{"location":"prompts/04-concept-taxonomy/#final-notes","title":"Final Notes","text":"
    1. Balancing the Categories

      • Each category has ~11--12 items (with minor adjustments possible).
      • Some concepts (e.g., \"Servo Motors,\" \"Implementing Clock Themes,\" or \"Cuckoo Clocks\") could fit either under a main topic (like \"Sensors & Modules\" or \"Audio & Power\") or under \"Example Projects,\" depending on whether you treat them as discrete lessons or culminating builds.
      • Avoiding Duplication

    In a real curriculum, certain topics (e.g., \"External RTC Modules\" vs. \"Setting Alarms with the RTC\") might overlap across multiple categories. To keep it simple, each concept is listed once here.

    1. Adapt as Needed

    This taxonomy is a starting point. You may decide to rename categories (e.g., split \"Audio & Power Management\" into two) or move individual concepts around to best match your teaching flow.

    By defining these ten thematic groupings, you'll have a clear roadmap for both the sequence of lessons and the range of coverage in \"Building Clocks and Watches with MicroPython.\"

    "},{"location":"prompts/05-taxonomy-assignment/","title":"Taxonomy Assignment","text":"

    Prompt

    That is very good. Now please return a new CSV file that appends the TaxonomyID as the fourth column. The new CSV file you create now has the following format:

    1. The first column in the CSV file is a numeric ConceptID\nID you assigned in the CSV file above.\n2. The second column is the ConceptLabel from the CSV file above.\n3. The third column is a pipe-delimited Dependencies of the Concept IDs that the concept depends upon.\n4. The fourth column is the numeric TaxonomyID from the taxonomy you generated above.\n
    "},{"location":"prompts/06-banner-image/","title":"Generate a Banner Image","text":"

    Prompt

    Please generate a banner image for my new website called \"Designing and Building Clocks and Watches with MicroPython and AI\". Make the banner features high school age students with diverse skin tone having fun working together and building clock and watch projects in a school. Use bright colors but no text. Use images of both digital and analog clocks and smartwatches. Place breadboards, wire, microcontrollers digital watch displays, smartwatch displays and speakers on the table.

    "},{"location":"prompts/06-banner-image/#sample-result","title":"Sample Result","text":""},{"location":"prompts/07-faq/","title":"FAQ Prompt","text":"

    Prompt

    Take a look at the course description and the concepts lists file in this project. Now create a FAQ of the 100 most likely questions that students will ask.

    Return the FAQ in Markdown format with the question in level 4 headers and the answers in the body text. Group the FAQs in level 2 headers.

    "},{"location":"prompts/07-faq/#result","title":"Result","text":""},{"location":"prompts/07-faq/#building-clocks-and-watches-with-micropython-frequently-asked-questions","title":"Building Clocks and Watches with MicroPython - Frequently Asked Questions","text":""},{"location":"prompts/07-faq/#general-course-information","title":"General Course Information","text":""},{"location":"prompts/07-faq/#what-prior-knowledge-do-i-need-for-this-course","title":"What prior knowledge do I need for this course?","text":"

    No specific electronics or programming experience is required. However, basic computer literacy and comfort with mathematics at a high school level will be helpful. The course starts with fundamentals and builds up gradually.

    "},{"location":"prompts/07-faq/#how-long-is-each-class-session","title":"How long is each class session?","text":"

    While the course runs for 14 weeks, specific class session lengths are determined by your school's schedule. Contact your instructor for the exact timing of your sessions.

    "},{"location":"prompts/07-faq/#do-i-need-to-purchase-my-own-equipment","title":"Do I need to purchase my own equipment?","text":"

    Check with your instructor about equipment policies. Generally, core components like the Raspberry Pi Pico W and basic electronics will be provided, but you may want to purchase additional components for your final project.

    "},{"location":"prompts/07-faq/#what-software-do-i-need-to-install","title":"What software do I need to install?","text":"

    You'll need the Thonny IDE (a Python editor designed for MicroPython), which is free and works on Windows, Mac, and Linux. Your instructor will guide you through the installation process during the first week.

    "},{"location":"prompts/07-faq/#technical-questions","title":"Technical Questions","text":""},{"location":"prompts/07-faq/#what-is-micropython-and-how-is-it-different-from-regular-python","title":"What is MicroPython and how is it different from regular Python?","text":"

    MicroPython is a streamlined version of Python designed to run on microcontrollers. While it maintains Python's core features and syntax, it's optimized for hardware control and has special libraries for working with electronic components.

    "},{"location":"prompts/07-faq/#what-is-a-raspberry-pi-pico-w","title":"What is a Raspberry Pi Pico W?","text":"

    The Raspberry Pi Pico W is a small, affordable microcontroller board with built-in Wi-Fi. It's perfect for learning because it's user-friendly, well-documented, and has plenty of input/output pins for connecting different components.

    "},{"location":"prompts/07-faq/#will-we-be-doing-any-soldering","title":"Will we be doing any soldering?","text":"

    Most projects will use breadboards for non-permanent connections. Some optional advanced projects might involve soldering, but this will be optional and supervised.

    "},{"location":"prompts/07-faq/#how-accurate-will-our-clocks-be","title":"How accurate will our clocks be?","text":"

    The accuracy depends on the components used. With the basic oscillator, clocks might drift a few seconds per day. When we add a Real-Time Clock (RTC) module, accuracy improves significantly to within a few seconds per month.

    "},{"location":"prompts/07-faq/#project-related-questions","title":"Project-Related Questions","text":""},{"location":"prompts/07-faq/#what-kind-of-displays-will-we-use","title":"What kind of displays will we use?","text":"

    We'll work with several types: - Simple LEDs for basic digital displays - 128\u00d764 OLED displays for more sophisticated interfaces - Other display options for final projects

    "},{"location":"prompts/07-faq/#can-i-create-my-own-custom-clock-design-for-the-final-project","title":"Can I create my own custom clock design for the final project?","text":"

    Yes! The final project is designed to be creative and personal. You can combine different components and features we've learned about to create something unique.

    "},{"location":"prompts/07-faq/#how-will-we-handle-time-zones-and-daylight-saving-time","title":"How will we handle time zones and daylight saving time?","text":"

    We'll learn to sync time using web services (when Wi-Fi is available) and program time zone adjustments. Managing daylight saving time will be covered as part of the advanced features.

    "},{"location":"prompts/07-faq/#learning-and-assessment","title":"Learning and Assessment","text":""},{"location":"prompts/07-faq/#how-will-i-be-graded","title":"How will I be graded?","text":"

    Assessment typically includes: - Participation in class activities and discussions - Completion of hands-on labs and exercises - Quality and functionality of projects - Final project presentation and documentation

    "},{"location":"prompts/07-faq/#what-happens-if-my-clock-doesnt-work","title":"What happens if my clock doesn't work?","text":"

    Troubleshooting is a crucial part of the learning process. You'll have support from instructors and peers, and we'll learn systematic debugging approaches. Making mistakes and fixing them is how we learn!

    "},{"location":"prompts/07-faq/#can-i-work-with-ai-tools-during-the-course","title":"Can I work with AI tools during the course?","text":"

    Yes, part of the course includes learning how to effectively use AI tools for design and problem-solving. We'll cover best practices for AI collaboration while ensuring you understand the fundamental concepts.

    "},{"location":"prompts/07-faq/#hardware-and-components","title":"Hardware and Components","text":""},{"location":"prompts/07-faq/#what-happens-if-i-accidentally-damage-a-component","title":"What happens if I accidentally damage a component?","text":"

    Don't worry! Learning electronics involves some trial and error. Basic components are relatively inexpensive and replaceable. Just inform your instructor if something breaks.

    "},{"location":"prompts/07-faq/#how-do-breadboards-work","title":"How do breadboards work?","text":"

    A breadboard is a reusable platform for creating temporary electrical connections. We'll spend time early in the course understanding how they work and practicing proper connection techniques.

    "},{"location":"prompts/07-faq/#whats-the-difference-between-digital-and-analog-inputsoutputs","title":"What's the difference between digital and analog inputs/outputs?","text":"

    Digital signals are either on (1) or off (0), while analog signals can have many values in between. We'll use both types: digital for buttons and simple LEDs, analog for sensors and variable controls.

    "},{"location":"prompts/07-faq/#programming-concepts","title":"Programming Concepts","text":""},{"location":"prompts/07-faq/#do-i-need-to-memorize-all-the-micropython-commands","title":"Do I need to memorize all the MicroPython commands?","text":"

    No, you don't need to memorize everything. We'll provide reference materials, and part of learning is knowing how to find and use documentation effectively.

    "},{"location":"prompts/07-faq/#what-if-i-miss-a-class-and-fall-behind","title":"What if I miss a class and fall behind?","text":"

    Each concept builds on previous learning, but we'll provide catch-up resources and extra help sessions. Talk to your instructor as soon as possible if you fall behind.

    "},{"location":"prompts/07-faq/#how-will-we-debug-our-code","title":"How will we debug our code?","text":"

    We'll learn several debugging techniques: - Using print statements for troubleshooting - Reading error messages - Using the Thonny debugger - Systematic problem-solving approaches

    "},{"location":"prompts/07-faq/#safety-and-best-practices","title":"Safety and Best Practices","text":""},{"location":"prompts/07-faq/#is-there-any-risk-of-electric-shock","title":"Is there any risk of electric shock?","text":"

    The Pico W and components we use operate at very low voltages (3.3V or 5V) which are safe to handle. However, we'll still learn and follow proper safety procedures.

    "},{"location":"prompts/07-faq/#how-do-i-protect-the-electronic-components","title":"How do I protect the electronic components?","text":"

    We'll cover basic handling procedures including: - Static electricity precautions - Proper connection techniques - Component storage and handling - Avoiding common mistakes that could damage components

    "},{"location":"prompts/07-faq/#advanced-topics-and-extensions","title":"Advanced Topics and Extensions","text":""},{"location":"prompts/07-faq/#can-we-add-features-like-alarms-or-stopwatch-functions","title":"Can we add features like alarms or stopwatch functions?","text":"

    Yes! As you progress through the course, you'll learn to add various features including: - Multiple alarms - Stopwatch and timer functions - Custom sounds and alerts - Special display effects

    "},{"location":"prompts/07-faq/#will-we-learn-about-power-management","title":"Will we learn about power management?","text":"

    Yes, we'll cover power management including: - Battery operation - Sleep modes - Power-efficient programming - Battery life optimization

    "},{"location":"prompts/07-faq/#future-applications","title":"Future Applications","text":""},{"location":"prompts/07-faq/#can-i-use-these-skills-for-other-projects","title":"Can I use these skills for other projects?","text":"

    Absolutely! The skills you'll learn apply to many other electronics and programming projects: - Other types of electronic devices - Home automation projects - Sensor-based systems - IoT (Internet of Things) devices

    "},{"location":"prompts/07-faq/#how-does-this-course-prepare-me-for-further-study","title":"How does this course prepare me for further study?","text":"

    This course builds valuable skills for: - Computer science courses - Engineering programs - Electronics projects - General problem-solving - Understanding modern technology

    "},{"location":"prompts/07-faq/#tools-and-resources","title":"Tools and Resources","text":""},{"location":"prompts/07-faq/#what-online-resources-can-we-use","title":"What online resources can we use?","text":"

    We'll use various resources including: - MicroPython documentation - Raspberry Pi Pico documentation - Component datasheets - Online simulators - Programming reference guides

    "},{"location":"prompts/07-faq/#will-we-use-version-control-like-git","title":"Will we use version control like Git?","text":"

    While not required, we'll introduce basic version control concepts and how they can help manage your code as projects become more complex.

    "},{"location":"prompts/07-faq/#collaboration-and-community","title":"Collaboration and Community","text":""},{"location":"prompts/07-faq/#can-we-work-in-teams","title":"Can we work in teams?","text":"

    Yes! Many activities will involve pair programming or team collaboration. The final project can be individual or team-based, depending on complexity and scope.

    "},{"location":"prompts/07-faq/#how-can-we-share-our-projects-with-others","title":"How can we share our projects with others?","text":"

    We'll discuss ways to: - Document your work - Create project presentations - Share code responsibly - Collaborate with other students - Showcase your projects

    "},{"location":"prompts/07-faq/#getting-help","title":"Getting Help","text":""},{"location":"prompts/07-faq/#what-if-i-get-stuck-on-a-problem","title":"What if I get stuck on a problem?","text":"

    Multiple support options are available: - In-class help from instructors - Peer support - Office hours - Online resources - Lab assistance sessions

    "},{"location":"prompts/07-faq/#can-i-get-extra-help-outside-of-class","title":"Can I get extra help outside of class?","text":"

    Yes, instructors will have office hours and may offer additional lab time for students who want extra practice or help.

    "},{"location":"prompts/07-faq/#course-materials","title":"Course Materials","text":""},{"location":"prompts/07-faq/#what-should-i-bring-to-class","title":"What should I bring to class?","text":"

    Typically you'll need: - Notebook for taking notes - Computer (if not provided) - Any assigned reading materials - Your project components once distributed

    "},{"location":"prompts/07-faq/#how-should-i-store-and-transport-my-projects","title":"How should I store and transport my projects?","text":"

    We'll provide guidance on: - Component storage - Project organization - Safe transport methods - Protecting delicate components

    "},{"location":"prompts/07-faq/#final-projects","title":"Final Projects","text":""},{"location":"prompts/07-faq/#what-makes-a-good-final-project","title":"What makes a good final project?","text":"

    Strong final projects typically: - Solve a real problem or fulfill a genuine need - Demonstrate technical skills learned in the course - Show creativity and originality - Are well-documented - Function reliably

    "},{"location":"prompts/07-faq/#can-i-continue-working-on-my-project-after-the-course-ends","title":"Can I continue working on my project after the course ends?","text":"

    Yes! You'll have the knowledge to continue developing and improving your projects. We'll discuss ways to extend your learning and continue exploring electronics and programming.

    "},{"location":"prompts/08-glossary/","title":"Generating a Glossary of Terms","text":""},{"location":"prompts/08-glossary/#prompt","title":"Prompt","text":"

    Prompt

    Prompt Name: Glossary for Clocks and Watches with MicroPython Book

    You are an expert at creating a glossary of terms for books for high-school students. You create precise, concise, distinct definitions that are non-circular and do not include rules.

    Your terms are written for the 9th grade reading level.

    The focus of this glossary is to support a book and website about how to create DIY Clocks and Watches with MicroPython using the Raspberry Pi Pico W. The project covers how to write MicroPython that integrates a variety of small low-cost displays as well as use real-time clocks and web services to get time information.

    For each term, return a term label in a level 4 markdown header. Place a precise, concise, distinct, non-circular definition after the header in a separate paragraph. Do not include the term in the definitions.

    Go to the project area and use the file MicroPython_Clock_Concepts.csv for a complete list of concepts that need definitions.

    If appropriate create an example of how that term might be\nused in the website.  Use **Example:** with no newline after it.\n\nReturn the entire glossary of terms in a single Markdown file\nfor all concepts in alphabetical order.\n
    "},{"location":"setup/","title":"A Guide to Setting up Your Clocks and Watches Labs","text":"

    This section is intended for parents, mentors, teachers and curriculum developers who are responsible for creating a great experience for your students. Within this audience we have typically seen two extremes.

    1. Value-based purchasers with limited budgets who are good at long-term planning. They pre-order parts form China on eBay and Alibaba in bulk and avoid high-cost shipping fees.

    2. Parents in high-disposable income households with limited time and large budgets. They just want to click on a few links and have the parts shipped overnight.

    This Setup Guide attempts to provide information for both of these groups. Note that we have used generative AI to help you source the lowest costs parts. We encourage you to ask your generative AI chatbot about sourcing strategies that balance low-cost and fast delivery.

    "},{"location":"setup/#minimal-setup","title":"Minimal Setup","text":"

    The minimal setup consists of just four parts:

    1. A 1/2 size solderless breadboard - about $2
    2. 20cm jumper wires (male-to-female) - also known as Dupont connectors - about $1
    3. A Raspberry Pi Pico - about $4 or $5 with headers presoldered - you can get the \"W\" if you want to go wireless and use WiFi to sync the time
    4. A OLED display - which range from $5 to $20 depending on the size

    If you are patient and clever you can purchase these parts in bulk and keep the kit price under $10 - although the OLED display will be hard to read from more than a few feet away.

    Image Caption: An example of a 2.42\" OLED display connected to a 400-tie breadboard holding a Raspberry Pi W with two buttons for changing the display settings.

    "},{"location":"setup/#sample-amazon-links","title":"Sample Amazon Links","text":"

    Here are the Amazon Links for these parts:

    1. Half Size Solderless Breadboard Search on Amazon
    2. Sample 4-Pack for $6
    3. 20cm male-to-female Dupont Connectors $4 for 40 connectors
    4. Raspberry Pi Pico $8
    5. Amazon Keyword Search for 2.42\" OLED Display 128*64 SPI SSD1309
    6. Amazon Prime 2.42\" OLED Display for $14 in 4 Colors

    Note that MicroCenter sells the Pico for $3.99. So you are paying about double on Amazon for some of these parts.

    "},{"location":"setup/#sample-e-bay-links","title":"Sample E-Bay Links","text":"
    1. Half Size Solderless Breadboard Search on EBay
    2. 10X 400 Point Solderless Breadboard for $14
    3. 20cm male-to-female dupont connectors
    4. 10/20/30CM MM, MF, FF Dupont Wire Jumper Cable 40PIN Dupont Line Connector for $4
    5. 2.42\" OLED Display 128*64 SPI SSD1309
    "},{"location":"setup/#other-components","title":"Other Components","text":""},{"location":"setup/#display-cable-harness","title":"Display Cable Harness","text":"

    Display Cable Harness

    "},{"location":"setup/#real-time-clocks","title":"Real Time Clocks","text":"

    Technically you can get a clock or watch running without a real-time clock (RTC). The problem is that the clock will not be very accurate unless you continually sync the time using WiFi or with your host computer.

    However, learning how to use the a RTC is a key learning concept and learning how to use the I2C serial interface is also a good concept to know. So it is optional but strongly encouraged.

    "},{"location":"setup/#the-ds1307","title":"The DS1307","text":"

    Although this board is old, it is a simple and low-cost part that is easy to use. Most of the development boards come with their own crystal and an I2C interface.

    "},{"location":"setup/#the-ds3231","title":"The DS3231","text":"

    The DS3231 is one of the most commonly used real-time clock (RTC) modules paired with microcontrollers like the Raspberry Pi Pico. It's popular because it:

    1. Has high accuracy (temperature-compensated crystal oscillator)
    2. Maintains accuracy over a wide temperature range
    3. Has built-in temperature compensation
    4. Uses the I2C interface, which is easy to implement
    5. Includes a battery backup option
    6. Is relatively inexpensive
    7. Has extensive library support across different platforms

    The second most common is probably the DS1307, which is an older and simpler version. While less accurate than the DS3231, it's even less expensive and still perfectly suitable for many basic timekeeping applications.

    For microcontrollers in particular, the DS3231 tends to be favored because its accuracy doesn't depend on the microcontroller's clock, and it maintains accurate time even when the main microcontroller is reset or loses power.

    "},{"location":"setup/02-purchasing-parts/","title":"Strategy for Parts Purchasing Guide","text":""},{"location":"setup/02-purchasing-parts/#breadboards","title":"Breadboards","text":"

    We strongly suggest purchasing breadboards in bulk at least 10 at a time.

    "},{"location":"setup/02-purchasing-parts/#microcontrollers","title":"MicroControllers","text":"

    We love MicroCenter because they sell the Pico for $4

    "},{"location":"setup/02-purchasing-parts/#raspberry-pi-pico","title":"Raspberry Pi Pico","text":""},{"location":"setup/02-purchasing-parts/#raspberry-pi-pico-w","title":"Raspberry Pi Pico W","text":""},{"location":"setup/02-purchasing-parts/#displays","title":"Displays","text":""},{"location":"setup/02-purchasing-parts/#oled-displays","title":"OLED Displays","text":"

    Although the small 1\" OLED displays work, they are hard to read from a distance. We like the 2.42\" inch OLED displays since they are bright and have a wide viewing angle.

    "},{"location":"setup/02-purchasing-parts/#smartwatch-displays","title":"SmartWatch Displays","text":"

    Waveshare RP2040-LCD-1.28

    Ebay Listing for $21

    "},{"location":"setup/02-purchasing-parts/#led-strips","title":"LED Strips","text":""},{"location":"setup/02-purchasing-parts/#smartwatch-displays_1","title":"Smartwatch Displays","text":""},{"location":"setup/02-purchasing-parts/#real-time-clock-boards","title":"Real-Time Clock Boards","text":""},{"location":"setup/02-purchasing-parts/#the-ds1307","title":"The DS1307","text":"

    Although this board is old, it is a simple and low-cost part that is easy to use. Most of the development boards come with their own crystal and an I2C interface.

    "},{"location":"setup/02-purchasing-parts/#the-ds3231","title":"The DS3231","text":"

    The DS3231 is one of the most commonly used real-time clock (RTC) modules paired with microcontrollers like the Raspberry Pi Pico. It's popular because it:

    1. Has high accuracy (temperature-compensated crystal oscillator)
    2. Maintains accuracy over a wide temperature range
    3. Has built-in temperature compensation
    4. Uses the I2C interface, which is easy to implement
    5. Includes a battery backup option
    6. Is relatively inexpensive
    7. Has extensive library support across different platforms

    The second most common is probably the DS1307, which is an older and simpler version. While less accurate than the DS3231, it's even less expensive and still perfectly suitable for many basic timekeeping applications.

    For microcontrollers in particular, the DS3231 tends to be favored because its accuracy doesn't depend on the microcontroller's clock, and it maintains accurate time even when the main microcontroller is reset or loses power.

    Since this is quite specific technical information and while I believe this is accurate, you may want to verify these details, particularly regarding current market availability and relative popularity.

    "},{"location":"setup/03-display-cable-harness/","title":"Display Cable Harness","text":"

    Unlike simple sensors that only have a few wires, displays have up to seven wires that need to be connected. This can be tricky when we use breadboards where we can accidentally pull one wire out.

    To keep our displays running reliably, we can use a 20 cm ribbon cable and some hot glue to make a connector that is easy to hook up and be much more reliable.

    We start by purchasing some 20cm long Male-Female Dupont ribbon connectors from eBay. The price should be about $8 for 120 connectors. Make sure to get the Male-Female version.

    We then separate out seven of these wires trying to use the black and red colors in the GND and VCC edge of the group of wires.

    You can see a close-up of each of the colors and their connections in the picture below.

    At the other end of the cable, we need to make a small change in the order of the cable. Here are the changes:

    1. We separate the red wire from the rest of the group and connect the red to the 3.3V regulated output of the Raspberry Pi Pico. All our displays run on 3.3v now.
    2. We move the back GND wire to be in between the blue and purple CS and DC wires. This allows the row of all the wires to be connected in a single block of wires.

    We can then plug this group of wires directly into the breadboard from breadboard rows 3 to 9. This is shown below. Make sure the black GND is on the Pico GND on row 8 of the breadboard.

    We designed these connections with the following rules:

    1. The Clock (SCL) and Data (SDA) MUST be connected to rows 4 and 5 respectively because this is where SPI0 CLK and SPI0 TX are located.
    2. The other three signals RES, DC and CS can be on pin so we will use the rows that make the cable connectors direct to rows 6, 7 and 9. Note that GND is on breadboard row 8 which I mark with a black marker.

    We have found that once we create these cable assemblies with hot glue to keep the pins in the right order it makes it much easier to connect the displays.

    Warning

    Note that we still MUST make sure that the black wire in the wiring harness is connected to the GND. It is easy to get the cable reversed so make sure to double-check the cable orientation before you use power on the board.

    "},{"location":"setup/04-led-clocks/","title":"LED Clocks","text":"

    Our strategy for teaching is to provide a base set of examples of working clocks and watches. We then also provide a set of \"Challenges\" for students to go further. One challenge is can you use simple LEDs to create your own clock? This is where creativity comes in.

    "},{"location":"setup/05-ai-in-the-classroom/","title":"AI in the Classroom","text":"

    We also provide a sample set of prompts you can use to feed generative AI systems to create other lesson plans and learning artifacts such as MicroSims to complement these resources.

    "},{"location":"sims/","title":"Clocks and Watches Micro Simulations","text":"

    Learning Graph

    Binary Clock

    "},{"location":"sims/4-digits/","title":"Example of a Four-Digit Digital Clock Face","text":""},{"location":"sims/analog-face/","title":"Analog Clock Face","text":""},{"location":"sims/binary-clock/","title":"Binary Clock","text":"

    Run the Binary Clock MicroSim

    Edit the Microsim

    "},{"location":"sims/learning-graph/","title":"Learning Graph for Clocks and Watches with MicroPython","text":"

    View Learning Graph MicroSim

    "},{"location":"sims/templates/","title":"MicroSim Templates","text":"

    These templates are used to help guild your generative AI responses for consistency of the user interface.

    "},{"location":"sims/themes/","title":"Index","text":"

    Analog Clock Face Themes

    "},{"location":"sims/themes/#background-color","title":"Background Color","text":""},{"location":"sims/themes/#color-selection","title":"Color Selection","text":""},{"location":"sims/themes/#hand-types","title":"Hand Types","text":""},{"location":"sims/themes/#tic-mark-types","title":"Tic Mark Types","text":""},{"location":"sims/themes/#digit-types","title":"Digit Types","text":""},{"location":"sims/themes/#four-digits","title":"Four Digits","text":""},{"location":"sims/themes/#12-digits","title":"12 Digits","text":""}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Designing and Building Clocks and Watches with MicroPython and AI","text":"

    Welcome to the Clocks and Watches website!

    This website is a resource for teachers, mentors and students who want to have fun hands-on ways to learn computational thinking using the popular Python language. This course gives junior high and high school students the tools to design and build their own digital clocks and smart watches using low-cost components.

    This website contains detailed instructions for finding low-cost parts (many under $20/student) and customizing your custom clock and watch displays using MicroPython.

    These projects have only recently been possible due to the following developments:

    1. The 2021 release of the powerful $4 Raspberry Pi Pico microcontroller. It had almost 100x the power of the Arduino Uno and sold for 1/8th the price.
    2. The availability of low-cost high-contrast OLED and TFT displays for as low as $7 each. When we use the $4 Raspberry Pi Pico our classrooms can create a development system for under $15.
    3. The support of highly-optimized drawing of complex ellipse and polygon shapes into the frame buffer by the MicroPython runtime. This only became available in version 20 of the standard MicroPython runtime released in April of 2023. Before this every clock and watch project used custom math functions that slowed drawing times.
    4. The ability of WiFi-enabled microcontrollers that can synchronize with centralized time services using standard WiFi networks. We use the $5 Raspberry Pi Pico W in many of our projects.
    5. The availability of low-cost yet ultra-precise real-time clock chips like the DS3231.

    Our goal is to provide fun ways to teach computational thinking to a wide variety of students from 6th to 12th grades. If you can type, we have fun lesson plans from drawing simple shapes to complex clock and watch face designs.

    "},{"location":"#acknowledgments","title":"Acknowledgments","text":"

    I want to thank everyone in the MicroPython community for sharing their code. Each of the displays requires MicroPython drivers that have special features to keep drawing fast. We could not have high-quality lesson plans without your contributions. If I have not referenced the cool features of your drivers, please let me know!

    "},{"location":"#feedback-and-comments","title":"Feedback and Comments","text":"

    If you have any comments or feedback, please feel free to post these to our GitHub Issues. I don't check these issues every day, so please be patient and connect with others in the MicroPython community if you have urgent questions for a classroom.

    Good Luck! - Dan McCreary on LinkedIn

    "},{"location":"about/","title":"About the MicroPython Clocks and Watchs Site","text":"

    My STEM students often hold a special facination with timekeeping. I don't know exactly what it is that gets them so excited about these projects. But the bottom line is they quickly become motivated to learn Python to create their own timekeeping devices that are customized to their interests. Owning their own devices and showing off these projects to their friends is also a big plus.

    At the core of Project Based Learning (PBL) is the desire to allow students to pick their own projects. My role as a mentor is to have a rich set of projects they can get started on. They may not understand all the components, but to fix and modify the projects they end up learning faster than if I gave them a dozen lectures with PowerPoint.

    "},{"location":"about/#the-timeless-allure-of-timekeeping-sparking-a-passion-for-coding-with-micropython-clocks-and-watches","title":"The Timeless Allure of Timekeeping: Sparking a Passion for Coding with MicroPython Clocks and Watches","text":"

    In a world driven by digital innovation, the essence of time remains universally compelling. From the ancient sundials to the modern-day smartwatches, humans have always been fascinated by the pursuit of measuring time. This intrigue, particularly among the younger generation, is why a library of fun MicroPython Clocks and Watches serves as an exceptional entry point into the universe of coding and computational thinking.

    "},{"location":"about/#tapping-into-the-childs-natural-curiosity","title":"Tapping into the Child's Natural Curiosity","text":"

    Children possess an innate sense of wonder. The ticking of a clock or the changing digits on a digital watch captivates their imagination. They question how it works, what makes it tick, and how they can possibly create one of their own. By introducing them to a collection of engaging MicroPython timekeeping projects, we are not only answering their questions but also kindling a flame of creativity and innovation.

    "},{"location":"about/#from-boring-lectures-to-tangible-results","title":"From Boring Lectures to Tangible Results","text":"

    Traditional pedagogical methods, characterized by long hours of lectures, often fail to hold the attention of young learners. However, project-based learning flips this paradigm. When a child is given the tools and guidance to create their very own digital clock or watch, the learning process transforms. They're no longer passive recipients of information but active creators, brimming with ideas and enthusiasm.

    A MicroPython Clock project, for instance, isn\u2019t just a coding endeavor; it's a journey. From understanding the concept, drafting the design, writing the first line of code, to finally witnessing their creation come to life \u2013 every step is a lesson in problem-solving, critical thinking, and perseverance.

    "},{"location":"about/#building-blocks-of-computational-thinking","title":"Building Blocks of Computational Thinking","text":"

    Computational thinking is a cornerstone of modern education. It\u2019s not just about writing code, but a way of approaching problems logically, breaking them down into smaller tasks, and finding efficient solutions. By creating a timekeeping device, children undergo a practical exercise in computational thinking. They decide the features they want, debug issues, and constantly refine their work, all while having fun!

    "},{"location":"about/#social-construction-the-joy-of-shared-creation","title":"Social Construction: The Joy of Shared Creation","text":"

    Imagine a part of every school library or a display case where clocks and watches are on display. Each devices can tell its unique story, representing a young coder's journey. Sharing these creations allows children to learn from each other, celebrate their achievements, and draw inspiration. Such a collaborative environment fosters not just coding skills but also empathy, teamwork, and a sense of community. Technically, we call group building projects Social constructivism. And there is ample research to show that students that learn in groups have higer participation rates and can usually develop better outcomes.

    "},{"location":"about/#engineered-for-user-experience","title":"Engineered for User Experience","text":"

    Great STEM projects don't just fall off a shelf into our laps. They need to be designed and tested carefully using the same agile processes that we use in software development. User Experience (UX) professionals need to help us observe our students using and learning from our lessons.

    "},{"location":"about/#in-conclusion","title":"In Conclusion","text":"

    A library of MicroPython Clocks and Watches isn't just a collection of projects; it\u2019s a treasure trove of experiences, learnings, and memories. By introducing children to the magic of timekeeping in the digital age, we are equipping them with skills for the future, fostering a love for coding, and most importantly, reminding them that learning can be both fun and profoundly meaningful. The timeless allure of time, coupled with the dynamic world of coding, creates a perfect blend to mold the innovators and thinkers of tomorrow.

    "},{"location":"contact/","title":"Contact","text":"

    Dan McCreary on LinkedIn

    "},{"location":"course-description/","title":"Course Description","text":"

    Course Title: Building Clocks and Watches with MicroPython Duration: 14 Weeks Target Audience: High School Students Learning Computational Thinking

    Course Description: In this 14-week, hands-on course, high school students will learn to design and program functional timekeeping devices---from simple LED clocks to sophisticated stopwatches and web-connected displays---using MicroPython on the Raspberry Pi Pico W. Throughout the course, students will be guided by hands on labs, moving from foundational knowledge to creative invention.

    1. Remember: Students begin by identifying essential electronic components---breadboards, microcontrollers, buttons, knobs, real-time clocks, and displays---and recalling the fundamental concepts of MicroPython programming.
    2. Understand: Through teacher-led demonstrations, students explore how timing functions, input/output operations, and hardware connections work together to create a basic LED clock. They deepen their grasp of computational thinking by examining concepts like abstraction (focusing on relevant details) and decomposition (breaking large problems into smaller parts). They proceed to use these concepts to customize clock and watch faces using graphic displays.
    3. Apply: As their skills grow, students practice wiring and programming a 128\u00d764 OLED display, interfacing with web services to fetch real-time data. They also implement stopwatches and timers, applying algorithms and pattern-matching techniques to manage user inputs and display outputs accurately.
    4. Analyze: Learners diagnose and troubleshoot various clock behaviors, studying how code efficiency and hardware choices influence device performance. They dissect timing errors, lag issues, and integration problems, refining both their programming and problem-solving skills.
    5. Evaluate: Working in teams, students test multiple clock designs to compare accuracy, power consumption, and user experience. They assess trade-offs---such as display readability vs. complexity---and refine solutions based on feedback, cost, and practicality. They can also work with AI to design new clocks.
    6. Create: Ultimately, students design and assemble their own custom timekeeping projects, combining LEDs, OLED displays, push buttons, and encoders. This final challenge showcases their ability to unify hardware and code into a polished, functioning prototype.

    By the end of the course, students will have built a diverse collection of digital clocks, stopwatches, and timers while gaining a rich understanding of electronics, computational thinking, and MicroPython. They will leave empowered to continue exploring the world of embedded systems and creative hardware projects that blend into the AI-powered home.

    "},{"location":"faq/","title":"Building Clocks and Watches with MicroPython - Frequently Asked Questions","text":""},{"location":"faq/#general-course-information","title":"General Course Information","text":""},{"location":"faq/#what-prior-knowledge-do-i-need-for-this-course","title":"What prior knowledge do I need for this course?","text":"

    No specific electronics or programming experience is required. However, basic computer literacy and comfort with mathematics at a high school level will be helpful. The course starts with fundamentals and builds up gradually.

    "},{"location":"faq/#how-long-is-each-class-session","title":"How long is each class session?","text":"

    While the course runs for 14 weeks, specific class session lengths are determined by your school's schedule. Contact your instructor for the exact timing of your sessions.

    "},{"location":"faq/#do-i-need-to-purchase-my-own-equipment","title":"Do I need to purchase my own equipment?","text":"

    Check with your instructor about equipment policies. Generally, core components like the Raspberry Pi Pico W and basic electronics will be provided, but you may want to purchase additional components for your final project.

    "},{"location":"faq/#what-software-do-i-need-to-install","title":"What software do I need to install?","text":"

    You'll need the Thonny IDE (a Python editor designed for MicroPython), which is free and works on Windows, Mac, and Linux. Your instructor will guide you through the installation process during the first week.

    "},{"location":"faq/#technical-questions","title":"Technical Questions","text":""},{"location":"faq/#what-is-micropython-and-how-is-it-different-from-regular-python","title":"What is MicroPython and how is it different from regular Python?","text":"

    MicroPython is a streamlined version of Python designed to run on microcontrollers. While it maintains Python's core features and syntax, it's optimized for hardware control and has special libraries for working with electronic components.

    "},{"location":"faq/#what-is-a-raspberry-pi-pico-w","title":"What is a Raspberry Pi Pico W?","text":"

    The Raspberry Pi Pico W is a small, affordable microcontroller board with built-in Wi-Fi. It's perfect for learning because it's user-friendly, well-documented, and has plenty of input/output pins for connecting different components.

    "},{"location":"faq/#will-we-be-doing-any-soldering","title":"Will we be doing any soldering?","text":"

    Most projects will use breadboards for non-permanent connections. Some optional advanced projects might involve soldering, but this will be optional and supervised.

    "},{"location":"faq/#how-accurate-will-our-clocks-be","title":"How accurate will our clocks be?","text":"

    The accuracy depends on the components used. With the basic oscillator, clocks might drift a few seconds per day. When we add a Real-Time Clock (RTC) module, accuracy improves significantly to within a few seconds per month.

    "},{"location":"faq/#project-related-questions","title":"Project-Related Questions","text":""},{"location":"faq/#what-kind-of-displays-will-we-use","title":"What kind of displays will we use?","text":"

    We'll work with several types: - Simple LEDs for basic digital displays - 128\u00d764 OLED displays for more sophisticated interfaces - Other display options for final projects

    "},{"location":"faq/#can-i-create-my-own-custom-clock-design-for-the-final-project","title":"Can I create my own custom clock design for the final project?","text":"

    Yes! The final project is designed to be creative and personal. You can combine different components and features we've learned about to create something unique.

    "},{"location":"faq/#how-will-we-handle-time-zones-and-daylight-saving-time","title":"How will we handle time zones and daylight saving time?","text":"

    We'll learn to sync time using web services (when Wi-Fi is available) and program time zone adjustments. Managing daylight saving time will be covered as part of the advanced features.

    "},{"location":"faq/#learning-and-assessment","title":"Learning and Assessment","text":""},{"location":"faq/#how-will-i-be-graded","title":"How will I be graded?","text":"

    Assessment typically includes:

    • Participation in class activities and discussions
    • Ability to work in teams
    • Completion of hands-on labs and exercises
    • Quality and functionality of projects
    • Final project presentation and documentation
    "},{"location":"faq/#what-happens-if-my-clock-doesnt-work","title":"What happens if my clock doesn't work?","text":"

    Troubleshooting is a crucial part of the learning process. You'll have support from instructors and peers, and we'll learn systematic debugging approaches. Making mistakes and fixing them is how we learn!

    "},{"location":"faq/#can-i-work-with-ai-tools-during-the-course","title":"Can I work with AI tools during the course?","text":"

    Yes, part of the course includes learning how to effectively use AI tools for design and problem-solving. We'll cover best practices for AI collaboration while ensuring you understand the fundamental concepts.

    "},{"location":"faq/#hardware-and-components","title":"Hardware and Components","text":""},{"location":"faq/#what-happens-if-i-accidentally-damage-a-component","title":"What happens if I accidentally damage a component?","text":"

    Don't worry! Learning electronics involves some trial and error. Basic components are relatively inexpensive and replaceable. Just inform your instructor if something breaks.

    "},{"location":"faq/#how-do-breadboards-work","title":"How do breadboards work?","text":"

    A breadboard is a reusable platform for creating temporary electrical connections. We'll spend time early in the course understanding how they work and practicing proper connection techniques.

    "},{"location":"faq/#whats-the-difference-between-digital-and-analog-inputsoutputs","title":"What's the difference between digital and analog inputs/outputs?","text":"

    Digital signals are either on (1) or off (0), while analog signals can have many values in between. We'll use both types: digital for buttons and simple LEDs, analog for sensors and variable controls.

    "},{"location":"faq/#programming-concepts","title":"Programming Concepts","text":""},{"location":"faq/#do-i-need-to-memorize-all-the-micropython-commands","title":"Do I need to memorize all the MicroPython commands?","text":"

    No, you don't need to memorize everything. We'll provide reference materials, and part of learning is knowing how to find and use documentation effectively.

    "},{"location":"faq/#what-if-i-miss-a-class-and-fall-behind","title":"What if I miss a class and fall behind?","text":"

    Each concept builds on previous learning, but we'll provide catch-up resources and extra help sessions. Talk to your instructor as soon as possible if you fall behind.

    "},{"location":"faq/#how-will-we-debug-our-code","title":"How will we debug our code?","text":"

    We'll learn several debugging techniques:

    • Using print statements for troubleshooting
    • Reading error messages
    • Using the Thonny debugger
    • Systematic problem-solving approaches
    "},{"location":"faq/#safety-and-best-practices","title":"Safety and Best Practices","text":""},{"location":"faq/#is-there-any-risk-of-electric-shock","title":"Is there any risk of electric shock?","text":"

    The Pico W and components we use operate at very low voltages (3.3V or 5V) which are safe to handle. However, we'll still learn and follow proper safety procedures.

    "},{"location":"faq/#how-do-i-protect-the-electronic-components","title":"How do I protect the electronic components?","text":"

    We'll cover basic handling procedures including:

    • Static electricity precautions
    • Proper connection techniques
    • Component storage and handling
    • Avoiding common mistakes that could damage components
    "},{"location":"faq/#advanced-topics-and-extensions","title":"Advanced Topics and Extensions","text":""},{"location":"faq/#can-we-add-features-like-alarms-or-stopwatch-functions","title":"Can we add features like alarms or stopwatch functions?","text":"

    Yes! As you progress through the course, you'll learn to add various features including:

    • Multiple alarms
    • Stopwatch and timer functions
    • Custom sounds and alerts
    • Special display effects
    "},{"location":"faq/#will-we-learn-about-power-management","title":"Will we learn about power management?","text":"

    Yes, we'll cover power management including:

    • Battery operation
    • Sleep modes
    • Power-efficient programming
    • Battery life optimization
    "},{"location":"faq/#future-applications","title":"Future Applications","text":""},{"location":"faq/#can-i-use-these-skills-for-other-projects","title":"Can I use these skills for other projects?","text":"

    Absolutely! The skills you'll learn apply to many other electronics and programming projects:

    • Other types of electronic devices
    • Home automation projects
    • Sensor-based systems
    • IoT (Internet of Things) devices
    "},{"location":"faq/#how-does-this-course-prepare-me-for-further-study","title":"How does this course prepare me for further study?","text":"

    This course builds valuable skills for:

    • Computer science courses
    • Engineering programs
    • Electronics projects
    • General problem-solving
    • Understanding modern technology
    "},{"location":"faq/#tools-and-resources","title":"Tools and Resources","text":""},{"location":"faq/#what-online-resources-can-we-use","title":"What online resources can we use?","text":"

    We'll use various resources including:

    • MicroPython documentation
    • Raspberry Pi Pico documentation
    • Component datasheets
    • Online simulators
    • Programming reference guides
    "},{"location":"faq/#will-we-use-version-control-like-git","title":"Will we use version control like Git?","text":"

    While not required, we'll introduce basic version control concepts and how they can help manage your code as projects become more complex.

    "},{"location":"faq/#collaboration-and-community","title":"Collaboration and Community","text":""},{"location":"faq/#can-we-work-in-teams","title":"Can we work in teams?","text":"

    Yes! Many activities will involve pair programming or team collaboration. The final project can be individual or team-based, depending on complexity and scope.

    "},{"location":"faq/#how-can-we-share-our-projects-with-others","title":"How can we share our projects with others?","text":"

    We'll discuss ways to:

    • Document your work
    • Create project presentations
    • Share code responsibly
    • Collaborate with other students
    • Showcase your projects
    "},{"location":"faq/#getting-help","title":"Getting Help","text":""},{"location":"faq/#what-if-i-get-stuck-on-a-problem","title":"What if I get stuck on a problem?","text":"

    Multiple support options are available:

    • In-class help from instructors
    • Peer support
    • Office hours
    • Online resources
    • Lab assistance sessions
    "},{"location":"faq/#can-i-get-extra-help-outside-of-class","title":"Can I get extra help outside of class?","text":"

    Yes, instructors will have office hours and may offer additional lab time for students who want extra practice or help.

    "},{"location":"faq/#course-materials","title":"Course Materials","text":""},{"location":"faq/#what-should-i-bring-to-class","title":"What should I bring to class?","text":"

    Typically you'll need:

    • Notebook for taking notes
    • Computer (if not provided)
    • Any assigned reading materials
    • Your project components once distributed
    "},{"location":"faq/#how-should-i-store-and-transport-my-projects","title":"How should I store and transport my projects?","text":"

    We'll provide guidance on:

    • Component storage
    • Project organization
    • Safe transport methods
    • Protecting delicate components
    "},{"location":"faq/#final-projects","title":"Final Projects","text":""},{"location":"faq/#what-makes-a-good-final-project","title":"What makes a good final project?","text":"

    Strong final projects typically:

    • Solve a real problem or fulfill a genuine need
    • Demonstrate technical skills learned in the course
    • Show creativity and originality
    • Are well-documented
    • Function reliably
    "},{"location":"faq/#can-i-continue-working-on-my-project-after-the-course-ends","title":"Can I continue working on my project after the course ends?","text":"

    Yes! You'll have the knowledge to continue developing and improving your projects. We'll discuss ways to extend your learning and continue exploring electronics and programming.

    "},{"location":"glossary/","title":"Glossary of Terms DIY Clocks and Watches with MicroPython","text":""},{"location":"glossary/#12-hour-vs-24-hour-formats","title":"12-Hour vs 24-Hour Formats","text":"

    Methods for displaying time in either 12-hour (AM/PM) or 24-hour (military) format, including conversion between the two.

    Example: Converting 13:00 to 1:00 PM and handling the AM/PM indicator.

    "},{"location":"glossary/#3d-printing-watch-enclosures","title":"3D Printing Watch Enclosures","text":"

    A process of creating custom protective cases for watch components using additive manufacturing technology.

    "},{"location":"glossary/#abstraction","title":"Abstraction","text":"

    A technique for managing complexity by hiding unnecessary details while keeping essential features visible.

    Example: Using a display_time() function that accepts hours and minutes without needing to know how individual LED segments are controlled.

    "},{"location":"glossary/#accelerometer","title":"Accelerometer","text":"

    A sensor that measures physical acceleration and orientation, useful for tilt-based display activation.

    Example: Detecting when a user lifts their wrist to view the watch face.

    "},{"location":"glossary/#alarm","title":"Alarm","text":"

    A scheduled alert that triggers audio, visual, or vibration notifications at specific times.

    Example: Setting multiple daily alarms using the RTC module.

    "},{"location":"glossary/#analog-clock-face","title":"Analog Clock Face","text":"

    A traditional clock display using rotating hands to show time on a circular dial.

    Example: Drawing hour and minute hands using math.sin() and math.cos() for position calculations.

    "},{"location":"glossary/#animation","title":"Animation","text":"

    The process of creating movement by rapidly updating display contents.

    Example: Smoothly rotating second hands or creating blinking colons between hours and minutes.

    "},{"location":"glossary/#asynchronous-programming","title":"Asynchronous Programming","text":"

    A coding technique that allows multiple tasks to run concurrently without blocking each other.

    Example: Using uasyncio to handle display updates while monitoring button presses.

    "},{"location":"glossary/#battery-backup","title":"Battery Backup","text":"

    A power system that maintains time and settings when main power is disconnected.

    "},{"location":"glossary/#battery-drain-calculation","title":"Battery Drain Calculation","text":"

    The process of measuring and estimating power consumption to determine battery life.

    Example: Measuring current draw during different display update modes.

    "},{"location":"glossary/#battery-power","title":"Battery Power","text":"

    Portable electrical energy storage used to operate mobile timepieces.

    Example: Calculating power consumption to estimate battery life.

    "},{"location":"glossary/#battery-tools","title":"Battery Tools","text":"

    Instruments and methods for measuring power consumption and battery health.

    Example: Using multimeters to measure current draw in different modes.

    "},{"location":"glossary/#blitting","title":"Blitting","text":"

    A technique for rapidly copying rectangular portions of memory to update displays efficiently.

    Example: Using framebuffer operations to reduce screen flicker.

    "},{"location":"glossary/#breadboard","title":"Breadboard","text":"

    A reusable plastic board with holes and internal connections for prototyping electronic circuits without soldering.

    Example: Connecting LED displays and buttons to the Pico W using jumper wires on a breadboard.

    "},{"location":"glossary/#button-debouncing","title":"Button Debouncing","text":"

    A technique to prevent false button readings caused by mechanical switch contacts bouncing when pressed or released.

    Example: debounce_time = 100 in button configuration prevents multiple accidental triggers.

    "},{"location":"glossary/#button-input-handling","title":"Button Input Handling","text":"

    Software techniques for detecting and responding to button presses.

    Example: Using interrupts and debouncing for reliable input detection.

    "},{"location":"glossary/#callback-function","title":"Callback Function","text":"

    A function passed as an argument to another function, which will be executed when a specific event occurs.

    Example: button_mode_irq function that runs whenever the mode button is pressed.

    "},{"location":"glossary/#changing-fonts","title":"Changing Fonts","text":"

    The process of modifying text appearance by loading and applying different typefaces.

    Example: Using the micropython-ufont library to load compact digital number styles.

    "},{"location":"glossary/#chimes","title":"Chimes","text":"

    Musical or tone sequences played at specific intervals or times.

    Example: Playing Westminster quarter-hour chimes using PWM audio output.

    "},{"location":"glossary/#chronograph","title":"Chronograph","text":"

    A timepiece with both timekeeping and stopwatch capabilities.

    "},{"location":"glossary/#color-animations","title":"Color Animations","text":"

    Dynamic changes in display colors to create visual effects or indicate status.

    Example: Gradually shifting background colors throughout the day.

    "},{"location":"glossary/#color-conversion","title":"Color Conversion","text":"

    The process of transforming between different color representation systems.

    Example: Converting RGB colors to 16-bit format for TFT displays.

    "},{"location":"glossary/#color-conversion-palettes","title":"Color Conversion & Palettes","text":"

    Methods for transforming between different color representations and managing limited color sets.

    Example: Converting RGB colors to display-specific formats and creating custom color themes.

    "},{"location":"glossary/#color-depth","title":"Color Depth","text":"

    The number of bits used to represent colors in a display.

    Example: Using 16 bits per pixel to show 65,536 different colors.

    "},{"location":"glossary/#concurrency","title":"Concurrency","text":"

    The ability to handle multiple tasks or events simultaneously in a program.

    Example: Updating the display while checking for button presses.

    "},{"location":"glossary/#conditionals","title":"Conditionals","text":"

    Programming statements that perform different actions based on whether a condition is true or false.

    Example: Switching between 12-hour and 24-hour time formats.

    "},{"location":"glossary/#connecting-speakers","title":"Connecting Speakers","text":"

    Methods for attaching and controlling audio output devices to create sound effects and alarms.

    Example: Wiring a piezo speaker to a PWM-capable GPIO pin for generating tones.

    "},{"location":"glossary/#console-output","title":"Console Output","text":"

    Text-based information displayed in the development environment for debugging.

    Example: print(\"Current time:\", hours, \":\", minutes)

    "},{"location":"glossary/#cuckoo-clock","title":"Cuckoo Clock","text":"

    A timepiece that marks specific hours with sound and optional mechanical movement.

    Example: Playing bird sounds and activating a servo at the top of each hour.

    "},{"location":"glossary/#custom-font","title":"Custom Font","text":"

    A specialized set of character designs loaded into memory for display purposes.

    Example: Loading compact number fonts using the micropython-ufont library.

    "},{"location":"glossary/#custom-segment-display","title":"Custom Segment Display","text":"

    A specialized arrangement of LED segments for showing numbers or characters.

    Example: Creating unique digit patterns using individual LED segments.

    "},{"location":"glossary/#ds1307","title":"DS1307","text":""},{"location":"glossary/#ds3231","title":"DS3231","text":"

    A high-precision real-time clock (RTC) integrated circuit with temperature compensation for accurate timekeeping.

    Example: Using the DS3231 to maintain time accuracy within seconds per month.

    "},{"location":"glossary/#date-and-calendar-display","title":"Date and Calendar Display","text":"

    Showing current date information including day of week, month, and year.

    Example: Formatting and displaying full date alongside time information.

    "},{"location":"glossary/#daylight-saving-time","title":"Daylight Saving Time","text":"

    A seasonal time adjustment typically involving a one-hour shift.

    Example: Automatically adjusting clock time based on DST rules.

    "},{"location":"glossary/#deep-sleep","title":"Deep Sleep","text":"

    A low-power mode that disables most system functions to conserve energy.

    Example: Entering sleep mode when the watch face isn't being viewed.

    "},{"location":"glossary/#digital-display","title":"Digital Display","text":"

    An electronic output device that shows numbers, letters, or symbols using discrete segments or pixels.

    Example: Four-digit seven-segment LED display showing hours and minutes.

    "},{"location":"glossary/#display-driver","title":"Display Driver","text":"

    Software that controls how information is shown on a specific type of display.

    Example: Using the ST7735 driver for TFT LCD screens.

    "},{"location":"glossary/#display-technology-comparison","title":"Display Technology Comparison","text":"

    Analysis of different screen types' advantages and limitations.

    Example: Evaluating power consumption versus update speed for various displays.

    "},{"location":"glossary/#double-buffering","title":"Double Buffering","text":"

    A technique using two memory areas to prepare the next frame while displaying the current one.

    Example: Creating smooth animations without visible drawing operations.

    "},{"location":"glossary/#drawing-arcs","title":"Drawing Arcs","text":"

    Creating curved lines as portions of circles on displays.

    Example: Drawing round clock face elements and decorative features.

    "},{"location":"glossary/#drawing-circles","title":"Drawing Circles","text":"

    Creating perfect circular shapes on displays.

    Example: Drawing clock face outlines and hour markers.

    "},{"location":"glossary/#drawing-ellipses","title":"Drawing Ellipses","text":"

    Creating oval shapes on displays.

    Example: Designing stylized clock faces and decorative elements.

    "},{"location":"glossary/#drawing-hands","title":"Drawing Hands","text":"

    Creating moving indicators for hours, minutes, and seconds.

    Example: Using line drawing functions to show analog time.

    "},{"location":"glossary/#drawing-libraries","title":"Drawing Libraries","text":"

    Software collections that provide functions for creating visual elements.

    Example: Using built-in graphics functions to draw clock hands and numbers.

    "},{"location":"glossary/#drawing-lines","title":"Drawing Lines","text":"

    Creating straight line segments on displays.

    Example: Drawing clock hand indicators and markings.

    "},{"location":"glossary/#drawing-numbers","title":"Drawing Numbers","text":"

    Displaying numerical values on screen.

    Example: Showing digital time values and markers.

    "},{"location":"glossary/#drawing-pixels","title":"Drawing Pixels","text":"

    Setting individual display points for custom graphics.

    Example: Creating fine details in watch face designs.

    "},{"location":"glossary/#drawing-polygons","title":"Drawing Polygons","text":"

    Creating shapes with multiple straight sides.

    Example: Making custom hour markers and decorative elements.

    "},{"location":"glossary/#drawing-primitives","title":"Drawing Primitives","text":"

    Basic shapes and elements used to create more complex visual displays.

    Example: Using lines and arcs to create clock hands.

    "},{"location":"glossary/#drawing-rectangles","title":"Drawing Rectangles","text":"

    Creating four-sided shapes with right angles.

    Example: Drawing display borders and menu backgrounds.

    "},{"location":"glossary/#drawing-text","title":"Drawing Text","text":"

    Displaying characters and strings on screen.

    Example: Showing time, date, and menu options.

    "},{"location":"glossary/#drawing-tick-marks","title":"Drawing Tick Marks","text":"

    Creating small indicators around a clock face.

    Example: Marking hours and minutes on an analog display.

    "},{"location":"glossary/#e-paper-display","title":"E-Paper Display","text":"

    A low-power screen technology that maintains its image without constant power.

    Example: Using partial updates to change only modified portions of the display.

    "},{"location":"glossary/#error-handling-and-recovery","title":"Error Handling and Recovery","text":"

    Techniques for detecting and recovering from timing errors, power issues, or communication failures.

    Example: Implementing watchdog timers and automatic resynchronization after power loss.#### Event Handler A function that responds to specific occurrences like button presses or timer updates.

    Example: The button_mode_irq function handles mode button press events.

    "},{"location":"glossary/#external-rtc","title":"External RTC","text":"

    A separate timekeeping chip that maintains accurate time independent of the main processor.

    Example: Using a DS3231 module for precise timekeeping.

    "},{"location":"glossary/#external-sensors","title":"External Sensors","text":"

    Additional hardware components that measure environmental conditions.

    Example: Reading temperature and humidity for weather display.

    "},{"location":"glossary/#fast-redraw","title":"Fast Redraw","text":"

    Techniques for updating displays quickly to maintain smooth animation.

    Example: Using hardware acceleration for screen updates.

    "},{"location":"glossary/#filesystem","title":"Filesystem","text":"

    A system for storing and organizing files on the microcontroller.

    Example: Saving configuration settings and logs to internal storage.

    "},{"location":"glossary/#flicker-reduction","title":"Flicker Reduction","text":"

    Methods to minimize visible display instability during updates.

    Example: Using double buffering to prevent partial frame displays.

    "},{"location":"glossary/#framebuffer","title":"Framebuffer","text":"

    A region of memory that holds the complete contents of a display.

    Example: Modifying pixel data before updating the screen.

    "},{"location":"glossary/#functions","title":"Functions","text":"

    Reusable blocks of code that perform specific tasks.

    Example: Creating a function to convert between 12-hour and 24-hour formats.

    "},{"location":"glossary/#gpio-pin","title":"GPIO Pin","text":"

    General Purpose Input/Output connection on a microcontroller that can be programmed to send or receive electrical signals.

    Example: Using GPIO pin 16 for the mode button: mode_pin = Pin(16, Pin.IN, Pin.PULL_UP)

    "},{"location":"glossary/#generating-waveforms-for-audio","title":"Generating Waveforms for Audio","text":"

    Creating electrical signals for producing sounds and tones using digital-to-analog conversion or PWM.

    Example: Synthesizing different frequencies for alarm sounds and hourly chimes.

    "},{"location":"glossary/#ghosting","title":"Ghosting","text":"

    A visual artifact where previous images remain partially visible on certain display types.

    Example: Using display clearing techniques on e-paper screens.

    "},{"location":"glossary/#hardware-documentation","title":"Hardware Documentation","text":"

    Technical specifications and usage instructions for electronic components.

    Example: Consulting pinout diagrams for display connections.

    "},{"location":"glossary/#i2c","title":"I2C","text":"

    A communication protocol that allows multiple digital components to exchange data using just two wires plus power and ground.

    "},{"location":"glossary/#i2c-sensors","title":"I2C Sensors","text":"

    Digital components that communicate using the I2C protocol to provide measurements.

    Example: Reading temperature and humidity data for weather display.

    "},{"location":"glossary/#implementing-clock-themes","title":"Implementing Clock Themes","text":"

    Creating customizable visual styles for clock displays, including colors, fonts, and layouts.

    Example: Allowing users to switch between day/night themes or seasonal variations.

    "},{"location":"glossary/#incremental-drawing","title":"Incremental Drawing","text":"

    Updating only the necessary portions of a display to improve efficiency.

    Example: Refreshing only the seconds indicator rather than the full screen.

    "},{"location":"glossary/#interrupt","title":"Interrupt","text":"

    A signal that temporarily pauses normal program execution to handle important events.

    Example: Responding immediately to button presses.

    "},{"location":"glossary/#json","title":"JSON","text":"

    A text-based data format commonly used for exchanging information with web services.

    Example: Parsing weather data from online APIs.

    "},{"location":"glossary/#led-clock-displays","title":"LED Clock Displays","text":"

    A digital timepiece display using light-emitting diodes arranged in segments or matrices to show time information.

    Example: Using a four-digit seven-segment LED display to show hours and minutes.

    "},{"location":"glossary/#led-matrix","title":"LED Matrix","text":"

    An array of light-emitting diodes arranged in rows and columns that can display patterns, numbers, or text.

    "},{"location":"glossary/#lipo-charging","title":"LiPo Charging","text":"

    The process of safely recharging Lithium Polymer batteries.

    Example: Implementing USB charging circuits with protection features.

    "},{"location":"glossary/#lipo-charging-circuit","title":"LiPo Charging Circuit","text":"

    Electronic system for safely charging Lithium Polymer batteries while protecting against overcharge and overdischarge.

    Example: Implementing USB charging with voltage regulation and protection features.

    "},{"location":"glossary/#libraries","title":"Libraries","text":"

    Collections of pre-written code that provide useful functions and features.

    Example: Using the math module for trigonometric calculations.

    "},{"location":"glossary/#loading-drivers","title":"Loading Drivers","text":"

    Installing and initializing software that controls specific hardware components.

    Example: Importing and configuring TFT display drivers.

    "},{"location":"glossary/#logging","title":"Logging","text":"

    The practice of recording program events and data for debugging or analysis.

    Example: Saving timing discrepancies to investigate accuracy issues.

    "},{"location":"glossary/#logging-time-data-to-an-sd-card","title":"Logging Time Data to an SD Card","text":"

    Recording timestamped information to external storage for debugging or data collection.

    Example: Saving temperature readings with timestamps every hour.

    "},{"location":"glossary/#loops","title":"Loops","text":"

    Programming structures that repeat code blocks multiple times.

    Example: Continuously updating the display every second.

    "},{"location":"glossary/#math-module","title":"Math Module","text":"

    A collection of mathematical functions for complex calculations.

    Example: Using trigonometry to position clock hands.

    "},{"location":"glossary/#menu-system","title":"Menu System","text":"

    An interface allowing users to navigate options and settings.

    Example: Creating hierarchical settings menus for watch configuration.

    "},{"location":"glossary/#menu-systems-for-watch-settings","title":"Menu Systems for Watch Settings","text":"

    Hierarchical interface structures for configuring watch parameters and features.

    Example: Creating nested menus for time, alarm, and display settings.

    "},{"location":"glossary/#micropython","title":"MicroPython","text":"

    A streamlined version of Python programming language designed to run on microcontrollers and embedded systems.

    "},{"location":"glossary/#micropython-drawing","title":"MicroPython Drawing","text":"

    Built-in functions for creating visual elements on displays.

    Example: Using framebuf methods to draw shapes and text.

    "},{"location":"glossary/#micropython-syntax","title":"MicroPython Syntax","text":"

    The specific programming language rules and structure for MicroPython code.

    Example: Using Python-style indentation for code blocks.

    "},{"location":"glossary/#micropython-network","title":"MicroPython network","text":"

    A module providing Wi-Fi and network connectivity functions.

    Example: Connecting to wireless networks for time synchronization.

    "},{"location":"glossary/#network-time-protocol-ntp","title":"Network Time Protocol (NTP)","text":"

    A method for synchronizing time over the internet.

    Example: Updating the RTC from online time servers.

    "},{"location":"glossary/#oled-display","title":"OLED Display","text":"

    A thin, bright display that uses organic light-emitting diodes to show text and graphics without a backlight.

    "},{"location":"glossary/#pwm","title":"PWM","text":"

    Pulse Width Modulation - a technique for creating varying levels of brightness or speed by rapidly switching a signal on and off.

    "},{"location":"glossary/#pwm-audio","title":"PWM Audio","text":"

    Using Pulse Width Modulation to generate sounds and tones.

    Example: Creating alarm beeps and hourly chimes.

    "},{"location":"glossary/#partial-refresh","title":"Partial Refresh","text":"

    Updating only changed portions of a display to improve efficiency.

    Example: Refreshing only the seconds digits each update.

    "},{"location":"glossary/#partial-screen-updates","title":"Partial Screen Updates","text":"

    Techniques for refreshing only the changed portions of a display to improve efficiency and reduce flicker.

    Example: Updating only the seconds digits while leaving hours and minutes static.

    "},{"location":"glossary/#pedometer","title":"Pedometer","text":"

    A feature that counts steps using motion sensor data.

    Example: Calculating daily step counts from accelerometer readings.

    "},{"location":"glossary/#pin","title":"Pin","text":"

    A metal connector on electronic components that carries electrical signals or power.

    "},{"location":"glossary/#power-management","title":"Power Management","text":"

    Techniques for minimizing and controlling energy consumption.

    Example: Using sleep modes and efficient display updates.

    "},{"location":"glossary/#power-monitoring","title":"Power Monitoring","text":"

    Methods for measuring and tracking power consumption in battery-operated devices.

    Example: Logging battery voltage and current draw to optimize device lifetime.

    "},{"location":"glossary/#pull-up-resistor","title":"Pull-up Resistor","text":"

    An electronic component that ensures a consistent voltage level on input pins when buttons or switches are not pressed.

    Example: Using internal pull-up resistors with Pin.PULL_UP for button inputs.

    "},{"location":"glossary/#raspberry-pi-pico-w","title":"Raspberry Pi Pico W","text":"

    A small, low-cost microcontroller board with built-in wireless capabilities, designed for learning and DIY projects.

    "},{"location":"glossary/#real-time-clock-rtc","title":"Real-Time Clock (RTC)","text":"

    A specialized chip or circuit that keeps accurate time even when main power is removed.

    Example: Using the RTC module to maintain accurate time: rtc = RTC()

    "},{"location":"glossary/#real-time-clock-rtc-overview","title":"Real-time Clock (RTC) Overview","text":"

    A comprehensive explanation of how real-time clock modules maintain accurate time, including initialization, synchronization, and backup power considerations.

    Example: Understanding how the RTC maintains time even when main power is disconnected.

    "},{"location":"glossary/#rotary-encoder","title":"Rotary Encoder","text":"

    A input device that converts rotational movement into digital signals.

    Example: Using encoder rotation to adjust time settings.

    "},{"location":"glossary/#spi","title":"SPI","text":"

    Serial Peripheral Interface - a fast communication protocol for connecting digital components using multiple signal lines.

    "},{"location":"glossary/#spi-interface","title":"SPI Interface","text":"

    A high-speed serial communication protocol for connecting displays and sensors.

    Example: Transferring data to TFT displays efficiently.

    "},{"location":"glossary/#screen-tearing-prevention","title":"Screen Tearing Prevention","text":"

    Techniques to avoid visual artifacts caused by updating display content while it's being refreshed.

    Example: Using vsync or double buffering to ensure clean display updates.

    "},{"location":"glossary/#screen-update","title":"Screen Update","text":"

    The process of refreshing display contents to show new information.

    Example: Efficiently updating only changed portions of the time display.

    "},{"location":"glossary/#screen-via-spi","title":"Screen Via SPI","text":"

    High-speed serial communication method for updating displays.

    Example: Sending framebuffer data to TFT screens efficiently.

    "},{"location":"glossary/#servo-motor","title":"Servo Motor","text":"

    An actuator that can rotate to precise positions.

    Example: Moving physical clock hands on a hybrid display.

    "},{"location":"glossary/#setting-system-clock","title":"Setting System Clock","text":"

    Configuring the internal timekeeping system with accurate time.

    Example: Updating RTC time from an external time source.

    "},{"location":"glossary/#setting-time-with-buttons","title":"Setting Time with Buttons","text":"

    Interface design and implementation for adjusting clock time using physical buttons.

    Example: Using mode, increment, and decrement buttons to set hours and minutes.

    "},{"location":"glossary/#setting-up-i2c-communication","title":"Setting Up I\u00b2C Communication","text":"

    Configuring and using the Inter-Integrated Circuit (I\u00b2C) protocol for connecting multiple devices.

    Example: Initializing I\u00b2C bus for communicating with RTC and sensor modules.

    "},{"location":"glossary/#setting-up-wifi-on-the-pico-w","title":"Setting Up Wi\u2011Fi on the Pico W","text":"

    Process of configuring wireless network connectivity on the Raspberry Pi Pico W microcontroller.

    Example: Connecting to a local network using SSID and password credentials.

    "},{"location":"glossary/#seven-segment-display","title":"Seven-Segment Display","text":"

    A display made of seven LED segments plus a decimal point that can show numbers and some letters.

    Example: Creating patterns for digits using segments 'a' through 'g': SEGMENTS = {'a': 4, 'b': 3, 'c': 2, 'd': 7, 'e': 6, 'f': 5, 'g': 1}

    "},{"location":"glossary/#shift-register","title":"Shift Register","text":"

    An integrated circuit that converts serial data into parallel outputs, useful for controlling multiple LEDs with fewer pins.

    Example: Using SR74HC595 shift register to control display segments.

    "},{"location":"glossary/#sleep-mode","title":"Sleep Mode","text":"

    A low-power state that reduces energy consumption.

    Example: Entering deep sleep between display updates.

    "},{"location":"glossary/#sleep-scheduling","title":"Sleep Scheduling","text":"

    Managing when the device enters and exits low-power states.

    Example: Programming wake-up times for hourly updates.

    "},{"location":"glossary/#smartwatch-displays","title":"Smartwatch Displays","text":"

    Advanced display modules designed specifically for wearable devices, optimizing size, power consumption, and readability.

    Example: Using a small, high-resolution display with automatic brightness adjustment.

    "},{"location":"glossary/#sound-encoding","title":"Sound Encoding","text":"

    Methods for storing and playing audio data for alarms and notifications.

    Example: Converting WAV files to suitable format for playback.

    "},{"location":"glossary/#state-machine","title":"State Machine","text":"

    A programming concept where a system can be in one of several defined states, with specific rules for transitioning between them.

    Example: Clock modes including \"run\", \"set hour\", \"set minute\", and \"set AM/PM\".

    "},{"location":"glossary/#step-counting-pedometer","title":"Step Counting (Pedometer)","text":"

    Using motion sensors to detect and count walking steps for fitness tracking.

    Example: Processing accelerometer data to identify step patterns and maintain daily count.

    "},{"location":"glossary/#stopwatch","title":"Stopwatch","text":"

    A timing device that measures elapsed time from a starting point, typically with precision to fractions of a second.

    Example: Implementing start, stop, and lap timing functions with millisecond accuracy.

    "},{"location":"glossary/#synchronizing-time-from-the-pc","title":"Synchronizing Time from the PC","text":"

    The process of setting a microcontroller's clock using the connected computer's time.

    Example: Using Thonny IDE to automatically update the Pico's RTC when uploading code.

    "},{"location":"glossary/#tft-displays","title":"TFT Displays","text":"

    Thin-film-transistor liquid crystal displays for showing color graphics.

    Example: Using ST7735 or ILI9341 displays for watch faces.

    "},{"location":"glossary/#temperature-sensor","title":"Temperature Sensor","text":"

    A component that measures ambient temperature.

    Example: Displaying current temperature alongside time.

    "},{"location":"glossary/#temperature-and-humidity","title":"Temperature and Humidity","text":"

    Integration of environmental sensors to display current conditions alongside time.

    Example: Reading DHT22 sensor data to show temperature and humidity with clock display.

    "},{"location":"glossary/#thonny-ide","title":"Thonny IDE","text":"

    An integrated development environment optimized for MicroPython programming.

    Example: Using Thonny to upload code and debug timing issues.

    "},{"location":"glossary/#time-module","title":"Time Module","text":"

    MicroPython library for handling time-related operations.

    Example: Using scheduling functions for regular updates.

    "},{"location":"glossary/#time-synchronization","title":"Time Synchronization","text":"

    Process of updating device time from an accurate external source.

    Example: Getting current time from network time servers.

    "},{"location":"glossary/#time-zone","title":"Time Zone","text":"

    A region that observes a uniform standard time.

    Example: Converting between local time and UTC.

    "},{"location":"glossary/#time-based-tasks-with-uasyncio","title":"Time-Based Tasks with uasyncio","text":"

    Scheduling and managing time-dependent operations using MicroPython's asynchronous I/O framework.

    Example: Updating multiple display elements at different intervals without blocking.

    "},{"location":"glossary/#timer","title":"Timer","text":"

    A system resource that generates regular time-based events.

    Example: Creating precise one-second update intervals.

    "},{"location":"glossary/#timer-based-events","title":"Timer-Based Events","text":"

    Actions triggered by internal timing mechanisms.

    Example: Updating display elements at specific intervals.

    "},{"location":"glossary/#usb-power","title":"USB Power","text":"

    A 5-volt power source available through Universal Serial Bus connections, commonly used for powering small electronic projects.

    "},{"location":"glossary/#utc","title":"UTC","text":"

    Coordinated Universal Time, the primary time standard for global time coordination.

    Example: Converting local time to UTC for synchronization.

    "},{"location":"glossary/#ultra-low-power","title":"Ultra-Low Power","text":"

    Operating modes and techniques that minimize energy consumption.

    Example: Using sleep modes and efficient screen updates.

    "},{"location":"glossary/#using-16-bits-to-represent-color","title":"Using 16 Bits to Represent Color","text":"

    A color depth specification that allocates 16 bits per pixel, typically with 5 bits for red, 6 for green, and 5 for blue (RGB565 format).

    Example: Converting RGB colors to 16-bit format for efficient storage and display.

    "},{"location":"glossary/#wake-on-alarm","title":"Wake on Alarm","text":"

    Feature that activates the device from sleep mode at specific times.

    Example: Waking the display for scheduled notifications.

    "},{"location":"glossary/#watch-face-design","title":"Watch Face Design","text":"

    Principles and techniques for creating visually appealing and functional clock displays.

    Example: Balancing aesthetics and readability in analog and digital layouts.

    "},{"location":"glossary/#watchdog-timer","title":"Watchdog Timer","text":"

    A hardware feature that resets the system if the program stops responding.

    Example: Ensuring reliability in long-running clock applications.

    "},{"location":"glossary/#weather-updates","title":"Weather Updates","text":"

    Real-time environmental data obtained through internet services.

    Example: Displaying current conditions alongside time.

    "},{"location":"glossary/#web-services","title":"Web Services","text":"

    Online resources that provide data or functionality through standard internet protocols.

    Example: Fetching current time from an internet time server for clock synchronization.

    "},{"location":"glossary/#wi-fi-module","title":"Wi-Fi Module","text":"

    Hardware that enables wireless network connectivity.

    Example: Connecting to the internet for time synchronization.

    "},{"location":"glossary/#wifibased-weather-updates","title":"Wi\u2011Fi\u2013Based Weather Updates","text":"

    Retrieving and displaying current weather conditions using wireless internet connectivity.

    Example: Fetching temperature, humidity, and forecast data from online weather services.

    "},{"location":"glossary/#world-clock","title":"World Clock","text":"

    A timepiece that displays times for multiple time zones simultaneously.

    Example: Showing local time alongside other major cities' times.

    "},{"location":"glossary/#datetime-objects","title":"datetime Objects","text":"

    Programming structures that store date and time information together.

    Example: Converting between timestamp integers and datetime format.

    "},{"location":"glossary/#localtime-function","title":"localtime() Function","text":"

    A MicroPython function that returns the current time as a tuple of values.

    Example: year, month, day, hour, minute, second = localtime()

    "},{"location":"glossary/#mathsin-and-mathcos","title":"math.sin() and math.cos()","text":"

    Trigonometric functions used for calculating positions on circular displays.

    Example: Computing analog clock hand coordinates.

    "},{"location":"glossary/#micropython-ufont-library","title":"micropython-ufont Library","text":"

    A specialized library for handling compact font rendering in MicroPython applications.

    Example: Loading custom digit fonts optimized for small displays.

    "},{"location":"references/","title":"References","text":"
    1. watchmaker - custom watch faces
    2. Makerfabs GC9A01 1.28 Inch Round LCD Module
    3. Dronebotworkshop Using GC9A01 Round LCD Modules
    4. DroneBot Workshop YouTube Video
    5. Mr. Volt YouTube Exotic Round Displays and How to Use Them - this videos demonstrates some very new round displays up to 5 inches. These would be ideal for robot faces but they cost up to $200 for the larger displays.
    6. NTP Pool Project - sites that run the network time protocol
    7. Pico Displays and Fonts
    8. Analog Clock Face Generator - a wonderful way to try out different designs. This web app allows you to change the format of the markers, digits and hands.
    9. Blocklayer Clock Face
    10. Mick Make's YouTube Video: Build a talking Alarm Clock synced to Google calendars - great example of how to use the Google API to access your personal calendar.
    "},{"location":"references/#inspirational-electronic-clocks","title":"Inspirational Electronic Clocks","text":"

    \"The Clock\" using 1,916 parts by Gislain Benoit

    Divoom Times Gate Clock - Five 128x128 color LCD displays.

    ClocTech Tube Shaped Nixie Clock available for $49 at WalMart. This clock shines an LED into a Plexiglass plate to give the appearance of a 3D Nixie Tube.

    "},{"location":"kits/","title":"Introduction to Clock and Watch Kits","text":""},{"location":"kits/#standard-oled","title":"Standard OLED","text":""},{"location":"kits/#raspberry-pi-and-monchorme-oled","title":"Raspberry Pi and Monchorme OLED","text":""},{"location":"kits/#raspberry-pi-w-and-monchorme-oled","title":"Raspberry Pi W and Monchorme OLED","text":""},{"location":"kits/#lilygo-rp240","title":"LilyGo RP240","text":""},{"location":"kits/e-ink/","title":"E-Ink Displays","text":"

    Prompt

    Please suggest a low-cost e-ink display that has strong support for a microPython driver.

    ChatGPT

    Thought about e-ink display and MicroPython for 5 seconds

    If you're looking for a budget-friendly e-ink module that's well-documented and easy to use in MicroPython projects, a great place to start is with the smaller Waveshare e-Paper displays. Specifically, the Waveshare 1.54-inch e-Paper module is often cited for its low cost and good MicroPython support. Here are some details:

    "},{"location":"kits/e-ink/#chatgpt-response","title":"ChatGPT Response","text":"

    1) Waveshare 1.54-inch e-Paper Module

    Why it's a good pick

    • Affordability: Often in the \\(15--\\)25 range, depending on where you purchase.
    • MicroPython libraries: Strong community support and official Waveshare repositories on GitHub. There are also third-party MicroPython drivers floating around that make it easier to integrate.
    • Multiple variants: You can find \"red/black/white\" or \"black/white\" only variants. The simpler (black/white) ones tend to be cheaper.
    • Low power consumption: Typical for e-ink, so it's great for battery-powered projects.

    Where to find drivers

    • Waveshare's official GitHub has examples in C, Arduino, and sometimes MicroPython.
    • Look for community forks or repos titled similarly to micropython-waveshare-epaper (there are a few) for more up-to-date drivers.

    Key specs

    • Resolution: ~200 \u00d7 200 pixels (for the 1.54\" black/white version)
    • Interfaces: SPI, typically 3.3 V (works well with ESP8266, ESP32, etc.)
    • Refresh time: ~2 seconds for a full refresh; partial refresh also possible on some models.
    "},{"location":"kits/e-ink/#2-waveshare-213-inch-e-paper-slightly-larger-option","title":"2) Waveshare 2.13-inch e-Paper (Slightly Larger Option)","text":"

    If you need a bit more display real estate, the 2.13-inch Waveshare e-Paper module is another solid choice. It's still relatively low cost (somewhere around \\(25--\\)30) but gives you higher resolution (around 250 \u00d7 122 or 212 \u00d7 104, depending on the version) for more text or small graphics.

    • Strong MicroPython support (similarly to the 1.54-inch).
    • Typically uses the same library approach from Waveshare, so upgrading the size is straightforward.
    "},{"location":"kits/e-ink/#3-lilygo-t5-series-all-in-one-board","title":"3) LilyGo T5 Series (All-in-One Board)","text":"

    Another cost-effective route (if you don't mind an all-in-one solution rather than a separate module) is the LilyGo T5 board series. These boards come with an ESP32 already integrated and a small e-ink display (like 1.54\", 2.13\", 2.7\", 4.7\" versions).

    • Pros:
      • ESP32 + e-ink combined in one board
      • Some have built-in battery circuitry
      • Often includes MicroPython support or ready-to-flash firmware
    • Cons:
      • Slightly more expensive than just a raw display
      • Tied to LilyGo's board layout and pins

    If you already have a microcontroller board and want to keep costs low, a stand-alone Waveshare display will likely be cheaper. However, if you're starting from scratch, the LilyGo T5 might save you some setup time (fewer wiring hassles, etc.).

    "},{"location":"kits/e-ink/#summary","title":"Summary","text":"
    • Best Overall Low-Cost: Waveshare 1.54-inch e-Paper module. It's consistently among the cheapest e-ink modules, with decent resolution for text/graphics and ample MicroPython support from both the official Waveshare examples and the community.

    • Slightly Larger Screen: Waveshare 2.13-inch e-Paper offers more room but at a slightly higher price.

    • All-in-One Alternative: LilyGo T5 boards combine an ESP32 and e-ink, and often come with MicroPython pre-installed or easily flashed.

    All of these displays have active communities, plenty of tutorials, and code examples you can adapt for MicroPython, making them a great fit if you're just getting started with e-ink in your microcontroller projects.

    o1

    "},{"location":"kits/gc9a01/","title":"GC9A01 Display","text":"

    The gc9a01 is a chip that drives a 240x240 round display that is connected to a microcontroller by an SPI display.

    The current gc9a01 drivers are not compatable with the current release of framebuf in the standard MicroPython runtime. Therefore the standard framebuf functions such as ellipse() and poly() functions do not work. This limits the portability of many of or clock and watch example.

    The good news is that you can do some drawing operations faster and your code does not have to run the show() command. Functions such as line() will draw directly to the display.

    To connect we need to either use a firmware version or load the driver into the /lib directory and we can then use the following code:

    from machine import Pin, SPI\nimport gc9a01 as gc9a01\n\n# hardware config\nSCL_PIN = 2\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\nRST_PIN = 6\nspi = SPI(0, baudrate=60000000, sck=Pin(SCL_PIN), mosi=Pin(SDA_PIN))\n\n# initialize the display\ntft = gc9a01.GC9A01(\n    spi,\n    dc=Pin(DC_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT),\n    reset=Pin(RST_PIN, Pin.OUT),\n    rotation=0)\n\ntft.fill(gc9a01.BLACK)\n\n# x, y, width, height\n# red\ntft.fill_rect(50,  75, 50, 60, gc9a01.color565(255,0,0))\n# green\ntft.fill_rect(100, 75, 50, 60, gc9a01.color565(0,255,0))\n# blue\ntft.fill_rect(150, 75, 50, 60, gc9a01.color565(0,0,255))\n
    "},{"location":"kits/gc9a01/#rotation","title":"Rotation","text":"

    The driver supports 8 different types of rotations:

    • 0 - PORTRAIT
    • 1 - LANDSCAPE
    • 2 - INVERTED PORTRAIT
    • 3 - INVERTED LANDSCAPE
    • 4 - PORTRAIT MIRRORED
    • 5 - LANDSCAPE MIRRORED
    • 6 - INVERTED PORTRAIT MIRRORED
    • 7 - INVERTED LANDSCAPE MIRRORED

    In our labs we have the connector at the bottom so we use the Portrait rotation of 0 which is the default rotation.

    "},{"location":"kits/gc9a01/#references","title":"References","text":"
    1. Russ Hughes - Russ provides firmware images that you can use for both the Pico and Pico W.
      1. Raspberry Pi Pico
      2. Raspberry Pi Pico W
    "},{"location":"kits/gc9a01/01-hello-world/","title":"Hello World Test","text":"

    We begin by carefully setting up the 7 wires that connect from the gc9a01 graphics controller to the breadboard that we have our Raspberry Pi Pico W connected.

    # 01-hello-world-firmware.py\n# \nfrom machine import Pin, SPI\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\ntft.init()\ntft.fill(0) # fill the screen with black\ntft.text(font, \"Hello world!\", 20, 100, gc9a01.color565(255,0,0), gc9a01.color565(0,0,255))\n
    "},{"location":"kits/gc9a01/02-display-time/","title":"Display Time and Date","text":"

    Here is a program that will display the time and date including the day-of-the-week and the name of the month.

    We use the ``localtime()``` function to get the current time in an array of integers that looks like this:

    (2023, 9, 30, 13, 18, 9, 5, 273)\n

    The fields are:

    1. Year
    2. Month
    3. Day of Month
    4. Hour in 24-hour format
    5. Minutes
    6. Seconds
    7. Day of Week (Monday = 0, Sunday = 6)
    8. Day of the Year

    We could convert each of these numbers to strings and display them. However, most people like to do a bit of formatting such as displaing a 12-hour am/pm format and returning the name of the month and day of the week. Here is the complete progam with the formatting.

    # 02-display-time.py\n# \nfrom machine import Pin, SPI\nfrom utime import sleep, localtime\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\ntft.init()\ntft.fill(0) # fill the screen with black\n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\n# I limit the month names to 5 characters max\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\ndef format_time(now):\n    hour_number = now[3]\n    if hour_number < 13:\n        hour_12 = hour_number\n        am_pm = 'am'\n    else:\n        hour_12 = hour_number - 12\n        am_pm = 'pm'\n    minutes_num = now[4]\n    if minutes_num < 10:\n        min_leading_zero = '0'\n    else:\n        min_leading_zero = ''\n    seconds_num = now[5]\n    if seconds_num < 10:\n        sec_leading_zero = '0'\n    else:\n        sec_leading_zero = ''\n    return \"{}:{}{}:{}{} {}\".format(hour_12, min_leading_zero, minutes_num, sec_leading_zero, seconds_num, am_pm)\n\ndef day_of_week(now):\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    return day_name\n\ndef format_date(now):\n    month_number = now[1]\n    month_name = months[month_number - 1]\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    hour_number = now[3]\n    return \"{} {}, {}\".format(month_name, now[2], now[0])\n\ntft.fill(0) # erase the screen to black\nwhite = gc9a01.color565(255, 255, 255)\nwhile(True):\n    # get the time from the local real-time clock\n    now = localtime()\n    print(now)    \n    tft.text(font, format_time(now), 35, 50, white)\n    tft.text(font, day_of_week(now), 50, 80, white)\n    tft.text(font, format_date(now), 5, 110, white)\n    #tft.show()\n    sleep(1)\n
    "},{"location":"kits/gc9a01/03-display-hand/","title":"Display Second Hand","text":"

    In this lesson we will use a bit of trigonometry to display a second hand that ticks every second.

    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nHAND_LENGTH = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nwhite = gc9a01.color565(255, 255, 255)\n\nwhile True:\n    radians = (counter/60)*TWO_PI\n    x = int(math.sin(radians)*HAND_LENGTH)\n    y = -int(math.cos(radians)*HAND_LENGTH)\n    print(radians, x, y)\n    tft.fill(0)\n    tft.line(CENTER, CENTER, CENTER+x,CENTER+y, white)\n    sleep(1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0\n
    "},{"location":"kits/gc9a01/04-cycle-fonts/","title":"Cycle Through the Builtin Fonts","text":"

    This program will cycle through the built-in fonts showing greetings in different fonts, langauges and colors.

    # Adapted from the hersey.py program\nfrom machine import Pin, SPI\nfrom utime import sleep, localtime\nimport random\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0)\n\n# Load several frozen fonts from flash\n\nimport greeks\nimport italicc\nimport italiccs\nimport meteo\nimport romanc\nimport romancs\nimport romand\nimport romanp\nimport romans\nimport scriptc\nimport scripts\n\n\ndef cycle(p):\n    '''\n    return the next item in a list\n    '''\n    try:\n        len(p)\n    except TypeError:\n        cache = []\n        for i in p:\n            yield i\n            cache.append(i)\n        p = cache\n    while p:\n        yield from p\n\n\nCOLORS = cycle([0xe000, 0xece0, 0xe7e0, 0x5e0, 0x00d3, 0x7030])\n\nFONTS = cycle([\n    greeks, italicc, italiccs, meteo, romanc, romancs,\n    romand, romanp, romans, scriptc, scripts])\n\nGREETINGS = cycle([\n    \"bonjour\", \"buenas noches\", \"buenos dias\",\n    \"good day\", \"good morning\", \"hey\",\n    \"hi-ya\", \"hi\", \"how are you\", \"how goes it\",\n    \"howdy-do\", \"howdy\", \"shalom\", \"welcome\",\n    \"what's happening\", \"what's up\"])\n\ntft.init()\nrow = 120\n\nwhile True:\n    color = next(COLORS)\n    tft.fill(gc9a01.BLACK)\n    tft.draw(next(FONTS), next(GREETINGS), 0, row, color)\n    sleep(0.5)\n
    "},{"location":"kits/gc9a01/04-cycle-fonts/#references","title":"References","text":"
    1. Russ Hughes Example
    "},{"location":"kits/gc9a01/05-draw-ticks/","title":"Draw Clock Face Ticks","text":"

    This program draws 12 short white radial lines around a watch face.

    We use the same math we used to draw a single hand. However, in this example we just need to iterate through a range of 0 to 12.

    for i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, WHITE)\n

    Instead of just drawing from the center to a point at (x,y), we need to calculate four numbers. These are the start and ending points of each tick.

    "},{"location":"kits/gc9a01/05-draw-ticks/#full-program","title":"Full Program","text":"
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nTICK_START = 80\nTICK_END = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nWHITE = gc9a01.color565(255, 255, 255)\nBLACK = gc9a01.color565(0, 0, 0)\ntft.fill(BLACK)\nfor i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    print(i, radians, x1, y1, x2, y2)  \n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, WHITE)\n
    "},{"location":"kits/gc9a01/07-draw-12-digits/","title":"Draw Clock Dial Digits","text":"

    This program builds on the previous progam that draws the ticks. It also draws a ditit at the end of each tick.

    We use the same math we used to draw a single hand. However, in this example we just need to iterate through a range of 0 to 12.

    We have to remember to load our 16x32 fonts. Although this is a bit large for most watch faces, they are easy to read.

    Here is the line we added:

    import vga1_bold_16x32 as font\n

    Note that there are other sizes we can use. A list of the other fonts is here:

    GitHub Site for Russ Hughes for GC9a01 bitmap fonts

    These fonts include the following sizes:

    1. 8x8
    2. 8x16
    3. 16x16
    4. 16x32

    Here is the appropriate line for the normal 16x16:

    import vga1_16x16 as font\n

    if i == 0:\n    num_str = \"12\"\nelse:\n    num_str = str(i)\ntft.text(font, num_str, CENTER+x3-8, CENTER+y3-16, WHITE)\n
    Note because the fonts are 16 wide and 32 high we move 8 to the left and 16 up.

    "},{"location":"kits/gc9a01/07-draw-12-digits/#full-program","title":"Full Program","text":"
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\nimport vga1_bold_16x32 as font\n\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nTICK_START = 50\nTICK_END = 80\nNUM_POS = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nWHITE = gc9a01.color565(255, 255, 255)\nBLACK = gc9a01.color565(0, 0, 0)\nBLUE = gc9a01.color565(0, 0, 255)\ntft.fill(BLACK)\nfor i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    x3 = int(math.sin(radians)*NUM_POS)\n    y3 = -int(math.cos(radians)*NUM_POS)\n    print(i, radians, x1, y1, x2, y2)  \n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, BLUE)\n    if i == 0:\n        num_str = \"12\"\n    else:\n        num_str = str(i)\n    tft.text(font, num_str, CENTER+x3-8, CENTER+y3-16, WHITE)\n

    If you use the 16x16 font the offset in the last line are:

        if i == 0:\n        num_str = \"12\"\n        xOffest = 16\n    else:\n        num_str = str(i)\n        xOffest = 8\n    tft.text(font, num_str, CENTER+x3-xOffest, CENTER+y3-8, WHITE)\n

    The exception is for the \"12\" at the top of the dial. The \"12\" needed to be exactly centered above the top tick mark.

    "},{"location":"kits/gc9a01/07-draw-12-digits/#full-code-for-16x16-clock-face-digits","title":"Full Code for 16x16 Clock Face Digits","text":"
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\nimport vga1_16x16 as font\n\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n\nCENTER = 120\nTICK_START = 70\nTICK_END = 100\nNUM_POS = 111\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nWHITE = gc9a01.color565(255, 255, 255)\nBLACK = gc9a01.color565(0, 0, 0)\nBLUE = gc9a01.color565(0, 0, 255)\ntft.fill(BLACK)\nfor i in range(0,12):\n    radians = (i/12)*TWO_PI\n    x1 = int(math.sin(radians)*TICK_START)\n    y1 = -int(math.cos(radians)*TICK_START)\n    x2 = int(math.sin(radians)*TICK_END)\n    y2 = -int(math.cos(radians)*TICK_END)\n    x3 = int(math.sin(radians)*NUM_POS)\n    y3 = -int(math.cos(radians)*NUM_POS)\n    print(i, radians, x1, y1, x2, y2)  \n    tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, BLUE)\n    if i == 0:\n        num_str = \"12\"\n        xOffest = 16\n    else:\n        num_str = str(i)\n        xOffest = 8\n    tft.text(font, num_str, CENTER+x3-xOffest, CENTER+y3-8, WHITE)\n
    "},{"location":"kits/gc9a01/08-draw-filled-triangle/","title":"Draw a Filled Triangle","text":"

    Analog clock hands can be draw with simple lines. But the display will be more pleasing if we use clock hands that are made of triangles.

    If the framebuf functions were supported in the driver drawing a filled triangle would be easy. We would just put the three points in an array and call the poly() with a fill option.

    However, the current driver does not support the framebuf functions. To overcome this limiation we will need to write our own function that will fill all the points in a triangle.

    Our founction must take in the three points and a color and draw the traingle.

    "},{"location":"kits/gc9a01/08-draw-filled-triangle/#draw-filled-triangle","title":"Draw Filled Triangle","text":"

    Without going into too much detail, here is the algorithm we will use dto draw a filled triangle. Note that only the last line does drawing using the line() function. You will note that it must get the points in order before the main loops run. This version also checks for divide by zero errors.

    def drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n\n    # get our points in order\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n\n        for x in range(xa, xb+1):\n            # sleep(.1)\n            tft.line(x, y, x, y, color)\n
    "},{"location":"kits/gc9a01/08-draw-filled-triangle/#full-test-program","title":"Full Test Program","text":"

    To test our alforithm we can genrate three random points near the center of the display and then call the traingle fill on these points. If you would like to see how the algorithm does the drawing, you can uncomment the sleep function just before the tft.line() above.

    # 01-display-test.py\n# \nfrom machine import Pin, SPI\nimport random\nimport gc9a01\nimport vga1_16x16 as font\nfrom utime import sleep\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\nWHITE = gc9a01.color565(255,255,255)\nBLUE = gc9a01.color565(0,0,255)\nBLACK = gc9a01.color565(0,0,0)\n\ntft.init()\ntft.fill(0) # fill the screen with black\ntft.text(font, \"Draw Filled Triangle Test\", 20, 10, BLUE, BLACK)\n\n\n\ndef drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n\n        for x in range(xa, xb+1):\n            tft.line(x, y, x, y, color)\n\n\nmin = 50\nmax = 150\nwhile True:\n    tft.fill(BLACK)\n    x1 = random.randint(min, max)\n    y1 = random.randint(min, max)\n    x2 = random.randint(min, max)\n    y2 = random.randint(min, max)\n    x3 = random.randint(min, max)\n    y3 = random.randint(min, max)\n    drawFilledTriangle(x1, y1, x2, y2, x3, y3, WHITE)\n    sleep(.1)\n
    "},{"location":"kits/gc9a01/08-draw-filled-triangle/#crazy-triangles","title":"Crazy Triangles","text":"
    # lab 15: Filled Triangles\n# \nfrom machine import Pin, SPI\nimport random\nimport gc9a01\nimport vga1_16x16 as font\nfrom utime import sleep\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\n\nWHITE = gc9a01.color565(255,255,255)\nBLUE = gc9a01.color565(0,0,255)\nBLACK = gc9a01.color565(0,0,0)\n\ntft.init()\ntft.fill(0) # fill the screen with black\ntft.text(font, \"Triangles\", 57, 22, BLUE, BLACK)\n\ndef drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n\n        for x in range(xa, xb+1):\n            # for wathing the drawing\n            # sleep(.001)\n            tft.line(x, y, x, y, color)\n\nmin = 40\nmax = 220\nwhile True:\n    # tft.fill(BLACK)\n    x1 = random.randint(min, max)\n    y1 = random.randint(min, max)\n    x2 = random.randint(min, max)\n    y2 = random.randint(min, max)\n    x3 = random.randint(min, max)\n    y3 = random.randint(min, max)\n    red = random.randint(0, 255)\n    green = random.randint(0, 255)\n    blue = random.randint(0, 255)\n    color = gc9a01.color565(red,green,blue)\n    drawFilledTriangle(x1, y1, x2, y2, x3, y3, color)\n    # slow down the drawing here\n    sleep(.1)\n
    "},{"location":"kits/gc9a01/09-watch-face/","title":"Watch Face","text":"
    1. Ticks
    2. Second hand
    3. Minute hand
    4. Hour hand
    from machine import Pin, SPI\nfrom utime import sleep, localtime\nimport math\nimport gc9a01\n\n# this uses the standard Dupont ribbon cable spanning rows 4-9 on our breadboard\nSCK_PIN = 2 # row 4\nSDA_PIN = 3\nDC_PIN = 4\nCS_PIN = 5\n# GND is row 8\nRST_PIN = 6\n\n# define the SPI intrface\nspi = SPI(0, baudrate=60000000, sck=Pin(SCK_PIN), mosi=Pin(SDA_PIN))\ntft = gc9a01.GC9A01(spi, 240, 240, reset=Pin(RST_PIN, Pin.OUT),\n    cs=Pin(CS_PIN, Pin.OUT), dc=Pin(DC_PIN, Pin.OUT), rotation=0\n)\ntft.init()\n# A full circle is 2*Pi radians\nTWO_PI = 3.1415926*2\nWHITE = gc9a01.color565(255, 255, 255)\nBLUE = gc9a01.color565(0, 0, 255)\nGREEN = gc9a01.color565(0, 255, 0)\nPURPLE = gc9a01.color565(255, 0, 255)\nBLACK = gc9a01.color565(0, 0, 0)\ntft.fill(BLACK)\nCENTER = 120\nMIN_TICK_START = 80\nMIN_TICK_END = 98\nSEC_TICK_START = 100\nSEC_TICK_END = 120\n\ndef drawFilledTriangle(x1, y1, x2, y2, x3, y3, color=WHITE):\n    def swap(x, y):\n        return y, x\n    if y1 > y2:\n        x1, x2 = swap(x1, x2)\n        y1, y2 = swap(y1, y2)\n    if y1 > y3:\n        x1, x3 = swap(x1, x3)\n        y1, y3 = swap(y1, y3)\n    if y2 > y3:\n        x2, x3 = swap(x2, x3)\n        y2, y3 = swap(y2, y3)\n    for y in range(y1, y3+1):\n        if y2 - y1 != 0 and y < y2:\n            xa = x1 + (x2 - x1) * (y - y1) // (y2 - y1)\n        elif y3 - y1 != 0:\n            xa = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n        if y3 - y2 != 0 and y >= y2:\n            xb = x2 + (x3 - x2) * (y - y2) // (y3 - y2)\n        elif y3 - y1 != 0:\n            xb = x1 + (x3 - x1) * (y - y1) // (y3 - y1)\n        else:\n            continue\n        if xa > xb:\n            xa, xb = swap(xa, xb)\n        for x in range(xa, xb+1):\n            tft.line(x, y, x, y, color)\n\ndef drawTicks():\n    for i in range(0,60):\n        radians = (i/60)*TWO_PI\n        x1 = int(math.sin(radians)*SEC_TICK_START)\n        y1 = -int(math.cos(radians)*SEC_TICK_START)\n        x2 = int(math.sin(radians)*SEC_TICK_END)\n        y2 = -int(math.cos(radians)*SEC_TICK_END)\n        # print(i, radians, x1, y1, x2, y2)  \n        tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, BLUE)\n\n    for i in range(0,12):\n        radians = (i/12)*TWO_PI\n        x1 = int(math.sin(radians)*MIN_TICK_START)\n        y1 = -int(math.cos(radians)*MIN_TICK_START)\n        x2 = int(math.sin(radians)*MIN_TICK_END)\n        y2 = -int(math.cos(radians)*MIN_TICK_END)\n        # print(i, radians, x1, y1, x2, y2)  \n        tft.line(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, GREEN)\n\nCENTER = 120\nSEC_HAND_LENGTH = 118\ndef drawSecondHand(sec):\n    # print('sec=', sec)\n    if sec ==0:\n        radians = 0\n    else: radians = (sec/60)*TWO_PI\n    x = int(math.sin(radians)*SEC_HAND_LENGTH)\n    y = -int(math.cos(radians)*SEC_HAND_LENGTH)\n    # print(radians, x, y)\n    tft.line(CENTER, CENTER, CENTER+x,CENTER+y, WHITE)\n    sleep(.1)\n    tft.line(CENTER, CENTER, CENTER+x,CENTER+y, BLACK)\n\n\nMIN_HAND_LENGTH = 90\nMIN_HAND_WIDTH = 5\ndef drawMinuteHand(min, color):\n    radians = (min/60)*TWO_PI\n    x1 = -int(math.cos(radians)*MIN_HAND_WIDTH)\n    y1 = -int(math.sin(radians)*MIN_HAND_WIDTH)\n    x2 = int(math.sin(radians)*MIN_HAND_LENGTH)\n    y2 = -int(math.cos(radians)*MIN_HAND_LENGTH)\n    x3 = int(math.cos(radians)*MIN_HAND_WIDTH)\n    y3 = int(math.sin(radians)*MIN_HAND_WIDTH)\n    # print('min:', x1, y1, x2, y2, x3, y3)\n    drawFilledTriangle(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, CENTER+x3, CENTER+y3, color)\n\nHOUR_HAND_LENGTH = 60\nHOUR_HAND_WIDTH = 6\ndef drawHourHand(hour, color):\n    radians = (hour/12)*TWO_PI\n    x1 = -int(math.cos(radians)*HOUR_HAND_WIDTH)\n    y1 = -int(math.sin(radians)*HOUR_HAND_WIDTH)\n    x2 = int(math.sin(radians)*HOUR_HAND_LENGTH)\n    y2 = -int(math.cos(radians)*HOUR_HAND_LENGTH)\n    x3 = int(math.cos(radians)*HOUR_HAND_WIDTH)\n    y3 = int(math.sin(radians)*HOUR_HAND_WIDTH)\n    # print('hour:', x1, y1, x2, y2, x3, y3)\n    drawFilledTriangle(CENTER+x1, CENTER+y1, CENTER+x2, CENTER+y2, CENTER+x3, CENTER+y3, color)\n\ncounter = 0\nmin = 58\nhour = 6\ndrawMinuteHand(min, GREEN)\ndrawHourHand(hour, PURPLE)\nhour = 6\nwhile True:\n    # this is the flicker\n    # tft.fill(BLACK)\n    drawTicks()\n\n    drawSecondHand(counter)\n    # if we are at 60 we start over\n    if counter > 59:\n        drawMinuteHand(min, BLACK)\n        counter = 0\n        min += 1\n        drawMinuteHand(min, GREEN)\n        if min > 59:\n            min=0\n            drawHourHand(hour, BLACK)\n            hour += 1\n            drawHourHand(hour, PURPLE)\n            if hour > 11:\n                hour = 0\n    counter += 1\n    # sleep(.5)\n
    "},{"location":"kits/ili9341/","title":"ILI9341 Display","text":"

    The ILI9341 is a low-cost color single-chip driver for a TFT liquid crystal display with a resolution of 240x320.

    The board for the ILI9341 with a display costs around $9.00. Although these displays are not a high contrast as OLED displays, they are still adequate for many clock projects that would like to draw smooth circles on a clock face.

    "},{"location":"kits/ili9341/#driver","title":"Driver","text":"

    dagger GitHub Repo

    "},{"location":"kits/ili9341/#characteristics","title":"Characteristics","text":"

    Direct write No support for standard micropython framebuf

    "},{"location":"kits/ili9341/#sample-lesson-plan","title":"Sample Lesson Plan","text":"

    GPT-4 Generated Lesson Plan

    "},{"location":"kits/ili9341/#source-code","title":"Source Code","text":"

    Source Code

    "},{"location":"kits/ili9341/01-rainbow-test/","title":"Rainbow Test","text":"
    from ili9341 import Display, color565\nfrom machine import Pin, SPI\n\n# Use these PIN definitions.  SCK must be on 2 and data (SDL) on 3 for SPI bus 0\nSCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\n\nspi = SPI(0, baudrate=40000000, sck=Pin(SCK_PIN), mosi=Pin(MISO_PIN))\ndisplay = Display(spi, dc=Pin(DC_PIN), cs=Pin(CS_PIN), rst=Pin(RESET_PIN), width=WIDTH, height=HEIGHT, rotation=ROTATION)\n\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nPURPLE = color565(255,0,255)\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\n\ndisplay.fill_rectangle(0,0, 50,HEIGHT, RED)\ndisplay.fill_rectangle(50,0, 50,HEIGHT, ORANGE)\ndisplay.fill_rectangle(100,0, 50,HEIGHT, YELLOW)\ndisplay.fill_rectangle(150,0, 50,HEIGHT, GREEN)\ndisplay.fill_rectangle(200,0, 50,HEIGHT, BLUE)\ndisplay.fill_rectangle(250,0, 50,HEIGHT, PURPLE)\ndisplay.fill_rectangle(300,0, 20,HEIGHT, WHITE)\n\nprint('Done')\n
    "},{"location":"kits/ili9341/01-rainbow-test/#color-definitions","title":"Color Definitions","text":"

    We can also use this same process for storing all of the common constants that we duplicate in our examples. For example all the named color defintions can be moved into a serate color-defs.py file like this:

    Sample colors.py

    from ili9341 import color565\n\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nCYAN = color565(0,255,255)\nPURPLE = color565(255,0,255)\n

    This sample program imports both the config and the colors file:

    from ili9341 import Display, color565\nfrom machine import Pin, SPI\nimport config\nimport colors\n\n# Use these PIN definitions.  SCK must be on 2 and data (SDL) on 3\nSCK_PIN = config.SCK_PIN\nMISO_PIN = config.MISO_PIN # labeled SDI(MOSI) on the back of the display\nDC_PIN = config.DC_PIN\nRESET_PIN = config.RESET_PIN\nCS_PIN = config.CS_PIN\n\nWIDTH=config.WIDTH\nHEIGHT=config.HEIGHT\nROTATION=config.ROTATION\n\n# mosi=Pin(23)\n# miso=Pin(MISO_PIN)\nspi = SPI(0, baudrate=40000000, sck=Pin(SCK_PIN), mosi=Pin(MISO_PIN))\ndisplay = Display(spi, dc=Pin(DC_PIN), cs=Pin(CS_PIN), rst=Pin(RESET_PIN), width=WIDTH, height=HEIGHT, rotation=ROTATION)\n\ndisplay.fill_rectangle(0,0, 50,HEIGHT, colors.RED)\ndisplay.fill_rectangle(50,0, 50,HEIGHT, colors.ORANGE)\ndisplay.fill_rectangle(100,0, 50,HEIGHT, colors.YELLOW)\ndisplay.fill_rectangle(150,0, 50,HEIGHT, colors.GREEN)\ndisplay.fill_rectangle(200,0, 50,HEIGHT, colors.BLUE)\ndisplay.fill_rectangle(250,0, 50,HEIGHT, colors.PURPLE)\ndisplay.fill_rectangle(300,0, 20,HEIGHT, colors.WHITE)\n\nprint('Done')\n

    Note that the string colors. must appear before each color name. You can shorten this to be just c. if you want to keep your code smaller and easier to read.

    "},{"location":"kits/ili9341/01-rainbow-test/#hiding-hardware-initialization","title":"Hiding Hardware Initialization","text":"

    We could take this one step further and put the lines that setup the SPI and the Display into a separate function. However, in our labs we want to keep some of this code explicit so we will leave the SPI and Display initialization in our examples.

    "},{"location":"kits/ili9341/02-config/","title":"Creating a Hardware Configuration File","text":"

    Rather than hard-coding the pin numbers in every example, let's put all our hardware configuration data in a single file. All the examples from here on can use that configuration data.

    "},{"location":"kits/ili9341/02-config/#hardware-configuration-file","title":"Hardware Configuration File","text":"
    # Dan's Robot Labs configuration file for ILI9341 clock project\n# The colors on the SPI bus cable are:\n# 3.3v power - red\n# SCK - orange\n# MISO/Data - yellow\n# DC - green\n# RESET - blue\n# GND - black\n# CS - purple\nSCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\n
    "},{"location":"kits/ili9341/02-config/#sample-use-of-haredwre-configuration-file","title":"Sample Use of Haredwre Configuration File","text":"
    # print out \"Hello World!\" using the rotation=3 using 32-bit high font\n# the default is white text on a black background\nfrom ili9341 import Display, color565\nfrom machine import Pin, SPI\nimport config\n\n# Use these PIN definitions.  SCK must be on 2 and data (SDL) on 3\nSCK_PIN = config.SCK_PIN\nMISO_PIN = config.MISO_PIN # labeled SDI(MOSI) on the back of the display\nDC_PIN = config.DC_PIN\nRESET_PIN = config.RESET_PIN\nCS_PIN = config.CS_PIN\n\nWIDTH=config.WIDTH\nHEIGHT=config.HEIGHT\nROTATION=config.ROTATION\n\n# mosi=Pin(23)\n# miso=Pin(MISO_PIN)\nspi = SPI(0, baudrate=40000000, sck=Pin(SCK_PIN), mosi=Pin(MISO_PIN))\ndisplay = Display(spi, dc=Pin(DC_PIN), cs=Pin(CS_PIN), rst=Pin(RESET_PIN), width=WIDTH, height=HEIGHT, rotation=ROTATION)\n\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nPURPLE = color565(255,0,255)\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\n\ndisplay.fill_rectangle(0,0, 50,HEIGHT, RED)\ndisplay.fill_rectangle(50,0, 50,HEIGHT, ORANGE)\ndisplay.fill_rectangle(100,0, 50,HEIGHT, YELLOW)\ndisplay.fill_rectangle(150,0, 50,HEIGHT, GREEN)\ndisplay.fill_rectangle(200,0, 50,HEIGHT, BLUE)\ndisplay.fill_rectangle(250,0, 50,HEIGHT, PURPLE)\ndisplay.fill_rectangle(300,0, 20,HEIGHT, WHITE)\n\nprint('Done')\n
    "},{"location":"kits/led-displays/","title":"LED Display Clock","text":""},{"location":"kits/led-displays/#simple-tm1637","title":"Simple TM1637","text":"

    Simple TM1637

    "},{"location":"kits/led-displays/#shift-register-displays","title":"Shift Register Displays","text":"

    Shift Register Displays

    We can use the TM1637 4-Digit LED Display Module which can be purchased on e-Bay for a few dollars. This means that your clock will cost under $10 total.

    Sample Listing on EBay

    "},{"location":"kits/led-displays/#hookup-instructions","title":"Hookup Instructions","text":"

    We can hook this up to the Raspberry Pi.

    |Name|Pin|| |5 Volts|VBUS or VSYS| |GND|Any GND Pin| |CLK|Pins 4| |Data|Pin 5 |

    "},{"location":"kits/led-displays/#micropython-driver","title":"MicroPython Driver","text":"

    Mike Causer's TM1637 GitHub Driver

    "},{"location":"kits/led-displays/#sample-code","title":"Sample Code","text":""},{"location":"kits/led-displays/#python-imports","title":"Python Imports","text":"
    import tm1637\nfrom machine import Pin\nfrom utime import sleep\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n
    "},{"location":"kits/led-displays/#test-program","title":"Test Program","text":"
    import tm1637\nfrom machine import Pin\nfrom utime import sleep\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n\nwhile True:\n    # all LEDS on \"88:88\"\n    tm.write([127, 255, 127, 127])\n    sleep(1)\n\n    # all LEDS off\n    tm.write([0, 0, 0, 0])\n    sleep(1)\n\n    # show \"0123\"\n    tm.write([63, 6, 91, 79])\n    sleep(1)\n\n    # show \"COOL\"\n    tm.write([0b00111001, 0b00111111, 0b00111111, 0b00111000])\n    sleep(1)\n\n    # show \"HELP\"\n    tm.show('help')\n    sleep(1)\n\n    # display \"dEAd\", \"bEEF\"\n    tm.hex(0xdead)\n    sleep(1)\n\n    tm.hex(0xbeef)\n    sleep(1)\n\n    # show \"12:59\"\n    tm.numbers(12, 59)\n    sleep(1)\n\n    # show \"-123\"\n    tm.number(-123)\n    sleep(1)\n\n    # show temperature '24*C'\n    tm.temperature(24)\n    sleep(1)\n

    Next, will will use the localtime() function to build a simple clock.

    Simple Clock

    "},{"location":"kits/led-displays/#references","title":"References","text":"
    • Mike Causer TM1637 Driver GitHub Repo
    • YouTube Video by NerdCave
    "},{"location":"kits/led-displays/clock-simple/","title":"A Simple Clock with the TM1637 LED Display","text":"

    Here is a simple clock program that will display the hours and minutes from the localtime() function. It will also turn the colon LEDs on and off every second using the modulo function to test for the even/odd property of the second.

    "},{"location":"kits/led-displays/clock-simple/#the-localtime-function","title":"The Localtime function","text":"
    # display hours and minutes on the TM1637 LED display\n# make the colon go on and off every second\nimport tm1637\nfrom machine import Pin\nfrom utime import sleep, localtime\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n\nwhile True:\n    now = localtime() # returns 8 inits for date and time\n    hours = now[3]\n    minutes = now[4]\n    seconds = now[5]\n    print(hours, \":\", minutes, ' ', seconds)\n    # flash the colon on and off every second\n    if (seconds % 2): # modulo 2 will be true for odd numbers\n        tm.numbers(hours, minutes, True)\n    else:\n        tm.numbers(hours, minutes, False)\n    sleep(1)\n

    That is it! Pretty cool that you can write an entire clock program in that few lines of code. But it is not perfect. Let's find some ways to make the clock work a little better.

    Note that the hours is always in 24 hour time. If you want to use 12 hour time you will need to subtract 12 from the hours if the hours is greater than 12.

    We can add the following lines of code to make the display better for people that use a 12-hour clock.

    if hours > 12:\n    hours = now[3]\n    hours = hours - 12\n

    This will work, but it has the disadvantage of displaying the leading zero before the ones digit. Unfortunately, this is the way that the numbers() function was written in the TM1637 module. Let's take a look at how we can clean this up a bit.

    "},{"location":"kits/led-displays/clock-simple/#removing-leading-zeros","title":"Removing Leading Zeros","text":"

    In order to fix the leading zeros problem in the hours place, we need to write our own version of the numbers() function that changes '0' to be a space (all 7 segments off) if the hours is less than 10.

    Here is the original numbers() function taken directly from the driver:

    def numbers(self, num1, num2, colon=True):\n    \"\"\"Display two numeric values -9 through 99, with leading zeros\n    and separated by a colon.\"\"\"\n    num1 = max(-9, min(num1, 99))\n    num2 = max(-9, min(num2, 99))\n    segments = self.encode_string('{0:0>2d}{1:0>2d}'.format(num1, num2))\n    if colon:\n        segments[1] |= 0x80 # colon on\n    self.write(segments)\n

    You can see that the author used the Python .format function to display the first number using a leading zero. This is fine for our minutes, but not a standard for the hours.

    We will need to modify this code to put in a space character in if the hours is less than 10 and to only display the hours number without a leading zero. The format {0:0>2d} will be changed to be: {prefix}{num1:d} where:

    prefix = ' ' if num1 < 10 else ''\n
    def numbers_nlz(num1, num2, colon=True):\n    \"\"\"Display two numeric values -9 through 99, with a leading space before\n    single-digit first numbers and separated by a colon.\"\"\"\n    num1 = max(-9, min(num1, 99))\n    num2 = max(-9, min(num2, 99))\n    prefix = ' ' if num1 < 10 else ''\n    print(f'\"{prefix}{num1:d}{num2:0>2d}\"')\n    segments = tm.encode_string(f'{prefix}{num1:d}{num2:0>2d}')\n    if colon:\n        segments[1] |= 0x80  # colon on\n    tm.write(segments)\n

    Now the display will work as most normal digital clocks.

    So as long as the localtime() function is working, this clock should work fine. An as long as your device is connected to your computer via an USB cable it will be fine.

    What if you would like your clock to work without being connected to a computer. We have two options:

    1. Used a Raspberry Pi Pico W to get time from a central time service over Wifi
    2. or use a local clock and set the time manually
    "},{"location":"kits/led-displays/reference/","title":"Programming Reference for the TM1637 Clock LED Driver","text":""},{"location":"kits/led-displays/reference/#seven-segment-font","title":"Seven Segment Font","text":"

    They are called 7-segment displays as there are 7 LEDs for each digit (segment). One byte (7 lower bits) for each segment. The 8th bit (MSB) is for the colon and only on the 2nd segment.

          A\n     ---\n  F |   | B   *\n     -G-      H (on 2nd segment)\n  E |   | C   *\n     ---\n      D\n\n  HGFEDCBA\n0b01101101 = 0x6D = 109 = show \"5\"\n
    Display Bin Hex Dec 0 0b00111111 0x3F 63 1 0b00000110 0x06 6 2 0b01011011 0x5B 91 3 0b01001111 0x4F 79 4 0b01100110 0x66 102 5 0b01101101 0x6D 109 6 0b01111101 0x7D 125 7 0b00000111 0x07 7 8 0b01111111 0x7F 127 9 0b01101111 0x6F 111 A 0b01110111 0x77 119 b 0b01111100 0x7C 124 C 0b00111001 0x39 57 d 0b01011110 0x5E 94 E 0b01111001 0x79 121 F 0b01110001 0x71 113 G 0b00111101 0x3D 61 H 0b01110110 0x76 118 I 0b00000110 0x06 6 J 0b00011110 0x1E 30 K 0b01110110 0x76 118 L 0b00111000 0x38 56 M 0b01010101 0x55 85 n 0b01010100 0x54 84 O 0b00111111 0x3F 63 P 0b01110011 0x73 115 q 0b01100111 0x67 103 r 0b01010000 0x50 80 S 0b01101101 0x6D 109 t 0b01111000 0x78 120 U 0b00111110 0x3E 62 v 0b00011100 0x1C 28 W 0b00101010 0x2A 42 X 0b01110110 0x76 118 y 0b01101110 0x6E 110 Z 0b01011011 0x5B 91 blank 0b00000000 0x00 0 - 0b01000000 0x40 64 * 0b01100011 0x63 99"},{"location":"kits/led-displays/reference/#methods","title":"Methods","text":""},{"location":"kits/led-displays/reference/#set-brightneww","title":"Set Brightneww","text":"

    Get or set brightness.

    brightness(val=None)\n

    "},{"location":"kits/led-displays/reference/#write-segments","title":"Write Segments","text":"

    Write one or more segments at a given offset.

    write(segments, pos=0)\n

    "},{"location":"kits/led-displays/reference/#write-two-numbers-and-colon","title":"Write Two Numbers and Colon","text":"

    Write Two Numbers and Colon

    numbers(num1, num2, colon=True):\n
    "},{"location":"kits/led-displays/shift-register-displays/","title":"Shift Register Displays","text":"

    The 74hc595 is a chip that takes a clock and data stream in and turns many LEDs on or off. 74hc595 chips can be connected in series to control 7 segments on 4 digits.

    I'll create a detailed walkthrough of the clock-driver.py program, breaking it down into digestible sections with accompanying labs. This will help students understand both the code and the underlying concepts.

    "},{"location":"kits/led-displays/shift-register-displays/#1-core-components-and-imports","title":"1. Core Components and Imports","text":"
    from machine import Pin, RTC \nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep, localtime, ticks_ms\n

    This section imports the necessary libraries. The program uses: - machine.Pin: Controls individual GPIO pins on the Pico - RTC: Real-Time Clock for keeping time - sr74hc595: Manages the shift register that controls the display - utime: Provides timing functions

    "},{"location":"kits/led-displays/shift-register-displays/#lab-1-understanding-gpio-pins","title":"Lab 1: Understanding GPIO Pins","text":"

    Have students create a simple LED blink program:

    from machine import Pin\nfrom utime import sleep\n\nled = Pin(25, Pin.OUT)  # Built-in LED on Pico\nwhile True:\n    led.value(1)  # Turn on\n    sleep(1)\n    led.value(0)  # Turn off\n    sleep(1)\n
    "},{"location":"kits/led-displays/shift-register-displays/#2-rtc-initialization","title":"2. RTC Initialization","text":"
    def wait_for_rtc():\n    print(\"Waiting for RTC to be ready...\")\n    rtc = RTC()\n    while True:\n        current_time = rtc.datetime()\n        if current_time[0] != 2021 or current_time[1] != 1 or current_time[2] != 1:\n            print(\"RTC is ready!\")\n            return\n        print(\"RTC not ready yet...\")\n        sleep(1)\n

    This function ensures the RTC has been set to a valid time before proceeding.

    "},{"location":"kits/led-displays/shift-register-displays/#lab-2-rtc-basics","title":"Lab 2: RTC Basics","text":"

    Have students experiment with reading and setting the RTC:

    from machine import RTC\nfrom utime import sleep\n\nrtc = RTC()\n# Set the time (year, month, day, weekday, hour, minute, second, subsecond)\nrtc.datetime((2024, 12, 27, 5, 14, 30, 0, 0))\n\nwhile True:\n    current_time = rtc.datetime()\n    print(f\"Current time: {current_time[4]:02d}:{current_time[5]:02d}:{current_time[6]:02d}\")\n    sleep(1)\n
    "},{"location":"kits/led-displays/shift-register-displays/#3-seven-segment-display-setup","title":"3. Seven-Segment Display Setup","text":"

    class FourDigitClock:\n    ALL_OFF = 0xFF  # All segments off (inverted logic)\n\n    def __init__(self, ser_pin, srclk_pin, rclk_pin):\n        self.ser = Pin(ser_pin, Pin.OUT)\n        self.srclk = Pin(srclk_pin, Pin.OUT) \n        self.rclk = Pin(rclk_pin, Pin.OUT)\n
    This class manages the four-digit display. It uses three pins to control the shift register.

    "},{"location":"kits/led-displays/shift-register-displays/#lab-3-seven-segment-pattern-display","title":"Lab 3: Seven-Segment Pattern Display","text":"

    Have students create a simple program to display a single digit:

    from machine import Pin\nfrom utime import sleep\n\n# Create a simple version that lights up segments manually\nsegments = {\n    'a': Pin(2, Pin.OUT),\n    'b': Pin(3, Pin.OUT),\n    'c': Pin(4, Pin.OUT),\n    # ... add more segments\n}\n\ndef display_number(number):\n    # Pattern for number 1\n    if number == 1:\n        segments['b'].value(1)\n        segments['c'].value(1)\n    # Add more numbers...\n

    "},{"location":"kits/led-displays/shift-register-displays/#4-digit-patterns","title":"4. Digit Patterns","text":"

    self.SEGMENTS = {\n    'a': 4, 'b': 3, 'c': 2, \n    'd': 7, 'e': 6, 'f': 5, 'g': 1\n}\nself.DIGIT_SEGMENTS = {\n    0: 'abcdef', 1: 'bc', 2: 'abged', 3: 'abgcd',\n    4: 'fbcg', 5: 'afgcd', 6: 'afedcg', \n    7: 'abc', 8: 'abcdefg', 9: 'abfgcd'\n}\n
    This section defines which segments should be lit for each number.

    "},{"location":"kits/led-displays/shift-register-displays/#lab-4-pattern-design","title":"Lab 4: Pattern Design","text":"

    Have students draw and design their own custom characters using the seven segments. They can create: - Letters (A, b, C, d, E, F) - Custom symbols - Animated patterns

    "},{"location":"kits/led-displays/shift-register-displays/#5-time-display-logic","title":"5. Time Display Logic","text":"
    def display_time(self, hour, minute, colon_state):\n    # Convert to 12-hour format\n    if hour > 12:\n        hour -= 12\n    elif hour == 0:  \n        hour = 12\n
    "},{"location":"kits/led-displays/shift-register-displays/#lab-5-time-format-conversion","title":"Lab 5: Time Format Conversion","text":"

    Have students write a program that converts between 24-hour and 12-hour time formats:

    def convert_time(hour24):\n    if hour24 > 12:\n        return hour24 - 12, \"PM\"\n    elif hour24 == 0:\n        return 12, \"AM\"\n    elif hour24 == 12:\n        return 12, \"PM\"\n    else:\n        return hour24, \"AM\"\n
    "},{"location":"kits/led-displays/shift-register-displays/#advanced-labs-and-extensions","title":"Advanced Labs and Extensions:","text":""},{"location":"kits/led-displays/shift-register-displays/#1-alarm-clock-lab","title":"1. Alarm Clock Lab","text":"

    Modify the clock to add alarm functionality: - Add a button to set alarm time - Add a buzzer for the alarm - Implement snooze functionality

    "},{"location":"kits/led-displays/shift-register-displays/#2-temperature-display-lab","title":"2. Temperature Display Lab","text":"

    Alternate between showing time and temperature: - Add a temperature sensor - Display temperature for 3 seconds every minute - Add a button to toggle between time and temperature

    "},{"location":"kits/led-displays/shift-register-displays/#3-custom-animation-lab","title":"3. Custom Animation Lab","text":"

    Create animations for the display: - Make digits spin when changing - Create a \"snake\" animation for the top of each hour - Design transitions between numbers

    "},{"location":"kits/led-displays/shift-register-displays/#4-world-clock-lab","title":"4. World Clock Lab","text":"

    Modify the clock to show multiple time zones: - Add buttons to cycle through different time zones - Show timezone abbreviation - Store favorite time zones

    "},{"location":"kits/led-displays/shift-register-displays/#5-stopwatch-lab","title":"5. Stopwatch Lab","text":"

    Add stopwatch functionality: - Use buttons to start/stop/reset - Display tenths of seconds - Store lap times

    "},{"location":"kits/led-displays/shift-register-displays/#summary","title":"Summary","text":"

    These labs progressively build upon the base code while introducing new concepts and challenges. Each lab reinforces different programming concepts:

    • Variables and data types
    • Control structures (if/else, loops)
    • Functions and methods
    • Object-oriented programming
    • Hardware interaction
    • Time and date handling
    • User input processing

    This allows students to learn both programming and hardware concepts in a hands-on, engaging way while creating something practical and visible.

    "},{"location":"kits/led-strips/","title":"LED Strip Clocks","text":"

    In this section we will present two clocks that use and LED strip.

    1. The first kit displays binary numbers. Hard to read but very geeky.
    2. The second requires building four seven-segment displays from the LED strip (or LED string)
    "},{"location":"kits/led-strips/01-binary-clock/","title":"Binary Clock","text":"

    This kit just needs a Pico and a short segment of an LED strip - about 14 pixels.

    We can create a very simple binary clock using a single LED strip.

    The strip will have three color bands:

    1. One binary number will be the hour (0 to 12) (4 red pixels)
    2. One binary number will be the minutes (0 to 59) (6 green pixels)
    3. One binary number will be the seconds (0 to 59) (6 blue pixels)

    We can also put spaces between the bands

    We can optionally also have the seconds displayed by:

    1. A single LED that blinks on and off
    2. Two decimal digits
    3. A single binary from (0 to 60)
    "},{"location":"kits/led-strips/01-binary-clock/#sample-code","title":"Sample Code","text":"
    from machine import Pin\nfrom neopixel import NeoPixel\nfrom utime import sleep, localtime\n# get the configuration information\nimport config\n\nnp = config.NUMBER_PIXELS\nstrip = NeoPixel(Pin(config.NEOPIXEL_PIN), np)\n\nsec_bits = [0,0,0,0,0,0]\nmin_bits = [0,0,0,0,0,0]\nhr_bits = [0,0,0,0,0,0]\n\ndef decimal_to_binary(n, a):\n    global sec_bits\n    for i in range(0,6):\n        if n % 2:\n            a[i] = 1\n        else:\n            a[i] = 0\n        ## n halfed\n        n //= 2\n\ndef display_binary(binary, index, color):\n    for i in range(0, 6):\n        # print(i, ' ', end='')\n        if binary[i] == 1:\n            strip[index+i] = color\n        else:\n            strip[index+i] = (0,0,0)\n    strip.write()\n\n# light mark and write\ndef display_mark(loc):\n    strip[loc] = (5,5,5)\n    strip.write()\n\n# update from the first time\n# sec\ndisplay_mark(0)\ndisplay_mark(7)\n\n# min\ndisplay_mark(9)\ndisplay_mark(16)\n\n# min\ndisplay_mark(19)\ndisplay_mark(26)\n\nnow = localtime()\nhour = now[3]\n# use AM/PM 12 hour time\nif hour > 12:\n    hour = hour - 12\nminute = now[4]\n\n# this is not working\ndecimal_to_binary(minute, min_bits)\nprint('initial min:', minute, min_bits)\ndisplay_binary(min_bits, 10, (0,10,0))\n\ndecimal_to_binary(hour, hr_bits)\nprint('initial hour:', hour, hr_bits)\ndisplay_binary(hr_bits, 20, (0,0,10))\n\nwhile True:\n    now = localtime()\n    hour = now[3]\n    # use AM/PM 12 hour time\n    if hour > 12:\n        hour = hour - 12\n    minute = now[4]\n    sec = now[5]\n    print(hour, ':', minute, ' ', sec, sep='')\n    strip.write()\n    decimal_to_binary(sec, sec_bits)\n    print('sec:', sec, sec_bits)\n    display_binary(sec_bits, 1, (10,0,0))\n    if sec == 60:\n        minute = minute + 1\n        sec = 0\n        decimal_to_binary(minute, min_bits)\n        print('min:', minute, min_bits)\n        display_binary(min_bits, 10, (0,10,0))\n        if minute == 60:\n            decimal_to_binary(hour, hr_bits)\n            print('hour:', hour, hr_bits)\n            display_binary(hr_bits, 20, (0,0,10))\n            hour = hour + 1\n            minute = 0\n            if hour == 24:\n                hour = 0\n    sleep(1)\n
    "},{"location":"kits/led-strips/01-binary-clock/#references","title":"References","text":"
    • Moving Rainbow Clock
    "},{"location":"kits/led-strips/02-seven-segment-clock/","title":"Seven Segment Clock","text":"

    We can create a large, bright clock visible in a large classroom by lighting up selective pixels of an LED strip and arranging the pixels in the shape of seven segment displays. We can use three pixels per segment.

    • We can use three pixels per segment.
    • 21 pixels per digit
    • 63 pixels + 6 for the \"1\" + two for the colon = 70 pixels

    eBay 50 for $12

    Drawing Digits

    Lessons

    We can create an array of the segments like this:

    segmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n
    "},{"location":"kits/led-strips/02-seven-segment-clock/#digit-pixel-map","title":"Digit Pixel Map","text":"

    TBD

    • a: n, n+1, n+2
    • b: n+3, n+4, n+5

    def set_pixels(digit, value, color):\n    # look up start pixel for digit\n    # for value turn on pixels\n    n = startVals[digit]\n\n    segmentOn = segmentMapping[value];\n    for i in range(0, 9):\n        if (segmentOn[i]):\n            o = i*3 // offset\n            strip(n+o) = color\n            strip(n+o+1) = color\n            strip(n+o+2) = color\n
    ```

    7-Segment Display Demo with P5.js

    Moving Rainbow Arduino Sign

    "},{"location":"kits/lilygo/","title":"LILYGO T-Display RP2040","text":"

    LILYGO makes low-cost and high-quality microcontroller development boards that include small displays. Although most of their boards run on C programs on ESP-32 processors, they do have one that runs MicroPython on an RP2040. This \"kit\" is really just that development board placed on a breadboard. The device has two buttons on it which can be used to adjust the time.

    This is a color 1.14 inch LCD display PS with 240*135 resolution. It uses the ST7789V chip that has an extreamly high quality driver created by Russ Hughes that allows for flicker-free drawing.

    I purchased mine on Ebay for $10.66 and three dollars for shipping.

    Although the display is too small for most robotic applications where the robot is on the floor and we are standing, it is a good example of how we can get both clocks and watches to look great. My hope is that LILYGO comes out with a larger display in the future.

    Lilygo also sells their own \"wearable\" watch kits] for $35 to $45. However, I have not purchased any of these that can be programmed with an RP2040 and MicroPython yet. Here is a GitHub Page for the T-Watch that implies it might be on the way. Note that using this requires extensive knowledge of the ESP32 development system.

    "},{"location":"kits/lilygo/#getting-started","title":"Getting Started","text":"

    To use the ST7789V driver we MUST use a custom image provide by Rull Hughes. This is because the driver is written in low-level C code and the python driver requires it to be combiled into the firmware image.

    I downloaded the custom image here:

    T-DISPLAY RP2040 Firmware

    I then held the Boot button down while I powered up the device.

    I soldered my own header pins on the LILYGO and placed it on a breadboard. Unfortunatly this makes it impossible to hold down the boot button with the device on the breadboard.

    "},{"location":"kits/lilygo/#pinouts","title":"Pinouts","text":"

    The pinouts are very different from the Raspberry Pi Pico.

    "},{"location":"kits/lilygo/#config-file","title":"Config File","text":"

    This implementation puts the driver in a hidden C program, but it does have a configuration file that we must upload and place in the /lib directory.

    Here is a Link to the File for the T-Display RP2040

    \"\"\"TTGO T-Display RP2040 display\"\"\"\n\nfrom machine import Pin, SPI\nfrom time import sleep\nimport st7789\n\nTFA = 40    # top free area when scrolling\nBFA = 40    # bottom free area when scrolling\n\ndef config(rotation=0, buffer_size=0, options=0):\n\n    Pin(22, Pin.OUT, value=1)\n\n    spi = SPI(0,\n        baudrate=62500000,\n        polarity=1,\n        phase=0,\n        sck=Pin(2, Pin.OUT),\n        mosi=Pin(3, Pin.OUT),\n        miso=None)\n\n    return st7789.ST7789(\n        spi,\n        135,\n        240,\n        cs=Pin(5, Pin.OUT),\n        dc=Pin(1, Pin.OUT),\n        backlight=Pin(4, Pin.OUT),\n        rotation=rotation,\n        options=options,\n        buffer_size=buffer_size)\n
    "},{"location":"kits/lilygo/#blink-the-onboard-led","title":"Blink The Onboard LED","text":"

    This red LED is on the bottom of the board.

    Blink Timer example:

    from machine import Pin, Timer\nled = Pin(25,Pin.OUT)\ntim = Timer()\ndef tick(timer):\n    global led\n    led.toggle()\ntim.init(freq=2.5, mode=Timer.PERIODIC, callback=tick)\n
    "},{"location":"kits/lilygo/#display-example","title":"Display Example","text":"
    \"\"\"\ndisplay-test.py\nFills the screen with red, green and blue\n\"\"\"\n\nfrom utime import sleep\nimport st7789\nimport tft_config\ntft = tft_config.config(1)\ntft.init()\n\nwhile True:\n    tft.fill(st7789.RED)\n    sleep(1)\n    tft.fill(st7789.GREEN)\n    sleep(1)\n    tft.fill(st7789.BLUE)\n    sleep(1)\n
    "},{"location":"kits/lilygo/#drawing-text","title":"Drawing Text","text":"

    For this example to work, you will need to load a font library into the /lib directory.

    import random\nimport utime\nimport st7789\nimport tft_config\nimport vga2_bold_16x32 as font\n\ntft = tft_config.config(1)\ntft.init()\n\n# draw text using a 16X32 font using blue text on a white background\ntft.text(\n        font,\n        'Hello World!',\n        tft.width()//2-100, # x position to start writing\n        tft.height()//2-50, # y position\n        st7789.BLUE, # font in blue\n        st7789.WHITE # background in white\n)\n
    "},{"location":"kits/lilygo/#referneces","title":"Referneces","text":"

    Item on Aliexpress Sample GitHub repo: https://github.com/Xinyuan-LilyGO/LILYGO-T-display-RP2040

    ST7789V Submodule: Russ Hughes GitHub Repo

    Config: Sample Config File

    "},{"location":"kits/max7219/","title":"MAX7219 Clocks","text":"

    The Analog Devices MAX7219 is a low-cost chip that communicates with a row of seven-segment displays using a single serial interface.

    eBay search for MAX7219

    "},{"location":"kits/max7219/#lesson-plan-building-a-clock-with-the-max7219-chip-using-micropython-and-raspberry-pi-pico","title":"Lesson Plan: Building a Clock with the MAX7219 Chip using MicroPython and Raspberry Pi Pico","text":""},{"location":"kits/max7219/#objective","title":"Objective:","text":"

    Students will learn about basic electronics and programming by building a digital clock using the MAX7219 LED driver chip with a Raspberry Pi Pico programmed in MicroPython.

    "},{"location":"kits/max7219/#materials","title":"Materials:","text":"
    • MAX7219 LED dot matrix modules
    • Raspberry Pi Pico
    • Jumper wires
    • Breadboard
    • USB cable for the Raspberry Pi Pico
    • Computers with Thonny Python IDE installed
    • Basic electronic components (resistors, capacitors, etc.)
    • Reference materials on MAX7219 and MicroPython programming
    "},{"location":"kits/max7219/#duration","title":"Duration:","text":"

    5 classes (45 minutes each)

    "},{"location":"kits/max7219/#class-1-introduction-to-the-max7219-and-raspberry-pi-pico","title":"Class 1: Introduction to the MAX7219 and Raspberry Pi Pico","text":"
    • Lecture Topic: Overview of the MAX7219 chip and its applications in digital displays.
    • Activity: Demonstration of a simple LED matrix setup using the MAX7219 and Raspberry Pi Pico.
    • Homework: Read provided material about MAX7219 and basics of MicroPython.
    "},{"location":"kits/max7219/#class-2-basic-electronics-and-circuit-design","title":"Class 2: Basic Electronics and Circuit Design","text":"
    • Lecture Topic: Fundamentals of electronics, introduction to using a breadboard, and designing circuits.
    • Activity: Students practice creating basic circuits on the breadboard using Raspberry Pi Pico.
    • Homework: Sketch a basic circuit diagram for connecting the MAX7219 to the Raspberry Pi Pico.
    "},{"location":"kits/max7219/#class-3-introduction-to-micropython","title":"Class 3: Introduction to MicroPython","text":"
    • Lecture Topic: Basics of MicroPython programming and its application in controlling electronic components.
    • Activity: Simple programming exercises in Thonny Python IDE to

    understand MicroPython syntax and basic commands.

    • Homework: Write a simple program in MicroPython to blink an LED.
    "},{"location":"kits/max7219/#class-4-programming-the-max7219-with-micropython","title":"Class 4: Programming the MAX7219 with MicroPython","text":"
    • Lecture Topic: Detailed instruction on programming the MAX7219 using MicroPython.
    • Activity: Students will write and upload a MicroPython script to the Raspberry Pi Pico to control the MAX7219 module, starting with displaying static numbers.
    • Homework: Modify the script to create a simple animation or pattern on the LED matrix.
    "},{"location":"kits/max7219/#class-5-building-and-programming-the-clock","title":"Class 5: Building and Programming the Clock","text":"
    • Lecture Topic: Integrating the knowledge gained to build a digital clock.
    • Activity: Students will complete the assembly of their digital clocks and program them to display the current time. This will involve fetching the time from the Raspberry Pi Pico and displaying it on the MAX7219 LED matrix.
    • Assessment: Evaluate the students' projects based on functionality, creativity, and understanding of the concepts taught.
    "},{"location":"kits/max7219/#additional-notes","title":"Additional Notes:","text":"
    • Ensure that each student or group has access to all the necessary materials.
    • Supplement the course with online resources and forums for additional support.
    • Encourage students to document their progress and challenges for a reflective learning experience.
    • Consider having a session for students to present their finished clocks and share their learning experiences with the class.
    "},{"location":"kits/max7219/#references","title":"References","text":"

    DIY clock | Homemade 7 segments \"nixie\" tubes

    "},{"location":"kits/pico-oled/","title":"Pico OLED Kits","text":"

    These are our most popular kits. They use a bright monochrome 128x64 OLED with either the Raspberry Pi Pico or the Raspberry Pi Pico W.

    The OLEDs are mounted on a piece of plastic with a half-size breaboard.

    Each board has two buttons so you can adjust the time and alarm clock settings.

    "},{"location":"kits/pico-oled/#individual-exercises","title":"Individual Exercises","text":""},{"location":"kits/pico-oled/#hello-world","title":"Hello World","text":"

    Go to Hello World lab

    "},{"location":"kits/pico-oled/01-hello-world/","title":"Hello World","text":"

    To get started, let's just draw the string \"Hello world!\" on the display.

    Here is the code:

    import machine\nimport ssd1306\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\n\nRES = machine.Pin(4) # Reset\nDC = machine.Pin(5) # Data/command\nCS = machine.Pin(6) # Chip Select\n\nspi=machine.SPI(0, sck=SCL, mosi=SDA)\noled = ssd1306.SSD1306_SPI(128, 64, spi, DC, RES, CS)\n\n# erase the entire screen with black\noled.fill(0)\n\n# place a hello message at point (0,0) in white\noled.text(\"Hello world!\", 0, 0, 1)\n\n# send the entire frame buffer to the display via the SPI bus\noled.show()\n

    Challenges

    1. Can you change the message from \"Hello world!\" to have your name in it?
    2. Can you change the location of the text on the screen by changing the location point from (0,0) to another place on the screen? The screen is 128 pixels wide by 64 pixels high.
    3. How far down can you display the message without going off the screen?
    4. How many characters wide can a message be before it goes off the right edge of the dipsplay?
    5. Can you display multiple messages on different lines?
    "},{"location":"kits/pico-oled/02-display-time/","title":"Display Time","text":""},{"location":"kits/pico-oled/02-display-time/#the-localtime-function","title":"The Localtime function","text":"
    from time import localtime\n\nprint(localtime())\n
    import machine\nimport ssd1306\nimport config\nfrom time import localtime\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\n\nyear = localtime()[0]\nmonth = localtime()[1]\nday = localtime()[2]\nhour = localtime()[3]\nminute = localtime()[4]\n\n# display the time in hour and minute on the first line\noled.text(str(hour) + \":\" + str(minute), 0, 0, 1)\n\n# display the date on the second line\noled.text(str(month) + \"/\" + str(day) + \"/\" + str(year), 0, 10, 1)\noled.show()\n
    "},{"location":"kits/pico-oled/02-hello-config/","title":"Hello Configuraiton","text":""},{"location":"kits/pico-oled/03-display-localtime/","title":"Display Localtime","text":"
    import machine\nimport ssd1306\nimport config\nfrom time import localtime\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\n\nyear = localtime()[0]\nmonth = localtime()[1]\nday = localtime()[2]\nhour = localtime()[3]\nminute = localtime()[4]\n\n# display the time in hour and minute on the first line\noled.text(str(hour) + \":\" + str(minute), 0, 0, 1)\n\n# display the date on the second line\noled.text(str(month) + \"/\" + str(day) + \"/\" + str(year), 0, 10, 1)\noled.show()\n

    Challenges

    1. Change the display format of the date and time. Place the date and time in the center of the display.
    2. Add code to add a \"AM\" or \"PM\" string if the hour is greater than 12 noon
    3. Adding additional text to display if it is morning or evening
    "},{"location":"kits/pico-oled/04-display-localtime-updates/","title":"Display Local Time with Updates","text":"

    Now let's update the display every second.

    import machine\nimport ssd1306\nimport config\nfrom time import localtime\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\n\nwhile True:\n    # clear the entire screen\n\n    oled.fill(0)\n    year = localtime()[0]\n    month = localtime()[1]\n    day = localtime()[2]\n    hour = localtime()[3]\n    minute = localtime()[4]\n    second = localtime()[5]\n\n    # display the time in hour and minute on the first line\n    oled.text(str(hour) + \":\" + str(minute) + \":\" + str(second) , 0, 0, 1)\n\n    # display the date on the second line\n    oled.text(str(month) + \"/\" + str(day) + \"/\" + str(year), 0, 10, 1)\n    # send the entire screen to the display via SPI\n    oled.show()\n
    "},{"location":"kits/pico-oled/05-clock-hands/","title":"Clock Hands","text":"

    Now lets display the hands on a clock. We will need to do a little math to calculate were on the clock face to draw the hands to from the center.

    import machine\nimport ssd1306\nimport config\nfrom time import sleep, localtime\nimport math\n\nSCL=machine.Pin(config.SCL_PIN) # SPI CLock\nSDA=machine.Pin(config.SDA_PIN) # SPI Data\n\nRES = machine.Pin(config.RESET_PIN) # Reset\nDC = machine.Pin(config.DC_PIN) # Data/command\nCS = machine.Pin(config.CS_PIN) # Chip Select\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(config.WIDTH, config.HEIGHT, spi, DC, RES, CS)\nTWO_PI = 3.14159 * 2\n\nLENGTH = config.HEIGHT // 2\nCENTER_X = config.WIDTH // 2\nCENTER_Y = config.HEIGHT // 2\n\noled.fill(0)\n\nfor i in range(0,61):\n    radians = (i/60)*TWO_PI\n    x = int(math.sin(radians)*LENGTH)\n    y = -int(math.cos(radians)*LENGTH)\n    # print(i, radians, x, y, x, y)  \n    oled.line(CENTER_X, CENTER_Y, CENTER_X + x, CENTER_Y + y, 1)\n    oled.show()\n    sleep(.1)\n    oled.line(CENTER_X, CENTER_Y, CENTER_X + x, CENTER_Y + y, 0)\n
    "},{"location":"kits/pico-oled/10-draw-seven-segments/","title":"Draw Seven Segments","text":""},{"location":"kits/pico-oled/10-draw-seven-segments/#dight-to-segment-data","title":"Dight to Segment Data","text":"
    segmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n
    "},{"location":"kits/pico-oled/10-draw-seven-segments/#draw-segment-function","title":"Draw Segment Function","text":"

    Parameters:

    1. The digit to display - an integer in the range 0-9
    2. x of the upper left corner
    3. y of the upper left corner
    4. the width of the digit (about 20 is a good value)
    5. the height of the digit
    6. the thickness of each segment (3 or 4 are good values)
    7. the color (0=black, 1=white)
    # x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottem, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top row\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottem element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottum\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n
    "},{"location":"kits/pico-oled/10-draw-seven-segments/#full-program","title":"Full Program","text":"
    # Clock Lab 20: Draw Seven Segments\n# this lab uses the fill_rect function to draw the segments\nimport machine\nimport utime\nimport ssd1306\nfrom utime import sleep, localtime\nled = machine.Pin(25, machine.Pin.OUT)\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\nspi=machine.SPI(0, sck=SCL, mosi=SDA, baudrate=100000)\n\nRES = machine.Pin(4)\nDC = machine.Pin(5)\nCS = machine.Pin(6)\n\noled = ssd1306.SSD1306_SPI(128, 64, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottem, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottem element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottum\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n\noled.fill(0)\noled.text('Lab 12: rect', 0, 0, 1)\nx = 10 # upper left corner x\ny = 10 # upper left corner y\nw = 20 # digit width\nh = 30 # digit height\nt = 3\n\nwhile True:\n    for i in range(0, 10):\n\n        print(i)\n        # create an outline on px away from the drawing region\n        oled.rect(x-2, y-2, w+4, h+4, 1)\n        # draw one digit\n        drawDigit(i, x, y, w, h, t, 1)\n        # draw a second digit\n        #drawDigit(i, x + w + 4, w, h, t, 1)\n        oled.text(str(i), 0, 54, 1)\n        oled.show()\n        sleep(2)\n        oled.fill(0)\n
    "},{"location":"kits/pico-oled/11-draw-thickness/","title":"Draw Seven Segments with Thickness","text":""},{"location":"kits/pico-oled/15-digital-clock/","title":"OLED Digital Clock Display","text":""},{"location":"kits/shift-register-clock/","title":"74HC595 Shift Register Clock","text":"

    The display has five wires. In addition to power and ground we have:

    ser_pin=2,    # DIO\nsrclk_pin=1,  # SCLK\nrclk_pin=0    # RCLK\n

    The shift register takes in a set of 16 bit commands. The first byte is the segment information with one bit for each of the 7 segments and one bit for the colon. The second bit indicates what digit should be turned on.

    Note that for a segment to be on, the bit must be \"0\".

    Here are the letters associated with each of the 7 segments:

     aaaa\nf    b\nf    b\n gggg\ne    c\ne    c\n dddd\n
    # bit 0 is the right-most significant bit and is used to turn on the colon.\nself.SEGMENTS = {\n    'a': 4,  # bit 4\n    'b': 3,  # bit 3\n    'c': 2,  # bit 2\n    'd': 7,  # bit 7\n    'e': 6,  # bit 6\n    'f': 5,  # bit 5\n    'g': 1   # bit 1\n}\n

    \"d\" First byte: 00110000 Second byte: 00010000

    This is where \"a\" is missing. a is the fourth bit. First byte: 00010000

    This is where all the segments are on except f. \"f\" is the 3rd bit First byte: 00100000 \"A\" is First byte: 10000000

    "},{"location":"kits/shift-register-clock/#sample-test","title":"Sample Test","text":"

    The following program will cycle through the digits 0 to 9 on the right most digit to the left most digit.

    from machine import Pin\nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep, localtime\n\nclass FourDigitClock:\n    # Class constants\n    ALL_OFF = 0xFF            # All segments off (inverted logic)\n    SECOND_BYTE = 0b00010000  # Keep bit 4 set in second byte\n\n    def __init__(self, ser_pin, srclk_pin, rclk_pin):\n        # Initialize pins\n        self.ser = Pin(ser_pin, Pin.OUT)      # Serial data\n        self.srclk = Pin(srclk_pin, Pin.OUT)  # Shift register clock\n        self.rclk = Pin(rclk_pin, Pin.OUT)    # Storage register clock\n\n        self.sr = SR74HC595_BITBANG(self.ser, self.srclk, self.rclk)\n\n        # Segment bit positions (0 turns segment on)\n        # a is the top, b in the upper right, c is the lower right\n        # d is the bottom, e is the lower left, f is the upper right\n        # g is the middle segment\n        self.SEGMENTS = {\n            'a': 4,  # bit 4\n            'b': 3,  # bit 3\n            'c': 2,  # bit 2\n            'd': 7,  # bit 7\n            'e': 6,  # bit 6\n            'f': 5,  # bit 5\n            'g': 1   # bit 1\n        }\n\n        # Define segments needed for each digit\n        self.DIGIT_SEGMENTS = {\n            0: 'abcdef',   # 0 needs all but g\n            1: 'bc',       # 1 needs just b and c\n            2: 'abged',    # 2 needs all but c and f\n            3: 'abgcd',    # 3 needs all but e and f\n            4: 'fbcg',     # 4 needs these four\n            5: 'afgcd',    # 5 needs all but e and b\n            6: 'afedcg',   # 6 needs all but b\n            7: 'abc',      # 7 needs just these three\n            8: 'abcdefg',  # 8 needs all segments\n            9: 'abfgcd'    # 9 needs all but e\n        }\n\n        # Pre-calculate patterns for all digits\n        self.DIGIT_PATTERNS = {\n            digit: self.create_pattern(segments) \n            for digit, segments in self.DIGIT_SEGMENTS.items()\n        }\n\n    def create_pattern(self, segments):\n        \"\"\"Create bit pattern from segment letters with inverted logic\"\"\"\n        pattern = self.ALL_OFF\n        for segment in segments:\n            if segment in self.SEGMENTS:\n                pattern &= ~(1 << self.SEGMENTS[segment])\n        return pattern\n\n    def display_pattern(self, first_byte, digit_select_byte):\n        \"\"\"Display a pattern with specified digit selection\"\"\"\n        self.sr.bits(first_byte, 8)\n        self.sr.bits(digit_select_byte, 8)\n        self.sr.latch()\n\n    def test_all_positions(self):\n        \"\"\"Test counting 0-9 on all digit positions\"\"\"\n        print(\"Testing all digit positions...\")\n\n        # Digit selection patterns to try\n        digit_patterns = [\n            (0, 0b00010000, \"Rightmost digit\"),\n            (1, 0b00100000, \"Second digit\"),\n            (2, 0b01000000, \"Third digit\"),\n            (3, 0b10000000, \"Leftmost digit\")\n        ]\n\n        # Test each digit position\n        for position, digit_select, position_name in digit_patterns:\n            print(f\"\\nTesting {position_name}\")\n\n            # Count 0-9 on this position\n            for number in range(10):\n                print(f\"Displaying {number} on {position_name}\")\n\n                # Display the number\n                self.display_pattern(self.DIGIT_PATTERNS[number], digit_select)\n                sleep(.25)\n\n                # Clear display between numbers\n                self.display_pattern(self.ALL_OFF, self.ALL_OFF)\n                sleep(0.05)\n\n            # Wait for user input before moving to next position\n            #input(f\"Press Enter to test next position...\")\n\ndef run_position_test():\n    \"\"\"Run position testing\"\"\"\n    clock = FourDigitClock(\n        ser_pin=2,    # DIO\n        srclk_pin=1,  # SCLK\n        rclk_pin=0    # RCLK\n    )\n\n    print(\"Starting position tests...\")\n    clock.test_all_positions()\n\n# Run the position test\nif __name__ == '__main__':\n    run_position_test()\n
    "},{"location":"kits/shift-register-clock/#references","title":"References","text":"

    74HC595 Shift Register

    "},{"location":"kits/shift-register-clock/clock-main/","title":"Clock Main","text":""},{"location":"kits/shift-register-clock/clock-main/#details","title":"Details","text":"

    This program use 12 hour time and also flashes the colon ever 1/2 second. It also is designed to work with a real-time clock that might take a bit of time to startup with the Pico first powers up.

    from machine import Pin, RTC \nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep, localtime, ticks_ms\n\ndef wait_for_rtc():\n    print(\"Waiting for RTC to be ready...\")\n    rtc = RTC()\n    while True:\n        current_time = rtc.datetime()\n        # On Pico, default RTC starts at (2021, 1, 1, 0, 0, 0, 0, 0)\n        # So we check if it's been set to something else\n        if current_time[0] != 2021 or current_time[1] != 1 or current_time[2] != 1:\n            print(\"RTC is ready!\")\n            return\n        print(\"RTC not ready yet...\")\n        sleep(1)  # Check every second\n\nclass FourDigitClock:\n    ALL_OFF = 0xFF  # All segments off (inverted logic)\n\n    def __init__(self, ser_pin, srclk_pin, rclk_pin):\n        self.ser = Pin(ser_pin, Pin.OUT)\n        self.srclk = Pin(srclk_pin, Pin.OUT) \n        self.rclk = Pin(rclk_pin, Pin.OUT)\n        self.sr = SR74HC595_BITBANG(self.ser, self.srclk, self.rclk)\n\n        self.SEGMENTS = {\n            'a': 4, 'b': 3, 'c': 2, \n            'd': 7, 'e': 6, 'f': 5, 'g': 1\n        }\n        self.DIGIT_SEGMENTS = {\n            0: 'abcdef', 1: 'bc', 2: 'abged', 3: 'abgcd',\n            4: 'fbcg', 5: 'afgcd', 6: 'afedcg', \n            7: 'abc', 8: 'abcdefg', 9: 'abfgcd'\n        }\n        self.DIGIT_PATTERNS = {\n            digit: self.create_pattern(segments)\n            for digit, segments in self.DIGIT_SEGMENTS.items()\n        }\n        self.DIGIT_SELECT = [\n            0b00010000,  # Rightmost digit\n            0b00100000,  # Second digit \n            0b01000000,  # Third digit\n            0b10000000   # Leftmost digit  \n        ]\n\n    def create_pattern(self, segments):\n        pattern = self.ALL_OFF\n        for segment in segments:\n            if segment in self.SEGMENTS:\n                pattern &= ~(1 << self.SEGMENTS[segment]) \n        return pattern\n\n    def display_digit(self, digit, position, dp=False):\n        pattern = self.DIGIT_PATTERNS[digit]\n        if dp:\n            pattern &= ~(1 << 0)  # Turn on decimal point\n        self.sr.bits(pattern, 8)\n        self.sr.bits(self.DIGIT_SELECT[position], 8)\n        self.sr.latch()\n\n    def display_time(self, hour, minute, colon_state):\n        # Convert to 12-hour format\n        if hour > 12:\n            hour -= 12\n        elif hour == 0:  \n            hour = 12\n\n        digits = [hour // 10, hour % 10, minute // 10, minute % 10]\n\n        for position, digit in enumerate(reversed(digits)):\n            self.display_digit(digit, position, dp=(position == 1 and colon_state))\n            sleep(0.002)  # Reduced persistence timing\n\n\ndef run_clock():\n    # wait for a good time to come from localtime()\n    wait_for_rtc()\n\n    clock = FourDigitClock(ser_pin=2, srclk_pin=1, rclk_pin=0)\n    print(\"Starting clock...\")\n\n    last_second = -1\n    colon_state = True\n    last_toggle = ticks_ms()\n\n    while True:\n        current_time = localtime()\n        hour = current_time[3]\n        minute = current_time[4]\n        current_second = current_time[5]\n\n        if ticks_ms() - last_toggle >= 500:\n            colon_state = not colon_state\n            last_toggle = ticks_ms()\n\n        clock.display_time(hour, minute, colon_state)\n\n\nif __name__ == '__main__':\n    run_clock()\n
    "},{"location":"kits/shift-register-clock/sample-prompt/","title":"Sample ChatGPT Prompt","text":"

    Prompt

    Please help me write a micropython program for a 4-digit clock. I have a digital clock display with 4 digits I purchased on eBay. Each of the 4 digits has 7 segments and there is also a colon between the 2nd and 3rd digits. The part says they use 74hc595 shift registers. The names of the connectors are:

    1. GND
    2. VCC
    3. RCLK
    4. SCLK
    5. DIO

    I found a micropython driver called: sr74hc595. When I run a test program the various segments do light up, but I don't see a pattern. Can you give me some suggestions on how to write a driver that writes the correct time like 12:34?

    Here is the code that is working:

    # SPDX-FileCopyrightText: 2021 Mike Causer <https://github.com/mcauser>\n# SPDX-License-Identifier: MIT\n\n\"\"\"\nMicroPython 74HC595 8-Bit Shift Register\nhttps://github.com/mcauser/micropython-74hc595\n\"\"\"\n\nfrom machine import Pin\n# from sr74hc595 import SR74HC595_BITBANG\nfrom sr74hc595 import SR74HC595_BITBANG\nfrom utime import sleep\n\nser = Pin(2, Pin.OUT)\nrclk = Pin(0, Pin.OUT)\nsrclk = Pin(1, Pin.OUT)\n\n# construct without optional pins\nsr = SR74HC595_BITBANG(ser, srclk, rclk)\n\n#sr.clear()  # raises RuntimeError because you haven't provide srclr pin\n#sr.enable()  # raises RuntimeError because you haven't provide oe pin\n\n# reconstruct with all pins\noe = Pin(3, Pin.OUT, value=0)  # low enables output\nsrclr = Pin(3, Pin.OUT, value=1)  # pulsing low clears data\n\nsr = SR74HC595_BITBANG(ser, srclk, rclk, srclr, oe)\n\nwhile True:\n\n    sr.bit(1)  # send high bit, do not latch yet\n    sr.bit(0)  # send low bit, do not latch yet\n    sr.latch()  # latch outputs, outputs=0000_0010\n\n    sr.bit(1, 1)  # send high bit and latch, outputs=0000_0101\n    sr.bit(0, 1)  # send low bit and latch, outputs=0000_1010\n\n    sr.bits(0xFF, 4)  # send 4 lowest bits of 0xff (sends 0x0f), outputs=1010_1111\n    sr.clear(0)  # clear the memory but don't latch yet\n    sr.latch()  # next latch shows the outputs have been reset\n    sr.bits(0b1010_1010, 8)  # write some bits\n    sr.clear()  # clear the memory and latch, outputs have been reset\n\n    sr.enable()  # outputs enabled\n    sr.enable(0)  # outputs disabled\n\n    sleep(1)\n\n    sr.bits(0b1111_1111, 8)  # write some bits\n    sr.clear()  # clear the memory and latch, outputs have been reset\n\n    sr.enable()  # outputs enabled\n    sr.enable(0)  # outputs disabled\n\n    sleep(1)\n\n    sr.bits(0b0000_0011, 8)  # write some bits\n    sr.clear()  # clear the memory and latch, outputs have been reset\n\n    sr.enable()  # outputs enabled\n    sr.enable(0)  # outputs disabled\n    sleep(1)\n
    "},{"location":"kits/tm1637/","title":"TM1637 LED Display","text":"

    Setting the Time

    The TM1637 LED digital display is an incredibly popular and cost-effective 4-digit 7-segment display module widely used in hobbyist electronics and educational projects. At around 30 cents per unit when purchased in bulk, it offers exceptional value for clock projects, counters, and basic numeric displays.

    Key features: - 4 digits with decimal points - Built-in controller chip that handles multiplexing - Simple 2-wire interface (clock and data) - 3.3V or 5V compatible - Brightness control - Colon indicator for clock displays

    What makes the TM1637 particularly appealing for MicroPython projects is its straightforward programming interface. Using just two pins (clock and data), you can control all segments and digits through a simple serial protocol. The module handles all the multiplexing internally, making it much easier to use than raw 7-segment displays.

    The TM1637 LED Clock is a low-cost way to get started. It is simple to setup and use and only requires the user to make 4 connections.

    "},{"location":"kits/tm1637/#parts-list","title":"Parts List","text":"
    1. 1/2 Size 400 tie solderless Breadboard
    2. 4 Male-Female 20cm jumper wires (Dupont Cables)
    3. Raspberry Pi Pico (or Pico W)
    4. TM1637 LED Clock display
    "},{"location":"kits/tm1637/#connection-diagram","title":"Connection Diagram","text":""},{"location":"kits/tm1637/#the-micropython-preamble","title":"The MicroPython Preamble","text":"
    import tm1637\nfrom machine import Pin, RTC\nfrom utime import sleep, localtime, ticks_ms\n\n# Initialize display\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n

    Here's some example MicroPython code to test various display features using your preamble:

    # Basic number display\ntm.numbers(12, 59)  # Display 12:59\nsleep(1)\n\n# Show temperature with decimal\ntm.temperature(23.4)  # Display 23.4\nsleep(1)\n\n# Control brightness (0-7)\ntm.brightness(2)  # Set to medium brightness\n\n# Blank the display\ntm.show('    ')\nsleep(1)\n\n# Show individual digits\ntm.write([0, 1, 2, 3])  # Display 0123\nsleep(1)\n\n# Toggle colon\ntm.show('1234', True)  # Show 12:34 with colon\nsleep(1)\ntm.show('1234', False)  # Show 1234 without colon\nsleep(1)\n\n# Scroll some numbers\nfor i in range(10):\n    tm.number(i * 111)\n    sleep(0.5)\n\n# Test all segments\ntm.write([0x7f, 0x7f, 0x7f, 0x7f])  # All segments on\nsleep(1)\n

    Given its popularity, there are several MicroPython libraries available for the TM1637. The example above uses one of the most common libraries. The display's simplicity and reliability have made it a staple in DIY electronics, particularly for clock projects, temperature displays, and basic counters. You'll find it used in countless Arduino and Raspberry Pi Pico projects, making it one of the most recognizable LED display modules in the maker community.

    "},{"location":"kits/tm1637/manual-time-setting/","title":"Manually Setting the Time","text":"

    Setting the Time

    Next, we will create a complete program that implements a clock with manual time setting using the three buttons. This is a great practical example that teaches state management and user input handling.

    import tm1637\nfrom machine import Pin, RTC\nfrom utime import sleep, localtime, ticks_ms\n\n# Initialize display and RTC\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\nrtc = RTC()\n\n# Initialize buttons with pull-up resistors\nmode_btn = Pin(2, Pin.IN, Pin.PULL_UP)\nnext_btn = Pin(3, Pin.IN, Pin.PULL_UP)\nprev_btn = Pin(4, Pin.IN, Pin.PULL_UP)\n\n# Clock modes\nRUNNING = 0\nSET_HOUR = 1\nSET_MINUTE = 2\nSET_AMPM = 3\n\nclass Clock:\n    def __init__(self):\n        self.mode = RUNNING\n        self.hours = 12\n        self.minutes = 0\n        self.is_pm = False\n        self.colon_on = True\n        self.last_button_time = ticks_ms()\n        self.button_debounce = 200  # milliseconds\n        self.load_time_from_rtc()\n\n    def load_time_from_rtc(self):\n        \"\"\"Get current time from RTC\"\"\"\n        _, _, _, _, hours, minutes, _, _ = rtc.datetime()\n        self.hours = hours % 12\n        if self.hours == 0:\n            self.hours = 12\n        self.is_pm = hours >= 12\n        self.minutes = minutes\n\n    def save_time_to_rtc(self):\n        \"\"\"Save current time to RTC\"\"\"\n        current_time = list(rtc.datetime())\n        hours = self.hours\n        if self.is_pm and hours != 12:\n            hours += 12\n        elif not self.is_pm and hours == 12:\n            hours = 0\n        current_time[4] = hours  # Set hours\n        current_time[5] = self.minutes  # Set minutes\n        rtc.datetime(tuple(current_time))\n\n    def debounce(self):\n        \"\"\"Handle button debouncing\"\"\"\n        current_time = ticks_ms()\n        if current_time - self.last_button_time < self.button_debounce:\n            return False\n        self.last_button_time = current_time\n        return True\n\n    def handle_buttons(self):\n        \"\"\"Process button inputs\"\"\"\n        if not self.debounce():\n            return\n\n        # Mode button cycles through modes\n        if mode_btn.value() == 0:  # Button pressed (active low)\n            self.mode = (self.mode + 1) % 4\n            if self.mode == RUNNING:\n                self.save_time_to_rtc()\n\n        # Next/Previous buttons modify current setting\n        elif next_btn.value() == 0 or prev_btn.value() == 0:\n            increment = -1 if prev_btn.value() == 0 else 1\n\n            if self.mode == SET_HOUR:\n                self.hours = ((self.hours + increment - 1) % 12) + 1\n            elif self.mode == SET_MINUTE:\n                self.minutes = (self.minutes + increment) % 60\n            elif self.mode == SET_AMPM:\n                self.is_pm = not self.is_pm\n\n    def update_display(self):\n        \"\"\"Update the TM1637 display based on current mode and time\"\"\"\n        if self.mode == RUNNING:\n            # Normal time display with blinking colon\n            self.colon_on = not self.colon_on\n        else:\n            # Setting mode - flash the active component\n            flash_on = (ticks_ms() // 500) % 2 == 0\n\n            if self.mode == SET_HOUR:\n                if not flash_on:\n                    tm.show('    ')\n                    return\n            elif self.mode == SET_MINUTE:\n                if not flash_on:\n                    tm.numbers(self.hours, 0)\n                    return\n            elif self.mode == SET_AMPM:\n                if flash_on:\n                    tm.show(' ' + ('P' if self.is_pm else 'A') + ' ')\n                    return\n\n        # Update display\n        tm.numbers(self.hours, self.minutes, colon=self.colon_on)\n\n    def run(self):\n        \"\"\"Main clock loop\"\"\"\n        tm.brightness(2)  # Set initial brightness\n\n        while True:\n            self.handle_buttons()\n\n            if self.mode == RUNNING:\n                self.load_time_from_rtc()\n\n            self.update_display()\n            sleep(0.1)  # Small delay to prevent display flicker\n\n# Create and run the clock\nif __name__ == '__main__':\n    clock = Clock()\n    print(\"Starting clock... Use buttons to set time:\")\n    print(\"Mode: Switch between run/set hour/set minute/set AM,PM\")\n    print(\"Next/Prev: Adjust current setting\")\n    clock.run()\n

    Key concepts and features of this implementation:

    1. Button Handling
    2. Uses pull-up resistors (buttons connect to ground when pressed)
    3. Implements debouncing to prevent multiple triggers
    4. Buttons are active-low (0 when pressed, 1 when released)

    5. Mode System

    6. RUNNING: Normal clock operation
    7. SET_HOUR: Adjust hours (1-12)
    8. SET_MINUTE: Adjust minutes (0-59)
    9. SET_AMPM: Toggle between AM and PM

    10. Visual Feedback

    11. Selected component flashes when being set
    12. Colon blinks in running mode
    13. Special AM/PM display during setting

    14. Time Management

    15. Maintains time in 12-hour format internally
    16. Converts to/from 24-hour format for RTC
    17. Handles midnight/noon edge cases

    18. State Management

    19. Uses a class to organize state and behavior
    20. Separates display, button handling, and time management

    Common challenges students might encounter:

    1. Button Debouncing
    2. Understanding why debouncing is necessary
    3. Adjusting debounce timing for reliable operation

    4. Time Format Conversion

    5. Converting between 12/24 hour formats
    6. Handling edge cases (12 AM/PM)

    7. Display Updates

    8. Managing display refresh rate
    9. Creating smooth visual feedback

    Suggested exercises for students:

    1. Add a temperature display mode
    2. Implement a brightness adjustment feature
    3. Add an alarm setting mode
    4. Save settings to flash memory
    5. Add a battery backup indicator

    Would you like me to explain any part in more detail or provide examples of these extensions?

    "},{"location":"kits/tm1637/running-clock/","title":"Full Running Clock Using the TM1637","text":"

    I'll create a detailed example of a running clock using the TM1637 display. This builds on some of the concepts shown in the clock-driver.py file you shared, but simplified for the TM1637.

    import tm1637\nfrom machine import Pin, RTC\nfrom utime import sleep, localtime\n\n# Initialize the display\ntm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))\n\n# Initialize the RTC (Real Time Clock)\nrtc = RTC()\n\ndef set_initial_time():\n    \"\"\"\n    Set an initial time if RTC isn't configured.\n    In a real project, you'd sync this with a time server or user input.\n    \"\"\"\n    # Format: (year, month, day, weekday, hours, minutes, seconds, subseconds)\n    rtc.datetime((2024, 12, 28, 5, 12, 0, 0, 0))\n\ndef format_time(hours, minutes):\n    \"\"\"\n    Convert 24-hour time to 12-hour format\n    Returns hours and whether it's PM\n    \"\"\"\n    is_pm = hours >= 12\n    if hours > 12:\n        hours -= 12\n    elif hours == 0:\n        hours = 12\n    return hours, is_pm\n\ndef run_clock():\n    # Set initial brightness (0-7)\n    tm.brightness(2)\n\n    # Track colon state for blinking\n    colon_on = True\n\n    while True:\n        # Get current time from RTC\n        year, month, day, weekday, hours, minutes, seconds, _ = rtc.datetime()\n\n        # Convert to 12-hour format\n        display_hours, is_pm = format_time(hours, minutes)\n\n        # Toggle colon every second\n        if seconds != prev_seconds:\n            colon_on = not colon_on\n            prev_seconds = seconds\n\n        # Display the time\n        tm.numbers(display_hours, minutes, colon=colon_on)\n\n        # Brief pause to prevent display flicker\n        sleep(0.1)\n\nif __name__ == '__main__':\n    set_initial_time()  # Only needed if RTC isn't set\n    print(\"Starting clock...\")\n    run_clock()\n

    Let's break down the key concepts students need to understand:

    1. Real-Time Clock (RTC)
    2. The RTC is a hardware component that keeps track of time
    3. It continues running even when the microcontroller is reset
    4. Time is stored as a tuple: (year, month, day, weekday, hours, minutes, seconds, subseconds)
    5. Students should understand why RTCs are important for accurate timekeeping

    6. Time Formats

    7. 24-hour vs 12-hour time conversion
    8. Why we need to handle special cases (midnight = 0 hours \u2192 12, noon = 12 stays 12)
    9. The concept of AM/PM

    10. Display Multiplexing

    11. How LED displays show multiple digits (though the TM1637 handles this internally)
    12. Why we need a brief sleep to prevent display flicker
    13. How brightness control works with PWM (Pulse Width Modulation)

    14. State Management

    15. Tracking the colon state for blinking
    16. Maintaining previous second value to detect changes
    17. Why we use global variables in this context

    18. Program Structure

    19. Main loop design
    20. Function organization
    21. Error handling (not shown but important in real applications)

    Common challenges students might encounter:

    1. Time Drift
    2. The RTC might drift slightly over time
    3. In real applications, you'd want to sync with an NTP server periodically

    4. Power Management

    5. Display brightness affects power consumption
    6. Consider dimming display in low light conditions
    7. Think about battery life in portable applications

    8. User Interface

    9. Adding buttons to set the time
    10. Handling time zone changes
    11. Adding features like alarms or timers

    Extensions students could try:

    1. Add a temperature display that alternates with the time
    2. Implement automatic brightness control using a light sensor
    3. Add alarm functionality with a buzzer
    4. Create a menu system for setting the time
    5. Add a battery backup system

    Would you like me to elaborate on any of these concepts or provide example code for any of the extensions?

    For reference, this code builds on the concepts shown in your clock-driver.py file, but simplifies the implementation thanks to the TM1637's built-in controller. The course-description.md suggests this would fit well in the early stages of your course, particularly during the \"Understanding\" phase where students explore how timing functions and hardware work together.

    "},{"location":"kits/waveshare/","title":"Waveshare RP2040","text":"

    The Waveshare RP2040 1.28\" IPS LCD Board is a wonderful developent board with a build in RP2040 processor that currently sells for about $18. The board has a USB-C connector, a place for a LiPo battery connection and built in Accelerometer & Gyroscope. It is a great value and a wonderful way to start to learn Python for smart watches!

    1. Waveshare SKU: 22668
    2. Waveshare Part Number: RP2040-LCD-1.28
    3. Link to Waveshare site

    Note that this watch does not have a real-time clock and has no ability to connect to time syhronization using WiFi. However, it is an ideal development tool for learning to program watch displays and integrate sensors.

    "},{"location":"kits/waveshare/#micropython-version","title":"MicroPython Version","text":"

    To use these lessions you much use MicroPython runtime v1.19.1-854-g35524a6fd released on 2023-02-07 or later. This version supports all the native framebuf drawing libraries (ellipse and polygon)

    See the documentation here: MicroPython Framebuffer Functions

    "},{"location":"kits/waveshare/#lessons","title":"Lessons","text":"
    1. Hello world! Lesson
    2. Color Lab
    3. Drawing Analog Hands
    4. 5x8 Fonts
    "},{"location":"kits/waveshare/#detailed-components","title":"Detailed Components","text":"Component Description USB Type-C connector USB 1.1 with device and host support ETA6096 high efficiency Lithium battery recharge manager Battery Header MX1.25 header, for 3.7V Lithium battery, allows recharging the battery and powering the board at the same time QMI8658C IMU, includes a 3-axis gyroscope and a 3-axis accelerometer 1.27mm pitch headers Adapting all GPIO and Debug pins W25Q16JVUXIQ 2MB NOR-Flash RP2040 Dual-core processor, up to 133MHz operating frequency RESET Button Reset the processor BOOT Button press it when resetting to enter download mode"},{"location":"kits/waveshare/#references","title":"References","text":"

    wiki

    Instructable by Tony Goodhew - note that this version does not leverage the built-in drawing libraries that were made available in version 19 of the MicroPython release. See The MicroPython FrameBuf Library

    Github Gist by Alasdair Allan

    "},{"location":"kits/waveshare/01-hello-world/","title":"Waveshare Hello World","text":""},{"location":"kits/waveshare/01-hello-world/#step-1-load-the-library","title":"Step 1: Load the Library","text":""},{"location":"kits/waveshare/01-hello-world/#step-2-load-a-test-program","title":"Step 2: Load a Test Program","text":"
    from LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \nLCD.set_bl_pwm(65535)\n\nLCD.fill(LCD.black)    \nLCD.text(\"Hello world!\", 50, 100, LCD.white)\nLCD.show()\n

    You should see \"Hello world!\" in a small white font near the center of the screen.

    Challenges

    1. Can you move the text around the screen by changing the x and y starting position of the text?
    2. Can you change the background fill from black to another color?
    3. Can you change the color of the text from white to be another color?
    4. Can you change the font size? (hint: this is not easy!)
    "},{"location":"kits/waveshare/02-color-test/","title":"Color Tests","text":"

    Now let's try to make the background screen change colors:

    from LCD_1inch28 import LCD_1inch28\nfrom utime import sleep\n\nLCD = LCD_1inch28()  \nLCD.set_bl_pwm(65535)\n\nLCD.fill(LCD.black)\nLCD.show()\nsleep(1)\nLCD.fill(LCD.white)\nsleep(1)\nLCD.show()\nLCD.fill(LCD.red)\nLCD.show()\nsleep(1)\nLCD.fill(LCD.green)\nLCD.show()\nsleep(1)\nLCD.fill(LCD.blue)\nLCD.show()\nprint('done')\n

    What happens when you change the color \"red\" to be \"orange\"? You shouild see:

    Traceback (most recent call last):\n  File \"<stdin>\", line 10, in <module>\nAttributeError: 'LCD_1inch28' object has no attribute 'orange'\n

    This shows you that although the driver knows about some basic colors, (black, white, red, green and blue), it has no understanding of other colors.

    To draw these colors we need to add our own color lists.

    "},{"location":"kits/waveshare/02-color-test/#custom-color-lists","title":"Custom Color Lists","text":"

    In order to get more nuanced colors, we need to define them using the binary of their red, green and blue values. With this display, we order the bits, blue, red and green.

    We can use the following binary notation to represent the colors:

    # binary representations of colors B=Blue bits, R=Red bits, G=Green bits\n# color = 0bBBBBBRRRRRGGGGGG\n# Cyan has all the blue and green bits on and the red bits off\ncyan = cyan = 0b1111100000111111\n
    from machine import Pin,I2C,SPI,PWM,ADC\nfrom time import sleep\nfrom LCD_1inch28 import LCD_1inch28, QMI8658\n\nCENTER = 120\nLCD = LCD_1inch28()\nLCD.set_bl_pwm(65535)\n\n# draw readability\nON = 1\nOFF = 0\nNO_FILL = 0\nFILL = 1\n# hex representation of colors\n# note that the bit order is blue, red, green\nblack = 0x0000\nred   = 0x07E0\ngreen = 0x001f\nblue  = 0xf800\nwhite = 0xffff\n\n# binary representations of colors\n# binary representations of colors B=5 Blue bits, R=5 Red bits, G=6 green bits\n# color = 0bBBBBBRRRRRGGGGGG\nyellow = 0b0000011111111111\norange = 0b0000001111000010\ncyan = 0b1111100000111111\nbrown = 0b0000000001000001\ngold = 0b0000001110011110\npurple = 0b1111111111000000\nmagenta = 0b0000001100011000\npink = 0b0000111111000010\nolive = 0b0000000001000010\ngray = 0b00001000010000100\nlightGreen = 0b0000100001111111\ndarkGreen  = 0b0000000000000001\n\nColorList =  (red,    green,   blue,   white,   yellow,  orange,\n              cyan, brown, gold, purple, magenta, pink, olive, gray, lightGreen, darkGreen)\nColorNames = ('red', 'green', 'blue', 'white', 'yellow', 'orange',\n              'cyan', 'brown', 'gold', 'purple', 'magenta', 'pink', 'olive', 'gray', 'lightGreen', 'darkGreen')\n\nradius = 120\nLCD.fill(LCD.black)\n\nfor i in range(0, len(ColorList)):\n    print(ColorNames[i])\n    # LCD.ellipse(CENTER, CENTER, radius, radius, ColorList[i], FILL)\n    LCD.fill(ColorList[i])\n    LCD.text(ColorNames[i], 100, 100, 1)\n    LCD.text(ColorNames[i], 100, 120, white)\n    LCD.show()\n    sleep(1)\n

    Note that we are using the fill function to draw on all the pixels on the screen. We could have used the ellipse funtion to draw into the frame buffer, but the fill function is a bit easier.

    "},{"location":"kits/waveshare/02-color-test/#converting-rgb888-to-brg556","title":"Converting RGB888 to BRG556","text":"
    def convert_color_RGB888_RGB565(R,G,B): # Convert RGB888 to RGB565\n    return (((G&0b00011100)<<3) +((B&0b11111000)>>3)<<8) + (R&0b11111000)+((G&0b11100000)>>5)\n
    "},{"location":"kits/waveshare/02-display-text/","title":"Display Time and Date in Text","text":"
    from utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\ndef format_time(now):\n    hour_number = now[3]\n    if hour_number < 13:\n        hour_12 = hour_number\n        am_pm = 'am'\n    else:\n        hour_12 = hour_number - 12\n        am_pm = 'pm'\n    minutes_num = now[4]\n    if minutes_num < 10:\n        min_leading_zero = '0'\n    else:\n        min_leading_zero = ''\n    seconds_num = now[5]\n    if seconds_num < 10:\n        sec_leading_zero = '0'\n    else:\n        sec_leading_zero = ''\n    return \"{}:{}{}:{}{} {}\".format(hour_12, min_leading_zero, minutes_num, sec_leading_zero, seconds_num, am_pm)\n\ndef format_date(now):\n    month_number = now[1]\n    month_name = months[month_number - 1]\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    hour_number = now[3]\n    return \"{} {} {}, {}\".format(day_name, month_name, now[2], now[0])\n\nwhile(True):\n    now = localtime()\n    # print(now)\n    LCD.fill(LCD.black)    \n    LCD.text(format_time(now), 77, 50, LCD.white)\n    LCD.text(format_date(now), 40, 80, LCD.white)\n    LCD.show()\n    sleep(1)\n
    "},{"location":"kits/waveshare/03-drawing-hands/","title":"Drawing Analog Hands","text":"

    Drawing a analog hand requirs drawing a line from the center of the screen to a point on the edge of the circle. The point positon varies periodically, just like the sine and cosine functions vary. We can demonstrate this will a counter that goes from 0 to 360 degrees.

    Consider the following:

    1. Since the sine(0) = 0 we can use that function for the displacement from the center on the x-axis.
    2. Since the cosine(0) = 1, we can use that as the negative Y displacement from the center. Remember in drawing pixels, (0,0) is in the upper-left corner of the screen.

    There is one other bit of math we need to review. The sine() and cosine() function take in a number called radians which is usually a number between 0 and two times Pi. They then return a value between 0 and 1. We need multiple both of these values by the length of the watch hand to get to the right part of the watch face.

    from utime import sleep\nfrom LCD_1inch28 import LCD_1inch28\nimport math\n\nLCD = LCD_1inch28()\n\nCENTER = 120\nHAND_LENGTH = 100\n\n# our counter will range from 0 to 59\n# A full circle is 2*Pi radians\nTWO_PI = 3.145175*2\ncounter = 0\nwhile True:\n    radians = (counter/60)*TWO_PI\n    x = int(math.sin(radians)*HAND_LENGTH)\n    y = -int(math.cos(radians)*HAND_LENGTH)\n    print(radians, x, y)\n    LCD.fill(LCD.black)\n    LCD.line(CENTER, CENTER, CENTER+x,CENTER+y, LCD.white)\n    LCD.show()\n    sleep(1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0\n

    You should now see a narrow white line moving much like a second hand on a watch!

    "},{"location":"kits/waveshare/03-drawing-hands/#adding-bling-to-your-hands","title":"Adding bling to your hands","text":"

    Although drawing a single white line is a clean efficent design, many people like to add other features such as an arrow head at the tip of the hand. To do this we can use the poly function to draw the arrow. To get this right, we also need to orient the arrow in the right direction.

    "},{"location":"kits/waveshare/03-drawing-hands/#drawing-a-triangle","title":"Drawing a Triangle","text":"

    We can use the MicroPython standard poly function to draw a triangle. The poly

    `FrameBuffer.poly(x, y, coords, c[, f])

    This will draw an arbitrary polygon at the given x, y location using the given color (c).

    The coords must be specified as a array of integers, e.g. array('h', [x0, y0, x1, y1, ... xn, yn]).

    The optional f parameter can be set to True to fill the polygon. Otherwise just a one pixel outline is drawn.

    Let's start with drawing a basic triangle in the center of the screen like this:

    LCD.

    # draw a triangle on a blue background\nfrom utime import sleep\nfrom LCD_1inch28 import LCD_1inch28\nimport math\nfrom array import array\nLCD = LCD_1inch28()\n\nCENTER = 120\nNO_FILL = 0 # just the border is drawn\nFILL = 1 # all pixels within the polygon are drawn\n# draw a blue background\nLCD.fill(LCD.blue)\n\n# distance from the center to the tip of the traiangle\nd = 50\nmy_array = array('B', [CENTER-d,CENTER+d, CENTER,CENTER-d, CENTER+d,CENTER+d])\nLCD.poly(0,0, my_array, LCD.white, FILL)\nLCD.show()\nprint('done')\n
    "},{"location":"kits/waveshare/03-drawing-hands/#drawing-a-triangle-rotating","title":"Drawing a Triangle Rotating","text":"

    Now we will modify the draw triangle program to rotate each of the three points. We do this by passing the CENTER and either a positve or negative value of the x and y which varies as we move around the circle.

    Here is the line that is the most difficult to understand:

    my_array = array('B', [CENTER-x,CENTER-y, CENTER+y,CENTER-x, CENTER+x,CENTER+y])\n

    Note that the first point is in the lower left corner:

    (CENTER-x, CENTER-y)\n

    The second point is at the top of the trainagle and the X is initially zero (sine(0) = y)

    (CENTER+y, CENTER-x)\n

    The third point is to the lower right where we need to add to both the X and Y:

    (CENTER+x, CENTER-y)\n

    Here is the full program:

    # draw rotating triangle\nfrom utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\nfrom array import array\nimport math\nTWO_PI = 3.145175*2\n\nLCD = LCD_1inch28()\n\nCENTER = 120\nNO_FILL = 0 # just the border is drawn\nFILL = 1 # all pixels within the polygon are drawn\n\n# distance from the center to the tip of the traiangle\nd = 50\n\ncounter = 0\nwhile True:\n    LCD.fill(LCD.blue)\n    radians = (counter/60)*TWO_PI\n    x = int(math.cos(radians)*d)\n    y = int(math.sin(radians)*d)\n\n    # the three points of the triangle are rotated in a circle\n    my_array = array('B', [CENTER-x,CENTER-y, CENTER+y,CENTER-x, CENTER+x,CENTER+y])\n    print(CENTER-x, CENTER+y)\n\n    LCD.poly(0,0, my_array, LCD.white, FILL)\n    LCD.show()\n    sleep(.1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0\n

    You might have to stare at the code and the drawing for a while to get this figured out.

    "},{"location":"kits/waveshare/03-drawing-hands/#create-a-draw-triangle-function","title":"Create a Draw Triangle Function","text":"

    Now we are ready to package our triangle drawing experiment into a single function to make it easier to use. We will pass in four parameters:

    1. The center of the triangle's X and Y coordinates
    2. The size of the triangle measured from the center to the tip
    3. The number of seconds on the clock (0 to 59) which we will convert to radians. This becomes the agle of the triangle.
    def drawTriangle(x, y, size, seconds):\n    radians = (seconds/60)*TWO_PI\n    # calculate the offsets\n    xo = int(math.cos(radians)*size)\n    yo = int(math.sin(radians)*size)\n    # build the array - use B if we have under 255 and h if over 255\n    arr = array('B', [x-xo,y-yo,  x+yo,y-xo,  x+xo,y+yo])\n    LCD.poly(0,0, arr, LCD.white, FILL)\n
    "},{"location":"kits/waveshare/03-drawing-hands/#full-program","title":"Full Program","text":"
    from utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\nfrom array import array\nimport math\nTWO_PI = 3.145175*2\n\nLCD = LCD_1inch28()\n\nCENTER = 120\nNO_FILL = 0 # just the border is drawn\nFILL = 1 # all pixels within the polygon are drawn\nHAND_LENGTH = 100\nTRIANGLE_SIZE = 10\n\ndef drawTriangle(x, y, size, seconds):\n    radians = (seconds/60)*TWO_PI\n    # calculate the offsets\n    xo = int(math.cos(radians)*size)\n    yo = int(math.sin(radians)*size)\n    # build the array - use B if we have under 255 and h if over 255\n    arr = array('B', [x-xo,y-yo,  x+yo,y-xo,  x+xo,y+yo])\n    LCD.poly(0,0, arr, LCD.white, FILL)\n\ncounter = 0\nwhile True:\n    LCD.fill(LCD.blue)\n    radians = (counter/60)*TWO_PI\n    x = int(math.sin(radians)*HAND_LENGTH)\n    y = -int(math.cos(radians)*HAND_LENGTH)\n    LCD.line(CENTER, CENTER, CENTER+x,CENTER+y, LCD.white)\n    drawTriangle(CENTER+x, CENTER+y, TRIANGLE_SIZE, counter)\n    LCD.show()\n    sleep(.1)\n    counter += 1\n    # if we are at 60 we start over\n    if counter > 59:\n        counter = 0```\n
    "},{"location":"kits/waveshare/03-drawing-hands/#drawing-x-and-y-axis","title":"Drawing X and Y Axis","text":"
    # draw thin blue axis lines through the center\n# vertical line\nLCD.line(CENTER, 0, CENTER, 2*CENTER, blue)\n# horizontal line\nLCD.line(0, CENTER, 2*CENTER, CENTER, blue)\n
    "},{"location":"kits/waveshare/04-5x8-font/","title":"5x8 Font Test","text":"

    We can create custom functions for drawing larger fonts. Here we have a byte array of 5X8 fonts. The function character() draws individual characters one at a time.

    from LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \n\n# Standard ASCII 5x8 font\n# https://gist.github.com/tdicola/229b3eeddc12d58fb0bc724a9062aa05\nFONT_HEIGHT = 8\nFONT_WIDTH = 5\nFONT = bytes([\n    0x00, 0x00, 0x00, 0x00, 0x00, # <space>\n    0x3E, 0x5B, 0x4F, 0x5B, 0x3E,\n    0x3E, 0x6B, 0x4F, 0x6B, 0x3E,\n    0x1C, 0x3E, 0x7C, 0x3E, 0x1C,\n    0x18, 0x3C, 0x7E, 0x3C, 0x18,\n    0x1C, 0x57, 0x7D, 0x57, 0x1C,\n    0x1C, 0x5E, 0x7F, 0x5E, 0x1C,\n    0x00, 0x18, 0x3C, 0x18, 0x00,\n    0xFF, 0xE7, 0xC3, 0xE7, 0xFF,\n    0x00, 0x18, 0x24, 0x18, 0x00,\n    0xFF, 0xE7, 0xDB, 0xE7, 0xFF,\n    0x30, 0x48, 0x3A, 0x06, 0x0E,\n    0x26, 0x29, 0x79, 0x29, 0x26,\n    0x40, 0x7F, 0x05, 0x05, 0x07,\n    0x40, 0x7F, 0x05, 0x25, 0x3F,\n    0x5A, 0x3C, 0xE7, 0x3C, 0x5A,\n    0x7F, 0x3E, 0x1C, 0x1C, 0x08,\n    0x08, 0x1C, 0x1C, 0x3E, 0x7F,\n    0x14, 0x22, 0x7F, 0x22, 0x14,\n    0x5F, 0x5F, 0x00, 0x5F, 0x5F,\n    0x06, 0x09, 0x7F, 0x01, 0x7F,\n    0x00, 0x66, 0x89, 0x95, 0x6A,\n    0x60, 0x60, 0x60, 0x60, 0x60,\n    0x94, 0xA2, 0xFF, 0xA2, 0x94,\n    0x08, 0x04, 0x7E, 0x04, 0x08, # UP\n    0x10, 0x20, 0x7E, 0x20, 0x10, # Down\n    0x08, 0x08, 0x2A, 0x1C, 0x08, # Right\n    0x08, 0x1C, 0x2A, 0x08, 0x08, # Left\n    0x1E, 0x10, 0x10, 0x10, 0x10,\n    0x0C, 0x1E, 0x0C, 0x1E, 0x0C,\n    0x30, 0x38, 0x3E, 0x38, 0x30,\n    0x06, 0x0E, 0x3E, 0x0E, 0x06,\n    0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x5F, 0x00, 0x00,\n    0x00, 0x07, 0x00, 0x07, 0x00,\n    0x14, 0x7F, 0x14, 0x7F, 0x14,\n    0x24, 0x2A, 0x7F, 0x2A, 0x12,\n    0x23, 0x13, 0x08, 0x64, 0x62,\n    0x36, 0x49, 0x56, 0x20, 0x50,\n    0x00, 0x08, 0x07, 0x03, 0x00,\n    0x00, 0x1C, 0x22, 0x41, 0x00,\n    0x00, 0x41, 0x22, 0x1C, 0x00,\n    0x2A, 0x1C, 0x7F, 0x1C, 0x2A,\n    0x08, 0x08, 0x3E, 0x08, 0x08,\n    0x00, 0x80, 0x70, 0x30, 0x00,\n    0x08, 0x08, 0x08, 0x08, 0x08,\n    0x00, 0x00, 0x60, 0x60, 0x00,\n    0x20, 0x10, 0x08, 0x04, 0x02,\n    0x3E, 0x51, 0x49, 0x45, 0x3E,\n    0x00, 0x42, 0x7F, 0x40, 0x00,\n    0x72, 0x49, 0x49, 0x49, 0x46,\n    0x21, 0x41, 0x49, 0x4D, 0x33,\n    0x18, 0x14, 0x12, 0x7F, 0x10,\n    0x27, 0x45, 0x45, 0x45, 0x39,\n    0x3C, 0x4A, 0x49, 0x49, 0x31,\n    0x41, 0x21, 0x11, 0x09, 0x07,\n    0x36, 0x49, 0x49, 0x49, 0x36,\n    0x46, 0x49, 0x49, 0x29, 0x1E,\n    0x00, 0x00, 0x14, 0x00, 0x00,\n    0x00, 0x40, 0x34, 0x00, 0x00,\n    0x00, 0x08, 0x14, 0x22, 0x41,\n    0x14, 0x14, 0x14, 0x14, 0x14,\n    0x00, 0x41, 0x22, 0x14, 0x08,\n    0x02, 0x01, 0x59, 0x09, 0x06,\n    0x3E, 0x41, 0x5D, 0x59, 0x4E,\n    0x7C, 0x12, 0x11, 0x12, 0x7C, # A\n    0x7F, 0x49, 0x49, 0x49, 0x36,\n    0x3E, 0x41, 0x41, 0x41, 0x22,\n    0x7F, 0x41, 0x41, 0x41, 0x3E,\n    0x7F, 0x49, 0x49, 0x49, 0x41,\n    0x7F, 0x09, 0x09, 0x09, 0x01,\n    0x3E, 0x41, 0x41, 0x51, 0x73,\n    0x7F, 0x08, 0x08, 0x08, 0x7F,\n    0x00, 0x41, 0x7F, 0x41, 0x00,\n    0x20, 0x40, 0x41, 0x3F, 0x01,\n    0x7F, 0x08, 0x14, 0x22, 0x41,\n    0x7F, 0x40, 0x40, 0x40, 0x40,\n    0x7F, 0x02, 0x1C, 0x02, 0x7F,\n    0x7F, 0x04, 0x08, 0x10, 0x7F,\n    0x3E, 0x41, 0x41, 0x41, 0x3E,\n    0x7F, 0x09, 0x09, 0x09, 0x06,\n    0x3E, 0x41, 0x51, 0x21, 0x5E,\n    0x7F, 0x09, 0x19, 0x29, 0x46,\n    0x26, 0x49, 0x49, 0x49, 0x32,\n    0x03, 0x01, 0x7F, 0x01, 0x03,\n    0x3F, 0x40, 0x40, 0x40, 0x3F,\n    0x1F, 0x20, 0x40, 0x20, 0x1F,\n    0x3F, 0x40, 0x38, 0x40, 0x3F,\n    0x63, 0x14, 0x08, 0x14, 0x63,\n    0x03, 0x04, 0x78, 0x04, 0x03,\n    0x61, 0x59, 0x49, 0x4D, 0x43,\n    0x00, 0x7F, 0x41, 0x41, 0x41,\n    0x02, 0x04, 0x08, 0x10, 0x20,\n    0x00, 0x41, 0x41, 0x41, 0x7F,\n    0x04, 0x02, 0x01, 0x02, 0x04,\n    0x40, 0x40, 0x40, 0x40, 0x40,\n    0x00, 0x03, 0x07, 0x08, 0x00,\n    0x20, 0x54, 0x54, 0x78, 0x40,\n    0x7F, 0x28, 0x44, 0x44, 0x38,\n    0x38, 0x44, 0x44, 0x44, 0x28,\n    0x38, 0x44, 0x44, 0x28, 0x7F,\n    0x38, 0x54, 0x54, 0x54, 0x18,\n    0x00, 0x08, 0x7E, 0x09, 0x02,\n    0x18, 0xA4, 0xA4, 0x9C, 0x78,\n    0x7F, 0x08, 0x04, 0x04, 0x78,\n    0x00, 0x44, 0x7D, 0x40, 0x00,\n    0x20, 0x40, 0x40, 0x3D, 0x00,\n    0x7F, 0x10, 0x28, 0x44, 0x00,\n    0x00, 0x41, 0x7F, 0x40, 0x00,\n    0x7C, 0x04, 0x78, 0x04, 0x78,\n    0x7C, 0x08, 0x04, 0x04, 0x78,\n    0x38, 0x44, 0x44, 0x44, 0x38,\n    0xFC, 0x18, 0x24, 0x24, 0x18,\n    0x18, 0x24, 0x24, 0x18, 0xFC,\n    0x7C, 0x08, 0x04, 0x04, 0x08,\n    0x48, 0x54, 0x54, 0x54, 0x24,\n    0x04, 0x04, 0x3F, 0x44, 0x24,\n    0x3C, 0x40, 0x40, 0x20, 0x7C,\n    0x1C, 0x20, 0x40, 0x20, 0x1C,\n    0x3C, 0x40, 0x30, 0x40, 0x3C,\n    0x44, 0x28, 0x10, 0x28, 0x44,\n    0x4C, 0x90, 0x90, 0x90, 0x7C,\n    0x44, 0x64, 0x54, 0x4C, 0x44,\n    0x00, 0x08, 0x36, 0x41, 0x00,\n    0x00, 0x00, 0x77, 0x00, 0x00,\n    0x00, 0x41, 0x36, 0x08, 0x00,\n    0x02, 0x01, 0x02, 0x04, 0x02,\n    0x3C, 0x26, 0x23, 0x26, 0x3C,\n    0x1E, 0xA1, 0xA1, 0x61, 0x12, # Extension starts here\n    0x3A, 0x40, 0x40, 0x20, 0x7A,\n    0x38, 0x54, 0x54, 0x55, 0x59,\n    0x21, 0x55, 0x55, 0x79, 0x41,\n    0x22, 0x54, 0x54, 0x78, 0x42, # a-umlaut\n    0x21, 0x55, 0x54, 0x78, 0x40,\n    0x20, 0x54, 0x55, 0x79, 0x40,\n    0x0C, 0x1E, 0x52, 0x72, 0x12,\n    0x39, 0x55, 0x55, 0x55, 0x59,\n    0x39, 0x54, 0x54, 0x54, 0x59,\n    0x39, 0x55, 0x54, 0x54, 0x58,\n    0x00, 0x00, 0x45, 0x7C, 0x41,\n    0x00, 0x02, 0x45, 0x7D, 0x42,\n    0x00, 0x01, 0x45, 0x7C, 0x40,\n    0x7D, 0x12, 0x11, 0x12, 0x7D, # A-umlaut\n    0xF0, 0x28, 0x25, 0x28, 0xF0,\n    0x7C, 0x54, 0x55, 0x45, 0x00,\n    0x20, 0x54, 0x54, 0x7C, 0x54,\n    0x7C, 0x0A, 0x09, 0x7F, 0x49,\n    0x32, 0x49, 0x49, 0x49, 0x32,\n    0x3A, 0x44, 0x44, 0x44, 0x3A, # o-umlaut\n    0x32, 0x4A, 0x48, 0x48, 0x30,\n    0x3A, 0x41, 0x41, 0x21, 0x7A,\n    0x3A, 0x42, 0x40, 0x20, 0x78,\n    0x00, 0x9D, 0xA0, 0xA0, 0x7D,\n    0x3D, 0x42, 0x42, 0x42, 0x3D, # O-umlaut\n    0x3D, 0x40, 0x40, 0x40, 0x3D,\n    0x3C, 0x24, 0xFF, 0x24, 0x24,\n    0x48, 0x7E, 0x49, 0x43, 0x66,\n    0x2B, 0x2F, 0xFC, 0x2F, 0x2B,\n    0xFF, 0x09, 0x29, 0xF6, 0x20,\n    0xC0, 0x88, 0x7E, 0x09, 0x03,\n    0x20, 0x54, 0x54, 0x79, 0x41,\n    0x00, 0x00, 0x44, 0x7D, 0x41,\n    0x30, 0x48, 0x48, 0x4A, 0x32,\n    0x38, 0x40, 0x40, 0x22, 0x7A,\n    0x00, 0x7A, 0x0A, 0x0A, 0x72,\n    0x7D, 0x0D, 0x19, 0x31, 0x7D,\n    0x26, 0x29, 0x29, 0x2F, 0x28,\n    0x26, 0x29, 0x29, 0x29, 0x26,\n    0x30, 0x48, 0x4D, 0x40, 0x20,\n    0x38, 0x08, 0x08, 0x08, 0x08,\n    0x08, 0x08, 0x08, 0x08, 0x38,\n    0x2F, 0x10, 0xC8, 0xAC, 0xBA,\n    0x2F, 0x10, 0x28, 0x34, 0xFA,\n    0x00, 0x00, 0x7B, 0x00, 0x00,\n    0x08, 0x14, 0x2A, 0x14, 0x22,\n    0x22, 0x14, 0x2A, 0x14, 0x08,\n    0x55, 0x00, 0x55, 0x00, 0x55, # 176 (25% block) missing in old code\n    0xAA, 0x55, 0xAA, 0x55, 0xAA, # 50% block\n    0xFF, 0x55, 0xFF, 0x55, 0xFF, # 75% block\n    0x00, 0x00, 0x00, 0xFF, 0x00,\n    0x10, 0x10, 0x10, 0xFF, 0x00,\n    0x14, 0x14, 0x14, 0xFF, 0x00,\n    0x10, 0x10, 0xFF, 0x00, 0xFF,\n    0x10, 0x10, 0xF0, 0x10, 0xF0,\n    0x14, 0x14, 0x14, 0xFC, 0x00,\n    0x14, 0x14, 0xF7, 0x00, 0xFF,\n    0x00, 0x00, 0xFF, 0x00, 0xFF,\n    0x14, 0x14, 0xF4, 0x04, 0xFC,\n    0x14, 0x14, 0x17, 0x10, 0x1F,\n    0x10, 0x10, 0x1F, 0x10, 0x1F,\n    0x14, 0x14, 0x14, 0x1F, 0x00,\n    0x10, 0x10, 0x10, 0xF0, 0x00,\n    0x00, 0x00, 0x00, 0x1F, 0x10,\n    0x10, 0x10, 0x10, 0x1F, 0x10,\n    0x10, 0x10, 0x10, 0xF0, 0x10,\n    0x00, 0x00, 0x00, 0xFF, 0x10,\n    0x10, 0x10, 0x10, 0x10, 0x10,\n    0x10, 0x10, 0x10, 0xFF, 0x10,\n    0x00, 0x00, 0x00, 0xFF, 0x14,\n    0x00, 0x00, 0xFF, 0x00, 0xFF,\n    0x00, 0x00, 0x1F, 0x10, 0x17,\n    0x00, 0x00, 0xFC, 0x04, 0xF4,\n    0x14, 0x14, 0x17, 0x10, 0x17,\n    0x14, 0x14, 0xF4, 0x04, 0xF4,\n    0x00, 0x00, 0xFF, 0x00, 0xF7,\n    0x14, 0x14, 0x14, 0x14, 0x14,\n    0x14, 0x14, 0xF7, 0x00, 0xF7,\n    0x14, 0x14, 0x14, 0x17, 0x14,\n    0x10, 0x10, 0x1F, 0x10, 0x1F,\n    0x14, 0x14, 0x14, 0xF4, 0x14,\n    0x10, 0x10, 0xF0, 0x10, 0xF0, # ok\n    0x00, 0x00, 0x1F, 0x10, 0x1F,\n    0x00, 0x00, 0x00, 0x1F, 0x14,\n#   0x00, 0x00, 0x00, 0xFC, 0x14, # any new after this line breaks\n    0x00, 0x00, 0x00, 0x00, 0x00  # 255 also a <space>\n])\n\ndef convert_color_RGB888_RGB565(R,G,B): # Convert RGB888 to RGB565\n    return (((G&0b00011100)<<3) + ((B&0b11111000)>>3)<<8) + (R&0b11111000) + ((G&0b11100000)>>5)\n\ndef character(asc, xt, yt, sz, r, g, b):  # Single character sz is size: 1 or 2\n    cc = convert_color_RGB888_RGB565(r,g,b)\n    code = asc * 5    # 5 bytes per character\n    for ii in range(5):\n        line = FONT[code + ii]\n        for yy in range(8):\n            if (line >> yy) & 0x1:\n                LCD.pixel(ii*sz+xt,yy*sz+yt,cc) \n                if sz > 1:\n                    LCD.pixel(ii*sz+xt+1,yy*sz+yt,cc)\n                    LCD.pixel(ii*sz+xt,yy*sz+yt+1,cc)\n                    LCD.pixel(ii*sz+xt+1,yy*sz+yt+1,cc)\n                if sz == 3:\n                    LCD.pixel(ii*sz+xt,  yy*sz+yt+2,cc)\n                    LCD.pixel(ii*sz+xt+1,yy*sz+yt+2,cc)\n                    LCD.pixel(ii*sz+xt+2,yy*sz+yt+2,cc)\n                    LCD.pixel(ii*sz+xt+2,yy*sz+yt,cc)\n                    LCD.pixel(ii*sz+xt+2,yy*sz+yt+1,cc)\n\n# Print a string\ndef prnt_st(asci, xx, yy, sz,r,g,b):  # Text string\n    if sz == 1: move = 6\n    if sz == 2: move = 11\n    if sz == 3: move = 17 \n    for letter in(asci):\n        asci = ord(letter)\n        character(asci,xx,yy,sz,r,g,b)\n        xx = xx + move\n\n# Center text string\ndef cntr_st(s,y,sz,r,g,b): # Centres text on line y\n    if sz == 1: w = 6\n    if sz == 2: w = 11\n    if sz == 3: w = 17 \n    gap = int((width - len(s) * w)/2)\n    prnt_st(s,gap,y,sz,r,g,b)\n\nLCD.fill(LCD.black)    \nprnt_st(\"Hello world! Red\", 20, 80, 2, 255, 0, 0)\nprnt_st(\"Hello world! Green\", 20, 100, 2, 0, 255, 0)\nprnt_st(\"Hello world! Blue\", 20, 120, 2, 0, 0, 255)\nprnt_st(\"Hello world! White\", 20, 140, 2, 255, 255, 255)\nLCD.show()\n
    "},{"location":"lessons/","title":"Python Project-Based Learning: Building Clocks and Watches with Smart Watch Displays","text":"

    These lessons are general to all of our kits. We often use the Pico OLED for many examples since that is the kit we have been using for the longest time.

    These lessons focus on using functions like the MicroPython localtime() to get the time in your current timezone.

    They also focus on drawing scalable numbers on different size displays and drawing times on larger color displays.

    Here are some sample lesson plans for a 14-week semimester hich school course on learning computational thining by using MicroPython to write clock and smartwatch application. This course assumes no prior knowledge of programming.

    "},{"location":"lessons/#weeks-1-2-introduction-to-python-and-basic-concepts","title":"Weeks 1-2: Introduction to Python and Basic Concepts","text":""},{"location":"lessons/#lesson-1-introduction-to-python","title":"Lesson 1: Introduction to Python","text":"
    • What is Python?
    • Why learn Python?
    • Data Science
    • Artificial Intellegence
    • Python Installation and Setup
    "},{"location":"lessons/#lesson-2-hello-world","title":"Lesson 2: Hello, World!","text":"
    • Writing the first Python program
    • Drawing a simple rectangle to the screen
    • Making the rectangle bounce around the screen
    • Understanding Python syntax
    • Using the graphics library for your clock or watch
    "},{"location":"lessons/#lesson-3-variables-and-data-types","title":"Lesson 3: Variables and Data Types","text":"
    • Introduction to variables
    • Common data types (integers, floats, strings, booleans)
    • Drawing with pixels, lines and rectangles
    • Chainging color
    "},{"location":"lessons/#lesson-4-basic-operations","title":"Lesson 4: Basic Operations","text":"
    • Arithmetic operations
    • Concatenation and repetition
    • Assignment operators
    • Lists of colors
    "},{"location":"lessons/#weeks-3-4-control-structures-and-functions","title":"Weeks 3-4: Control Structures and Functions","text":""},{"location":"lessons/#lesson-5-conditionals","title":"Lesson 5: Conditionals","text":"
    • if, else, and elif statements
    • Alternating the color of your lines
    • Horizontal and radial lines
    "},{"location":"lessons/#lesson-6-loops","title":"Lesson 6: Loops","text":"
    • for and while loops
    • Loop control with break and continue
    • Draing the tick marks on a watch
    "},{"location":"lessons/#lesson-7-functions","title":"Lesson 7: Functions","text":"
    • Defining and calling functions
    • Arguments and return values
    "},{"location":"lessons/#weeks-5-6-working-with-libraries-and-hardware","title":"Weeks 5-6: Working with Libraries and Hardware","text":""},{"location":"lessons/#lesson-8-importing-libraries","title":"Lesson 8: Importing Libraries","text":"
    • What is a library?
    • Importing and using libraries
    "},{"location":"lessons/#lesson-9-introduction-to-hardware-interaction","title":"Lesson 9: Introduction to Hardware Interaction","text":"
    • Communicating with smart watch displays
    • Sending and receiving data
    "},{"location":"lessons/#weeks-7-8-project-1-basic-digital-clock","title":"Weeks 7-8: Project 1: Basic Digital Clock","text":""},{"location":"lessons/#lesson-10-planning-the-project","title":"Lesson 10: Planning the Project","text":"
    • Project overview
    • Creating a project plan
    "},{"location":"lessons/#lesson-11-building-a-basic-digital-clock","title":"Lesson 11: Building a Basic Digital Clock","text":"
    • Displaying time on the smart watch display
    • Updating the time
    "},{"location":"lessons/#weeks-9-10-intermediate-python-concepts","title":"Weeks 9-10: Intermediate Python Concepts","text":""},{"location":"lessons/#lesson-12-lists-and-dictionaries","title":"Lesson 12: Lists and Dictionaries","text":"
    • Creating and manipulating lists and dictionaries
    "},{"location":"lessons/#lesson-13-error-handling","title":"Lesson 13: Error Handling","text":"
    • try and except blocks
    "},{"location":"lessons/#weeks-11-12-project-2-analog-clock-display","title":"Weeks 11-12: Project 2: Analog Clock Display","text":""},{"location":"lessons/#lesson-14-planning-the-project","title":"Lesson 14: Planning the Project","text":"
    • Project overview
    • Creating a project plan
    "},{"location":"lessons/#lesson-15-building-an-analog-clock-display","title":"Lesson 15: Building an Analog Clock Display","text":"
    • Designing an analog clock
    • Rotating clock hands based on the current time
    "},{"location":"lessons/#weeks-13-14-advanced-python-concepts-and-optimization","title":"Weeks 13-14: Advanced Python Concepts and Optimization","text":""},{"location":"lessons/#lesson-16-more-about-functions","title":"Lesson 16: More About Functions","text":"
    • Lambda functions, higher-order functions
    "},{"location":"lessons/#lesson-17-optimization-techniques","title":"Lesson 17: Optimization Techniques","text":"
    • Improving code efficiency
    "},{"location":"lessons/#weeks-15-16-final-project-customizable-clockwatch","title":"Weeks 15-16: Final Project: Customizable Clock/Watch","text":""},{"location":"lessons/#lesson-18-planning-the-project","title":"Lesson 18: Planning the Project","text":"
    • Project overview
    • Creating a project plan
    "},{"location":"lessons/#lesson-19-building-a-customizable-clockwatch","title":"Lesson 19: Building a Customizable Clock/Watch","text":"
    • Adding customization options (color, style, etc.)
    • Implementing user input for customization
    "},{"location":"lessons/#lesson-20-final-project-presentations","title":"Lesson 20: Final Project Presentations","text":"
    • Students present their final projects
    • Review and feedback session
    "},{"location":"lessons/#ongoing-reflection-and-feedback","title":"Ongoing: Reflection and Feedback","text":"
    • After each project, have students reflect on what went well, what they struggled with, and what they learned.
    • Continuously solicit feedback from students to improve the learning experience.

    This outline provides a balance between teaching Python concepts and applying them to real-world projects, which can keep students engaged and help them to better retain what they've learned. Tailor this outline to meet the specific needs and pace of your students, and ensure to provide plenty of opportunities for students to practice their skills, ask questions, and get feedback.

    "},{"location":"lessons/00-hardware-config/","title":"Hardware Configuration Files","text":"

    All our current displays use the SPI interface. The alternative microcontroller bus, I2C, is about 10x slower than SPI. The SPI intrface interface typically uses 7 wires, which can get a little complex. Just a single wire broken or two wires crossed can will cause the display to not work.

    We have dozens of sample programs for each kit. And the exact connections on our kits vary. Rather than hard-coding the hardware pin numbers in each example, we can move them to a separate config.py file. We can then just import that file into each of our examples.

    Here is a sample config.py file:

    # Dan's Robot Labs configuration file for ILI9341 clock project\n# The colors on the SPI bus cable are:\n# 3.3v power - red\n# SCK - orange\n# MISO/Data - yellow\n# DC - green\n# RESET - blue\n# GND - black\n# CS - purple\n\nSCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\nBUTTON_1_PIN = 14 # one up from lower-left corner\nBUTTON_2_PIN = 15 # lower left corner with USB on top\n

    To use this configuration file you will need to do two things:

    1. import the config file (don't add the .py extension)
    2. Add the prefix config. to each value you would like to reference.
    import config\n\nWIDTH=config.WIDTH\n
    "},{"location":"lessons/01-drawing-coordinates/","title":"Drawing Coordinates","text":"

    Screen Coordinates Lab on Robot Faces

    "},{"location":"lessons/01-get-local-time/","title":"Getting Local Time","text":""},{"location":"lessons/01-get-local-time/#lesson-overview","title":"Lesson Overview","text":"

    In this lesson, we will learn how to get the local date and time from the MicroPython runtime using the standard localtime() function. We will learn about how to use the eight integers returned by the localtime() functions.

    MicroPython provides a very convenient function called localtime() that will get the time from the host computer in your local timezone that you connect to via your USB cable. Your local computer has a clock and knows the time in the local timezone. This information is usually sent to MicroPython runtime when the computer is connected to the USB cable.

    Note

    The gmtime() function returns the time in UTC (Coordinated Universal Time) time. Use this if you want time stamps that are not dependent on time zone and daylight savings rules. For example, log files should use this function.

    "},{"location":"lessons/01-get-local-time/#sample-code","title":"Sample Code","text":"
    import time\n\nprint(time.localtime())\n
    "},{"location":"lessons/01-get-local-time/#result","title":"Result","text":"

    Local time returns a read-only tuple:

    (2023, 2, 28, 18, 54, 7, 1, 59)\n
    "},{"location":"lessons/01-get-local-time/#extracting-specific-datetime-components","title":"Extracting Specific Date/Time Components","text":"
    from time import localtime\n\nnow = localtime()\nprint(now)\n\nprint('year:',    now[0])\nprint('month:',   now[1])\nprint('day:',     now[2])\nprint('hour:',    now[3])\nprint('minute:',  now[4])\nprint('sec:',     now[5])\nprint('weekday:', now[6])\nprint('day of year:', now[7])\n
    "},{"location":"lessons/01-get-local-time/#format-of-the-localtime","title":"Format of the Localtime","text":"

    The format is a \"8-tuple\" of integers in the format (year, month, mday, hour, minute, second, weekday, yearday)

    Most of the values are pretty intuitive to figure out. There are a few notes.

    1. Hour is the hour in 24-hour format. If we want to display the hour in 12-hour format we will need to do some formatting.
    2. Weekday is a numeric code that runs from 0 for Monday to 6 for Sunday.
    3. Yearday is the day of the year. January 1st is the fist day of the year so it is a 1 (not 0).
    "},{"location":"lessons/01-get-local-time/#printing-formatted-dates","title":"Printing Formatted Dates","text":""},{"location":"lessons/01-get-local-time/#sample-code_1","title":"Sample Code","text":"
    import time\n\nnow = time.localtime()\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\nfor i in range(8):\n    print(label[i], ':', now[i])\n\nprint()\nprint(\"Date: {}/{}/{}\".format(now[1], now[2], now[0]))\nprint(\"Time: {}:{}\".format(now[3], now[4]))\n
    "},{"location":"lessons/01-get-local-time/#results","title":"Results","text":"
    year : 2023\nmonth : 2\nmday : 28\nhour : 19\nminute : 20\nsecond : 26\nweekday : 1\nyearday : 59\n\nDate: 2/28/2023\nTime: 19:20\n
    "},{"location":"lessons/01-get-local-time/#label-formatting","title":"Label Formatting","text":"

    We can also add labels to make the date and time easier to read.

    import time\n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\n\nnow = time.localtime()\n\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\nmonth_number = now[1]\nmonth_name = months[month_number]\nweekday_number = now[6]\nday_name = days[weekday_number]\nhour_number = now[3]\nif hour_number < 13:\n    hour_12 = hour_number\n    am_pm = 'am'\nelse:\n    hour_12 = hour_number - 12\n    am_pm = 'pm'\n\nprint()\nprint(\"Date: {} {} {}, {}\".format(day_name, month_name, now[2], now[0]))\nprint(\"Time: {}:{} {}\".format(hour_12, now[4], am_pm))\n
    "},{"location":"lessons/01-get-local-time/#label-formatted-results","title":"Label Formatted Results","text":"
    Date: Tuesday March 28, 2023\nTime: 7:46 pm\n
    "},{"location":"lessons/01-get-local-time/#modifying-the-thonny-parameters","title":"Modifying the Thonny Parameters","text":"

    By default Thonny syncs the host time at power up.

    However, to test that our code is setting the correct local time we will need to disable this in future labs.

    After we do this, the localtime() will return the number of seconds after midnight on January 1st, 2021.

    import time\nprint(time.localtime())\n

    (2021, 1, 1, 0, 0, 22, 4, 1)\n
    This was printed 22 seconds after power up.

    We will used this when we use a RTC and use the Pico \"W\" to sync with the NTP functions.

    from mpython import *\nimport ntptime\nimport secrets\n\n# summary\nmywifi=wifi()\nmywifi.connectWiFi(secrets.wifi_ssid, secrets.wifi_pass)\n\nprint(\"Local time before synchronization\uff1a%s\" %str(time.localtime()))\nntptime.settime()\nprint(\"Local time after synchronization\uff1a%s\" %str(time.localtime()))\n

    Result:

    Local time before synchronization\uff1a(2021, 1, 1, 0, 3, 31, 4, 1)\nLocal time after synchronization\uff1a(2023, 10, 16, 20, 16, 59, 0, 289)\n
    "},{"location":"lessons/01-get-local-time/#references","title":"References","text":"
    • MicroPython Time Documents
    • Bhavesh Kakwani's blog Sync time in MicroPython using NTP - although the blog uses an ESP32, the concepts are the same on other processors such as the Raspberry Pi Pico.
    "},{"location":"lessons/02-display-text/","title":"Display Time and Date in Text","text":"
    from utime import localtime, sleep\nfrom LCD_1inch28 import LCD_1inch28\n\nLCD = LCD_1inch28()  \n\ndays = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',\n        'Sunday')\nmonths = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',\n          'Aug', 'Sept', 'Oct', 'Nov', 'Dec')\nlabel = ('year', 'month', 'mday', 'hour', 'minute', 'second', 'weekday', 'yearday')\n\ndef format_time(now):\n    hour_number = now[3]\n    if hour_number < 13:\n        hour_12 = hour_number\n        am_pm = 'am'\n    else:\n        hour_12 = hour_number - 12\n        am_pm = 'pm'\n    minutes_num = now[4]\n    if minutes_num < 10:\n        min_leading_zero = '0'\n    else:\n        min_leading_zero = ''\n    seconds_num = now[5]\n    if seconds_num < 10:\n        sec_leading_zero = '0'\n    else:\n        sec_leading_zero = ''\n    return \"{}:{}{}:{}{} {}\".format(hour_12, min_leading_zero, minutes_num, sec_leading_zero, seconds_num, am_pm)\n\ndef format_date(now):\n    month_number = now[1]\n    month_name = months[month_number - 1]\n    weekday_number = now[6]\n    day_name = days[weekday_number]\n    hour_number = now[3]\n    return \"{} {} {}, {}\".format(day_name, month_name, now[2], now[0])\n\nwhile(True):\n    now = localtime()\n    # print(now)\n    LCD.fill(LCD.black)    \n    LCD.text(format_time(now), 77, 50, LCD.white)\n    LCD.text(format_date(now), 40, 80, LCD.white)\n    LCD.show()\n    sleep(1)\n
    "},{"location":"lessons/03-drawing-face/","title":"Drawing Watch Faces","text":"

    An analog watch ususally has hands that are drawn from the center to the edge of the display.

    The lines or marks that indicate the hours are often referred to as \"hour indices\" or \"hour markers.\"

    The smaller lines that indicate the minutes are called \"minute indices\" or \"minute markers.\"

    For simple lines, we can use the line(x1,y1, x2,y2,color) function which draws a sinle pixel line from the starting point at (x1,y1) to the end pint at (x2,y2) using the fifth color parameter. For monochrome clocks the color 1 is whtie and 0 is black.

    For thinker lines we can use the display.rect() function.

    Some watches have more complex hands that are composed of multiple geometries such as triangles.

    For most modern display drivers we can use the MicroPython poly() function to draw polygons on the screen. These are part of the MicroPython framebuf function.

    Some older drivers don't yet support these functions, so we might have to craft our own functions.

    "},{"location":"lessons/03-drawing-face/#references","title":"References","text":"

    Instructables on Filled Circles and Triangles by TonyGo2

    "},{"location":"lessons/04-larger-fonts/","title":"Larger Fonts","text":"

    Many display libraries use the MicroPython framebuf standards that only provide for a single font. This is sometimes fine for simple small displays, but it is sometimes insufficient for some projects where either a smaller or larger font is used.

    The ssd1306 driver is a good example of the default behaviour of text drawing. Only a single font is suppied.

    display.text('Hello, World!', 0, 0, 1)\ndisplay.show()\n

    Some display drivers allow you to change the default font:

    LCD160 Set Font

    Font to Py Command

    Sample Font Files

    "},{"location":"lessons/04-larger-fonts/#references","title":"References","text":"

    Peter Hinch's Font to Python Utility - a utility takes input a font file in ttf or otf form together with a height in pixels and outputs a Python source file containing the font as a bitmap.

    Peter Hinch's Nano GUI

    Les' Lab: Designing your own Pico fonts - Raspberry Pi Pico display fonts in MicroPython: How to design fonts for your Pi Pico project.

    "},{"location":"lessons/05-buttons/","title":"Buttons","text":"

    Our standard watch kit places two buttons on the breadboard. You can use these buttons to set the time.

    The buttons are connected to the lower-left corner of the pico using GPIO 14 and GPIO 15.

    Instructions on how to use these buttons are covered in our MicroPython class:

    Using Buttons in MicroPython

    We suggest using the top blue button to change the mode of operation. As you press this you cycle through various modes of your clock or watch. Here are some sample modes for a clock:

    1. Run mode
    2. Set current time hour
    3. Set current time minute
    4. Set alarm hour
    5. Set alarm minute

    After you are in a given mode, the bottom button can be used to cycle through the options. Remember to get the current value for the cycle for each mode. So if you are adjusting the hour you have to make sure the cycle value starts at the current hour.

    "},{"location":"lessons/05-buttons/#sample-button-mode-code","title":"Sample Button Mode Code","text":"
    from utime import sleep, ticks_ms\nfrom machine import Pin\n\n# Sample Raspberry Pi Pico MicroPython button press example with a debounce delay value of 200ms in the interrupt handler\n\n# Config\nMODE_BUTTON_PIN = 14\nCYCLE_BUTTON_PIN = 15\nmode = 0 # the count of times the button has been pressed\ncycle = 0\nlast_time = 0 # the last time we pressed the button\n\nbuiltin_led = machine.Pin(25, Pin.OUT)\n# The lower left corner of the Pico has a wire that goes through the buttons upper left and the lower right goes to the 3.3 rail\nmode_pin = machine.Pin(MODE_BUTTON_PIN, machine.Pin.IN, machine.Pin.PULL_UP)\ncycle_pin = machine.Pin(CYCLE_BUTTON_PIN, machine.Pin.IN, machine.Pin.PULL_UP)\n\n# This function gets called every time the button is pressed.  The parameter \"pin\" is not used.\ndef button_pressed_handler(pin):\n    global mode, cycle, last_time\n    new_time = ticks_ms()\n    # if it has been more that 1/5 of a second since the last event, we have a new event\n    if (new_time - last_time) > 200:\n        # this should be pin.id but it does not work\n        if '14' in str(pin):\n            mode +=1\n        else:\n            cycle +=1\n        # last, we update the last time we got an ISR here\n        last_time = new_time\n\n\n# now we register the handler function when the button is pressed\nmode_pin.irq(trigger=machine.Pin.IRQ_FALLING, handler = button_pressed_handler)\ncycle_pin.irq(trigger=machine.Pin.IRQ_FALLING, handler = button_pressed_handler)\n\n# This is for only printing when a new button press count value happens\nold_mode = 0\nold_cycle = 0 \n\nwhile True:\n    # only print on change in the button_presses value\n    if mode != old_mode:\n        print('New Mode:', mode)\n        builtin_led.toggle()\n        old_mode = mode\n    if cycle != old_cycle:\n        print('New Cycle:', cycle)\n        builtin_led.toggle()\n        old_cycle = cycle\n    sleep(.1)\n
    "},{"location":"lessons/05-buttons/#three-button-set","title":"Three Button Set","text":"
    from machine import Pin\nimport time\n\n# Pin setup\nmode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n\n# Time state\nhour = 12\nminute = 0\nis_pm = False\nmode = 0\nmode_names = [\"run\", \"set hour\", \"set minute\", \"set AM/PM\"]\nmode_count = len(mode_names)\n\n# Debounce state\nlast_mode_press = 0\nlast_next_press = 0\nlast_prev_press = 0\nDEBOUNCE_MS = 200\n\ndef format_time():\n    return f\"{hour:02d}:{minute:02d} {'PM' if is_pm else 'AM'}\"\n\ndef handle_mode(pin):\n    global mode, last_mode_press\n    current_time = time.ticks_ms()\n    if time.ticks_diff(current_time, last_mode_press) > DEBOUNCE_MS:\n        mode = (mode + 1) % mode_count\n        print(f\"Mode: {mode_names[mode]}\")\n        last_mode_press = current_time\n\ndef handle_next(pin):\n    global hour, minute, is_pm, last_next_press\n    current_time = time.ticks_ms()\n    if time.ticks_diff(current_time, last_next_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = (hour % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute + 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_next_press = current_time\n\ndef handle_previous(pin):\n    global hour, minute, is_pm, last_prev_press\n    current_time = time.ticks_ms()\n    if time.ticks_diff(current_time, last_prev_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = ((hour - 2) % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute - 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_prev_press = current_time\n\n# Set up interrupts\nmode_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_mode)\nnext_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_next)\nprevious_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_previous)\n\n# Main loop\nprint(\"Clock started. Press mode button to change settings.\")\nwhile True:\n    if mode == 0:  # Only update display in run mode\n        print(format_time())\n        time.sleep(1)\n
    "},{"location":"lessons/06-draw-performance/","title":"Drawing Performance","text":"

    One of the challenges we face when updating the watch display is that refreshing an entire screen using a relatively slow SPI interface means that we need to be thoughtful about updating the displays.

    By default, many screen drivers update every pixel of the screen when the user does a show() operation. For small monochrome screens this is not usually a problem. But for larger color screens the draw times can lead to slow updates.

    Let's do a little math to see when drawing performance becomes a problem. Remember that the human eye can's really see screen updates that occur faster than about 30 frames per second. That is why most film movies were filled at 25 frames per second.

    To calculate the full-screen draw time we need to calculate the total number of bits we need to send and then calculate the time it takes to send these bits. We can then check our math by looking at timestamps just before we draw and after we finish the drawing.

    Let's start out with our favorite clock screen: the 128X64 monochrome OLED screen.

    1. Width = 128
    2. Height = 64
    3. Bits per Pixel = 1

    Total bits = 128 * 64 * 1 = 8,192 bits = 1024 bytes

    Now we need to also know the transfer speed of our display interface. Although there are both I2C and SPI versions of these displays, we usually prefer the SPI that should transfer data at about

    Pi Pico SPI LCD using a frame buffer to get 30fps animation - ILI9341 and ST7789 MicroPython drivers

    "},{"location":"lessons/06-draw-performance/#sample-timer-code","title":"Sample Timer Code","text":"

    We can calculate the time to draw the full screen by recording the number of clock ticks in microseconds before and after we do a screen update.

    from utime import ticks_us\n\nstart = ticks_us()\nscreen_update()\nend = ticks_us()\nprint('Execution time in microseconds:', end - start)\n

    On the OLED screen, we get a result that is around 10 milliseconds which is 100 screen updates per second.

    "},{"location":"lessons/06-draw-performance/#references","title":"References","text":"
    1. Notes on the very slow refresh rate for ST7735
    "},{"location":"lessons/06-setting-time/","title":"Manually Setting Time","text":"

    We need a program that will use three buttons to set the time.

    "},{"location":"lessons/06-setting-time/#the-mode-button","title":"The Mode Button","text":"

    The first button is called the \"mode\" button. It will cycle through four internal \"states\" of our clock. Here are the modes:

    1. Mode 0: Clock Running - this is the normal mode of operation
    2. Mode 1: Setting the Hour
    3. Mode 2: Setting the Minute
    4. Mode 3: Setting AM/PM

    Here is a walkthrough of the button-mode-test.py program, breaking it down into clear, digestible concepts for everyone new to MicroPython.

    "},{"location":"lessons/06-setting-time/#code-walkthrough","title":"Code Walkthrough","text":""},{"location":"lessons/06-setting-time/#1-basic-setup-and-imports","title":"1. Basic Setup and Imports","text":"
    from mp_button import Button\nfrom time import localtime, sleep\nfrom machine import Pin\n

    Let's understand what these lines do: - These are import statements that bring in code we need to use - Button is a special module that helps us work with physical buttons - localtime and sleep are time-related functions - Pin lets us work with the physical pins on our Raspberry Pi Pico

    "},{"location":"lessons/06-setting-time/#2-setting-up-the-pins","title":"2. Setting Up the Pins","text":"
    mode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n

    Here's what's happening: - We're setting up three different pins (16, 17, and 18) on the Pico - Each pin is set as an input (Pin.IN) - meaning it receives signals rather than sends them - Pin.PULL_UP means the pin is naturally \"high\" (1) until a button press makes it \"low\" (0) - Think of it like a light switch that's normally on, and pressing the button turns it off

    "},{"location":"lessons/06-setting-time/#3-global-variables","title":"3. Global Variables","text":"
    counter_pressed = 0\ncounter_released = 0\nmode = 0  # default clock running\nmode_names = [\"run\",\"set hour\",\"set minute\",\"set AM/PM\"]\nmode_count = len(mode_names)\nnow = localtime()\nhours = now[3]\nminutes = now[4]\nam_pm = 0\n

    These are our program's variables: - counter_pressed and counter_released keep track of button presses - mode tells us which setting we're currently adjusting (starts at 0) - mode_names is a list of the different modes our clock can be in - mode_count is how many modes we have (4 in this case) - now gets the current time from the Pico - hours and minutes store the current time values - am_pm keeps track of whether it's morning (0) or afternoon (1)

    "},{"location":"lessons/06-setting-time/#4-button-handler-functions","title":"4. Button Handler Functions","text":"
    def button_mode_irq(button, event):\n    global mode, hours, minutes\n    if event == Button.PRESSED:\n        mode += 1\n        mode = mode % mode_count\n        print('new mode:', mode, mode_names[mode])\n

    This is our mode button handler: - global tells Python we want to change variables outside this function - When the button is pressed, we increase the mode by 1 - The % (modulo) operator helps us cycle back to 0 after reaching the last mode - For example: if mode is 3 and we add 1, 4 % 4 = 0, so we go back to the first mode

    "},{"location":"lessons/06-setting-time/#5-next-and-previous-button-handlers","title":"5. Next and Previous Button Handlers","text":"
    def button_next_irq(button, event):\n    global mode, hours, minutes, am_pm\n    if event == Button.PRESSED:\n        if mode == 1:\n            hours += 1\n        if mode == 2:\n            minutes += 1\n        if mode == 3:\n            am_pm = 1 if am_pm == 0 else 0\n

    The next/previous buttons: - They only work when we're in a setting mode (not mode 0) - Mode 1: adjust hours - Mode 2: adjust minutes - Mode 3: toggle between AM and PM - The previous button does the same thing but decreases values

    "},{"location":"lessons/06-setting-time/#6-creating-button-objects","title":"6. Creating Button Objects","text":"
    button_mode = Button(16, False, button_mode_irq, internal_pullup = True, debounce_time = 100)\nbutton_next = Button(17, False, button_next_irq, internal_pullup = True, debounce_time = 100)\nbutton_previous = Button(18, False, button_previous_irq, internal_pullup = True, debounce_time = 100)\n

    Here we create our button objects: - Each button gets a pin number (16, 17, or 18) - We tell it which function to call when pressed (the _irq functions) - debounce_time = 100 prevents multiple triggers from one press - Think of debouncing like waiting a moment to make sure someone really pressed the button once

    "},{"location":"lessons/06-setting-time/#7-main-loop","title":"7. Main Loop","text":"
    while(True):\n    button_mode.update()\n    button_next.update()\n    button_previous.update()\n

    This is our main program loop: - It runs forever (that's what while True means) - Each time through the loop, we check if any buttons were pressed - The update() function handles all the button checking for us

    "},{"location":"lessons/06-setting-time/#full-program-listing","title":"Full Program Listing","text":"
    from mp_button import Button\nfrom time import localtime, sleep\nfrom machine import Pin\n\nmode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n\n# we create a counter to increment as we press\n# and one to increment as we release\ncounter_pressed = 0\ncounter_released = 0\nmode = 0 # default clock running\nmode_names = [\"run\",\"set hour\",\"set minute\",\"set AM/PM\"]\nmode_count = len(mode_names)\nnow = localtime()\nhours = now[3]\nminutes = now[4]\nam_pm = 0\n\n# the following method (function) will be invoked\n# when the button changes state\n# the Button module expects a callback to handle \n# - pin number\n# - event (Button.PRESSED | Button.RELEASED)\n# the event contains a string 'pressed' or 'released'\n# which can be used in your code to act upon\ndef button_mode_irq(button, event):\n    global mode, hours, minutes\n    if event == Button.PRESSED:\n        mode +=1\n        # cycle back to zero if greater than mode_count\n        mode =  mode % mode_count\n        print('new mode:', mode, mode_names[mode])\n\ndef button_next_irq(button, event):\n    global mode, hours, minutes, am_pm\n    if event == Button.PRESSED:\n        if mode == 1:\n            hours += 1\n        if mode == 2:\n            minutes += 1\n        if mode == 3:\n            if am_pm == 0:\n                am_pm = 1\n            else:\n                am_pm = 0\n        print('next button:', hours, minutes, am_pm)\n\ndef button_previous_irq(button, event):\n    global mode, hours, minutes, am_pm\n    if event == Button.PRESSED:\n        if mode == 1:\n            hours -= 1\n        if mode == 2:\n            minutes -= 1\n        if mode == 3:\n            if am_pm == 0:\n                am_pm = 1\n            else:\n                am_pm = 0\n        print('prev button:', hours, minutes, am_pm)\n\nbutton_mode = Button(16, False, button_mode_irq, internal_pullup = True, debounce_time = 100)\nbutton_next = Button(17, False, button_next_irq, internal_pullup = True, debounce_time = 100)\nbutton_previous = Button(18, False, button_previous_irq, internal_pullup = True, debounce_time = 100)\n\nprint(\"year:\", now[0], \"month:\", now[1], \"day-of-month:\", now[2], \"hours\", now[3], \"minutes:\", now[4])\nwhile(True):\n    button_mode.update()\n    button_next.update()\n    button_previous.update()\n
    "},{"location":"lessons/06-setting-time/#the-decrement-time","title":"The Decrement Time","text":"

    The following line need some explanation:

    hour = ((hour - 2) % 12) + 1\n
    Let me break down that line, which handles decrementing hours while staying within the 1-12 range:

    Let's walk through it step by step:

    1. First, we subtract 2 from the current hour: (hour - 2)
    2. We subtract 2 (not 1) because we'll add 1 back at the end
    3. This shift is necessary because we want to work with 0-11 for the modulo operation

    4. Then we take modulo 12: % 12

    5. This ensures our number wraps around within 0-11
    6. For example, if hour was 1, then (1-2) = -1, and -1 % 12 = 11

    7. Finally, we add 1: + 1

    8. This shifts our range from 0-11 back to 1-12

    Here's an example sequence to show how it works: - Starting at hour = 1: - (1 - 2) = -1 - -1 % 12 = 11 - 11 + 1 = 12 - Starting at hour = 12: - (12 - 2) = 10 - 10 % 12 = 10 - 10 + 1 = 11

    This gives us the desired behavior of decrementing through the sequence: 12 \u2192 11 \u2192 10 \u2192 ... \u2192 1 \u2192 12

    "},{"location":"lessons/06-setting-time/#updating-the-display","title":"Updating the Display","text":"
    from machine import Pin\nfrom utime import localtime, sleep, ticks_ms, ticks_diff\nimport tm1637\n\n# Pin setup\nCLK_PIN = 0\nDST_PIN = 1\nPM_PIN = 25\n\nmode_pin = Pin(16, Pin.IN, Pin.PULL_UP)\nnext_pin = Pin(17, Pin.IN, Pin.PULL_UP)\nprevious_pin = Pin(18, Pin.IN, Pin.PULL_UP)\n# LED value 0 indicates AM, value 1 indicates PM\npm_pin = Pin(PM_PIN, Pin.OUT)\n\n# Time state\nnow = localtime()\nhour = now[3]\nminute = now[4]\nsecond = now[5]\n\ntm = tm1637.TM1637(clk=Pin(CLK_PIN), dio=Pin(DST_PIN))\n\nmode = 0\nmode_names = [\"run\", \"set hour\", \"set minute\", \"set AM/PM\"]\nmode_count = len(mode_names)\n\n# Debounce state\nlast_mode_press = 0\nlast_next_press = 0\nlast_prev_press = 0\nDEBOUNCE_MS = 100\n\ndef format_time():\n    return f\"{hour:d}:{minute:02d}:{second:02d} {'PM' if is_pm else 'AM'}\"\n\ndef set_pm():\n    if hour < 12:\n        is_pm = False\n        pm_pin.value(0)\n    else:\n        is_pm = True\n        pm_pin.value(1)\n\ndef handle_mode(pin):\n    global mode, last_mode_press\n    current_time = ticks_ms()\n    if ticks_diff(current_time, last_mode_press) > DEBOUNCE_MS:\n        mode = (mode + 1) % mode_count\n        print(f\"Mode: {mode_names[mode]}\")\n        last_mode_press = current_time\n\ndef handle_next(pin):\n    global hour, minute, is_pm, last_next_press\n    current_time = ticks_ms()\n    if ticks_diff(current_time, last_next_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = (hour % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute + 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_next_press = current_time\n\ndef handle_previous(pin):\n    global hour, minute, is_pm, last_prev_press\n    current_time = ticks_ms()\n    if ticks_diff(current_time, last_prev_press) > DEBOUNCE_MS:\n        if mode == 1:  # Set hour\n            hour = ((hour - 2) % 12) + 1\n        elif mode == 2:  # Set minute\n            minute = (minute - 1) % 60\n        elif mode == 3:  # Toggle AM/PM\n            is_pm = not is_pm\n\n        if mode != 0:\n            print(format_time())\n        last_prev_press = current_time\n\n# numbers modified to not dispaly the leading zero\ndef numbers_nlz(num1, num2, colon=True):\n    \"\"\"Display two numeric values -9 through 99, with a leading space before\n    single-digit first numbers and separated by a colon.\"\"\"\n    num1 = max(-9, min(num1, 99))\n    num2 = max(-9, min(num2, 99))\n    prefix = ' ' if num1 < 10 else ''\n    # print(f'\"{prefix}{num1:d}{num2:0>2d}\"')\n    segments = tm.encode_string(f'{prefix}{num1:d}{num2:0>2d}')\n    if colon:\n        segments[1] |= 0x80  # colon on\n    tm.write(segments)\n\n# Set up interrupts\nmode_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_mode)\nnext_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_next)\nprevious_pin.irq(trigger=Pin.IRQ_FALLING, handler=handle_previous)\n\n# Main loop\nprint(\"Clock started. Press mode button to change settings.\")\n\nwhile True:\n    second = localtime()[5]\n    if mode == 0:  # Only update display in run mode\n        print(format_time())\n        # flash the colon on and off every second\n        if (second % 2): # modulo 2 will be true for odd numbers\n            numbers_nlz(hour, minute, True)\n        else:\n            numbers_nlz(hour, minute, False)\n        set_pm()\n        sleep(1)\n
    "},{"location":"lessons/07-drawing-digits/","title":"Drawing Clock Digits","text":""},{"location":"lessons/07-drawing-digits/#the-seven-segments-of-a-numeric-digit","title":"The Seven Segments of a Numeric Digit","text":"

    Since the early history of computing, numeric displays were created using a grouping of seven individual lights to display a single digit. These are called Seven Segment Displays. An example is shown in the image below:

    The segments are labeled \"a\" through \"g\" starting at the top and going around in a clockwise direction. Note that the seventh segment is in the center element is the \"g\" segment.

    Technically, many displays have an 8th segment for the decimal point (DP). To keep things simple we will just focus on the main seven segments in this lesson.

    Clocks also usually have a colon that separates the hours and minutes and an AM/PM indicator for 12-hour displays. We will be treating these and independent drawing components in this lab. Many digital clocks have the colon flash on and off every second.

    "},{"location":"lessons/07-drawing-digits/#the-segment-map","title":"The Segment Map","text":"

    To start out, we need to create a \"digit-to-segment map\" data structure. We use this to help us figure out what segments to turn on for any given digit.

    We will also need to convert the segment letters into integers. These integers will form the index of an array.

    To write our code, we ask, for any given digit, is the segment on or off?

    To do this, we can create an array of segments like this:

    segmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n

    For any given digit like \"2\" we can then just pass the index of \"2\" to a Python list to get a list of the segments to turn on. That line of code looks like this:

    segmentOn = segmentMapping[digit];\n

    This will return the segments that are to be turned on for any given input digit. For example:

    segmentOn = segmentMapping[2];\nprint(segmentOn)\n# returns:\n[1, 1, 0, 1, 1, 0, 1]\n

    We now have the data structure to do the drawing. We will do this in two steps.

    1. Draw the three horizontal lines for a digit if they are on
    2. Draw all vertical lines for a given digit, keeping in mind that we need to only draw half the way down the digit for the upper left and upper right vertical segments (1 and 5)

    We will start out with a simple digit drawing using a single-pixel width line. Later we will add a parameter to change the thickness of the line. But we want to take this one-step-at-a-time.

    "},{"location":"lessons/07-drawing-digits/#drawing-horizontal-segments","title":"Drawing Horizontal Segments","text":"

    This sample code will step through the horizontal lines for segments 0, 3 and 6. It will check using the segmentOn[i] line which will ONLY be true if that segment should be turned on for a given digit.

    Next, we figure out how high to draw the horizontal line. To do this we will need to figure out the vertical offset (yOffset). The top line (segment 0) has no offset and the bottom line has the full height of the digit.

    Unlike the vertical lines, the horizontal lines will span the entire width of the area. That makes our code simple because the line will have a horizontal length of exactly the x plus the width of the digit.

    # reasonable test values for a small display\nx = 10\ny = 10\nwidth = 20\nheight = 30\n# Horizontal segments\n  for i in [0, 3, 6]:\n    # check if this digit has the segment on\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height # bottom element\n      if (i==6):\n          yOffset = height // 2 # bottom\n      # draw a signal thin line\n      oled.line(x, y+yOffset, x + width, y+yOffset, 1)\n
    "},{"location":"lessons/07-drawing-digits/#drawing-the-vertical-segments","title":"Drawing the Vertical Segments","text":"

    Next, we need to create some code to draw the four vertical segments. This is a little more complex because the lines do NOT span the full height of the digit.

    # Draw Vertical segments\nx = 10\ny = 10\nwidth = 20\nheight = 30\n# Draw the vertical segments ur, lr, ll, ul\nfor i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n        # top two segments\n        if (i==1 or i==5):\n            startY = 0\n            endY = height // 2\n        if (i==2 or i==4):\n            startY = height // 2\n            endY = height\n        # left segments\n        if (i==4 or i==5): xOffset = 0\n        # right segments\n        if (i==1 or i==2): xOffset = width\n        oled.line(x+xOffset, y+startY, x+xOffset, y+endY, 1)\n
    "},{"location":"lessons/07-drawing-digits/#testing-our-drawing","title":"Testing Our Drawing","text":"

    We can now wrap the code above in a drawDigit() function, and we will test each of the digits 0-9 in a small test program.

    Our first version of drawDigit is modeled after the rect() function. After we pass in the digit, it takes in the (x,y) and width and height parameters and the color value.

    Draw Digit Function Parameters:

    1. The digit to display - an integer in the range 0-9
    2. x of the upper left corner
    3. y of the upper left corner
    4. the width of the digit (about 20 is a good value)
    5. the height of the digit
    6. the color (0=black, 1=white)

    Here is our testing program that draws digits 0-9 in the center of a standard 128x64 monochrome OLED display:

    # Lab 20: Draw Digits with just the line function\n# this lab uses the line() function to draw the segments\nimport machine\nimport utime\nimport ssd1306\nfrom utime import sleep, localtime\nled = machine.Pin(25, machine.Pin.OUT)\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\nspi=machine.SPI(0, sck=SCL, mosi=SDA, baudrate=100000)\n\nRES = machine.Pin(4)\nDC = machine.Pin(5)\nCS = machine.Pin(6)\nWIDTH = 128\nHEIGHT = 64\n\noled = ssd1306.SSD1306_SPI(WIDTH, HEIGHT, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n\n\n# x and y are the center of the digit, size is the center to edge\ndef drawDigit(digit, x, y, width, height, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottem, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height # bottom element\n      if (i==6):\n          yOffset = height // 2 # middle line\n      oled.line(x, y+yOffset, x + width, y+yOffset, 1)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n        # top two segments\n        if (i==1 or i==5):\n            startY = 0\n            endY = height // 2\n        if (i==2 or i==4):\n            startY = height // 2\n            endY = height\n        # left segments\n        if (i==4 or i==5): xOffset = 0\n        # right segments\n        if (i==1 or i==2): xOffset = width\n        oled.line(x+xOffset, y+startY, x+xOffset, y+endY, 1)\n\n\noled.fill(0)\noled.text('Lab 12: rect', 0, 0, 1)\nx = 10 # upper left corner x\ny = 10 # upper left corner y\nw = 20 # digit width\nh = 30 # digit height\n\nwhile True:\n    for i in range(0, 10):\n\n        print(i)\n        # create an outline one px away from the drawing region\n        oled.rect(x-2, y-2, w+5, h+5, 1)\n        # draw one digit\n        drawDigit(i, x, y, w, h, 1)\n        # draw a second digit\n        #drawDigit(i, x + w + 4, w, h, t, 1)\n        oled.text(str(i), 0, 54, 1)\n        oled.show()\n        sleep(2)\n        oled.fill(0)\n

    This drawDigit() is very handy. We just need to give the function some parameters and it will draw the right digit at a location (x,y) as the upper left corner with the correct width and height!

    But the lines are somewhat thin. A more robust implementation will also allow us the change the thickness of the segments. That will be more complex since we will have to adjust the starting point of where we draw each segment based on the thickness of the segment. We will also need to use a rectangle, not a line. This requires we figure out the exact width and height before we draw.

    We explore that function in the next lesson.

    "},{"location":"lessons/09-digit-functions/","title":"Creating Digit Functions","text":"

    In the last section, we drew a seven-segment digit number using the line function. In this section, we will build a better function that will add a flexible new parameter for the thickness of the digit segments. We will then test the function under a variety of conditions and see how we can make the function easier to use.

    "},{"location":"lessons/09-digit-functions/#new-thickness-parameters","title":"New Thickness Parameters","text":"

    Placing the rectangles correctly within a seven-segment display when we have many drawing parameters requires some precision. We will use a decomposition process and take \"one step at a time\" to work out the details.

    "},{"location":"lessons/09-digit-functions/#draw-segment-function","title":"Draw Segment Function","text":"

    Here is our revised parameters list:

    1. The digit to display - an integer in the range 0-9
    2. x of the upper left corner
    3. y of the upper left corner
    4. the width of the digit (about 20 is a good value)
    5. the height of the digit
    6. (NEW) the thickness of each segment (3 or 4 are good values)
    7. the color (0=black, 1=white)

    Here is our revised function for drawing a single digit with the segment thickness added.

    # digit is the number to display\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottom, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottom element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottom\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n

    Let's now take a look at how we had to modify our code.

    The first item to note is that when we calculate a starting point to draw, we can't just draw at the edge of the region. We need to back off our initial drawing point by the width of the segment.

    Here is an example of subtracting the thickness from y when we draw the bottom segment:

    yOffset = height - thickness # bottom element\n

    "},{"location":"lessons/09-digit-functions/#full-test-program","title":"Full Test Program","text":"
    # Clock Lab 20: Draw Seven Segments\n# this lab uses the fill_rect function to draw the segments\nimport machine\nimport utime\nimport ssd1306\nfrom utime import sleep, localtime\nled = machine.Pin(25, machine.Pin.OUT)\n\nSCL=machine.Pin(2) # SPI CLock\nSDA=machine.Pin(3) # SPI Data\nspi=machine.SPI(0, sck=SCL, mosi=SDA, baudrate=100000)\n\nRES = machine.Pin(4)\nDC = machine.Pin(5)\nCS = machine.Pin(6)\n\noled = ssd1306.SSD1306_SPI(128, 64, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n\n# digit is the numer to display\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottom, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottom element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottom\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + height // 2\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n\noled.fill(0)\noled.text('Lab 12: rect', 0, 0, 1)\nx = 10 # upper left corner x\ny = 10 # upper left corner y\nw = 20 # digit width\nh = 30 # digit height\nt = 3\n\nwhile True:\n    for i in range(0, 10):\n\n        print(i)\n        # create an outline on px away from the drawing region\n        oled.rect(x-2, y-2, w+4, h+4, 1)\n        # draw one digit\n        drawDigit(i, x, y, w, h, t, 1)\n        # draw a second digit\n        #drawDigit(i, x + w + 4, w, h, t, 1)\n        oled.text(str(i), 0, 54, 1)\n        oled.show()\n        sleep(2)\n        oled.fill(0)\n
    "},{"location":"lessons/12-draw-time-functions/","title":"Draw a Digital Clock Time Function","text":"

    In this section, we will create a new function called drawTime. The input will be the upper left starting point (x,w), width and height, hours and minutes and the format (12-hour or 24-hour) and the color (black or white).

    This lab will build in the prior lab that displayed a single digit.

    Let's first of all create a plan of how we will layout our digital clock display.

    Our goal is to create a function that will be reusable over many types of displays with little or no modification. This will require us to think through the potential ways our users will use this function and anticipate their needs so they are not tempted to rewrite our code on their own.

    "},{"location":"lessons/12-draw-time-functions/#12-hour-display-format","title":"12-Hour Display Format","text":"

    Here is an example of our 12-hour clock layout:

    Note that there are six horizontal x-dimension numbers and three vertical y-dimension numbers that you can adjust to create a pleasant interface.

    "},{"location":"lessons/12-draw-time-functions/#automatically-scaling-the-layout","title":"Automatically Scaling the Layout","text":"

    It would be tempting to just hard-code the layout using a single set of numbers. But what if the user wanted a smaller or larger portion of their display used to display the time?

    As the user selects the height and width of their clock we would like to scale these numbers accordingly. The absolute values of these numbers is not too important now. We just want to get the relative values down. To start the process, I did a layout on an 11-inch wide drawing and I assigned the width of each digit to be 3.0.

    # horizontal\nx1 = .73\nx2 = .73\nx3 = 3.0\nx4 = 1.35\nx5 = .5\nx6 = .35\nx7 = 1.5\nx8 = .35\nx9 = .5\n# Vertical\ny1 = 5.31\ny2 = 1.58\ny3 = .68\ny4 = .68\n

    We need to make the width of the display be x1 + x2 + 3*x3 + x4 + x5 + x6 + x7 which is

    # Scale Test\n\ndef drawTime12h(hour, minute, x, y, width, height):\n    # horizontal\n    x1 = .73\n    x2 = .73\n    x3 = 3.0 # digit width\n    x4 = 1.35\n    x5 = .5\n    x6 = .35\n    x7 = 1.5\n    x8 = .35\n    x9 = .5 # colon width and height\n\n    # vertical\n    y1 = 5.31\n    y2 = 1.58 # to top colon\n    y3 = .68 # between colons\n\n    total_width = x1 + x2 + 3*x3 + x4 + x5 + x6 + x7\n    print(\"total width:\", total_width)\n    total_height = y1\n\n    # calculate the scaling ratios\n    x_scale = width / total_width\n    y_scale = height / total_height \n\n    digit_width = x3 * x_scale\n    digit_height = y1 * y_scale\n    print(\"x scale:\", x_scale, \"y scale:\", y_scale)\n\n    if hour > 12:\n        hour12 = hour - 12\n\n    # hour tens\n    if hour12 > 10:\n        oled.rect(x,y,int(x1*x_scale),int(y1*y_scale))\n\n    # hour ones x,y,w,h\n    drawDigit(hour % 10, int((x + x1 + x2)*x_scale), y, int(x3*x_scale), int(y1*y_scale))\n\n    # minute tens ones digit, x,y,w,h\n    min_tens_x = int((x + x1 + x2 + x3 + x4)*x_scale)\n    drawDigit(minute // 10, min_tens_x, y, int(x3*x_scale), int(y1*y_scale))\n\n    # minute  ones x,y,w,h\n    min_ones_x = int((x + x1 + x2 + 2*x3 + x4 + x5)*x_scale)\n    drawDigit(minute % 10, min_ones_x, y, int(x3*x_scale), int(y1*y_scale))\n\n    # draw colon\n    colon_size = x9\n    # top colon\n    oled.rect(int((x+x1+x2+x3+x8)*x_scale), y+int(y2*y_scale), colon_size, colon_size)\n    # bottom colon\n    oled.rect(int((x+x1+x2+x3+x8)*x_scale), y+int((y2+y3)*y_scale), colon_size, colon_size)\n\n    # AM/PM\n    if hours < 12:\n        am_pm_text = 'am'\n    else:\n        am_pm_text = 'pm'\n    am_pm_x = min_ones_x + int((x3+x6)*x_scale)\n    oled.text(am_pm_text, am_pm_x, y + int(y1*y_scale)) \n\ndrawTime12h(hour, minute, 0, 0, 100, 50)\n
    "},{"location":"lessons/13-testing-the-rtc/","title":"Real Time Clocks","text":"

    Prompt

    You are a friendly and fun science teacher working with a group of high-school students taking a course called \"Programming Clocks and Watches\". Today your lecture is on \"Real time Clocks\" like the old DS1307 and the newer super accurate DS3231. Give the full text of a 15-minute lecture before the hands-on lab and mention where images should be inserted.

    Hello everyone, and welcome to today's exciting lecture on Real Time Clocks! In our \"Programming Clocks and Watches\" course, we're going to dive into the fascinating world of the good old DS1307 used in our classrooms and the new super accurate DS3231.

    First, let's talk about what a Real Time Clock (RTC) is. An RTC is a computer chip that keeps track of the current time, even when the main power is off. It's like a tiny, dedicated clock inside your electronic devices. RTCs are found in computers, smartphones, appliances, and many other gadgets that need to keep accurate time.

    Here is how the DS1307 is typically used in a microcontroller project.

    The DS1307 is one of the most well-known RTCs. We have a LOT of them lying around the lab. This little chip was first introduced in 2005 and has been widely used in various electronic projects. The DS1307 keeps track of seconds, minutes, hours, days, months, and years. It communicates with the main processor using a protocol called I2C (Inter-Integrated Circuit).

    Now, let's take a look at how the DS1307 works. It has a built-in crystal oscillator that vibrates at a specific frequency, acting as a precise clock source. The chip counts these oscillations to keep track of time. The DS1307 also has a small amount of battery-backed memory, allowing it to maintain the time even when the main power is off.

    [Insert image of a coin cell battery]

    Speaking of power, the DS1307 uses a small coin cell battery to keep the clock running when the main power is disconnected. This battery can last for several years, ensuring that your device always has the correct time.

    [Insert image of a DS3231 chip]

    Now, let's move on to the newer and more accurate DS3231. Released in 2011, the DS3231 is known for its incredible precision. It has a temperature-compensated crystal oscillator (TCXO), which means it can maintain accurate timekeeping even when the temperature changes. This is important because temperature fluctuations can affect the frequency of regular crystal oscillators, causing the clock to drift over time.

    [Insert image comparing the accuracy of DS1307 and DS3231]

    How accurate is the DS3231, you might ask? Well, it has a typical accuracy of \u00b12 parts per million (ppm), which translates to a drift of about 1 minute per year! In comparison, the DS1307 has an accuracy of around \u00b120 ppm, which means it can drift by about 10 minutes per year. That's a significant difference!

    [Insert image of I2C communication]

    Just like the DS1307, the DS3231 communicates with the main processor using the I2C protocol. It has a simple register-based interface that allows you to read and set the time easily.

    Now, let's talk about some fun applications of RTCs. One cool project you can build is a digital clock that always displays the correct time, even if it's been unplugged for a while. You can also create a data logger that records temperature, humidity, or other sensor readings along with precise timestamps. The possibilities are endless!

    [Insert image of a digital clock or a data logger project]

    In our hands-on lab today, we'll be working with both the DS1307 and the DS3231. You'll learn how to wire them up, set the time, and read the current time using a microcontroller. We'll also explore some practical examples and discuss how to choose the right RTC for your projects.

    [Insert image of students working on a project]

    So, get ready to have some fun with Real Time Clocks! Remember, whether you're building a simple clock or a complex data logging system, an RTC is an essential component that keeps everything running on time.

    Let's head to the lab and start tinkering with these amazing little chips!

    "},{"location":"lessons/13-testing-the-rtc/#testing-the-ds1307-and-ds3232-real-time-clocks","title":"Testing the DS1307 and DS3232 Real Time Clocks","text":""},{"location":"lessons/13-testing-the-rtc/#hardware-configuration","title":"Hardware Configuration","text":""},{"location":"lessons/13-testing-the-rtc/#ds1307-connections","title":"DS1307 Connections","text":"
    1. CLK - clock
    2. DST - Data (incoming to Pico)
    3. RST - Reset
    4. VCC - must be 5 volts, not 3.2
    5. GND - ground

    We will use the lower right pins on the Pico so that the display can use the pins in the upper-right corner.

    These pin assignments are

    1. GP16 - far lower right - CLK
    2. GP17 - second from the bottom - DST
    3. GP18 - fourth pin up - RST

    Contents of config.py

    CLK_PIN = 16\nDST_PIN = 17\nRST_PIN = 18\n
    "},{"location":"lessons/13-testing-the-rtc/#sample-ds1307-micropython-test-program-for-the-raspberry-pi-pico","title":"Sample DS1307 MicroPython Test Program for the Raspberry Pi Pico","text":"
    from machine import I2C, Pin\nimport config\n\nCLK_PIN = config.CLK_PIN\nDST_PIN = config.DST_PIN\nDS_PIN = config.DS_PIN\n\nprint(\"Clock on pin:\", CLK_PIN)\nprint(\"Data on pin:\", DST_PIN)\nprint(\"Data Select on pin:\", DS_PIN)\n\ni2c = I2C(0, scl=Pin(CLK_PIN), sda=Pin(DST_PIN), freq=100000)\nscan_result = i2c.scan()\nprint(\"I2C addresses found:\", [hex(device_address) for device_address in scan_result])\n\nif 104 in scan_result:\n    print(\"PASS: DS1307 FOUND\")\nelse:\n    print(\"FAIL: DS1307 NOT FOUND\")\n
    "},{"location":"lessons/13-testing-the-rtc/#sample-test-result","title":"Sample Test Result","text":"
    Clock on pin: 17\nData on pin: 16\nData Select on pin: 18\nI2C addresses found: ['0x50', '0x68']\nPASS: DS1307 FOUND\n
    "},{"location":"lessons/13-testing-the-rtc/#full-test-of-ds1307","title":"Full Test of DS1307","text":"
    #!/usr/bin/env python3\n# -*- coding: UTF-8 -*-\n\n\"\"\"I2C DS1307 showcase\"\"\"\n\nfrom ds1307 import DS1307\nfrom machine import I2C, Pin\nfrom utime import gmtime, sleep, time\nimport config\nCLK_PIN = config.CLK_PIN\nDST_PIN = config.DST_PIN\nDS_PIN = config.DS_PIN\n\n# DS1307 on 0x68\nI2C_ADDR = 0x68     # DEC 104, HEX 0x68\n\n# define custom I2C interface, default is 'I2C(0)'\n# check the docs of your device for further details and pin infos\n# this are the pins for the Raspberry Pi Pico adapter board\ni2c = I2C(0, scl=Pin(CLK_PIN), sda=Pin(DST_PIN), freq=800000)\nprint(i2c.scan())\nds1307 = DS1307(addr=I2C_ADDR, i2c=i2c)\n\n# get LCD infos/properties\nprint(\"DS1307 is on I2C address 0x{0:02x}\".format(ds1307.addr))\nprint(\"Weekday start is {}\".format(ds1307.weekday_start))\n\n# get the current RTC time\nprint(\"Current RTC time: {}\".format(ds1307.datetime))\n\n# set the RTC time to the current system time\nnow = gmtime(time())\nds1307.datetime = now\n\n# Print the date and time in ISO8601 format: 2023-04-18T21:14:22\nprint(\"Today is {:04d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}\".format(\n    ds1307.year, ds1307.month, ds1307.day,\n    ds1307.hour, ds1307.minute, ds1307.second))\n\n# check whether this year is a leap year\nprint(\"Is this year a leap year? {}\".format(ds1307.is_leap_year(ds1307.year)))\n\n# get the day of the year\nprint(\"Today is day {} of {}\".format(\n    ds1307.day_of_year(year=ds1307.year, month=ds1307.month, day=ds1307.day),\n    ds1307.year))\n\n# halt the oscillator\nprint(\"The oscillator is currently active at {}? {}\".format(\n    ds1307.datetime, ds1307.halt))\nprint(\"Halt the oscillator and wait for 5 seconds ...\")\nds1307.halt = True\nsleep(5)\n\nprint(\"Current RTC time: {}\".format(ds1307.datetime))\n\nprint(\"Enable the oscillator and wait for 5 seconds ...\")\nds1307.halt = False\nsleep(5)\nprint(\"Current RTC time: {}\".format(ds1307.datetime))\n\n# control the squarewave pin SQ\nprint(\"Set square wave output to 1Hz and wait for 5 seconds ...\")\nds1307.square_wave(sqw=1)\nsleep(5)\n\nprint(\"Set square wave output to 4.096kHz and wait for 5 seconds ...\")\nds1307.square_wave(sqw=4)\nsleep(5)\n\nprint(\"Set square wave output to 8.192kHz and wait for 5 seconds ...\")\nds1307.square_wave(sqw=8)\nsleep(5)\n\nprint(\"Set square wave output to HIGH and wait for 5 seconds ...\")\nds1307.square_wave(out=1)\nsleep(5)\n\nprint(\"Set square wave output to LOW and wait for 5 seconds ...\")\nds1307.square_wave(sqw=0)\nsleep(5)\n
    "},{"location":"lessons/13-testing-the-rtc/#test-result","title":"Test Result","text":"
    [80, 104]\nDS1307 is on I2C address 0x68\nWeekday start is 0\nCurrent RTC time: (2024, 12, 27, 20, 29, 47, 4, 362)\nToday is 2024-12-27T20:29:51\nIs this year a leap year? True\nToday is day 362 of 2024\nThe oscillator is currently active at (2024, 12, 27, 20, 29, 51, 4, 362)? False\nHalt the oscillator and wait for 5 seconds ...\nCurrent RTC time: (2024, 12, 27, 20, 29, 51, 4, 362)\nEnable the oscillator and wait for 5 seconds ...\nCurrent RTC time: (2024, 12, 27, 20, 29, 56, 4, 362)\nSet square wave output to 1Hz and wait for 5 seconds ...\nSet square wave output to 4.096kHz and wait for 5 seconds ...\nSet square wave output to 8.192kHz and wait for 5 seconds ...\nSet square wave output to HIGH and wait for 5 seconds ...\nSet square wave output to LOW and wait for 5 seconds ...\n
    "},{"location":"lessons/13-testing-the-rtc/#localtime-and-gmtimetime","title":"Localtime and gmtime(time())","text":"
    from utime import gmtime, time, localtime\nprint(\"time()\", time())\nprint(\"   localtime()\", localtime())\nprint(\"gmtime(time())\", gmtime(time()))\n

    Result

    time() 1735332067\n   localtime() (2024, 12, 27, 20, 41, 7, 4, 362)\ngmtime(time()) (2024, 12, 27, 20, 41, 7, 4, 362)\n
    This code is running on MicroPython on the Raspberry Pi Pico (RP2040) and demonstrates the usage of time-related functions from the utime module.

    Let's break it down:

    1. from utime import gmtime, time, localtime: This line imports the gmtime, time, and localtime functions from the utime module, which is MicroPython's equivalent of the time module in standard Python.
    2. print(\"time()\", time()): This line prints the label \"time()\" followed by the result of calling the time() function. The time() function returns the number of seconds elapsed since the Unix epoch (January 1, 1970, 00:00:00 UTC) as an integer value. In your output, time() returned 1735332067, which represents the current timestamp.
    3. print(\" localtime()\", localtime()): This line prints the label \"localtime()\" followed by the result of calling the localtime() function. The localtime() function takes no arguments and returns a tuple representing the current local time. The tuple contains the following elements in order: (year, month, day, hour, minute, second, weekday, yearday). In your output, localtime() returned (2024, 12, 27, 20, 41, 7, 4, 362), indicating the current local time on the Raspberry Pi Pico.
    4. print(\"gmtime(time())\", gmtime(time())): This line prints the label \"gmtime(time())\" followed by the result of calling the gmtime() function with the current timestamp obtained from time(). The gmtime() function takes a timestamp as an argument and returns a tuple representing the corresponding UTC time. The tuple has the same format as the one returned by localtime(). In your output, gmtime(time()) returned (2024, 12, 27, 20, 41, 7, 4, 362), which represents the current UTC time.

    What does the number that time() returns represent?

    The number returned by time() represents the number of seconds that have elapsed since the Unix epoch (January 1, 1970, 00:00:00 UTC). This value is commonly known as the Unix timestamp or epoch time. It is a widely used standard for representing points in time and is independent of time zones.

    In our example, time() returned 1735332067. This timestamp corresponds to the date and time shown in the localtime() and gmtime(time()) outputs, which is December 27, 2024, at 20:41:07 UTC.

    The Unix timestamp is a useful representation of time because it allows for easy arithmetic operations on timestamps and can be converted to human-readable formats using functions like localtime() and gmtime(). It is widely used in various programming languages and systems for time-related operations.

    It's important to note that the accuracy and synchronization of the time on the Raspberry Pi Pico depend on its internal clock and any time synchronization mechanisms used. Without external time synchronization, the Pico's internal clock may drift over time, resulting in slight inaccuracies compared to the actual current time.

    "},{"location":"lessons/13-testing-the-rtc/#accuracy-of-the-clock-on-the-raspberry-pi-pico","title":"Accuracy of the Clock on the Raspberry Pi Pico**","text":"

    The Raspberry Pi Pico does not have a real-time clock (RTC) built into its hardware. Its clock is derived from the internal oscillator, which may be subject to drift and is not highly accurate for long-term timekeeping. The accuracy depends on the quality of the oscillator and the environmental conditions, such as temperature.

    • Drift: The internal clock is typically accurate to within 1% under normal conditions.

    • Seconds off per day: For a 1% drift:

    \\[ 1\\% \\text{ of 24 hours} = 0.01 \\times 24 \\times 3600 \\approx 864 \\, \\text{seconds off per day}. \\]

    Thus, the clock on the Pico can drift up to \u00b1864 seconds per day without correction.

    For improved accuracy, you can add an external RTC module to the Pico.

    Accuracy of the Clock on the DS1307

    The DS1307 is a low-cost RTC chip widely used in electronics projects. Its accuracy is based on an external 32.768 kHz quartz crystal oscillator, which is sensitive to factors like temperature and crystal quality. \u2022 Drift: The DS1307 typically drifts by \u00b120 ppm (parts per million) at 25\u00b0C. \u2022 Seconds off per day: With a drift of 20 ppm:

    \\[ 20 \\, \\text{ppm} \\times 24 \\times 3600 \\, \\text{seconds} = 1.728 \\, \\text{seconds off per day}. \\]

    The DS1307 clock may be off by approximately \u00b11.7 seconds per day under ideal conditions.

    For more accurate timekeeping, consider using a higher-quality RTC like the DS3231, which has a drift of \u00b12 ppm (about \u00b10.17 seconds per day) due to its temperature compensation feature.

    "},{"location":"lessons/13-testing-the-rtc/#references","title":"References","text":"
    • DS1307 Data Sheet
    • Reference Manual
    "},{"location":"lessons/15-scale-testing/","title":"Digital Clock Display Scale Testing","text":"

    We would like to test our digital clock display at a large range of different sizes to make sure our scale functions work. For example, the function should work over a range of sizes from 20 to 110 pixels wide.

    Here is a test driver for the drawTime12 function:

    # test times\ntt = [[00,00], [12,59], [12,00], [8,33], [13,59], [23,59]]\n\nwhile True:\n    ## tti is the test time index\n    for tti in range(0,len(tt)):\n        for size in range(20, 110):\n            oled.fill(0) # clear screen\n            # bounding box for the entire screen\n            # oled.rect(0,0, WIDTH-1, HEIGHT-1, 1)\n\n            # bounding box for the time region\n            height = int(size*.5)\n            oled.rect(0, 0, size+20, height+5, 1)\n            # print(\"h=\", tt[tti][0], \"min:\", tt[tti][1])\n            drawTime12h(tt[tti][0], tt[tti][1], 2, 2, size, height, 1)\n            oled.text(str(tt[tti][0]) + ':' + str(tt[tti][1]), 0, 54, 1)\n            oled.show()\n            sleep(.1)\n
    "},{"location":"lessons/15-scale-testing/#sample-code","title":"Sample Code","text":"
    # Lab 42: Scale Test test v2\n\nfrom machine import Pin\nfrom time import sleep\nimport ssd1306\nimport config\n\nSCL=Pin(config.SCL_PIN) # SPI CLock\nSDA=Pin(config.SDA_PIN) # SPI Data\n\nRES = Pin(config.RESET_PIN) # Reset\nDC = Pin(config.DC_PIN) # Data/command\nCS = Pin(config.CS_PIN) # Chip Select\nWIDTH = config.WIDTH\nHEIGHT = config.HEIGHT\n\nspi=machine.SPI(config.SPI_BUS, sck=SCL, mosi=SDA, baudrate=100000)\noled = ssd1306.SSD1306_SPI(WIDTH, HEIGHT, spi, DC, RES, CS)\n\nsegmentMapping = [\n  #a, b, c, d, e, f, g\n  [1, 1, 1, 1, 1, 1, 0], # 0\n  [0, 1, 1, 0, 0, 0, 0], # 1\n  [1, 1, 0, 1, 1, 0, 1], # 2\n  [1, 1, 1, 1, 0, 0, 1], # 3\n  [0, 1, 1, 0, 0, 1, 1], # 4\n  [1, 0, 1, 1, 0, 1, 1], # 5\n  [1, 0, 1, 1, 1, 1, 1], # 6\n  [1, 1, 1, 0, 0, 0, 0], # 7\n  [1, 1, 1, 1, 1, 1, 1], # 8\n  [1, 1, 1, 1, 0, 1, 1]  # 9\n];\n# digit is the numer to display\n# x and y are upper-left-corner\n# width and height are the dimensions of the digit\n# thickness is the width of the line segments\n# color is 1 for white and 0 for black\ndef drawDigit(digit, x, y, width, height, thickness, color):\n  # get a list of the segments that are on for this digit\n  if digit > 9 or digit < 0:\n      print('Error: digit out of range:', digit)\n      return -1\n  segmentOn = segmentMapping[digit];\n\n  # Draw the horizontal segments: top, bottom, middle\n  for i in [0, 3, 6]:\n    if (segmentOn[i]):\n      if (i==0): # top\n          yOffset = 0 \n      if (i==3):\n          yOffset = height - thickness # bottom element\n      if (i==6):\n          yOffset = height // 2 - thickness // 2# bottom\n      # oled.line(x - size, y+yOffset-size, x + size, y+yOffset-size, 1);\n      oled.fill_rect(x, y+yOffset, width, thickness, color)\n\n  # Draw the vertical segments ur, lr, ll, ul\n  for i in [1, 2, 4, 5]:\n    if (segmentOn[i]) :\n      # upper vertical lines\n      if (i==1 or i==5):\n          startY = y\n          endY = y + height // 2\n      # lower two vertical lines (2=lower right and 4=lower left)\n      if (i==2 or i==4):\n          startY = y + (height // 2)\n          endY = y + height\n      if (i==4 or i==5): xOffset = 0\n      if (i==1 or i==2): xOffset = width-thickness\n\n      oled.fill_rect(x+xOffset, startY, thickness, endY-startY, color)\n\ndef drawTime12h(hour, minute, x, y, width, height, color):\n\n    # this does not scale\n    am_pm_font_height = 8\n\n    # horizontal spacing\n    x1 = .73 # width of the hour tens digit (1 or off)\n    x2 = .25 # space between hour tens and hour ones\n    x3 = 3.0 # digit width\n    x4 = 1.35 # space beteen hour ones and minute tens\n    x5 = .5 # space between minute tens and minute ones\n    x6 = .35 # space between minute ones and am/pm text\n    x7 = 1.5 # an/pm text width\n\n    # colon x positioning\n    x8 = .35 # space between hour ones and colon\n    x9 = .5 # colon width and height\n\n    # vertical\n    y1 = 5.31 # digit height\n    y2 = (y1 // 2) - .1 # to top colon\n    y3 = 1.5 # space between colons\n\n    total_width = x1 + x2 + 3*x3 + x4 + x5 + x6 + x7\n    # print(\"total width:\", total_width)\n    total_height = y1\n\n    # calculate the scaling ratios\n    x_scale = width / total_width\n    y_scale = height / total_height \n\n    digit_width = x3 * x_scale\n    digit_height = y1 * y_scale\n    # print(\"x scale:\", x_scale, \"y scale:\", y_scale)\n\n\n    time_width = total_width * x_scale\n    # print(\"time_width:\", time_width)\n\n    # thickness calculation based on a fraction of the width\n    thickness = int(.25 * digit_width)\n\n    if hour > 12:\n        hour12 = hour - 12\n    else: hour12 = hour\n\n    hour_minute = hour % 10\n    if hour_minute == 0:\n        hour_minute = 2\n\n    # hour tens display \n    if hour12 == 0 or hour12 > 9:\n        oled.fill_rect(x,y,int(x1*x_scale),int(y1*y_scale), color)\n\n    # hour ones for the d, x,y,w,h, t,c\n    if hour12 == 0:\n        hour12 = 12\n    hour_ones_x = int((x + x1 + x2)*x_scale)\n    drawDigit(hour12 % 10, hour_ones_x, y, int(x3*x_scale), int(y1*y_scale), thickness, color)\n\n    # minute tens ones digit, x,y,w,h\n    min_tens_x = int((x + x1 + x2 + x3 + x4)*x_scale)\n    drawDigit(minute // 10, min_tens_x, y, int(x3*x_scale), int(y1*y_scale), thickness, color)\n\n    # minute ones digit d, x,y,w,h, t, c\n    min_ones_x = int((x + x1 + x2 + 2*x3 + x4 + x5)*x_scale)\n    drawDigit(minute % 10, min_ones_x, y, int(x3*x_scale), int(y1*y_scale), thickness, color)\n\n    # draw colon\n    colon_size = int(x9*x_scale)\n    # top colon\n    oled.fill_rect(int((x+x1+x2+x3+x8)*x_scale), y+int(y2*y_scale), colon_size, colon_size, color)\n    # bottom colon\n    oled.fill_rect(int((x+x1+x2+x3+x8)*x_scale), y+int((y2+y3)*y_scale), colon_size, colon_size, color)\n\n    # AM/PM\n    if hour < 12:\n        am_pm_text = 'am'\n    else:\n        am_pm_text = 'pm'\n    # but here.  It displays outside the width\n    am_pm_x = min_ones_x + int((x3+x6)*x_scale)\n    # print('am/pm x:', am_pm_x)\n    oled.text(am_pm_text, am_pm_x, y + int(y1*y_scale) - am_pm_font_height, color)\n\n    oled.show()\n\n# test times\ntt = [[00,00], [12,59], [12,00], [8,33], [13,59], [23,59]]\n\nwhile True:\n    ## tti is the test time index\n    for tti in range(0,len(tt)):\n        for size in range(20, 110):\n            oled.fill(0) # clear screen\n            # bounding box for the entire screen\n            # oled.rect(0,0, WIDTH-1, HEIGHT-1, 1)\n\n            # bounding box for the time region\n            height = int(size*.5)\n            oled.rect(0, 0, size+20, height+5, 1)\n            # print(\"h=\", tt[tti][0], \"min:\", tt[tti][1])\n            drawTime12h(tt[tti][0], tt[tti][1], 2, 2, size, height, 1)\n            oled.text(str(tt[tti][0]) + ':' + str(tt[tti][1]), 0, 54, 1)\n            oled.show()\n            sleep(.1)\n
    "},{"location":"lessons/30-ili9341/","title":"ILI9341 Drawing","text":"

    The ILI9341 chip is a 262144-color single-chip SOC driver for a TFT liquid crystal display with a resolution of 240x320 dots (RGB).

    Source Code

    "},{"location":"lessons/30-ili9341/#configuration-file","title":"Configuration file","text":"

    These examples will all use the following config file:

    config.py

    SCK_PIN = 2\nMISO_PIN = 3 # labeled SDI(MOSI) on the back of the display\nDC_PIN = 4\nRESET_PIN = 5\nCS_PIN = 6\nROTATION = 90\n\nWIDTH=320\nHEIGHT=240\n

    We also put the color names in a colors.py file that calculates the colors using a name.

    from ili9341 import color565\n\nWHITE = color565(255,255,255)\nBLACK = color565(0,0,0)\nRED = color565(255,0,0)\nORANGE = color565(255,128,0)\nYELLOW = color565(255,255,0)\nGREEN = color565(0,255,0)\nBLUE = color565(0,0,255)\nCYAN = color565(0,255,255)\nPURPLE = color565(255,0,255)\n
    "},{"location":"lessons/30-ili9341/#simple-drawing","title":"Simple Drawing","text":""},{"location":"lessons/40-machine-info/","title":"Machine Info","text":""},{"location":"lessons/40-machine-info/#modules","title":"Modules","text":"
    help('modules')\n
    "},{"location":"lessons/40-machine-info/#clock-frequency","title":"Clock Frequency","text":"
    import machine\nprint('freq:', machine.freq())\n
    "},{"location":"lessons/40-machine-info/#operating-system","title":"Operating System","text":"
    os.uname()\n
    os.statvfs(path)\n
    "},{"location":"lessons/40-machine-info/#platform","title":"Platform","text":"
    platform.platform()\n
    "},{"location":"lessons/50-ds1307-breadboard/","title":"Using the DS1307 IC On A Breadboard","text":"

    You can use the DS1307 IC directly on a breadboard without a development board. Here's what you'll need:

    1. DS1307 IC (8-pin DIP package)
    2. 32.768 kHz crystal oscillator
    3. CR2032 battery holder and battery (for backup power)
    4. Two 4.7k\u03a9 pull-up resistors (for I2C)
    5. 0.1\u00b5F decoupling capacitor
    6. Standard through-hole breadboard

    The basic connections are:

    DS1307 Pinout:\nPin 1 (X1) -> Crystal\nPin 2 (X2) -> Crystal\nPin 3 (VBAT) -> Battery positive\nPin 4 (GND) -> Ground\nPin 5 (SDA) -> I2C Data (needs pull-up)\nPin 6 (SCL) -> I2C Clock (needs pull-up)\nPin 7 (SQW) -> Optional square wave output\nPin 8 (VCC) -> 5V power`\n

    The biggest advantages of using the raw IC are:

    • Lower cost than module boards
    • Smaller footprint
    • More control over the circuit design
    • Better understanding of the RTC system

    Just remember that the DS1307 requires 5V power (unlike its successor DS3231 which can work with 3.3V), so make sure your microcontroller's I2C lines can handle 5V or use a level shifter if necessary.

    "},{"location":"prompts/","title":"Prompts","text":"
    • Course Description
    • Concept Enumeration
    • Concept Dependency
    • Concept Taxonomy
    • Taxonomy Assignments
    • Banner Image
    "},{"location":"prompts/01-course-description/","title":"Generating a Course Description for the Clocks and Watches with MicroPython Course","text":"

    Prompt

    Please generate a course description for a 14-week course for high-school students called \"Building Clocks and Watches with MicroPython\".

    The course is a hands on-course that uses the Raspberry Pi Pico W and low-cost displays to create a fun collection of projects for kids learning how to program.

    We start with a simple clock that uses a LED clock display and then progress to using a web service and an 128x64 OLED display. We also have demonstrations of building stopwatches and timers by integrating buttons and knobs to adjust settings.

    An underlying theme is to promote computational thinking including abstraction, decomposition, algorithms and pattern matching.

    The course provides students with a breadboard, Raspberry Pi Pico Ws, LEDs and OLED graphical displays.

    Use the 2001 Bloom Taxonomy to guild the course description.

    "},{"location":"prompts/01-course-description/#response","title":"Response","text":"

    Course Title: Building Clocks and Watches with MicroPython Duration: 14 Weeks Appropriate for: High School Students

    Course Description: In this 14-week, hands-on course, high school students will learn to design and program functional timekeeping devices---from simple LED clocks to sophisticated stopwatches and web-connected displays---using MicroPython on the Raspberry Pi Pico W. Throughout the course, students will be guided by the 2001 revision of Bloom's Taxonomy, moving from foundational knowledge to creative invention.

    1. Remember: Students begin by identifying essential electronic components---breadboards, microcontrollers, buttons, knobs, and displays---and recalling the fundamental concepts of MicroPython programming.
    2. Understand: Through teacher-led demonstrations, students explore how timing functions, input/output operations, and hardware connections work together to create a basic LED clock. They deepen their grasp of computational thinking by examining concepts like abstraction (focusing on relevant details) and decomposition (breaking large problems into smaller parts).
    3. Apply: As their skills grow, students practice wiring and programming a 128\u00d764 OLED display, interfacing with web services to fetch real-time data. They also implement stopwatches and timers, applying algorithms and pattern-matching techniques to manage user inputs and display outputs accurately.
    4. Analyze: Learners diagnose and troubleshoot various clock behaviors, studying how code efficiency and hardware choices influence device performance. They dissect timing errors, lag issues, and integration problems, refining both their programming and problem-solving skills.
    5. Evaluate: Working in teams, students test multiple clock designs to compare accuracy, power consumption, and user experience. They assess trade-offs---such as display readability vs. complexity---and refine solutions based on feedback, cost, and practicality.
    6. Create: Ultimately, students design and assemble their own custom timekeeping projects, combining LEDs, OLED displays, push buttons, and encoders. This final challenge showcases their ability to unify hardware and code into a polished, functioning prototype.

    By the end of the course, students will have built a diverse collection of digital clocks, stopwatches, and timers while gaining a rich understanding of electronics, computational thinking, and MicroPython. They will leave empowered to continue exploring the world of embedded systems and creative hardware projects.

    "},{"location":"prompts/02-concept-enumeration/","title":"Concept Enumeration","text":"
    1. MicroPython
    2. Raspberry Pi Pico W
    3. Breadboard
    4. Powering Your Clocks and Watches
    5. USB Power
    6. Battery Power
    7. Battery Backup
    8. Battery Drain Calculation
    9. LED Clock Displays
    10. Real-time Clock
    11. The Thoney IDE
    12. Synchronizing time from the PC
    13. the localtime function
    14. MicroPython Syntax
    15. Loops
    16. Conditionals
    17. Functions
    18. Libraries
    19. Loading MicroPython Drivers
    20. Printing time to the console
    21. MicroPython Drawing Libraries
    22. Drawing Lines
    23. Drawing Text
    24. Drawing Pixels
    25. Drawing Rectangles
    26. Seven Segment Digits
    27. Drawing Circles
    28. Drawing Ellipses
    29. Drawing Arcs
    30. Drawing Polygons
    31. Changing Fonts
    32. Using MicroPython Drivers
    33. OLED Displays
    34. The Draw_Digit Function
    35. SmartWatch Displays
    36. Using 16 bits to represent color
    37. Framebuffer
    38. SPI interfaces
    39. Updating the entire screen with SPI
    40. Incremental screen drawing
    41. Drawing hands on an analog clock
    42. Using the sine and cosine functions
    43. Drawing tic marks on a watch face
    44. Drawing numbers on a watch face
    45. Loading Custom fonts
    "},{"location":"prompts/02-concept-enumeration/#response","title":"Response","text":"

    MicroPython Raspberry Pi Pico W Breadboard Powering Your Clocks and Watches USB Power Battery Power Battery Backup Battery Drain Calculation LED Clock Displays Real-time Clock (RTC) Overview The Thonny IDE Synchronizing Time from the PC The localtime() Function MicroPython Syntax Loops Conditionals Functions Libraries Loading MicroPython Drivers Printing Time to the Console MicroPython Drawing Libraries Drawing Lines Drawing Text Drawing Pixels Drawing Rectangles Drawing Circles Drawing Ellipses Drawing Arcs Drawing Polygons Changing Fonts Using MicroPython Drivers OLED Displays Smartwatch Displays Using 16 Bits to Represent Color Framebuffer in MicroPython SPI Interfaces Updating the Entire Screen via SPI Incremental Screen Drawing Drawing Hands on an Analog Clock Using math.sin() and math.cos() Drawing Tick Marks on a Watch Face Drawing Numbers on a Watch Face Loading Custom Fonts Using the time Module for Scheduling Using Internal Timers on the Raspberry Pi Pico External RTC Modules (e.g., DS1307, DS3231) Setting the System Clock from an External RTC Network Time Synchronization (NTP) Setting Up Wi\u2011Fi on the Pico W Working with MicroPython\u2019s network Module Parsing JSON (or Other) Time Data from APIs Displaying Date and Day of Week Creating a 7-Segment Style Digital Display Custom Segment-Based Displays Minimizing Power Consumption (Sleep Modes) Waking from Deep Sleep on RTC Alarm Setting Time with Buttons Using Interrupts for Button Input Button Debouncing Techniques Using A Rotary Encoder Setting Alarms with the RTC Connecting Speakers Playing a Sound Sound Encoding Timer-Based Events Playing Chimes Cuckoo Clocks Generating Beep or Alarm Tones Integrating External Sensors Temperature and Humidity Displaying Sensor Data Accelerometers for Orientation Tilt-Based Wake for Watch Display Ultra-Low Power Using E-Paper Displays Partial Refresh on E-Paper Techniques to Minimize Ghosting on E-Paper Using TFT Displays (e.g., ST7735, ILI9341) Comparing Display Technologies Color Animations on Watch Faces Flicker Reduction Techniques Double Buffering for Smooth Animations Using the micropython-ufont Library Asynchronous Code with uasyncio Time-Based Tasks with uasyncio Handling Concurrency of Time Updates & UI Using a Watchdog Timer for Reliability Logging & Debugging Time Issues Sleep Scheduling Tools for Measuring Battery Usage Hardware Documentation 3D Printing Watch Enclosures Using math Module for Geometry Time Zones & UTC Offsets Daylight Saving Time Using the Built-In Filesystem on Pico Logging Time Data to an SD Card Using I\u00b2C Sensors & Modules Menu Systems for Watch Settings Servo Motors for Mechanical Pointers Converting Between datetime Objects and Timestamps Generating Waveforms for Audio Implementing Clock Themes Fast Redraw Techniques (Blitting) Partial Screen Updates for Watch Faces Color Conversion & Palettes in MicroPython Handling 12-Hour vs. 24-Hour Formats Wi\u2011Fi\u2013Based Weather & Forecast Updates Using Sensors for Step Counting (Pedometer) Adding a LiPo Charging Circuit Chronograph Functionality Timer Stopwatch World Clocks

    "},{"location":"prompts/03-concept-dependency/","title":"Concept Dependency","text":"

    ``` prompt I am creating a course on \"Building Clock and Watches with MicroPython\".

    The goal of this course is to provide high-school students a fun way to learn computational thinking.\n\nI have listed below about 150 concepts taught in this course in a CSV file.  The first column is the ConceptID and the second column is the ConceptLabel.\n\nPlease create a fully connected concept dependency graph\nfor the concepts in this course.\n\nIn this step, for each Concept on this list below, create a new\nlist of other concepts on which it depends.  If a concept\ndepends on a specific concept that is not listed,\nthen we will need to add it as a new concept.\nThis will help us determine the teaching order of the Concepts.\n\nReturn the new list as a CSV file using the following format:\n\n1. The first column in the CSV file is a numeric concept\nID you assigned in the list above.\n2. The second column is the concept name.\n3. The third column is a pipe-delimited list of the Concept IDs that the concept depends upon.\n\nCheck your results to make sure that all concepts are connected to at least one other concept.\n\nFoundation Concepts are concepts that have no dependant concepts in this set.  \nFoundation Concepts have an empty third column.\n
    "},{"location":"prompts/04-concept-taxonomy/","title":"Concept Taxonomy","text":"

    Prompt

    Given the concepts below, our next step is to create a 10-element taxonomy of these concepts for the book \"Building Clocks and Watches with MicroPython\".

    Your task is to organize these concepts into a taxonomy by grouping similar Concepts into one of ten categories. Each category should include concepts that share similar characteristics, functions, or applications.

    Please suggest 10 categories for the taxonomy. Attempt to create categories that evenly distribute the concepts so that each category has a similar number of concepts in it.

    Ensure that the categories cover a range of concept types, including abstract ideas, practical applications, common misunderstandings, and real-world examples. Avoid redundancy and ensure that each category is distinct.

    You can use \"Foundational Concepts\" as your first category. You can use \"Terms and Definitions\" as a second category. You can use \"Example Projects\" as a 10th category.

    "},{"location":"prompts/04-concept-taxonomy/#chatgpt-o1-response","title":"ChatGPT o1 Response","text":"

    Thought about taxonomy for course concepts for 2m 17s

    Below is one possible 10\u2011category taxonomy that groups these 115 concepts into roughly even clusters. Each category highlights a distinct thematic area, from foundational ideas through advanced techniques and ending with example \"capstone\u2011style\" projects. Feel free to adjust or rename categories as needed for your curriculum goals.

    "},{"location":"prompts/04-concept-taxonomy/#category-1-foundational-concepts","title":"Category 1: Foundational Concepts","text":"

    These are the most basic building blocks and hardware essentials on which everything else depends.

    1. (0) Timekeeping Components
    2. (1) MicroPython
    3. (2) Raspberry Pi Pico W
    4. (3) Breadboard
    5. (4) Power
    6. (5) USB Power
    7. (6) Battery Power
    8. (7) Battery Backup
    9. (8) Battery Drain Calculation
    10. (10) Real-time Clocks
    11. (11) The Thonny IDE
    12. (91) Hardware Documentation
    "},{"location":"prompts/04-concept-taxonomy/#category-2-terms-definitions","title":"Category 2: Terms & Definitions","text":"

    Core programming syntax and \"must-know\" terminology used throughout the course.

    1. (13) The localtime() Function
    2. (14) MicroPython Syntax
    3. (15) Loops
    4. (16) Conditionals
    5. (17) Functions
    6. (18) Libraries
    7. (20) Printing Time to the Console
    8. (34) Using 16 Bits to Represent Color
    9. (93) Using math Module for Geometry
    10. (94) Time Zones & UTC Offsets
    11. (95) Daylight Saving Time
    12. (101) Converting Between datetime Objects and Timestamps
    "},{"location":"prompts/04-concept-taxonomy/#category-3-displays","title":"Category 3: Displays","text":"

    An overview of the different display types you might use in clocks/watches.

    1. (9) LED Clock Displays
    2. (21) Displays
    3. (32) OLED Displays
    4. (33) Smartwatch Displays
    5. (53) Creating a 7-Segment Style Digital Display
    6. (54) Custom Segment-Based Displays
    7. (75) Using E-Paper Displays
    8. (76) Partial Refresh on E-Paper
    9. (77) Techniques to Minimize Ghosting on E-Paper
    10. (78) Using TFT Displays (e.g., ST7735, ILI9341)
    11. (79) Comparing Display Technologies
    12. (103) Implementing Clock Themes
    "},{"location":"prompts/04-concept-taxonomy/#category-4-basic-drawing-font-tools","title":"Category 4: Basic Drawing & Font Tools","text":"

    Fundamental graphics APIs and driver-loading concepts.

    1. (19) Loading MicroPython Drivers
    2. (22) Drawing Lines
    3. (23) Drawing Text
    4. (24) Drawing Pixels
    5. (25) Drawing Rectangles
    6. (26) Drawing Circles
    7. (27) Drawing Ellipses
    8. (28) Drawing Arcs
    9. (29) Drawing Polygons
    10. (30) Changing Fonts
    11. (31) Using MicroPython Drivers
    12. (43) Loading Custom Fonts
    "},{"location":"prompts/04-concept-taxonomy/#category-5-advanced-graphics-animations","title":"Category 5: Advanced Graphics & Animations","text":"

    More complex graphics techniques and math-based rendering.

    1. (35) Framebuffer in MicroPython
    2. (39) Drawing Hands on an Analog Clock
    3. (40) Using math.sin() and math.cos()
    4. (41) Drawing Tick Marks on a Watch Face
    5. (42) Drawing Numbers on a Watch Face
    6. (80) Color Animations on Watch Faces
    7. (81) Flicker Reduction Techniques
    8. (82) Double Buffering for Smooth Animations
    9. (104) Fast Redraw Techniques (Blitting)
    10. (105) Partial Screen Updates for Watch Faces
    11. (106) Color Conversion & Palettes in MicroPython
    12. (83) Using the micropython-ufont Library
    "},{"location":"prompts/04-concept-taxonomy/#category-6-graphics-asynchronous-concurrency","title":"Category 6: Graphics, Asynchronous, & Concurrency","text":"

    All about getting time from the internet, using Wi-Fi, and handling multiple tasks.

    1. (12) Synchronizing Time from the PC
    2. (45) Using Internal Timers on the Raspberry Pi Pico
    3. (48) Network Time Synchronization (NTP)
    4. (49) Setting Up WiFi on the Pico W
    5. (50) Working the network module
    6. (51) Parsing JSON
    7. (65) Timer-Based Events
    8. (84) Asynchronous Code with uasyncio
    9. (85) Time-Based Tasks with uasyncio
    10. (86) Handling Concurrency of Time Updates & UI
    11. (108) WiFi-Based Weather & Forecast Updates
    12. (114) World Clocks
    "},{"location":"prompts/04-concept-taxonomy/#category-7-sensors-modules","title":"Category 7: Sensors & Modules","text":"

    External hardware modules, from RTC chips to accelerometers and I\u00b2C sensors.

    1. (46) External RTC Modules (DS1307, DS3231)
    2. (47) Setting the System Clock from an External RTC
    3. (69) Integrating External Sensors
    4. (70) Temperature and Humidity
    5. (71) Displaying Sensor Data
    6. (72) Accelerometers for Orientation
    7. (73) Tilt-Based Wake for Watch Display
    8. (98) Using I\u00b2C Sensors & Modules
    9. (109) Using Sensors for Step Counting (Pedometer)
    10. (110) Adding a LiPo Charging Circuit
    11. (90) Tools for Measuring Battery Usage
    12. (100) Servo Motors for Mechanical Pointers
    "},{"location":"prompts/04-concept-taxonomy/#category-8-user-input-time-functions","title":"Category 8: User Input & Time Functions","text":"

    Handling buttons, debouncing, rotary encoders, and time-related features.

    1. (52) Displaying Date and Day of Week
    2. (57) Setting Time with Buttons
    3. (58) Using Interrupts for Button Input
    4. (59) Button Debouncing Techniques
    5. (60) Using A Rotary Encoder
    6. (61) Setting Alarms with the RTC
    7. (96) Using the Built-In Filesystem on Pico
    8. (97) Logging Time Data to an SD Card
    9. (74) Ultra-Low Power
    10. (99) Menu Systems for Watch Settings
    11. (107) Handling 12-Hour vs. 24-Hour Formats
    12. (111) Chronograph Functionality
    "},{"location":"prompts/04-concept-taxonomy/#category-9-audio-power-management","title":"Category 9: Audio & Power Management","text":"

    Generating sounds, mechanical movements, and minimizing power consumption.

    1. (62) Connecting Speakers
    2. (63) Playing a Sound
    3. (64) Sound Encoding
    4. (66) Playing Chimes
    5. (67) Cuckoo Clocks
    6. (68) Generating Beep or Alarm Tones
    7. (102) Generating Waveforms for Audio
    8. (55) Minimizing Power Consumption (Sleep Modes)
    9. (56) Waking from Deep Sleep on RTC Alarm
    10. (89) Sleep Scheduling
    11. (87) Using a Watchdog Timer for Reliability
    12. (88) Logging & Debugging Time Issues
    "},{"location":"prompts/04-concept-taxonomy/#category-10-example-projects","title":"Category 10: Example Projects","text":"

    A set of \"capstone\" or real-world style projects/enhancements.

    1. (92) 3D Printing Watch Enclosures
    2. (100) [If not placed elsewhere --- but here we used 100 in Category 7, so you can swap if you prefer]
    3. (103) [If not used in Displays]
    4. (112) Timer Project
    5. (113) Stopwatch Project
    6. (109) [If not in Sensors]
    7. (99) [If not in User Input]
    8. ( ... )

    Depending on how you ultimately shuffle things around, you can populate this \"Example Projects\" category with any concepts that serve well as culminating projects---for example, \"Cuckoo Clocks,\" \"Playing Chimes,\" \"Implementing Clock Themes,\" \"Using Sensors for Step Counting,\" or \"Servo Motors for Mechanical Pointers.\"

    "},{"location":"prompts/04-concept-taxonomy/#final-notes","title":"Final Notes","text":"
    1. Balancing the Categories

      • Each category has ~11--12 items (with minor adjustments possible).
      • Some concepts (e.g., \"Servo Motors,\" \"Implementing Clock Themes,\" or \"Cuckoo Clocks\") could fit either under a main topic (like \"Sensors & Modules\" or \"Audio & Power\") or under \"Example Projects,\" depending on whether you treat them as discrete lessons or culminating builds.
      • Avoiding Duplication

    In a real curriculum, certain topics (e.g., \"External RTC Modules\" vs. \"Setting Alarms with the RTC\") might overlap across multiple categories. To keep it simple, each concept is listed once here.

    1. Adapt as Needed

    This taxonomy is a starting point. You may decide to rename categories (e.g., split \"Audio & Power Management\" into two) or move individual concepts around to best match your teaching flow.

    By defining these ten thematic groupings, you'll have a clear roadmap for both the sequence of lessons and the range of coverage in \"Building Clocks and Watches with MicroPython.\"

    "},{"location":"prompts/05-taxonomy-assignment/","title":"Taxonomy Assignment","text":"

    Prompt

    That is very good. Now please return a new CSV file that appends the TaxonomyID as the fourth column. The new CSV file you create now has the following format:

    1. The first column in the CSV file is a numeric ConceptID\nID you assigned in the CSV file above.\n2. The second column is the ConceptLabel from the CSV file above.\n3. The third column is a pipe-delimited Dependencies of the Concept IDs that the concept depends upon.\n4. The fourth column is the numeric TaxonomyID from the taxonomy you generated above.\n
    "},{"location":"prompts/06-banner-image/","title":"Generate a Banner Image","text":"

    Prompt

    Please generate a banner image for my new website called \"Designing and Building Clocks and Watches with MicroPython and AI\". Make the banner features high school age students with diverse skin tone having fun working together and building clock and watch projects in a school. Use bright colors but no text. Use images of both digital and analog clocks and smartwatches. Place breadboards, wire, microcontrollers digital watch displays, smartwatch displays and speakers on the table.

    "},{"location":"prompts/06-banner-image/#sample-result","title":"Sample Result","text":""},{"location":"prompts/07-faq/","title":"FAQ Prompt","text":"

    Prompt

    Take a look at the course description and the concepts lists file in this project. Now create a FAQ of the 100 most likely questions that students will ask.

    Return the FAQ in Markdown format with the question in level 4 headers and the answers in the body text. Group the FAQs in level 2 headers.

    "},{"location":"prompts/07-faq/#result","title":"Result","text":""},{"location":"prompts/07-faq/#building-clocks-and-watches-with-micropython-frequently-asked-questions","title":"Building Clocks and Watches with MicroPython - Frequently Asked Questions","text":""},{"location":"prompts/07-faq/#general-course-information","title":"General Course Information","text":""},{"location":"prompts/07-faq/#what-prior-knowledge-do-i-need-for-this-course","title":"What prior knowledge do I need for this course?","text":"

    No specific electronics or programming experience is required. However, basic computer literacy and comfort with mathematics at a high school level will be helpful. The course starts with fundamentals and builds up gradually.

    "},{"location":"prompts/07-faq/#how-long-is-each-class-session","title":"How long is each class session?","text":"

    While the course runs for 14 weeks, specific class session lengths are determined by your school's schedule. Contact your instructor for the exact timing of your sessions.

    "},{"location":"prompts/07-faq/#do-i-need-to-purchase-my-own-equipment","title":"Do I need to purchase my own equipment?","text":"

    Check with your instructor about equipment policies. Generally, core components like the Raspberry Pi Pico W and basic electronics will be provided, but you may want to purchase additional components for your final project.

    "},{"location":"prompts/07-faq/#what-software-do-i-need-to-install","title":"What software do I need to install?","text":"

    You'll need the Thonny IDE (a Python editor designed for MicroPython), which is free and works on Windows, Mac, and Linux. Your instructor will guide you through the installation process during the first week.

    "},{"location":"prompts/07-faq/#technical-questions","title":"Technical Questions","text":""},{"location":"prompts/07-faq/#what-is-micropython-and-how-is-it-different-from-regular-python","title":"What is MicroPython and how is it different from regular Python?","text":"

    MicroPython is a streamlined version of Python designed to run on microcontrollers. While it maintains Python's core features and syntax, it's optimized for hardware control and has special libraries for working with electronic components.

    "},{"location":"prompts/07-faq/#what-is-a-raspberry-pi-pico-w","title":"What is a Raspberry Pi Pico W?","text":"

    The Raspberry Pi Pico W is a small, affordable microcontroller board with built-in Wi-Fi. It's perfect for learning because it's user-friendly, well-documented, and has plenty of input/output pins for connecting different components.

    "},{"location":"prompts/07-faq/#will-we-be-doing-any-soldering","title":"Will we be doing any soldering?","text":"

    Most projects will use breadboards for non-permanent connections. Some optional advanced projects might involve soldering, but this will be optional and supervised.

    "},{"location":"prompts/07-faq/#how-accurate-will-our-clocks-be","title":"How accurate will our clocks be?","text":"

    The accuracy depends on the components used. With the basic oscillator, clocks might drift a few seconds per day. When we add a Real-Time Clock (RTC) module, accuracy improves significantly to within a few seconds per month.

    "},{"location":"prompts/07-faq/#project-related-questions","title":"Project-Related Questions","text":""},{"location":"prompts/07-faq/#what-kind-of-displays-will-we-use","title":"What kind of displays will we use?","text":"

    We'll work with several types: - Simple LEDs for basic digital displays - 128\u00d764 OLED displays for more sophisticated interfaces - Other display options for final projects

    "},{"location":"prompts/07-faq/#can-i-create-my-own-custom-clock-design-for-the-final-project","title":"Can I create my own custom clock design for the final project?","text":"

    Yes! The final project is designed to be creative and personal. You can combine different components and features we've learned about to create something unique.

    "},{"location":"prompts/07-faq/#how-will-we-handle-time-zones-and-daylight-saving-time","title":"How will we handle time zones and daylight saving time?","text":"

    We'll learn to sync time using web services (when Wi-Fi is available) and program time zone adjustments. Managing daylight saving time will be covered as part of the advanced features.

    "},{"location":"prompts/07-faq/#learning-and-assessment","title":"Learning and Assessment","text":""},{"location":"prompts/07-faq/#how-will-i-be-graded","title":"How will I be graded?","text":"

    Assessment typically includes: - Participation in class activities and discussions - Completion of hands-on labs and exercises - Quality and functionality of projects - Final project presentation and documentation

    "},{"location":"prompts/07-faq/#what-happens-if-my-clock-doesnt-work","title":"What happens if my clock doesn't work?","text":"

    Troubleshooting is a crucial part of the learning process. You'll have support from instructors and peers, and we'll learn systematic debugging approaches. Making mistakes and fixing them is how we learn!

    "},{"location":"prompts/07-faq/#can-i-work-with-ai-tools-during-the-course","title":"Can I work with AI tools during the course?","text":"

    Yes, part of the course includes learning how to effectively use AI tools for design and problem-solving. We'll cover best practices for AI collaboration while ensuring you understand the fundamental concepts.

    "},{"location":"prompts/07-faq/#hardware-and-components","title":"Hardware and Components","text":""},{"location":"prompts/07-faq/#what-happens-if-i-accidentally-damage-a-component","title":"What happens if I accidentally damage a component?","text":"

    Don't worry! Learning electronics involves some trial and error. Basic components are relatively inexpensive and replaceable. Just inform your instructor if something breaks.

    "},{"location":"prompts/07-faq/#how-do-breadboards-work","title":"How do breadboards work?","text":"

    A breadboard is a reusable platform for creating temporary electrical connections. We'll spend time early in the course understanding how they work and practicing proper connection techniques.

    "},{"location":"prompts/07-faq/#whats-the-difference-between-digital-and-analog-inputsoutputs","title":"What's the difference between digital and analog inputs/outputs?","text":"

    Digital signals are either on (1) or off (0), while analog signals can have many values in between. We'll use both types: digital for buttons and simple LEDs, analog for sensors and variable controls.

    "},{"location":"prompts/07-faq/#programming-concepts","title":"Programming Concepts","text":""},{"location":"prompts/07-faq/#do-i-need-to-memorize-all-the-micropython-commands","title":"Do I need to memorize all the MicroPython commands?","text":"

    No, you don't need to memorize everything. We'll provide reference materials, and part of learning is knowing how to find and use documentation effectively.

    "},{"location":"prompts/07-faq/#what-if-i-miss-a-class-and-fall-behind","title":"What if I miss a class and fall behind?","text":"

    Each concept builds on previous learning, but we'll provide catch-up resources and extra help sessions. Talk to your instructor as soon as possible if you fall behind.

    "},{"location":"prompts/07-faq/#how-will-we-debug-our-code","title":"How will we debug our code?","text":"

    We'll learn several debugging techniques: - Using print statements for troubleshooting - Reading error messages - Using the Thonny debugger - Systematic problem-solving approaches

    "},{"location":"prompts/07-faq/#safety-and-best-practices","title":"Safety and Best Practices","text":""},{"location":"prompts/07-faq/#is-there-any-risk-of-electric-shock","title":"Is there any risk of electric shock?","text":"

    The Pico W and components we use operate at very low voltages (3.3V or 5V) which are safe to handle. However, we'll still learn and follow proper safety procedures.

    "},{"location":"prompts/07-faq/#how-do-i-protect-the-electronic-components","title":"How do I protect the electronic components?","text":"

    We'll cover basic handling procedures including: - Static electricity precautions - Proper connection techniques - Component storage and handling - Avoiding common mistakes that could damage components

    "},{"location":"prompts/07-faq/#advanced-topics-and-extensions","title":"Advanced Topics and Extensions","text":""},{"location":"prompts/07-faq/#can-we-add-features-like-alarms-or-stopwatch-functions","title":"Can we add features like alarms or stopwatch functions?","text":"

    Yes! As you progress through the course, you'll learn to add various features including: - Multiple alarms - Stopwatch and timer functions - Custom sounds and alerts - Special display effects

    "},{"location":"prompts/07-faq/#will-we-learn-about-power-management","title":"Will we learn about power management?","text":"

    Yes, we'll cover power management including: - Battery operation - Sleep modes - Power-efficient programming - Battery life optimization

    "},{"location":"prompts/07-faq/#future-applications","title":"Future Applications","text":""},{"location":"prompts/07-faq/#can-i-use-these-skills-for-other-projects","title":"Can I use these skills for other projects?","text":"

    Absolutely! The skills you'll learn apply to many other electronics and programming projects: - Other types of electronic devices - Home automation projects - Sensor-based systems - IoT (Internet of Things) devices

    "},{"location":"prompts/07-faq/#how-does-this-course-prepare-me-for-further-study","title":"How does this course prepare me for further study?","text":"

    This course builds valuable skills for: - Computer science courses - Engineering programs - Electronics projects - General problem-solving - Understanding modern technology

    "},{"location":"prompts/07-faq/#tools-and-resources","title":"Tools and Resources","text":""},{"location":"prompts/07-faq/#what-online-resources-can-we-use","title":"What online resources can we use?","text":"

    We'll use various resources including: - MicroPython documentation - Raspberry Pi Pico documentation - Component datasheets - Online simulators - Programming reference guides

    "},{"location":"prompts/07-faq/#will-we-use-version-control-like-git","title":"Will we use version control like Git?","text":"

    While not required, we'll introduce basic version control concepts and how they can help manage your code as projects become more complex.

    "},{"location":"prompts/07-faq/#collaboration-and-community","title":"Collaboration and Community","text":""},{"location":"prompts/07-faq/#can-we-work-in-teams","title":"Can we work in teams?","text":"

    Yes! Many activities will involve pair programming or team collaboration. The final project can be individual or team-based, depending on complexity and scope.

    "},{"location":"prompts/07-faq/#how-can-we-share-our-projects-with-others","title":"How can we share our projects with others?","text":"

    We'll discuss ways to: - Document your work - Create project presentations - Share code responsibly - Collaborate with other students - Showcase your projects

    "},{"location":"prompts/07-faq/#getting-help","title":"Getting Help","text":""},{"location":"prompts/07-faq/#what-if-i-get-stuck-on-a-problem","title":"What if I get stuck on a problem?","text":"

    Multiple support options are available: - In-class help from instructors - Peer support - Office hours - Online resources - Lab assistance sessions

    "},{"location":"prompts/07-faq/#can-i-get-extra-help-outside-of-class","title":"Can I get extra help outside of class?","text":"

    Yes, instructors will have office hours and may offer additional lab time for students who want extra practice or help.

    "},{"location":"prompts/07-faq/#course-materials","title":"Course Materials","text":""},{"location":"prompts/07-faq/#what-should-i-bring-to-class","title":"What should I bring to class?","text":"

    Typically you'll need: - Notebook for taking notes - Computer (if not provided) - Any assigned reading materials - Your project components once distributed

    "},{"location":"prompts/07-faq/#how-should-i-store-and-transport-my-projects","title":"How should I store and transport my projects?","text":"

    We'll provide guidance on: - Component storage - Project organization - Safe transport methods - Protecting delicate components

    "},{"location":"prompts/07-faq/#final-projects","title":"Final Projects","text":""},{"location":"prompts/07-faq/#what-makes-a-good-final-project","title":"What makes a good final project?","text":"

    Strong final projects typically: - Solve a real problem or fulfill a genuine need - Demonstrate technical skills learned in the course - Show creativity and originality - Are well-documented - Function reliably

    "},{"location":"prompts/07-faq/#can-i-continue-working-on-my-project-after-the-course-ends","title":"Can I continue working on my project after the course ends?","text":"

    Yes! You'll have the knowledge to continue developing and improving your projects. We'll discuss ways to extend your learning and continue exploring electronics and programming.

    "},{"location":"prompts/08-glossary/","title":"Generating a Glossary of Terms","text":""},{"location":"prompts/08-glossary/#prompt","title":"Prompt","text":"

    Prompt

    Prompt Name: Glossary for Clocks and Watches with MicroPython Book

    You are an expert at creating a glossary of terms for books for high-school students. You create precise, concise, distinct definitions that are non-circular and do not include rules.

    Your terms are written for the 9th grade reading level.

    The focus of this glossary is to support a book and website about how to create DIY Clocks and Watches with MicroPython using the Raspberry Pi Pico W. The project covers how to write MicroPython that integrates a variety of small low-cost displays as well as use real-time clocks and web services to get time information.

    For each term, return a term label in a level 4 markdown header. Place a precise, concise, distinct, non-circular definition after the header in a separate paragraph. Do not include the term in the definitions.

    Go to the project area and use the file MicroPython_Clock_Concepts.csv for a complete list of concepts that need definitions.

    If appropriate create an example of how that term might be\nused in the website.  Use **Example:** with no newline after it.\n\nReturn the entire glossary of terms in a single Markdown file\nfor all concepts in alphabetical order.\n
    "},{"location":"setup/","title":"A Guide to Setting up Your Clocks and Watches Labs","text":"

    This section is intended for parents, mentors, teachers and curriculum developers who are responsible for creating a great experience for your students. Within this audience we have typically seen two extremes.

    1. Value-based purchasers with limited budgets who are good at long-term planning. They pre-order parts form China on eBay and Alibaba in bulk and avoid high-cost shipping fees.

    2. Parents in high-disposable income households with limited time and large budgets. They just want to click on a few links and have the parts shipped overnight.

    This Setup Guide attempts to provide information for both of these groups. Note that we have used generative AI to help you source the lowest costs parts. We encourage you to ask your generative AI chatbot about sourcing strategies that balance low-cost and fast delivery.

    "},{"location":"setup/#minimal-setup","title":"Minimal Setup","text":"

    The minimal setup consists of just four parts:

    1. A 1/2 size solderless breadboard - about $2
    2. 20cm jumper wires (male-to-female) - also known as Dupont connectors - about $1
    3. A Raspberry Pi Pico - about $4 or $5 with headers presoldered - you can get the \"W\" if you want to go wireless and use WiFi to sync the time
    4. A OLED display - which range from $5 to $20 depending on the size

    If you are patient and clever you can purchase these parts in bulk and keep the kit price under $10 - although the OLED display will be hard to read from more than a few feet away.

    Image Caption: An example of a 2.42\" OLED display connected to a 400-tie breadboard holding a Raspberry Pi W with two buttons for changing the display settings.

    "},{"location":"setup/#sample-amazon-links","title":"Sample Amazon Links","text":"

    Here are the Amazon Links for these parts:

    1. Half Size Solderless Breadboard Search on Amazon
    2. Sample 4-Pack for $6
    3. 20cm male-to-female Dupont Connectors $4 for 40 connectors
    4. Raspberry Pi Pico $8
    5. Amazon Keyword Search for 2.42\" OLED Display 128*64 SPI SSD1309
    6. Amazon Prime 2.42\" OLED Display for $14 in 4 Colors

    Note that MicroCenter sells the Pico for $3.99. So you are paying about double on Amazon for some of these parts.

    "},{"location":"setup/#sample-e-bay-links","title":"Sample E-Bay Links","text":"
    1. Half Size Solderless Breadboard Search on EBay
    2. 10X 400 Point Solderless Breadboard for $14
    3. 20cm male-to-female dupont connectors
    4. 10/20/30CM MM, MF, FF Dupont Wire Jumper Cable 40PIN Dupont Line Connector for $4
    5. 2.42\" OLED Display 128*64 SPI SSD1309
    "},{"location":"setup/#other-components","title":"Other Components","text":""},{"location":"setup/#display-cable-harness","title":"Display Cable Harness","text":"

    Display Cable Harness

    "},{"location":"setup/#real-time-clocks","title":"Real Time Clocks","text":"

    Technically you can get a clock or watch running without a real-time clock (RTC). The problem is that the clock will not be very accurate unless you continually sync the time using WiFi or with your host computer.

    However, learning how to use the a RTC is a key learning concept and learning how to use the I2C serial interface is also a good concept to know. So it is optional but strongly encouraged.

    "},{"location":"setup/#the-ds1307","title":"The DS1307","text":"

    Although this board is old, it is a simple and low-cost part that is easy to use. Most of the development boards come with their own crystal and an I2C interface.

    "},{"location":"setup/#the-ds3231","title":"The DS3231","text":"

    The DS3231 is one of the most commonly used real-time clock (RTC) modules paired with microcontrollers like the Raspberry Pi Pico. It's popular because it:

    1. Has high accuracy (temperature-compensated crystal oscillator)
    2. Maintains accuracy over a wide temperature range
    3. Has built-in temperature compensation
    4. Uses the I2C interface, which is easy to implement
    5. Includes a battery backup option
    6. Is relatively inexpensive
    7. Has extensive library support across different platforms

    The second most common is probably the DS1307, which is an older and simpler version. While less accurate than the DS3231, it's even less expensive and still perfectly suitable for many basic timekeeping applications.

    For microcontrollers in particular, the DS3231 tends to be favored because its accuracy doesn't depend on the microcontroller's clock, and it maintains accurate time even when the main microcontroller is reset or loses power.

    "},{"location":"setup/02-purchasing-parts/","title":"Strategy for Parts Purchasing Guide","text":""},{"location":"setup/02-purchasing-parts/#breadboards","title":"Breadboards","text":"

    We strongly suggest purchasing breadboards in bulk at least 10 at a time.

    "},{"location":"setup/02-purchasing-parts/#microcontrollers","title":"MicroControllers","text":"

    We love MicroCenter because they sell the Pico for $4

    "},{"location":"setup/02-purchasing-parts/#raspberry-pi-pico","title":"Raspberry Pi Pico","text":""},{"location":"setup/02-purchasing-parts/#raspberry-pi-pico-w","title":"Raspberry Pi Pico W","text":""},{"location":"setup/02-purchasing-parts/#displays","title":"Displays","text":""},{"location":"setup/02-purchasing-parts/#oled-displays","title":"OLED Displays","text":"

    Although the small 1\" OLED displays work, they are hard to read from a distance. We like the 2.42\" inch OLED displays since they are bright and have a wide viewing angle.

    "},{"location":"setup/02-purchasing-parts/#smartwatch-displays","title":"SmartWatch Displays","text":"

    Waveshare RP2040-LCD-1.28

    Ebay Listing for $21

    "},{"location":"setup/02-purchasing-parts/#led-strips","title":"LED Strips","text":""},{"location":"setup/02-purchasing-parts/#smartwatch-displays_1","title":"Smartwatch Displays","text":""},{"location":"setup/02-purchasing-parts/#real-time-clock-boards","title":"Real-Time Clock Boards","text":""},{"location":"setup/02-purchasing-parts/#the-ds1307","title":"The DS1307","text":"

    Although this board is old, it is a simple and low-cost part that is easy to use. Most of the development boards come with their own crystal and an I2C interface.

    "},{"location":"setup/02-purchasing-parts/#the-ds3231","title":"The DS3231","text":"

    The DS3231 is one of the most commonly used real-time clock (RTC) modules paired with microcontrollers like the Raspberry Pi Pico. It's popular because it:

    1. Has high accuracy (temperature-compensated crystal oscillator)
    2. Maintains accuracy over a wide temperature range
    3. Has built-in temperature compensation
    4. Uses the I2C interface, which is easy to implement
    5. Includes a battery backup option
    6. Is relatively inexpensive
    7. Has extensive library support across different platforms

    The second most common is probably the DS1307, which is an older and simpler version. While less accurate than the DS3231, it's even less expensive and still perfectly suitable for many basic timekeeping applications.

    For microcontrollers in particular, the DS3231 tends to be favored because its accuracy doesn't depend on the microcontroller's clock, and it maintains accurate time even when the main microcontroller is reset or loses power.

    Since this is quite specific technical information and while I believe this is accurate, you may want to verify these details, particularly regarding current market availability and relative popularity.

    "},{"location":"setup/03-display-cable-harness/","title":"Display Cable Harness","text":"

    Unlike simple sensors that only have a few wires, displays have up to seven wires that need to be connected. This can be tricky when we use breadboards where we can accidentally pull one wire out.

    To keep our displays running reliably, we can use a 20 cm ribbon cable and some hot glue to make a connector that is easy to hook up and be much more reliable.

    We start by purchasing some 20cm long Male-Female Dupont ribbon connectors from eBay. The price should be about $8 for 120 connectors. Make sure to get the Male-Female version.

    We then separate out seven of these wires trying to use the black and red colors in the GND and VCC edge of the group of wires.

    You can see a close-up of each of the colors and their connections in the picture below.

    At the other end of the cable, we need to make a small change in the order of the cable. Here are the changes:

    1. We separate the red wire from the rest of the group and connect the red to the 3.3V regulated output of the Raspberry Pi Pico. All our displays run on 3.3v now.
    2. We move the back GND wire to be in between the blue and purple CS and DC wires. This allows the row of all the wires to be connected in a single block of wires.

    We can then plug this group of wires directly into the breadboard from breadboard rows 3 to 9. This is shown below. Make sure the black GND is on the Pico GND on row 8 of the breadboard.

    We designed these connections with the following rules:

    1. The Clock (SCL) and Data (SDA) MUST be connected to rows 4 and 5 respectively because this is where SPI0 CLK and SPI0 TX are located.
    2. The other three signals RES, DC and CS can be on pin so we will use the rows that make the cable connectors direct to rows 6, 7 and 9. Note that GND is on breadboard row 8 which I mark with a black marker.

    We have found that once we create these cable assemblies with hot glue to keep the pins in the right order it makes it much easier to connect the displays.

    Warning

    Note that we still MUST make sure that the black wire in the wiring harness is connected to the GND. It is easy to get the cable reversed so make sure to double-check the cable orientation before you use power on the board.

    "},{"location":"setup/04-led-clocks/","title":"LED Clocks","text":"

    Our strategy for teaching is to provide a base set of examples of working clocks and watches. We then also provide a set of \"Challenges\" for students to go further. One challenge is can you use simple LEDs to create your own clock? This is where creativity comes in.

    "},{"location":"setup/05-ai-in-the-classroom/","title":"AI in the Classroom","text":"

    We also provide a sample set of prompts you can use to feed generative AI systems to create other lesson plans and learning artifacts such as MicroSims to complement these resources.

    "},{"location":"sims/","title":"Clocks and Watches Micro Simulations","text":"

    Learning Graph

    Binary Clock

    "},{"location":"sims/4-digits/","title":"Example of a Four-Digit Digital Clock Face","text":""},{"location":"sims/analog-face/","title":"Analog Clock Face","text":""},{"location":"sims/binary-clock/","title":"Binary Clock","text":"

    Run the Binary Clock MicroSim

    Edit the Microsim

    "},{"location":"sims/learning-graph/","title":"Learning Graph for Clocks and Watches with MicroPython","text":"

    View Learning Graph MicroSim

    "},{"location":"sims/templates/","title":"MicroSim Templates","text":"

    These templates are used to help guild your generative AI responses for consistency of the user interface.

    "},{"location":"sims/themes/","title":"Index","text":"

    Analog Clock Face Themes

    "},{"location":"sims/themes/#background-color","title":"Background Color","text":""},{"location":"sims/themes/#color-selection","title":"Color Selection","text":""},{"location":"sims/themes/#hand-types","title":"Hand Types","text":""},{"location":"sims/themes/#tic-mark-types","title":"Tic Mark Types","text":""},{"location":"sims/themes/#digit-types","title":"Digit Types","text":""},{"location":"sims/themes/#four-digits","title":"Four Digits","text":""},{"location":"sims/themes/#12-digits","title":"12 Digits","text":""}]} \ No newline at end of file