Pianoforte a pulsanti con Raspberry Pi Pico (5 pulsanti + buzzer + registratore)
Un mini pianoforte a cinque tasti che si ricorda cosa suoni! Il **Raspberry Pi Pico** suona DO, RE, MI, FA e SOL su un **buzzer passivo** con **cinque pulsanti**, e la nota dura finché tieni premuto il tasto. **Tieni premuto DO per un secondo**, suona la tua melodia e tieni di nuovo DO: il Pico la risuona e **accorcia a 1,5 secondi i silenzi tra le note che superano questa durata**. L'indicatore di registrazione è il LED sulla scheda, nessun pezzo in più. Note con il PWM, antirimbalzo e tempi no

Video
Schema circuito

Codice sorgente
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Pianoforte a pulsanti con Raspberry Pi Pico (5 pulsanti + buzzer + registratore)
4# ─────────────────────────────────────────
5# Mini pianoforte a cinque pulsanti: DO, RE, MI, FA, SOL. Una nota suona
6# finché il suo tasto è tenuto premuto. Tieni premuto DO per 1 s: parte la
7# registrazione e le note vengono memorizzate con la loro temporizzazione.
8# Tieni premuto di nuovo DO per 1 s: la registrazione si ferma e la
9# melodia viene riprodotta a tempo.
10#
11# Pin:
12# GP7 -> Pulsante DO (altro piedino a GND)
13# GP8 -> Pulsante RE (altro piedino a GND)
14# GP9 -> Pulsante MI (altro piedino a GND)
15# GP10 -> Pulsante FA (altro piedino a GND)
16# GP11 -> Pulsante SOL (altro piedino a GND)
17# GP17 -> Buzzer (+), altro piedino a GND
18# LED -> LED integrato: registrazione / riproduzione
19
20from machine import Pin, PWM
21import time
22
23# ============ IMPOSTAZIONI ============
24NOTE_PINS = (7, 8, 9, 10, 11)
25NOTE_NAMES = ("DO", "RE", "MI", "FA", "SOL")
26NOTE_HZ = (523, 587, 659, 698, 784) # C5 D5 E5 F5 G5 (Hz)
27VOLUME = 32768 # Duty PWM, 32768 = 50%
28
29REC_KEY = 0 # Tasto di registrazione: DO
30LONG_PRESS_MS = 1000 # Tempo di permanenza del record
31DEBOUNCE_MS = 20 # Antirimbalzo del pulsante
32MAX_NOTES = 64 # Numero massimo di note in una registrazione
33MAX_GAP_MS = 1500 # Silenzio più lungo nella riproduzione
34PLAY_DELAY_MS = 500 # Pausa prima della riproduzione
35REC_BLINK_MS = 500 # Il LED lampeggia durante la registrazione
36LOOP_MS = 2 # Passo del ciclo principale
37
38FREE, REC, PLAY = 0, 1, 2 # Modalità
39
40# ============ HARDWARE ============
41buzzer = PWM(Pin(17))
42buzzer.duty_u16(0)
43try:
44 led = Pin("LED", Pin.OUT) # LED integrato
45except (TypeError, ValueError):
46 led = Pin(25, Pin.OUT) # Firmware più vecchio
47led.value(0)
48
49
50class Key:
51 # Pulsante con antirimbalzo; update() restituisce +1 alla pressione, -1 al rilascio
52 def __init__(self, gpio):
53 self.pin = Pin(gpio, Pin.IN, Pin.PULL_UP)
54 self.raw = 1
55 self.stable = 1
56 self.changed = time.ticks_ms()
57 self.down_at = 0
58 self.used = False # Consumato da un comando
59
60 def update(self, now):
61 raw = self.pin.value()
62 if raw != self.raw:
63 self.raw = raw
64 self.changed = now
65 if raw != self.stable and time.ticks_diff(now, self.changed) >= DEBOUNCE_MS:
66 self.stable = raw
67 if raw == 0:
68 self.down_at = now
69 self.used = False
70 return 1
71 return -1
72 return 0
73
74 def held_ms(self, now):
75 return time.ticks_diff(now, self.down_at) if self.stable == 0 else 0
76
77
78keys = [Key(p) for p in NOTE_PINS]
79
80
81# ============ SUONO ============
82def tone(hz):
83 buzzer.freq(hz)
84 buzzer.duty_u16(VOLUME)
85
86
87def silence():
88 buzzer.duty_u16(0)
89
90
91def chirp(*steps):
92 # Breve suono di segnale: coppie (Hz, ms); 0 Hz = silenzio
93 for hz, ms in steps:
94 if hz:
95 tone(hz)
96 else:
97 silence()
98 time.sleep_ms(ms)
99 silence()
100
101
102# ============ STATO ============
103mode = FREE
104held = [] # Note tenute premute, l'ultima in fondo
105rec_notes = [] # Registrazione: [tasto, inizio ms, durata ms]
106rec_t0 = 0
107play_list = [] # Riproduzione: (tempo ms, tasto, durata ms)
108play_index = 0
109play_start = 0
110play_end = 0
111play_sounding = False
112
113
114def update_sound():
115 # Il buzzer suona una nota: vince l'ultimo tasto premuto
116 if held:
117 tone(NOTE_HZ[held[-1]])
118 else:
119 silence()
120
121
122def start_recording(now):
123 global mode, rec_notes, rec_t0
124 mode = REC
125 rec_notes = []
126 rec_t0 = now
127 chirp((880, 70), (0, 40), (1319, 110)) # Segnale in salita
128 print("Kayit basladi / Recording started (en fazla / max %d nota / notes)" % MAX_NOTES)
129
130
131def build_play_list():
132 # Ordinare le note per inizio, spostare la prima a 0, accorciare i silenzi lunghi
133 notes = sorted(rec_notes, key=lambda n: n[1])
134 result = []
135 t = 0
136 for i, (k, start, length) in enumerate(notes):
137 if i > 0:
138 prev_k, prev_start, prev_len = notes[i - 1]
139 t += min(start - prev_start, prev_len + MAX_GAP_MS)
140 result.append((t, k, length))
141 return result
142
143
144def stop_recording(now):
145 global mode, play_list, play_index, play_start, play_end, play_sounding
146 led.value(0)
147 chirp((1319, 70), (0, 40), (880, 110)) # Segnale in discesa
148 if not rec_notes:
149 mode = FREE
150 print("Kayit bos / Recording is empty")
151 chirp((220, 300))
152 return
153 play_list = build_play_list()
154 names = " ".join(NOTE_NAMES[n[1]] for n in play_list)
155 print("Kayit bitti / Recording stopped: %d nota / notes" % len(play_list))
156 print("Melodi / Melody:", names)
157 mode = PLAY
158 play_index = 0
159 play_end = 0
160 play_sounding = False
161 play_start = time.ticks_add(time.ticks_ms(), PLAY_DELAY_MS)
162 print("Geri calma / Playback...")
163
164
165def finish_playback(message):
166 global mode
167 mode = FREE
168 silence()
169 led.value(0)
170 print(message)
171
172
173def update_playback(now):
174 # Riproduzione non bloccante: avviare le note quando è il momento, zittirle quando finiscono
175 global play_index, play_end, play_sounding
176 elapsed = time.ticks_diff(now, play_start)
177 if elapsed < 0:
178 return
179 while play_index < len(play_list) and elapsed >= play_list[play_index][0]:
180 t, k, length = play_list[play_index]
181 tone(NOTE_HZ[k])
182 led.value(1) # Il LED si accende con la nota
183 play_end = t + length
184 play_sounding = True
185 play_index += 1
186 if play_sounding and elapsed >= play_end:
187 silence()
188 led.value(0)
189 play_sounding = False
190 if not play_sounding and play_index >= len(play_list):
191 finish_playback("Bitti / Done. DO 1 sn = yeni kayit / DO 1 s = new recording")
192
193
194def on_press(k, now):
195 if mode == PLAY:
196 # Qualsiasi tasto ferma la riproduzione
197 keys[k].used = True
198 finish_playback("Durduruldu / Stopped")
199 return
200 held.append(k)
201 update_sound()
202 tag = "[REC] " if mode == REC else ""
203 print("%sNota / Note: %s (%d Hz)" % (tag, NOTE_NAMES[k], NOTE_HZ[k]))
204
205
206def on_release(k, now):
207 if k in held:
208 held.remove(k)
209 update_sound()
210 if keys[k].used or mode != REC:
211 return
212 start = time.ticks_diff(keys[k].down_at, rec_t0)
213 length = time.ticks_diff(now, keys[k].down_at)
214 rec_notes.append([k, start, length])
215 if len(rec_notes) >= MAX_NOTES:
216 print("Kayit dolu / Recording full")
217 stop_recording(now)
218
219
220def on_long_press(k, now):
221 # Pressione lunga su DO: avviare o fermare la registrazione. La nota DO tenuta premuta non viene
222 # registrata.
223 keys[k].used = True
224 if k in held:
225 held.remove(k)
226 update_sound()
227 if mode == FREE:
228 start_recording(now)
229 elif mode == REC:
230 stop_recording(now)
231
232
233# ============ CICLO PRINCIPALE ============
234print("== BlueGrays · bluegrays.com ==")
235print("Pico Buton Piyano / Button Piano")
236print("Tuslar / Keys: DO RE MI FA SOL")
237print("DO 1 sn basili = kayit baslat / bitir + geri cal")
238print("Hold DO 1 s = start / stop recording + play back")
239chirp((NOTE_HZ[0], 90), (NOTE_HZ[2], 90), (NOTE_HZ[4], 90), (1047, 180)) # Avvio
240
241while True:
242 now = time.ticks_ms()
243 for i, key in enumerate(keys):
244 event = key.update(now)
245 if event == 1:
246 on_press(i, now)
247 elif event == -1:
248 on_release(i, now)
249
250 rec_key = keys[REC_KEY]
251 if (mode != PLAY and not rec_key.used
252 and rec_key.held_ms(now) >= LONG_PRESS_MS):
253 on_long_press(REC_KEY, now)
254
255 if mode == PLAY:
256 update_playback(now)
257 elif mode == REC:
258 # Il LED lampeggia durante la registrazione
259 led.value(1 if (time.ticks_diff(now, rec_t0) // REC_BLINK_MS) % 2 == 0 else 0)
260
261 time.sleep_ms(LOOP_MS)
262FAQ
Come registro una melodia e la faccio risuonare?▾
Tieni premuto DO per un secondo: due bip ascendenti indicano che la registrazione è partita. Suona la melodia, poi tieni di nuovo DO per un secondo. Dopo due bip discendenti la melodia viene riprodotta; i silenzi tra le note che superano 1,5 secondi vengono accorciati a 1,5 secondi. Premere un tasto qualsiasi durante l'ascolto la ferma.
Devo aggiungere un LED per l'indicatore di registrazione?▾
No. Il codice usa il LED sulla scheda tramite `Pin("LED")`, che sul Pico corrisponde a GP25 e funziona anche sul Pico W. Lampeggia ogni mezzo secondo durante la registrazione e si accende con ogni nota durante la riproduzione.
Come cambio le note o l'ottava?▾
Le frequenze sono in `NOTE_HZ`: 523, 587, 659, 698 e 784 Hz. Dividile tutte per due per scendere di un'ottava o moltiplicale per due per salire. Per un sesto tasto aggiungi pin, nome e frequenza (880 per il LA) a `NOTE_PINS`, `NOTE_NAMES` e `NOTE_HZ`.
Come suono il pianoforte su Wokwi?▾
Avvia la simulazione e clicca una volta sul circuito. I tasti da 1 a 5 della tastiera suonano da DO a SOL, e più tieni premuto, più dura la nota. Per registrare tieni premuto 1 per circa un secondo; le note suonate e la melodia registrata compaiono sul monitor seriale.
