#169Orta

Raspberry Pi Pico LED Kamp Ateşi (8x8 NeoPixel Matris + Potansiyometre + Buzzer)

Yakmayan, ısıtmayan ama çıtırdayan bir kamp ateşi! **Raspberry Pi Pico**, **8x8 NeoPixel matriste** her karede yeniden hesaplanan gerçekçi bir alev çizer: tabanda kıvılcımlar çıkar, ısı yükselirken soğur ve kırmızıdan beyaza renk alır. **Potansiyometre** alevin boyunu ayarlar, **buton** Ateş, Gaz, Büyü ve Ametist temaları arasında geçer, **buzzer** odun çıtırtısı sesi verir. Prosedürel animasyon, ADC, PWM ve MicroPython tek projede.

0.0(0)
Raspberry Pi Pico LED Kamp Ateşi (8x8 NeoPixel Matris + Potansiyometre + Buzzer)
Masana sığan, hiç yakmayan bir kamp ateşi. 8x8 ışık matrisinde alevler alttan kıvılcımlarla doğar, yükseldikçe kırmızıdan sarıya ve beyaza döner; çevirmeli düğmeyle alevi kısar ya da büyütürsün. Butona kısa basınca ateş maviye, yeşile ya da mora bürünür, uzun basınca buzzer'dan gelen odun çıtırtısı açılıp kapanır.

Video

Devre Şeması

Raspberry Pi Pico LED Kamp Ateşi (8x8 NeoPixel Matris + Potansiyometre + Buzzer) - Circuit

Kaynak Kodu

