import machine
import math
import time
# constant variables
SEVEN_SEGMENT_BASE_PIN = 0
ADC_INPUT_PIN = 26
BUTTON_INPUT_PIN = 16
NUM_DISPLAYS = 4
NUM_MEASUREMENTS = 4
DECIMAL_PLACES = 3
ADC_MAX_VALUE = float((math.pow(2, 16) - 1))
BUTTON_DEBOUNCE_DELAY = 200 # milliseconds
# 7 segment hex values
DIGIT_SEGMENTS = [
0x40, # 0
0x79, # 1
0x24, # 2
0x30, # 3
0x19, # 4
0x12, # 5
0x02, # 6
0x78, # 7
0x00, # 8
0x10, # 9
0x08, # A
0x03, # B
0x46, # C
0x21, # D
0x06, # E
0x0E, # F
0x7F # Empty
]
# global variables
current_display_value = 0
segment_output_pins = []
digit_select_pins = []
adc_pin = None
button_pin = None
active_display_index = NUM_DISPLAYS - 1
display_timer = None
last_adc_value = -1
last_button_press_time = 0
def read_adc_voltage(pin):
global current_display_value
global last_adc_value
total_adc_value = sum(pin.read_u16() for _ in range(NUM_MEASUREMENTS))
average_adc_value = total_adc_value // NUM_MEASUREMENTS
voltage = round((average_adc_value / ADC_MAX_VALUE) * 3.3, DECIMAL_PLACES)
if voltage != last_adc_value:
last_adc_value = voltage
new_display_value = int(voltage * (10 ** DECIMAL_PLACES))
max_display_value = (10 ** NUM_DISPLAYS) - 1
if new_display_value > max_display_value:
print(f'Warning: {new_display_value} exceeds {max_display_value}, clipping')
new_display_value = max_display_value
if current_display_value != new_display_value:
current_display_value = new_display_value
refresh_display()
return voltage
def stop_display_timer():
global display_timer
if display_timer:
display_timer.deinit()
def start_display_timer():
global display_timer
display_timer = machine.Timer()
display_timer.init(period=5, mode=machine.Timer.PERIODIC, callback=update_display)
def update_display(timer_int):
global active_display_index
global current_display_value
digit_value = int(abs(current_display_value) // (10 ** active_display_index)) % 10
show_digit(digit_value, active_display_index, active_display_index == DECIMAL_PLACES and DECIMAL_PLACES != 0)
active_display_index = (active_display_index - 1) % NUM_DISPLAYS
def show_digit(digit_value, display_index, decimal_point=False):
if digit_value < 0 or digit_value >= len(DIGIT_SEGMENTS):
return
for pin in digit_select_pins:
pin.value(0)
segment_mask = DIGIT_SEGMENTS[digit_value]
for i in range(7):
segment_output_pins[i].value((segment_mask >> i) & 1)
segment_output_pins[7].value(not decimal_point)
if display_index == -1:
for pin in digit_select_pins:
pin.value(1)
elif 0 <= display_index < NUM_DISPLAYS:
digit_select_pins[display_index].value(1)
def refresh_display():
global active_display_index
stop_display_timer()
active_display_index = NUM_DISPLAYS - 1
show_digit(16, -1)
time.sleep(0.1)
start_display_timer()
def test_display_values():
for i in range(16):
show_digit(i, 0)
time.sleep(0.5)
def initialize():
global segment_output_pins
global digit_select_pins
global adc_pin
global button_pin
global display_timer
digit_select_pins = [machine.Pin(SEVEN_SEGMENT_BASE_PIN + 8 + i, machine.Pin.OUT) for i in range(NUM_DISPLAYS)]
segment_output_pins = [machine.Pin(SEVEN_SEGMENT_BASE_PIN + i, machine.Pin.OUT) for i in range(8)]
for pin in segment_output_pins:
pin.value(1)
for pin in digit_select_pins:
pin.value(0)
adc_pin = machine.ADC(ADC_INPUT_PIN)
button_pin = machine.Pin(BUTTON_INPUT_PIN, machine.Pin.IN, machine.Pin.PULL_UP)
button_pin.irq(trigger=machine.Pin.IRQ_FALLING, handler=button_isr)
start_display_timer()
def button_isr(pin):
global last_button_press_time
current_time = time.ticks_ms()
if current_time - last_button_press_time > BUTTON_DEBOUNCE_DELAY:
last_button_press_time = current_time
voltage = read_adc_voltage(adc_pin)
if voltage is not None:
print(f'Voltage: {voltage} V')
if __name__ == '__main__':
initialize()
while True:
time.sleep(1)