diff --git a/main.py b/main.py new file mode 100644 index 0000000..bb3701c --- /dev/null +++ b/main.py @@ -0,0 +1,158 @@ +from machine import Pin, UART +import time + +# ============================================================ +# PIN-EMPFEHLUNGEN (Pico 2 W) +# ============================================================ +# UART für DFPlayer-kompatibles MP3-Modul +UART_ID = 1 +UART_TX_GPIO = 8 # Pico TX -> MP3 RX +UART_RX_GPIO = 9 # Pico RX <- MP3 TX + +# Buttons (jeweils gegen GND, interner Pull-Up) +GPIO_CRY = 2 +GPIO_WHIM = 3 +GPIO_GIG = 4 +GPIO_STOP = 5 +GPIO_PEE = 6 + +# Pumpen-Ausgang (später Treiber/ULN2003 etc.) +GPIO_PUMP_OUT = 7 + +# ============================================================ +# DFPLAYER / MP3-MODUL SETUP (laut Datenblatt 9600 baud, 3.3V TTL) +# ============================================================ +uart = UART( + UART_ID, + baudrate=9600, + bits=8, + parity=None, + stop=1, + tx=Pin(UART_TX_GPIO), + rx=Pin(UART_RX_GPIO), +) + +def dfplayer_cmd(cmd, param=0, feedback=False): + """ + DFPlayer Serial Protocol: + 0x7E 0xFF 0x06 CMD FB PAR_H PAR_L CHK_H CHK_L 0xEF + """ + start = 0x7E + ver = 0xFF + ln = 0x06 + fb = 0x01 if feedback else 0x00 + ph = (param >> 8) & 0xFF + pl = param & 0xFF + + checksum = -(ver + ln + cmd + fb + ph + pl) & 0xFFFF + ch = (checksum >> 8) & 0xFF + cl = checksum & 0xFF + + packet = bytes([start, ver, ln, cmd, fb, ph, pl, ch, cl, 0xEF]) + uart.write(packet) + +def df_set_volume(vol): + """Volume 0..30""" + vol = max(0, min(30, vol)) + dfplayer_cmd(0x06, vol) + +def df_play_mp3(track_no): + """ + Play track from /mp3 folder: + /mp3/0001.mp3 -> track_no=1 + /mp3/0002.mp3 -> track_no=2 + ... + """ + dfplayer_cmd(0x12, track_no) + +def df_stop(): + """Stop playback""" + dfplayer_cmd(0x16, 0) + +def df_pause(): + """Pause (optional)""" + dfplayer_cmd(0x0E, 0) + +def df_resume(): + """Resume (optional)""" + dfplayer_cmd(0x0D, 0) + +# Kurze Boot-Wartezeit, damit Modul initialisieren kann +time.sleep_ms(800) +df_set_volume(22) # 0..30, ggf. anpassen + +# ============================================================ +# BUTTONS SETUP +# ============================================================ +btn_cry = Pin(GPIO_CRY, Pin.IN, Pin.PULL_UP) +btn_whim = Pin(GPIO_WHIM, Pin.IN, Pin.PULL_UP) +btn_gig = Pin(GPIO_GIG, Pin.IN, Pin.PULL_UP) +btn_stop = Pin(GPIO_STOP, Pin.IN, Pin.PULL_UP) +btn_pee = Pin(GPIO_PEE, Pin.IN, Pin.PULL_UP) + +pump_out = Pin(GPIO_PUMP_OUT, Pin.OUT) +pump_out.value(0) + +# Entprellung +DEBOUNCE_MS = 80 + +last_ms = { + "cry": 0, + "whim": 0, + "gig": 0, + "stop": 0, + "pee": 0, +} + +def is_pressed(pin: Pin) -> bool: + """Active-low button""" + return pin.value() == 0 + +def allow(key: str) -> bool: + now = time.ticks_ms() + if time.ticks_diff(now, last_ms[key]) > DEBOUNCE_MS: + last_ms[key] = now + return True + return False + +# ============================================================ +# PIPI-LOGIK (erstmal als Impuls, bühnenfreundlicher als 'solange gedrückt') +# ============================================================ +PIPI_PULSE_MS = 900 # Dauer Pumpen-Impuls (später anpassen) +pipi_until = 0 + +def pipi_trigger(): + global pipi_until + pipi_until = time.ticks_add(time.ticks_ms(), PIPI_PULSE_MS) + +# ============================================================ +# MAIN LOOP +# ============================================================ +while True: + # STOP hat Priorität (soll sofort alles beenden) + if is_pressed(btn_stop) and allow("stop"): + df_stop() + pipi_until = 0 + pump_out.value(0) + + # Sounds + if is_pressed(btn_cry) and allow("cry"): + df_play_mp3(1) # /mp3/0001.mp3 + + if is_pressed(btn_whim) and allow("whim"): + df_play_mp3(2) # /mp3/0002.mp3 + + if is_pressed(btn_gig) and allow("gig"): + df_play_mp3(3) # /mp3/0003.mp3 + + # Pipi-Trigger (Impuls) + if is_pressed(btn_pee) and allow("pee"): + pipi_trigger() + + # Pumpen-Ausgang entsprechend Impulszeit + if time.ticks_diff(pipi_until, time.ticks_ms()) > 0: + pump_out.value(1) + else: + pump_out.value(0) + + time.sleep_ms(10)