# imports
import machine
import math
import time
from machine import Pin

#######################################
# Pin and constant definitions
#######################################
button_1 = machine.Pin(16, Pin.IN, Pin.PULL_UP)

SEVEN_SEGMENT_START_PIN = 0
ANALOGUE_INPUT_PIN = 26  
DISPLAY_COUNT = 4
MEASUREMENT_COUNT = 16
DECIMAL_PRECISION = 3
ADC_RANGE = float((math.pow(2, 16) - 1))
DEBOUNCE_TIME_MS = 200

digit_list_hex = [
    0xC0, #0  -> 0b11000000
    0xF9, #1
    0xA4, #2
    0xB0, #3
    0x99, #4
    0x92, #5
    0x82, #6
    0xF8, #7
    0x80, #8
    0x90  #9
]

#######################################
# Global variables
#######################################
last_button_time = 0
display_value = 0
segment_pins = []
display_select_pins = []
analogue_voltage_pin = None
current_display_index = DISPLAY_COUNT - 1  
display_timer = None

#######################################
# Function definitions
#######################################

def read_analogue_voltage(pin):  
    global display_value, current_display_index, last_button_time
    
    # debouncing check
    current_time = time.ticks_ms()
    if time.ticks_diff(current_time, last_button_time) <= DEBOUNCE_TIME_MS:
        return
    last_button_time = current_time
    
    # read and average ADC values
    total_value = 0
    for _ in range(MEASUREMENT_COUNT):
        total_value += analogue_voltage_pin.read_u16()
    average_value = total_value // MEASUREMENT_COUNT

    analogue_voltage = round((average_value / ADC_RANGE) * 3.3, DISPLAY_COUNT - 1)
    new_display_val = int(analogue_voltage * math.pow(10, DECIMAL_PRECISION))

    max_val = math.pow(10, DISPLAY_COUNT) - 1
    if new_display_val > max_val:
        new_display_val = max_val

    print(f'voltage: {analogue_voltage * 1000:.0f} mV')
    display_value = new_display_val

    disable_display_timer()
    current_display_index = DISPLAY_COUNT - 1
    display_digit(16, -1)
    time.sleep(0.1)
    enable_display_timer()

# Function to disable timer that triggers scanning 7 segment displays
def disable_display_timer():
    global display_timer
    display_timer.deinit()

# Function to enable timer that triggers scanning 7 segment displays
def enable_display_timer():
    global display_timer
    display_timer.init(period=4, mode=machine.Timer.PERIODIC, callback=scan_display)

# Function to handle scanning 7 segment displays
def scan_display(timer_int):
    global current_display_index, display_value

    digit = int((abs(display_value) // math.pow(10, current_display_index))) % 10

    display_digit(digit, current_display_index, 
        current_display_index == DECIMAL_PRECISION and 0 != DECIMAL_PRECISION)

    current_display_index = (current_display_index - 1)
    if current_display_index < 0:
        current_display_index = DISPLAY_COUNT - 1

# Function display the given value on the display with the specified index
def display_digit(digit_value, digit_index, dp_enable=False):
    if digit_value < 0 or digit_value >= len(digit_list_hex):
        return

    for pin in display_select_pins:
        pin.value(0)

    mask = digit_list_hex[digit_value]
    for i in range(7):  
        segment_pins[i].value((mask >> i) & 1)

    segment_pins[7].value(1 if dp_enable == False else 0)

    if digit_index == -1:
        for pin in display_select_pins:
            pin.value(1)
    elif 0 <= digit_index < DISPLAY_COUNT:
        display_select_pins[digit_index].value(1)

# Function to test available 7-segment displays
def display_value_test():
    global current_display_index

    disable_display_timer()
    current_display_index = 0

    for i in range(0, len(digit_list_hex)):
        display_digit(i, -1, i % 2 != 0)
        time.sleep(0.75)

    for i in range(0, len(digit_list_hex)):
        display_digit(i, DISPLAY_COUNT - 1 - (i % DISPLAY_COUNT), True)
        time.sleep(0.75)        

    enable_display_timer()

# Function to setup GPIO/ADC pins, timers and interrupts
def setup():
    global segment_pins, display_select_pins, analogue_voltage_pin, display_timer

    for i in range(SEVEN_SEGMENT_START_PIN + 8, SEVEN_SEGMENT_START_PIN + 8 + DISPLAY_COUNT):
        pin = machine.Pin(i, machine.Pin.OUT)
        pin.value(0)
        display_select_pins.append(pin)

    for i in range(SEVEN_SEGMENT_START_PIN, SEVEN_SEGMENT_START_PIN + 8):
        pin = machine.Pin(i, machine.Pin.OUT)
        pin.value(1)
        segment_pins.append(pin)

    analogue_voltage_pin = machine.ADC(ANALOGUE_INPUT_PIN)

    display_timer = machine.Timer()
    enable_display_timer()
    
    button_1.irq(trigger=Pin.IRQ_FALLING, handler=read_analogue_voltage)

if __name__ == '__main__':
    setup()
    
    while True:
        time.sleep(0.01)  
$abcdeabcde151015202530fghijfghij
$abcdeabcde151015202530354045505560fghijfghij
BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT