#171Başlangıç

Raspberry Pi Pico Buton Piyano (5 Buton + Buzzer + Melodi Kaydı)

Beş butonlu bir mini piyano, üstelik çaldığını hatırlıyor! **Raspberry Pi Pico**, **beş butonla** DO, RE, MI, FA ve SOL notalarını **pasif buzzer**'dan çalar; tuş basılı kaldıkça nota uzar. **DO'yu 1 saniye basılı tut**, melodini çal ve DO'yu yine basılı tut: Pico melodiyi geri çalar; notalar arasındaki **1,5 saniyeden uzun sessizlikleri 1,5 saniyeye kısaltır**. Kayıt göstergesi kartın üstündeki LED, ek parça yok. PWM ile nota, debounce ve bloklamayan zamanlama tek projede.

0.0(0)
Raspberry Pi Pico Buton Piyano (5 Buton + Buzzer + Melodi Kaydı)
Beş butonlu küçük bir piyano: her buton do, re, mi, fa ya da sol notasını buzzerdan çalar ve basılı tuttukça nota uzar. Do tuşunu bir saniye basılı tutunca kayıt başlar, kartın üstündeki LED yanıp söner; ezgini çalıp do'yu yine bir saniye basılı tutunca Raspberry Pi Pico onu aynı ritimle sana geri çalar. Kendi ezgini kaydedip dinlemenin en kolay yolu.

Video

Devre Şeması

Raspberry Pi Pico Buton Piyano (5 Buton + Buzzer + Melodi Kaydı) - Circuit

Kaynak Kodu

