import time
import board
import digitalio
import busio
import lcd
import i2c_pcf8574_interface
# =========================================
# LCD I2C SETUP
# =========================================
i2c_bus = busio.I2C(scl=board.GP5, sda=board.GP4)
i2c_lcd = i2c_pcf8574_interface.I2CPCF8574Interface(
i2c_bus,
0x27
)
display = lcd.LCD(i2c_lcd, num_rows=2, num_cols=16)
display.set_backlight(True)
display.set_display_enabled(True)
# =========================================
# SWITCHES
# =========================================
door_sw = digitalio.DigitalInOut(board.GP8)
door_sw.direction = digitalio.Direction.INPUT
door_sw.pull = digitalio.Pull.UP
overload_sw = digitalio.DigitalInOut(board.GP9)
overload_sw.direction = digitalio.Direction.INPUT
overload_sw.pull = digitalio.Pull.UP
# =========================================
# EXTERNAL LEDs
# =========================================
led_up = digitalio.DigitalInOut(board.GP16)
led_up.direction = digitalio.Direction.OUTPUT
led_down = digitalio.DigitalInOut(board.GP17)
led_down.direction = digitalio.Direction.OUTPUT
led_stop = digitalio.DigitalInOut(board.GP18)
led_stop.direction = digitalio.Direction.OUTPUT
# =========================================
# 7-SEGMENT DISPLAY
# =========================================
seg_pins = [
board.GP19,
board.GP20,
board.GP21,
board.GP22,
board.GP26,
board.GP27,
board.GP28
]
segments = [digitalio.DigitalInOut(pin) for pin in seg_pins]
for seg in segments:
seg.direction = digitalio.Direction.OUTPUT
# Common Anode Patterns
patterns = [
[0,0,0,0,0,0,1], # 0
[1,0,0,1,1,1,1], # 1
[0,0,1,0,0,1,0], # 2
[0,0,0,0,1,1,0], # 3
[1,0,0,1,1,0,0], # 4
[0,1,0,0,1,0,0], # 5
[0,1,0,0,0,0,0], # 6
[0,0,0,1,1,1,1], # 7
[0,0,0,0,0,0,0], # 8
[0,0,0,1,1,0,0] # 9
]
def show_digit(digit):
if 0 <= digit <= 9:
pattern = patterns[digit]
else:
pattern = [1] * 7
for i, value in enumerate(pattern):
segments[i].value = not value
# =========================================
# KEYPAD SETUP
# =========================================
rows = [
digitalio.DigitalInOut(board.GP0),
digitalio.DigitalInOut(board.GP1),
digitalio.DigitalInOut(board.GP2),
digitalio.DigitalInOut(board.GP3)
]
for row in rows:
row.direction = digitalio.Direction.OUTPUT
row.value = True
cols = [
digitalio.DigitalInOut(board.GP12),
digitalio.DigitalInOut(board.GP13),
digitalio.DigitalInOut(board.GP14),
digitalio.DigitalInOut(board.GP15)
]
for col in cols:
col.direction = digitalio.Direction.INPUT
col.pull = digitalio.Pull.UP
key_map = {
(0,0): '1',
(0,1): '2',
(0,2): '3',
(0,3): 'A',
(1,0): '4',
(1,1): '5',
(1,2): '6',
(1,3): 'B',
(2,0): '7',
(2,1): '8',
(2,2): '9',
(2,3): 'C',
(3,0): '*',
(3,1): '0',
(3,2): '#',
(3,3): 'D'
}
def scan_keypad():
for r_idx, row in enumerate(rows):
# Reset rows HIGH
for r in rows:
r.value = True
# Pull current row LOW
row.value = False
# Check columns
for c_idx, col in enumerate(cols):
if not col.value:
time.sleep(0.02)
if not col.value:
return key_map[(r_idx, c_idx)]
return None
# =========================================
# ELEVATOR STATES
# =========================================
current_floor = 1
target_floor = 1
weight_percent = 40
direction = "IDLE"
lcd_width = 16
# =========================================
# STARTUP SCREEN
# =========================================
display.set_cursor_pos(0, 0)
display.print("Elevator Ready")
display.set_cursor_pos(1, 0)
display.print("Floor:1 Load:40")
time.sleep(2)
# =========================================
# MAIN LOOP
# =========================================
while True:
# -------------------------------------
# Read keypad
# -------------------------------------
key = scan_keypad()
if key and key.isdigit():
target_floor = int(key)
if target_floor > current_floor:
direction = "UP"
elif target_floor < current_floor:
direction = "DOWN"
# -------------------------------------
# Read switches
# -------------------------------------
is_door_open = not door_sw.value
is_overload = not overload_sw.value
# -------------------------------------
# Reset LEDs
# -------------------------------------
led_up.value = False
led_down.value = False
led_stop.value = False
# -------------------------------------
# Elevator Logic
# -------------------------------------
if is_overload:
direction = "OVERLOAD"
led_stop.value = True
weight_percent = 110
elif is_door_open:
direction = "DOOR OPEN"
led_stop.value = True
elif direction == "UP":
led_up.value = True
if current_floor < target_floor:
current_floor += 1
weight_percent = min(
100,
weight_percent + 3
)
else:
direction = "IDLE"
time.sleep(0.4)
elif direction == "DOWN":
led_down.value = True
if current_floor > target_floor:
current_floor -= 1
weight_percent = max(
0,
weight_percent - 2
)
else:
direction = "IDLE"
time.sleep(0.4)
else:
direction = "IDLE"
weight_percent = max(
0,
weight_percent - 1
)
# -------------------------------------
# LCD DISPLAY (NO BLINK)
# -------------------------------------
line1 = f"F:{current_floor} {direction}"
line2 = f"Load:{weight_percent:3d}%"
# Fill empty spaces
line1 += " " * (lcd_width - len(line1))
line2 += " " * (lcd_width - len(line2))
display.set_cursor_pos(0, 0)
display.print(line1)
display.set_cursor_pos(1, 0)
display.print(line2)
# -------------------------------------
# 7-SEGMENT DISPLAY
# -------------------------------------
show_digit(weight_percent // 10)
# -------------------------------------
# Blink STOP LED
# -------------------------------------
if is_overload or is_door_open:
led_stop.value = not led_stop.value
time.sleep(0.15)