import machine
import math
import time
# Pin and constant definitions
SEGMENT_START_PIN = 0
ANALOG_INPUT_PIN = 26
INPUT_BUTTON_PIN = 16
NUM_DISPLAYS = 4
NUM_MEASUREMENTS = 16
VOLTAGE_PRECISION = 3
ADC_MAX_VALUE = float((math.pow(2, 16) - 1))
# HEX values for 7-segment display digits
SEGMENT_DIGIT_HEX = [
0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78,
0x00, 0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0E, 0x7F
]
# Global variables
current_display_value = 0
segment_control_pins = []
display_control_pins = []
analog_pin = None
button_control_pin = None
current_digit_index = NUM_DISPLAYS - 1
display_update_timer = None
previous_voltage = -1
last_button_press_time = 0
def read_voltage(pin):
global current_display_value, previous_voltage, VOLTAGE_PRECISION
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, VOLTAGE_PRECISION)
if voltage != previous_voltage:
previous_voltage = voltage
new_display_value = float(voltage * math.pow(10, VOLTAGE_PRECISION))
if False: # Placeholder for temperature reading logic
VOLTAGE_PRECISION = 2
try:
temp = round(1 / (math.log(1 / (ADC_MAX_VALUE / average_adc_value - 1)) / 3950 + 1.0 / 298.15) - 273.15, 1)
print(f'temp: {temp} C')
except:
pass
new_display_value = int(temp * math.pow(10, VOLTAGE_PRECISION))
max_display_value = math.pow(10, NUM_DISPLAYS) - 1
if new_display_value > max_display_value:
print(f'warn: {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
stop_display_timer()
global current_digit_index
current_digit_index = NUM_DISPLAYS - 1
update_digit_display(16, -1)
time.sleep(0.1)
start_display_timer()
return voltage
def stop_display_timer():
global display_update_timer
display_update_timer.deinit()
def start_display_timer():
global display_update_timer
display_update_timer.init(period=4, mode=machine.Timer.PERIODIC, callback=scan_display)
def scan_display(timer):
global current_digit_index, current_display_value
digit = int(abs(current_display_value) // math.pow(10, current_digit_index)) % 10
update_digit_display(digit, current_digit_index, current_digit_index == VOLTAGE_PRECISION and VOLTAGE_PRECISION != 0)
current_digit_index = (current_digit_index - 1) % NUM_DISPLAYS
def update_digit_display(digit_value, digit_index, decimal_point=False):
if not 0 <= digit_value < len(SEGMENT_DIGIT_HEX):
return
for pin in display_control_pins:
pin.value(0)
mask = SEGMENT_DIGIT_HEX[digit_value]
for i in range(7):
segment_control_pins[i].value((mask >> i) & 1)
segment_control_pins[7].value(not decimal_point)
if digit_index == -1:
for pin in display_control_pins:
pin.value(1)
elif 0 <= digit_index < NUM_DISPLAYS:
display_control_pins[digit_index].value(1)
def button_pressed(pin):
global last_button_press_time
current_time = time.ticks_ms()
if current_time - last_button_press_time > 200: # Debounce period of 200ms
last_button_press_time = current_time
voltage = read_voltage(analog_pin)
if voltage is not None:
print(f'voltage: {voltage} V')
def setup():
global segment_control_pins, display_control_pins, analog_pin, button_control_pin, display_update_timer
display_control_pins = [machine.Pin(i, machine.Pin.OUT, value=0) for i in range(SEGMENT_START_PIN + 8, SEGMENT_START_PIN + 8 + NUM_DISPLAYS)]
segment_control_pins = [machine.Pin(i, machine.Pin.OUT, value=1) for i in range(SEGMENT_START_PIN, SEGMENT_START_PIN + 8)]
analog_pin = machine.ADC(ANALOG_INPUT_PIN)
button_control_pin = machine.Pin(INPUT_BUTTON_PIN, machine.Pin.IN, machine.Pin.PULL_UP)
button_control_pin.irq(trigger=machine.Pin.IRQ_FALLING, handler=button_pressed)
display_update_timer = machine.Timer()
start_display_timer()
if __name__ == '__main__':
setup()
while True:
time.sleep(1) # Main loop idle, waiting for interrupts