from machine import Pin, I2C, PWM
import time
import lcd_api
from i2c_lcd import I2cLcd
# LCD Configuration
I2C_ADDR = 0x27 # LCD I2C address (typically 0x27 or 0x3F)
LCD_ROWS = 2 # Number of rows (16x2 LCD = 2, 20x4 LCD = 4)
LCD_COLS = 16 # Number of columns (typically 16 or 20)
I2C_SCL_PIN = 22 # SCL pin number (Wokwi uses pin 22 by default for SCL)
I2C_SDA_PIN = 21 # SDA pin number (Wokwi uses pin 21 by default for SDA)
# Other Constants
DISTANCE_THRESHOLD = 10 # cm
MEASUREMENT_INTERVAL = 0.5 # seconds
BUZZER_FREQUENCY = 500 # Hz
BUZZER_DUTY_CYCLE = 512 # 50% of 1024
TRIGGER_PULSE_DURATION = 10 # microseconds
class PinConfig:
TRIGGER = 16
ECHO = 17
BUZZER = 4
class LCDDisplay:
def __init__(self):
"""Initialize LCD display."""
try:
# Initialize I2C using machine.I2C
i2c = I2C(scl=Pin(I2C_SCL_PIN), sda=Pin(I2C_SDA_PIN), freq=400000)
self.lcd = I2cLcd(i2c, I2C_ADDR, LCD_ROWS, LCD_COLS)
self.clear()
self.lcd.putstr("Distance Sensor")
time.sleep(1) # Show initial message
print("LCD initialized successfully")
except Exception as e:
print("Error initializing LCD:", e)
self.lcd = None
def clear(self):
"""Clear the LCD display."""
if self.lcd:
self.lcd.clear()
def update_display(self, distance):
"""Update the LCD display with current distance."""
if not self.lcd:
return
try:
self.clear()
# First row: Distance measurement
if distance is not None:
distance_text = f"Distance:{distance:.1f}cm"
self.lcd.move_to(0, 0)
self.lcd.putstr(distance_text)
# Second row: Status or alert
self.lcd.move_to(0, 1)
if distance < DISTANCE_THRESHOLD:
self.lcd.putstr("** TOO CLOSE! **")
else:
self.lcd.putstr("Status: Normal")
else:
self.lcd.move_to(0, 0)
self.lcd.putstr("Sensor Error")
self.lcd.move_to(0, 1)
self.lcd.putstr("Check connection")
except Exception as e:
print("Error updating LCD:", e)
class DistanceSensor:
def __init__(self):
# Initialize ultrasonic sensor pins
self.trig_pin = Pin(PinConfig.TRIGGER, Pin.OUT)
self.echo_pin = Pin(PinConfig.ECHO, Pin.IN)
# Initialize buzzer
self.buzzer_pin = Pin(PinConfig.BUZZER, Pin.OUT)
self.buzzer_pwm = PWM(self.buzzer_pin)
self.buzzer_pwm.freq(BUZZER_FREQUENCY)
self.buzzer_pwm.duty(0) # Start with buzzer off
def measure_distance(self):
"""Measure distance using ultrasonic sensor."""
try:
# Send trigger pulse
self.trig_pin.value(0)
time.sleep_us(2)
self.trig_pin.value(1)
time.sleep_us(TRIGGER_PULSE_DURATION)
self.trig_pin.value(0)
# Wait for echo with timeout
timeout = time.ticks_add(time.ticks_us(), 30000) # 30ms timeout
while self.echo_pin.value() == 0:
if time.ticks_diff(timeout, time.ticks_us()) <= 0:
return None
pulse_start = time.ticks_us()
# Wait for echo end
while self.echo_pin.value() == 1:
if time.ticks_diff(timeout, time.ticks_us()) <= 0:
return None
pulse_end = time.ticks_us()
# Calculate distance
pulse_duration = time.ticks_diff(pulse_end, pulse_start)
distance = pulse_duration * 0.034 / 2
return round(distance, 2)
except Exception as e:
print("Error measuring distance:", e)
return None
def activate_buzzer(self, duration=0.1):
"""Activate buzzer for specified duration."""
try:
self.buzzer_pwm.duty(BUZZER_DUTY_CYCLE)
time.sleep(duration)
self.buzzer_pwm.duty(0)
except Exception as e:
print("Error activating buzzer:", e)
def cleanup(self):
"""Clean up resources."""
try:
self.buzzer_pwm.deinit()
self.trig_pin.init(Pin.IN)
self.echo_pin.init(Pin.IN)
except Exception as e:
print("Error during cleanup:", e)
def main():
# Initialize sensor and display
sensor = DistanceSensor()
display = LCDDisplay()
print("Starting distance monitoring...")
try:
while True:
# Measure distance
distance = sensor.measure_distance()
if distance is not None:
print("Distance:", distance, "cm")
# Update LCD
display.update_display(distance)
# Activate buzzer if object is too close
if distance < DISTANCE_THRESHOLD:
sensor.activate_buzzer()
else:
print("Failed to measure distance")
display.update_display(None)
time.sleep(MEASUREMENT_INTERVAL)
except KeyboardInterrupt:
print("\nProgram terminated by user")
except Exception as e:
print("Unexpected error:", e)
finally:
sensor.cleanup()
display.clear()
print("Cleanup completed")
if __name__ == "__main__":
main()