MicroPython
1# ─────────────────────────────────────────
2#   BlueGrays · bluegrays.com
3#   Raspberry Pi Pico Buton Piyano (5 Buton + Buzzer + Melodi Kaydı)
4# ─────────────────────────────────────────
5# Beş butonlu mini piyano: DO, RE, MI, FA, SOL. Tuş basılı kaldıkça nota
6# çalar. DO tuşunu 1 sn basılı tut: kayıt başlar, çalınan notalar
7# süreleriyle saklanır. DO'yu tekrar 1 sn basılı tut: kayıt biter ve
8# melodi aynı ritimle geri çalınır.
9#
10# Pinler:
11#   GP7  -> DO butonu (diğer ucu GND)
12#   GP8  -> RE butonu (diğer ucu GND)
13#   GP9  -> MI butonu (diğer ucu GND)
14#   GP10 -> FA butonu (diğer ucu GND)
15#   GP11 -> SOL butonu (diğer ucu GND)
16#   GP17 -> Buzzer (+), diğer ucu GND
17#   LED  -> Kart üstü LED (GP25): kayıt / çalma göstergesi
18
19from machine import Pin, PWM
20import time
21
22# ============ AYARLAR ============
23NOTE_PINS = (7, 8, 9, 10, 11)
24NOTE_NAMES = ("DO", "RE", "MI", "FA", "SOL")
25NOTE_HZ = (523, 587, 659, 698, 784)   # C5 D5 E5 F5 G5 (Hz)
26VOLUME = 32768         # PWM doluluk (0-65535), 32768 = %50
27
28REC_KEY = 0            # Kayıt tuşu: DO
29LONG_PRESS_MS = 1000   # Kayıt için basılı tutma süresi
30DEBOUNCE_MS = 20       # Buton titreşim süzgeci
31MAX_NOTES = 64         # Kayıttaki en fazla nota
32MAX_GAP_MS = 1500      # Geri çalmada en uzun sessizlik
33PLAY_DELAY_MS = 500    # Kayıt bitince çalmadan önce bekleme
34REC_BLINK_MS = 500     # Kayıtta LED yanıp sönme
35LOOP_MS = 2            # Ana döngü adımı
36
37FREE, REC, PLAY = 0, 1, 2   # Modlar
38
39# ============ DONANIM ============
40buzzer = PWM(Pin(17))
41buzzer.duty_u16(0)
42try:
43    led = Pin("LED", Pin.OUT)      # Pico ve Pico W kart üstü LED
44except (TypeError, ValueError):
45    led = Pin(25, Pin.OUT)         # Eski firmware
46led.value(0)
47
48
49class Key:
50    # Titreşim süzgeçli buton; update() basınca +1, bırakınca -1 döndürür
51    def __init__(self, gpio):
52        self.pin = Pin(gpio, Pin.IN, Pin.PULL_UP)
53        self.raw = 1
54        self.stable = 1
55        self.changed = time.ticks_ms()
56        self.down_at = 0
57        self.used = False      # Uzun basış ya da durdurma için kullanıldı
58
59    def update(self, now):
60        raw = self.pin.value()
61        if raw != self.raw:
62            self.raw = raw
63            self.changed = now
64        if raw != self.stable and time.ticks_diff(now, self.changed) >= DEBOUNCE_MS:
65            self.stable = raw
66            if raw == 0:
67                self.down_at = now
68                self.used = False
69                return 1
70            return -1
71        return 0
72
73    def held_ms(self, now):
74        return time.ticks_diff(now, self.down_at) if self.stable == 0 else 0
75
76
77keys = [Key(p) for p in NOTE_PINS]
78
79
80# ============ SES ============
81def tone(hz):
82    buzzer.freq(hz)
83    buzzer.duty_u16(VOLUME)
84
85
86def silence():
87    buzzer.duty_u16(0)
88
89
90def chirp(*steps):
91    # Kısa sinyal sesi: (Hz, ms) çiftleri; 0 Hz = sessizlik
92    for hz, ms in steps:
93        if hz:
94            tone(hz)
95        else:
96            silence()
97        time.sleep_ms(ms)
98    silence()
99
100
101# ============ DURUM ============
102mode = FREE
103held = []          # Basılı notalar, son basılan en sonda
104rec_notes = []     # Kayıt: [tuş, başlangıç ms, süre ms]
105rec_t0 = 0
106play_list = []     # Çalma listesi: (zaman ms, tuş, süre ms)
107play_index = 0
108play_start = 0
109play_end = 0
110play_sounding = False
111
112
113def update_sound():
114    # Buzzer tek nota çalar: en son basılan tuş kazanır
115    if held:
116        tone(NOTE_HZ[held[-1]])
117    else:
118        silence()
119
120
121def start_recording(now):
122    global mode, rec_notes, rec_t0
123    mode = REC
124    rec_notes = []
125    rec_t0 = now
126    chirp((880, 70), (0, 40), (1319, 110))       # Yükselen sinyal
127    print("Kayit basladi / Recording started (en fazla / max %d nota / notes)" % MAX_NOTES)
128
129
130def build_play_list():
131    # Notaları başlangıca göre sırala, ilk notayı 0'a çek, uzun sessizlikleri kısalt
132    notes = sorted(rec_notes, key=lambda n: n[1])
133    result = []
134    t = 0
135    for i, (k, start, length) in enumerate(notes):
136        if i > 0:
137            prev_k, prev_start, prev_len = notes[i - 1]
138            t += min(start - prev_start, prev_len + MAX_GAP_MS)
139        result.append((t, k, length))
140    return result
141
142
143def stop_recording(now):
144    global mode, play_list, play_index, play_start, play_end, play_sounding
145    led.value(0)
146    chirp((1319, 70), (0, 40), (880, 110))       # Alçalan sinyal
147    if not rec_notes:
148        mode = FREE
149        print("Kayit bos / Recording is empty")
150        chirp((220, 300))
151        return
152    play_list = build_play_list()
153    names = " ".join(NOTE_NAMES[n[1]] for n in play_list)
154    print("Kayit bitti / Recording stopped: %d nota / notes" % len(play_list))
155    print("Melodi / Melody:", names)
156    mode = PLAY
157    play_index = 0
158    play_end = 0
159    play_sounding = False
160    play_start = time.ticks_add(time.ticks_ms(), PLAY_DELAY_MS)
161    print("Geri calma / Playback...")
162
163
164def finish_playback(message):
165    global mode
166    mode = FREE
167    silence()
168    led.value(0)
169    print(message)
170
171
172def update_playback(now):
173    # Bloklamayan geri çalma: zamanı gelen notayı başlat, süresi dolanı sustur
174    global play_index, play_end, play_sounding
175    elapsed = time.ticks_diff(now, play_start)
176    if elapsed < 0:
177        return
178    while play_index < len(play_list) and elapsed >= play_list[play_index][0]:
179        t, k, length = play_list[play_index]
180        tone(NOTE_HZ[k])
181        led.value(1)                  # LED notayla yanar
182        play_end = t + length
183        play_sounding = True
184        play_index += 1
185    if play_sounding and elapsed >= play_end:
186        silence()
187        led.value(0)
188        play_sounding = False
189    if not play_sounding and play_index >= len(play_list):
190        finish_playback("Bitti / Done. DO 1 sn = yeni kayit / DO 1 s = new recording")
191
192
193def on_press(k, now):
194    if mode == PLAY:
195        # Çalarken herhangi bir tuş çalmayı durdurur
196        keys[k].used = True
197        finish_playback("Durduruldu / Stopped")
198        return
199    held.append(k)
200    update_sound()
201    tag = "[REC] " if mode == REC else ""
202    print("%sNota / Note: %s (%d Hz)" % (tag, NOTE_NAMES[k], NOTE_HZ[k]))
203
204
205def on_release(k, now):
206    if k in held:
207        held.remove(k)
208        update_sound()
209    if keys[k].used or mode != REC:
210        return
211    start = time.ticks_diff(keys[k].down_at, rec_t0)
212    length = time.ticks_diff(now, keys[k].down_at)
213    rec_notes.append([k, start, length])
214    if len(rec_notes) >= MAX_NOTES:
215        print("Kayit dolu / Recording full")
216        stop_recording(now)
217
218
219def on_long_press(k, now):
220    # DO uzun basış: kayıt başlat ya da bitir. Basılı DO notası kayda girmez.
221    keys[k].used = True
222    if k in held:
223        held.remove(k)
224    update_sound()
225    if mode == FREE:
226        start_recording(now)
227    elif mode == REC:
228        stop_recording(now)
229
230
231# ============ ANA DÖNGÜ ============
232print("== BlueGrays · bluegrays.com ==")
233print("Pico Buton Piyano / Button Piano")
234print("Tuslar / Keys: DO RE MI FA SOL")
235print("DO 1 sn basili = kayit baslat / bitir + geri cal")
236print("Hold DO 1 s = start / stop recording + play back")
237chirp((NOTE_HZ[0], 90), (NOTE_HZ[2], 90), (NOTE_HZ[4], 90), (1047, 180))   # Açılış
238
239while True:
240    now = time.ticks_ms()
241    for i, key in enumerate(keys):
242        event = key.update(now)
243        if event == 1:
244            on_press(i, now)
245        elif event == -1:
246            on_release(i, now)
247
248    rec_key = keys[REC_KEY]
249    if (mode != PLAY and not rec_key.used
250            and rec_key.held_ms(now) >= LONG_PRESS_MS):
251        on_long_press(REC_KEY, now)
252
253    if mode == PLAY:
254        update_playback(now)
255    elif mode == REC:
256        # Kayıtta LED yanıp söner
257        led.value(1 if (time.ticks_diff(now, rec_t0) // REC_BLINK_MS) % 2 == 0 else 0)
258
259    time.sleep_ms(LOOP_MS)
260

Sıkça Sorulanlar

Melodiyi nasıl kaydedip geri çaldırırım?▾

DO tuşunu 1 saniye basılı tut: yükselen iki bip duyulur ve kayıt başlar. Melodini çal, sonra DO'yu yine 1 saniye basılı tut. Alçalan iki bipten sonra melodi geri çalınır; notalar arasındaki 1,5 saniyeden uzun sessizlikler 1,5 saniyeye kısaltılır. Çalarken herhangi bir tuşa basmak çalmayı durdurur.

Kayıt göstergesi için ayrı bir LED takmam gerekiyor mu?▾

Hayır. Kod, kartın üstündeki LED'i `Pin("LED")` ile kullanır; bu Pico'da GP25'e bağlıdır, Pico W'de de çalışır. LED kayıt sırasında yarım saniye aralıkla yanıp söner, geri çalarken her notayla birlikte yanar.

Notaları ya da oktavı nasıl değiştiririm?▾

Frekanslar `NOTE_HZ` içinde: 523, 587, 659, 698 ve 784 Hz. Bir oktav pes için hepsini ikiye böl, tiz için iki ile çarp. Altıncı tuş eklemek için `NOTE_PINS`, `NOTE_NAMES` ve `NOTE_HZ` listelerine yeni pini, adı ve frekansı (LA için 880) ekle.

Wokwi'de piyanoyu nasıl çalarım?▾

Simülasyonu başlat ve devreye bir kez tıkla. Klavyedeki 1–5 tuşları DO'dan SOL'a kadar notaları çalar, tuşu basılı tuttukça nota uzar. Kayıt için 1'i yaklaşık 1 saniye basılı tut; çalınan notalar ve melodi seri monitörde görünür.

Raspberry Pi Pico ile Buton Piyano ve Melodi Kaydı | BlueGrays