66 — Raspberry Pi 4 simulation

An interactive Raspberry Pi 4 circuit simulation you can run free in your browser on Velxio, by qwez.

Components

Sketch code

import time
import RPi.GPIO as GPIO

try:
    from smbus2 import SMBus
except ImportError:
    from smbus import SMBus


# ---------- 引脚 ----------
RELAY_PIN = 18
DRIVE_PIN = 13
LIGHT_PIN = 17

KEYS = {
    "K1": 27,
    "K2": 22,
    "K3": 23,
    "K4": 24,
}

LCD_ADDR = 0x27
RTC_ADDR = 0x68

# 开灯、关灯时间:[小时, 分钟]
on_time = [18, 0]
off_time = [6, 0]

# 0正常显示;1~4为四个设置项
setting = 0
manual_brightness = None
manual_mode = False
lamp_on = False
dark_count = 0
dark_confirmed = False
last_light_read = 0.0

bus = None
pwm = None

GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY_PIN, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(DRIVE_PIN, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(LIGHT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

for pin in KEYS.values():
    GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)


# ---------- 按键消抖 ----------
# 电平变化后连续稳定20毫秒,才接受新状态
key_raw = {name: GPIO.HIGH for name in KEYS}
key_stable = {name: GPIO.HIGH for name in KEYS}
key_changed_at = {name: time.monotonic() for name in KEYS}
key_armed = {name: False for name in KEYS}


def read_keys():
    events = []
    now = time.monotonic()

    for name, pin in KEYS.items():
        value = GPIO.input(pin)

        if value != key_raw[name]:
            key_raw[name] = value
            key_changed_at[name] = now

        elif (
            value != key_stable[name]
            and now - key_changed_at[name] >= 0.02
        ):
            key_stable[name] = value

            print(
                f"[KEY {now:.2f}] {name} GPIO{pin} "
                f"{'LOW/pressed' if value == GPIO.LOW else 'HIGH/released'}",
                flush=True
            )

            if value == GPIO.HIGH:
                key_armed[name] = True
            elif key_armed[name]:
                key_armed[name] = False
                events.append(name)

        # A stable released input arms the next press.
        if (
            value == GPIO.HIGH
            and key_stable[name] == GPIO.HIGH
            and now - key_changed_at[name] >= 0.02
        ):
            key_armed[name] = True

    return events


# ---------- LCD ----------
def write_nibble(value):
    value |= 0x08
    bus.write_byte(LCD_ADDR, value)
    bus.write_byte(LCD_ADDR, value | 0x04)
    time.sleep(0.001)
    bus.write_byte(LCD_ADDR, value)
    time.sleep(0.001)


def send(value, is_data=False):
    mode = 1 if is_data else 0
    write_nibble((value & 0xF0) | mode)
    write_nibble(((value << 4) & 0xF0) | mode)


def show_line(text, row):
    send(0x80 if row == 0 else 0xC0)

    for char in text[:16].ljust(16):
        send(ord(char), True)


def init_lcd():
    time.sleep(0.05)

    for value in (0x30, 0x30, 0x30, 0x20):
        write_nibble(value)
        time.sleep(0.005)

    for command in (0x28, 0x08, 0x01, 0x06, 0x0C):
        send(command)
        time.sleep(0.005)


# ---------- 时钟 ----------
def from_bcd(value):
    return (value >> 4) * 10 + (value & 0x0F)


def read_clock():
    data = bus.read_i2c_block_data(RTC_ADDR, 0x00, 7)

    sec

More projects by qwez