from time import sleep_ms
from machine import Pin, SoftI2C
from i2c_lcd import I2cLcd
######## Definitions ########
# Define LCD params
AddressOfLcd = 0x27
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=400000) # connect scl to GPIO 22, sda to GPIO 21
lcd = I2cLcd(i2c, AddressOfLcd, 4, 20)
# Define keypad layout
keypad = [
['1', '2', '3', '+' ],
['4', '5', '6', '-' ],
['7', '8', '9', '*' ],
['C', '0', '=', '/' ]
]
# Define the row and column pins
row_pins = [Pin(13, Pin.OUT), Pin(12, Pin.OUT), Pin(14, Pin.OUT), Pin(27, Pin.OUT)]
col_pins = [Pin(26, Pin.IN, Pin.PULL_UP), Pin(25, Pin.IN, Pin.PULL_UP), Pin(33, Pin.IN, Pin.PULL_UP), Pin(32, Pin.IN, Pin.PULL_UP)]
# Initialize the row pins to HIGH
for row_pin in row_pins:
row_pin.value(1)
# Initialize the col pins to LOW
for col_pin in col_pins:
col_pin.value(0)
# Variables to store user input and calculation
user_input = ""
result = None
math_sign = ""
sign_applied = False # When sign button has not been clicked
######## Methods ########
# Pad String
def pad_string(input_string, desired_length = 15):
current_length = len(input_string)
if current_length >= desired_length:
return input_string # No need to pad if it's long enough
# Calculate the number of spaces needed
spaces_needed = desired_length - current_length
# Append the required spaces to the string
padded_string = input_string + " " * spaces_needed
return padded_string
# Print user input
def lcd_print(row, value, start_col = 1, space_padding = True):
print("move to : " + str(row))
lcd.move_to(start_col,row)
if space_padding:
lcd.putstr(pad_string(str(value)))
else:
lcd.putstr(str(value))
# Get Key Pressed value
def get_key():
keys_detected = []
for i, row_pin in enumerate(row_pins):
# Drive the current row LOW
row_pin.value(0)
for j, col_pin in enumerate(col_pins):
if col_pin.value() == 0:
keys_detected.append(keypad[i][j])
# Key is pressed, return the corresponding character
return keypad[i][j]
# Release the row
row_pin.value(1)
return None
# Evaluate Math Expression
def evaluate_expression():
global user_input
global result
global math_sign
try:
calc_result = float(result)
except ValueError:
calc_result = 0.0
print("Invalid Result float format: " + result)
try:
calc_user_input = float(user_input)
except ValueError:
calc_user_input = 0.0
print("Invalid User Input format: " + user_input)
try:
return str(eval(str(calc_result) + " " + str(math_sign) + " " + str(user_input)))
except:
return "Error"
# Run keyboard scan
def keyboard_scan():
global user_input
global result
global math_sign
global sign_applied
key = get_key()
if key is not None:
if key == 'C':
# Clear the input and result
user_input = ''
result = None
lcd.clear()
math_sign = ""
sign_applied = False
lcd_print(2, "-----", 0, False)
elif key == '=':
# Calculate the result
try:
if user_input:
result = evaluate_expression()
#result = evaluate_expression(result if result is not None else "" + math_sign + user_input)
lcd_print(3, " " if result is None else str(result))
user_input = "" # Clear input after result is calculated
except Exception as e:
print("Error Occured: ", e)
elif key == '+' or key == '-' or key == '*' or key == '/':
# save and print sign
math_sign = key # store sign
lcd_print(1, key, 0, False) # Print current sign
result = user_input if sign_applied == False else result
user_input = ""
sign_applied = True
else:
# Append the key to the user input
user_input += key
lcd_input_row = 0 if sign_applied == False else 1
lcd_print(lcd_input_row, str(user_input))
# Add a small delay to debounce the keypad
sleep_ms(100)
lcd_print(2, "-----", 0, False)
while True:
keyboard_scan()