from machine import Pin, ADC
from time import sleep
# LCD pins
rs = Pin(0, Pin.OUT)
e = Pin(1, Pin.OUT)
d4 = Pin(2, Pin.OUT)
d5 = Pin(3, Pin.OUT)
d6 = Pin(4, Pin.OUT)
d7 = Pin(5, Pin.OUT)
# ADC Inputs
adc_v = ADC(Pin(27))
adc_i = ADC(Pin(26))
adc_r = ADC(Pin(28))
# Buttons
btn_mode = Pin(14, Pin.IN, Pin.PULL_UP)
btn_select = Pin(15, Pin.IN, Pin.PULL_UP)
btn_menu = Pin(16, Pin.IN, Pin.PULL_UP)
# UI states
STATE_MENU = 0
STATE_MEASURE = 1
state = STATE_MENU
# Constants for measurements
Vin = 3.3
R_KNOWN = 1000
R_SHUNT = 0.1
# Menu items list
menu_items = ["Voltage", "Current", "Resistance", "Capacitance"]
menu_index = 0
# LCD setup
def pulse():
e.value(1)
sleep(0.001)
e.value(0)
sleep(0.001)
def send4(bits):
d4.value((bits >> 0) & 1)
d5.value((bits >> 1) & 1)
d6.value((bits >> 2) & 1)
d7.value((bits >> 3) & 1)
pulse()
def send(cmd, mode=0):
rs.value(mode)
send4(cmd >> 4)
send4(cmd & 0x0F)
sleep(0.002)
def lcd_init():
sleep(0.02)
send(0x33)
send(0x32)
send(0x28)
send(0x0C)
send(0x06)
send(0x01)
sleep(0.002)
def write(msg):
for c in msg:
send(ord(c), 1)
def set_cursor(col, row):
addr = 0x80 + (0x40 * row) + col
send(addr)
# Obtaining the average of 10 ADC values to reduce noise
def read_avg(adc):
total = 0
for _ in range(10):
total += adc.read_u16()
sleep(0.002)
return total / 10
# Measurement calculations
def read_voltage():
return read_avg(adc_v) * Vin / 65535
def read_current():
v = read_avg(adc_i) * Vin / 65535
return v / R_SHUNT
def read_resistance():
raw = read_avg(adc_r)
Vout = (raw / 65535) * Vin
if Vout <= 0.01 or Vout >= Vin:
return None
R2 = R_KNOWN * (Vout / (Vin - Vout))
return R2
def read_capacitance():
v = read_avg(adc_r) * Vin / 65535
t = v * 50000
return t / (10000 * 1000000)
# R = 10000
# t = 50000 #Simulated charging time(microseconds)
# return t / (R * 1000000)
# Variables for keeping button states
last_mode = 1
last_select = 1
last_menu = 1
# Function for the buttons
def check_buttons():
global menu_index, state, power_on
global last_mode, last_select, last_menu
# Mode button
m = btn_mode.value()
if m == 0 and last_mode == 1:
sleep(0.02)
if btn_mode.value() == 0:
if state == STATE_MENU:
menu_index = (menu_index + 1) % len(menu_items)
while btn_mode.value() == 0:
sleep(0.01)
last_mode = m
# Select button
s = btn_select.value()
if s == 0 and last_select == 1:
sleep(0.02)
if btn_select.value() == 0:
if state == STATE_MENU:
state = STATE_MEASURE
send(0x01)
while btn_select.value() == 0:
sleep(0.01)
last_select = s
# Menu button
p = btn_menu.value()
if p == 0 and last_menu == 1:
sleep(0.02)
if btn_menu.value() == 0:
state = STATE_MENU
send(0x01)
while btn_menu.value() == 0:
sleep(0.01)
last_menu = p
# Turning up the LCD
lcd_init()
while True:
check_buttons()
# Display menu
if state == STATE_MENU:
set_cursor(0, 0)
write("Select Mode:")
item = menu_items[menu_index]
text = item + " " * (16 - len(item))
set_cursor(0, 1)
write(text)
# Display measurements
elif state == STATE_MEASURE:
mode = menu_items[menu_index]
set_cursor(0, 0)
write(mode + " " * (16 - len(mode)))
if mode == "Voltage":
val = read_voltage()
text = "{:.2f} V".format(val)
elif mode == "Current":
val = read_current()
text = "{:.2f} A".format(val)
elif mode == "Resistance":
val = read_resistance()
if val is None:
text = "Invalid Value"
elif val < 1000:
text = "{:.1f} Ohm".format(val)
else:
text = "{:.2f} kOhm".format(val / 1000)
elif mode == "Capacitance":
val = read_capacitance()
text = "{:.6f} F".format(val)
text += " " * (16 - len(text))
set_cursor(0, 1)
write(text)
sleep(0.05)Voltage
Current
Resistance &
Capacitance
Mode
Menu
Select