MicroPython
1# ─────────────────────────────────────────
2#   BlueGrays · bluegrays.com
3#   Raspberry Pi Pico LED Kamp Ateşi (8x8 NeoPixel Matris + Potansiyometre + Buzzer)
4# ─────────────────────────────────────────
5# 8x8 NeoPixel matriste gerçekçi ateş animasyonu. Potansiyometre alevin
6# boyunu ayarlar, kısa buton basışı renk temasını değiştirir (Ateş, Gaz,
7# Büyü, Ametist), uzun basış çıtırtı sesini açar/kapatır.
8#
9# Pinler:
10#   GP2  -> 8x8 matris DIN
11#   GP26 -> Potansiyometre orta bacak (ADC0)
12#   GP14 -> Buton (diğer ucu GND)
13#   GP17 -> Buzzer (+)
14
15from machine import Pin, PWM, ADC
16from neopixel import NeoPixel
17import time
18import random
19
20# ============ AYARLAR ============
21W = 8                  # Sütun
22H = 8                  # Satır
23SERPENTINE = False     # Zigzag kablolu panel ise True
24BRIGHTNESS = 0.4       # 0-1; Wokwi renkleri birebir çizer, 0.4 alevi net gösterir
25                       # USB 2.0 (500 mA) ile 0.15-0.2 önerilir, daha parlak için harici 5V
26FRAME_MS = 35          # Kare süresi (~28 FPS)
27LONG_PRESS_MS = 900    # Ses aç/kapat için basılı tutma
28
29# ============ DONANIM ============
30matrix = NeoPixel(Pin(2), W * H)
31pot = ADC(26)                           # ADC0
32button = Pin(14, Pin.IN, Pin.PULL_UP)
33buzzer = PWM(Pin(17))
34buzzer.duty_u16(0)
35
36# ============ DURUM ============
37# heat[x][y]: sütun x, y = 0 en alt satır; 0 = soğuk, 255 = en sıcak
38heat = [[0] * H for _ in range(W)]
39theme = 0
40THEME_NAMES = ["Ates / Fire", "Gaz / Gas", "Buyu / Magic", "Ametist / Amethyst"]
41sound_on = True
42
43
44# ============ RENK PALETİ ============
45def heat_color(t):
46    # Isıyı (0-255) temaya göre renge çevir: siyah -> koyu -> parlak -> beyaz
47    t192 = (t * 191) // 255
48    ramp = (t192 & 0x3F) << 2      # Her bölgede 0-252 rampa
49    if t192 & 0x80:
50        r, g, b = 255, 255, ramp   # En sıcak: sarı -> beyaz
51    elif t192 & 0x40:
52        r, g, b = 255, ramp, 0     # Orta: kırmızı -> sarı
53    else:
54        r, g, b = ramp, 0, 0       # Soğuk: siyah -> kırmızı
55    if theme == 1:
56        r, b = b, r                # Gaz: mavi alev
57    elif theme == 2:
58        r, g = g, r                # Büyü: yeşil alev
59    elif theme == 3:
60        b = max(b, r * 3 // 4)     # Ametist: mor alev
61        g = g // 2
62    return (int(r * BRIGHTNESS), int(g * BRIGHTNESS), int(b * BRIGHTNESS))
63
64
65def pixel_index(x, row):
66    # row 0 = üst satır
67    if SERPENTINE and row % 2 == 1:
68        return row * W + (W - 1 - x)
69    return row * W + x
70
71
72# ============ ATEŞ SİMÜLASYONU ============
73def fire_step(intensity):
74    # intensity 0-1: alev boyu. Yüksek = az soğutma + çok kıvılcım
75    cooling = int(115 - 55 * intensity)    # 115 (kısa alev) -> 60 (uzun)
76    sparking = int(70 + 150 * intensity)   # 70 -> 220 (/255 olasılık)
77    max_cool = (cooling * 10) // H + 2
78
79    for x in range(W):
80        col = heat[x]
81        # 1) Her hücre biraz soğur
82        for y in range(H):
83            c = col[y] - random.getrandbits(8) % max_cool
84            col[y] = c if c > 0 else 0
85        # 2) Isı yukarı taşınır ve yayılır
86        for y in range(H - 1, 1, -1):
87            col[y] = (col[y - 1] + col[y - 2] + col[y - 2]) // 3
88        # 3) Tabanda rastgele kıvılcım
89        if random.getrandbits(8) < sparking:
90            y = random.getrandbits(1)
91            col[y] = min(255, col[y] + 160 + random.getrandbits(6))
92
93    # 4) Komşu sütunlarla hafif karışım: alev daha doğal dalgalanır
94    for y in range(2, H):
95        row_vals = [heat[x][y] for x in range(W)]
96        for x in range(W):
97            left = row_vals[x - 1] if x > 0 else row_vals[x]
98            right = row_vals[x + 1] if x < W - 1 else row_vals[x]
99            heat[x][y] = (row_vals[x] * 2 + left + right) // 4
100
101
102def render():
103    for x in range(W):
104        for y in range(H):
105            matrix[pixel_index(x, H - 1 - y)] = heat_color(heat[x][y])
106    matrix.write()
107
108
109# ============ ÇITIRTI SESİ ============
110def crackle(intensity):
111    # Rastgele çok kısa "tik" sesleri = odun çıtırtısı
112    if not sound_on:
113        return
114    if random.getrandbits(8) < int(10 + 50 * intensity):
115        buzzer.freq(1500 + random.getrandbits(12))   # 1500-5595 Hz
116        buzzer.duty_u16(6000)
117        time.sleep_ms(2 + random.getrandbits(2))
118        buzzer.duty_u16(0)
119
120
121def beep(freq, ms):
122    buzzer.freq(freq)
123    buzzer.duty_u16(20000)
124    time.sleep_ms(ms)
125    buzzer.duty_u16(0)
126
127
128# ============ BUTON ============
129btn_state = 1
130btn_raw = 1
131btn_changed = time.ticks_ms()
132press_start = 0
133long_done = False
134
135
136def handle_button():
137    # Kısa basış = tema, uzun basış = ses aç/kapat
138    global btn_state, btn_raw, btn_changed, press_start, long_done, theme, sound_on
139    now = time.ticks_ms()
140    raw = button.value()
141    if raw != btn_raw:
142        btn_raw = raw
143        btn_changed = now
144    if time.ticks_diff(now, btn_changed) > 25 and raw != btn_state:
145        btn_state = raw
146        if raw == 0:
147            press_start = now
148            long_done = False
149        elif not long_done:
150            theme = (theme + 1) % len(THEME_NAMES)
151            print("Tema / Theme:", THEME_NAMES[theme])
152            beep(1200, 30)
153    if btn_state == 0 and not long_done and time.ticks_diff(now, press_start) > LONG_PRESS_MS:
154        long_done = True
155        sound_on = not sound_on
156        print("Ses / Sound:", "ACIK / ON" if sound_on else "KAPALI / OFF")
157        beep(1600 if sound_on else 500, 80)
158
159
160# ============ ANA DÖNGÜ ============
161print("== BlueGrays · bluegrays.com ==")
162print("Pico 8x8 Kamp Atesi / Campfire")
163print("Pot = alev boyu / flame height | Kisa basis = tema / short press = theme | Uzun basis = ses / long press = sound")
164
165smooth = pot.read_u16() / 65535
166while True:
167    start = time.ticks_ms()
168    handle_button()
169
170    # Pot değerini yumuşat (titreme alevi zıplatmasın)
171    smooth += (pot.read_u16() / 65535 - smooth) * 0.2
172    fire_step(smooth)
173    render()
174    crackle(smooth)
175
176    # Sabit kare hızı
177    spent = time.ticks_diff(time.ticks_ms(), start)
178    if spent < FRAME_MS:
179        time.sleep_ms(FRAME_MS - spent)
180

Sıkça Sorulanlar

Gerçek devrede parlaklığı neden düşürmeliyim?▾

Koddaki `BRIGHTNESS = 0.4`, Wokwi renkleri olduğu gibi çizdiği için seçildi. Gerçek matris büyük alevde yaklaşık 1 A çekebilir, USB 2.0 portu ise 500 mA verir. USB'den besliyorsan 0.15–0.2 yap; daha parlak için matrisi 5V 2A adaptörden besle ve GND'leri birleştir.

Alevin boyunu ve rengini nasıl değiştiririm?▾

Potansiyometreyi sola çevirince yalnızca kor kalır, sağa çevirince alev matrisin tepesine yükselir. Butona kısa basış temayı Ateş, Gaz, Büyü ve Ametist arasında değiştirir. Wokwi'de pota tıklayıp ok tuşlarını, tema için T tuşunu kullan.

Çıtırtı sesini nasıl kapatırım ya da seyreltirim?▾

Butonu yaklaşık 1 saniye basılı tut: ince bip sesin açıldığını, kalın bip kapandığını gösterir. Çıtırtıyı seyreltmek için `crackle()` içindeki `10 + 50 * intensity` ifadesinde 10 ve 50'yi küçült. Ses için pasif buzzer kullan.

Kod için ek kütüphane kurmam gerekiyor mu?▾

Hayır. `neopixel`, `machine` ve `random` modülleri Pico'nun MicroPython sürümünde hazır gelir. Pico'ya MicroPython yükle, Thonny'de kodu Pico'ya `main.py` adıyla kaydet; Pico her açılışta ateşi kendiliğinden başlatır.

Raspberry Pi Pico ile LED Kamp Ateşi: 8x8 NeoPixel Matris | BlueGrays