import time
import board
import digitalio
# ----------------------------
# SET PARAMETERS
# ----------------------------
x = 30 # Initial countdown value (e.g., 30, 45, or 60 seconds)
interval = 1.0 # Countdown speed (1 second per count)
# ----------------------------
# BUTTON INPUTS
# ----------------------------
sw1 = digitalio.DigitalInOut(board.GP15) # Start button (SW1)
sw1.direction = digitalio.Direction.INPUT
sw1.pull = digitalio.Pull.UP # Pressed = LOW
sw2 = digitalio.DigitalInOut(board.GP16) # Reset/Stop button (SW2)
sw2.direction = digitalio.Direction.INPUT
sw2.pull = digitalio.Pull.UP # Pressed = LOW
# ----------------------------
# SHARED BCD DATA LINES (D0-D3)
# ----------------------------
A = digitalio.DigitalInOut(board.GP2) # BCD bit 0 (LSB)
B = digitalio.DigitalInOut(board.GP3) # BCD bit 1
C = digitalio.DigitalInOut(board.GP4) # BCD bit 2
D = digitalio.DigitalInOut(board.GP5) # BCD bit 3 (MSB)
for pin in [A, B, C, D]:
pin.direction = digitalio.Direction.OUTPUT
bcd_pins = [A, B, C, D]
# ----------------------------
# LATCH ENABLE PINS (CD4511 control)
# ----------------------------
s72 = digitalio.DigitalInOut(board.GP0) # TENS display latch
s72.direction = digitalio.Direction.OUTPUT
s71 = digitalio.DigitalInOut(board.GP1) # ONES display latch
s71.direction = digitalio.Direction.OUTPUT
# ----------------------------
# BCD FUNCTIONS
# ----------------------------
def send_bcd(value):
"""Send 4-bit BCD value to CD4511"""
for i in range(4):
bcd_pins[i].value = (value >> i) & 1
def latch(pin):
"""Latch data into 7-segment display"""
pin.value = 0 # Enable latch (active low)
time.sleep(0.001) # Hardware stability delay
pin.value = 1 # Disable latch
def display_number(num):
"""Display a 2-digit number on the 7-segment displays"""
tens = num // 10
ones = num % 10
send_bcd(tens)
latch(s72)
send_bcd(ones)
latch(s71)
def display_off():
send_bcd(15)
latch(s72)
send_bcd(15)
latch(s71)
# ----------------------------
# MAIN VARIABLES
# ----------------------------
count = x # Start from initial value x
running = False # Timer state (False = stopped, True = counting down)
display_off() # Initial blank display
# ----------------------------
# EDGE DETECTION VARIABLES
# ----------------------------
last_sw1_state = True
last_sw2_state = True
# ----------------------------
# MAIN LOOP
# ----------------------------
while True:
# Read current button states (True = not pressed, False = pressed)
sw1_pressed = not sw1.value
sw2_pressed = not sw2.value
# START BUTTON (SW1) - Rising edge detection
if sw1_pressed and not last_sw1_state:
if not running:
running = True
print(f"COUNTDOWN STARTED from {count:02d}")
# RESET/STOP BUTTON (SW2) - Rising edge detection
if sw2_pressed and not last_sw2_state:
running = False
count = x
display_off()
print(f"STOPPED & RESET to {x:02d} (Display OFF)")
# Update button states for next iteration
last_sw1_state = sw1_pressed
last_sw2_state = sw2_pressed
# COUNTDOWN PROCESS
if running:
# Update display with current count
display_number(count)
# Countdown logic (decrement every 'interval' seconds)
time.sleep(interval)
if count > 0:
count -= 1
print(f"Time remaining: {count:02d}")
# REACHED ZERO - Auto stop
if count == 0:
running = False
print("COUNTDOWN COMPLETE! Time's up! 🎯")
display_number(0) # Show "00" momentarily
time.sleep(0.5) # Brief pause to see "00"
display_off() # Turn off displays
count = x # Reset for next run
print(f"System stopped. Press SW1 to start from {x:02d}")
else:
# When not running, keep display OFF (per lab requirement)
# Small delay to prevent excessive looping
time.sleep(0.05)