Skip to main content

7.2 Mini piano

Ovaj projekt pretvara četiri tipke i pasivni buzzer u mali piano. Svaka tipka dobiva svoju notu, a držanje pritisnutom svira tu notu dokle god tamo držiš prst.

Ništa ovdje nije novo. Tipke se čitaju točno kao u 2.1 Brojač pritisaka tipke, a buzzer se pobuđuje točno kao u 2.4 Piskanje buzzera. Projektom ga čini razmjer: četiri ulaza i jedan izlaz na breadboardu odjednom, i prvi sklop u ovom kitu koji koristi pinove na obje strane pločice.

U ovoj dokumentaciji naučit ćeš:

  • Kako spojiti četiri tipke odjednom, svaku na svoj pin
  • Kako spojiti dvije plave vodilice u jednu dijeljenu masu
  • Kako pisati vlastite male funkcije da petlja ostane čitljiva
  • Zašto elif lanac znači da se u jednom trenutku može svirati samo jedna nota

Potreban hardver:

  • 1x Soldered NULA MINI pločica
  • 1x Breadboard
  • 4x Tipke
  • 1x Pasivni buzzer
  • 12x Jumper žice
  • 1x USB-C kabel
ℹ️
Ovom primjeru ne trebaju otpornici uopće. Ni za tipke: one koriste otpornike ugrađene u čip, uključene u kodu pomoću Pin.PULL_UP. Ni za buzzer: pin se uvijek kreće samo između 0 V i 3.3 V, pa ga nema od čega štititi. Ako si vidio krug za piano nacrtan s četiri otpornika od 10 kΩ, to je drugačiji način spajanja tipki i nije ono što ova skripta očekuje.
⚠️
Pobrini se da u ruci držiš pasivni buzzer, a ne aktivni. Pasivni buzzer svira onu frekvenciju koju mu pošalješ, a to je ovdje cijela svrha. Aktivni buzzer sadrži vlastiti oscilator i može piskati samo na jednoj fiksnoj visini, pa bi svaka tipka zvučala identično.

Spajanje komponenti

Ovaj sklop koristi pet pinova na pločici, i oni su razdijeljeni na obje njezine strane:

PinRedStranaŠto radi
IO225f–jTipka 1, nota C4
IO326f–jTipka 2, nota D4
IO427f–jTipka 3, nota E4
IO528f–jTipka 4, nota F4
IO1828a–eBuzzer
GND30f–jMasa za sve
⚠️
Red 28 pojavljuje se dvaput u toj tablici, a dva unosa su različiti pinovi. Na f–j strani red 28 je IO5, jedna od tipki. Na a–e strani red 28 je IO18, buzzer. Sjede na suprotnim krajevima istog broja reda i nisu spojeni međusobno. Čitaj ime ispisano na pločici, nikada broj reda sam.

Tijelo pločice prekriva srednje stupce, pa su uz nju slobodni samo stupac a na a–e strani i stupac j na f–j strani. Svaka žica koja dotiče pločicu ide zato u a… ili j… rupicu.

Prati osam koraka ispod. Svaka fotografija snimljena je s istog položaja, pa je možeš usporediti s prethodnom i vidjeti točno što se promijenilo.

1. Umetni NULA MINI pločicu na breadboard

ℹ️
Ovaj korak pretpostavlja da znaš kako je breadboard spojen iznutra i što su njegove naponske vodilice (power rails). Za uvod pogledaj stranicu dokumentacije Osnove breadboarda.

Utisni pločicu u jedan kraj breadboarda tako da njezina dva reda pinova sjednu s obje strane središnjeg kanala, s čipom okrenutim prema dolje. Pritisni je ravnomjerno dok svi pinovi ne sjednu.

NULA MINI pločica postavljena na breadboard
Korak 1: pločica postavljena na breadboard

Na fotografijama koje slijede pločica zauzima redove 25 do 30.

ℹ️
Tvoja pločica može sjediti u drugim redovima od one na fotografijama. Važno je u koji red sleti koji pin. Čitaj imena ispisana duž rubova pločice, a ne prepisuj brojeve.

2. Izvedi masu na plavu − vodilicu

Jedna kratka jumper žica iz j30 (red u kojem je GND) do plave vodilice na f–j rubu.

Jumper žica iz j30 do plave negativne vodilice na f-j rubu
Korak 2: GND izveden na plavu − vodilicu
ℹ️
Žica mora ići u red rupica koji ide uz plavu liniju. Svaki rub breadboarda nosi dva reda vodilica, a onaj uz crvenu liniju je zaseban pojas koji nije spojen s njim.

3. Spoji dvije plave − vodilice međusobno

Tipke i buzzer masu će uzimati s a–e ruba, ali je GND izveden na f–j rubu. Zato se dvije plave vodilice moraju spojiti u jednu.

Povuci jumper žicu s plave vodilice na f–j rubu, oko dalekog kraja breadboarda, do plave vodilice na a–e rubu. Postavi je blizu reda 1, dobro odmaknuto od svega drugoga.

Jumper žica premošćuje dvije plave negativne vodilice na kraju breadboarda kod reda 1
Korak 3: dvije plave − vodilice spojene u jednu liniju mase
ℹ️
Vodilice duž dva ruba breadboarda nisu spojene unutar njega: svaki pojas ide dužinom jednog ruba i tamo staje. Ta jedna žica je ono što ih pretvara u jednu liniju mase koju obje strane pločice mogu dosegnuti. Svaki spoj na masu odsad ide samo do bliže plave vodilice.

4. Postavi četiri tipke

Utisni četiri tipke u sredinu breadboarda tako da svaka premosti središnji kanal, nekoliko redova dalje od pločice. Svaka tipka obuhvaća dva reda.

Na fotografijama sjede u redovima 18 i 20, 15 i 17, 12 i 14, te 9 i 11, najbliža pločici prva, tri reda razmaknute, što je ugodan razmak za četiri prsta.

Četiri tipke postavljene preko središnjeg kanala
Korak 4: četiri tipke premošćuju središnji kanal
⚠️
Tipka ima četiri nožice, ali samo dvije su važne. Dvije nožice na istoj strani tipke trajno su spojene unutar nje. Pritisak tipke spaja jednu stranu s drugom. Zato za svaku tipku uvijek koristi jednu nožicu s a–e strane i jednu s f–j strane, u njezina dva različita reda. Ako uzmeš obje žice s iste strane, te dvije su već spojene i pločica će se ponašati kao da je ta tipka zauvijek pritisnuta.

5. Spoji svaku tipku na masu

Četiri kratke jumper žice, jedna po tipki, s a–e strane tipke do plave vodilice na tom rubu. Na fotografiji su to redovi 20, 17, 14 i 11, viši red svakog para.

Četiri jumper žice spajaju svaku tipku na plavu negativnu vodilicu na a-e rubu
Korak 5: sve četiri tipke spojene na masu na plavoj − vodilici

6. Spoji svaku tipku na svoj pin

Sada četiri signalne žice, sve na f–j strani. Svaka ide od pina pločice do nižeg reda para jedne tipke:

IzUTipkaNota
j25 (IO2)j181C4, 262 Hz
j26 (IO3)j152D4, 294 Hz
j27 (IO4)j123E4, 330 Hz
j28 (IO5)j94F4, 349 Hz
Četiri signalne jumper žice idu od pinova pločice do četiri tipke
Korak 6: svaka tipka spojena na svoj pin, IO2 na tipku najbližu pločici

Primijeti da četiri žice idu paralelno i nikada se ne križaju. IO2, pin najbliži tipkama, ide na najbližu tipku; IO5, najdalji pin, ide na najdalju tipku. Držanje tog redoslijeda je ono što tjera note da rastu kako ti se ruka odmiče od pločice, i vrijedi to dvaput provjeriti, jer sve četiri žice izgledaju jednako kada su unutra.

ℹ️
Svaka tipka sada ima masu s jedne strane središnjeg kanala i svoj pin s druge. To je isti dijagonalni par koji je za jednu tipku korišten u 2.1 Brojač pritisaka tipke, samo ponovljen četiri puta.

7. Postavi buzzer i spoji ga

Buzzer ide na a–e stranu, na daleki kraj breadboarda, s nožicama u dva susjedna reda, na fotografiji redovi 3 i 4.

Pogledaj vrh njegovog kućišta prije nego ga utisneš. Uz oznaku HWDZ nalazi se mali + unutar kružića, i nožica na toj strani kućišta je pozitivna. Ta nožica ide u red 4.

Zatim dvije žice:

  • Iz a4, reda u kojem je + nožica, u a28, a to je IO18. To je žica koja nosi pravokutni signal.
  • Iz a3, druge nožice buzzera, do plave vodilice na istom rubu.
Pasivni buzzer u redovima 3 i 4, jedna žica na IO18 i jedna na negativnu vodilicu
Korak 7: buzzer spojen između IO18 i mase
⚠️
Dvije nožice sjede u susjednim redovima, pa odvoji trenutak da provjeriš da su stvarno sletjele u dva različita reda. Ako obje nožice završe u istom redu, buzzer je kratko spojen i ostaje tih bez obzira što kod radi.

Krug je sada zatvoren: IO18 → buzzer → GND. Kućište od 12 mm skriva nožice kada je buzzer utisnut, pa ako spajanje moraš provjeriti kasnije, čitaj umjesto toga dvije jumper žice.

8. Spoji pločicu na računalo

Utisni USB-C kabel u pločicu. PWR LED-ica se upali čim pločica dobije struju.

Gotov krug mini piana napajan preko USB-C
Korak 8: gotov krug, napajan preko USB-C
ℹ️
Svi brojevi redova iznad samo su redovi koje fotografije slučajno koriste. Bilo koji slobodni redovi rade, dokle god svaka tipka premošćuje kanal u dva različita reda, vlastiti pin svake tipke doseže jednu njezinu stranu a masa drugu, i dokle god dvije nožice buzzera sjede u dva različita reda s IO18 na onoj s +.

Kako četiri tipke dijele jedan buzzer

Čitanje tipke. Svaki od četiri pina stvoren je s Pin.IN i Pin.PULL_UP, što uključuje otpornik unutar čipa koji nježno veže pin na 3.3 V. Pin zato čita 1 dok je njegova tipka otpuštena, a posao tipke je samo spojiti taj pin na GND, što ga povuče na 0.

btn1 = Pin(BTN1, Pin.IN, Pin.PULL_UP)
btn2 = Pin(BTN2, Pin.IN, Pin.PULL_UP)
btn3 = Pin(BTN3, Pin.IN, Pin.PULL_UP)
btn4 = Pin(BTN4, Pin.IN, Pin.PULL_UP)
ℹ️
Zato pritisnuta tipka daje 0. To je obrnuto od onoga što većina ljudi očekuje. Tipka spojena na ovaj način naziva se active low, i to je standardni način spajanja tipke na bilo koji mikrokontroler. 2.1 Brojač pritisaka tipke to pokriva detaljno.

Pravljenje note. PWM prebacuje IO18 između 3.3 V i 0 V iznova. To je pravokutni signal. Broj prebacivanja u sekundi je frekvencija, a tvoje uho frekvenciju čita kao visinu tona. Četiri frekvencije, četiri note:

NotaFrekvencija (Hz)
C4262
D4294
E4330
F4349

To su prve četiri note C-dur skale, počevši od C-a u sredini klavijature piana. Promijeni brojeve i mijenjaš štimanje. Nema ništa posebno u tim četirima vrijednostima, a potražiti frekvenciju bilo koje druge note dovoljno je da sagradiš vlastitu skalu.

Dvije male funkcije drže petlju čitljivom. Gdje Arduino skica ima gotove tone() i noTone(), MicroPython nema ni jednu, pa skripta definira vlastiti par:

def play_note(frequency):
buzzer.freq(frequency)
buzzer.duty_u16(SOUND_ON)


def stop_note():
buzzer.duty_u16(SOUND_OFF)

Obje su dugačke dvije linije, i nijedna ne radi ništa što nisi već vidio u 2.4 Piskanje buzzera. Ono što time dobivaš je petlja koja se čita kao odsviraj ovu notu, a ne kao dva PWM poziva ponovljena četiri puta.

ℹ️
Ovo vrijedi usvojiti kao naviku. def gotovo ništa ne košta a komad detalja pretvara u ime, a to je razlika između petlje koju možeš pročitati na prvi pogled i one koju moraš dešifrirati.

Samo jedna nota u jednom trenutku. Četiri provjere spojene su u jedan lanac if / elif, pa se pločica zaustavi na prvoj tipki koju nađe pritisnutu i ostale nikada ne pogleda. Pritisni dvije tipke zajedno i čuješ samo onu koja dolazi ranije u lancu, a to je niža nota. Pravi piano svira akorde; ovaj ne može, a elif lanac je razlog.

Puštanje. Kada nijedna od četiri nije pritisnuta, lanac propada do svojeg else i poziva stop_note(). To je ono što notu čini da traje točno onoliko dugo koliko tipku držiš pritisnutom.

ℹ️

time.sleep_ms(50) na kraju petlje postavlja koliko često pločica gleda tipke: 20 puta u sekundi. To je ono što ta pauza stvarno radi, i gotovo možeš osjetiti: do 50 ms može proći između slijetanja tvog prsta i početka note, što brzom sviranju otupi rub.

Komentar u kodu to naziva debounceom, ali ta je ideja posuđena iz 2.2 Debounce tipke i ovdje se zapravo ne primjenjuje. Debounce je važan kada program broji pritiske ili nešto prebacuje na bridu, jer se tamo jedan bučan pritisak može zabilježiti kao dva. Ova petlja ne broji ništa i ne pamti ništa: u svakom prolazu jednostavno pita je li tipka pritisnuta upravo sada, i svira ili zaustavlja u skladu s tim. Nema pritiska koji bi pločica pročitala dvaput.


Kod

# PWM uključuje i isključuje pin vrlo brzo, a dovođenje toga u buzzer je ono što ga tjera da proizvede zvuk.
# Brzina prebacivanja je ono što čujemo kao visinu tona.
from machine import Pin, PWM
import time

# Ovo je varijabla kojoj predajemo broj pina na koji smo spojili buzzer.
# NULA pločica ima logiku imenovanja pinova ovako: IO18, gdje je 18 broj koji dajemo varijabli.
BUZZER_PIN = 18

# Ovo su varijable kojima predajemo brojeve pinova na koje smo spojili četiri TIPKE. Svaka
# tipka dobiva svoj pin, jer ih pločica mora moći razlikovati.
BTN1 = 2
BTN2 = 3
BTN3 = 4
BTN4 = 5

# Ovo su frekvencije četiri note, u hercima. Frekvencija je koliko se puta u sekundi buzzer pomakne
# naprijed i natrag, i to je ono što naše uho čuje kao visinu zvuka: što je broj veći, to je nota viša.
# Imena dolaze iz glazbene skale, gdje je C4 onaj C u sredini klavijature piana.
NOTE_C4 = 262
NOTE_D4 = 294
NOTE_E4 = 330
NOTE_F4 = 349

# Ovdje stvaramo naša četiri Pin objekta za tipke. Pin.IN govori pločici da ovi pinovi treba čitati vrijednost
# umjesto da je pišu, a Pin.PULL_UP uključuje otpornik unutar čipa koji svaki pin veže na 3.3V dok je
# njegova tipka otpuštena. To znači da pin čita visoko (1) kada mu je tipka gore i nisko (0) dok je pritisnuta.
btn1 = Pin(BTN1, Pin.IN, Pin.PULL_UP)
btn2 = Pin(BTN2, Pin.IN, Pin.PULL_UP)
btn3 = Pin(BTN3, Pin.IN, Pin.PULL_UP)
btn4 = Pin(BTN4, Pin.IN, Pin.PULL_UP)

# Ovdje stvaramo naš PWM objekt za buzzer. duty_u16() postavlja koji dio vremena pin ostaje uključen, kao
# broj od 0 (uvijek isključen) do 65535 (uvijek uključen). Polovica toga je ravnomjerno prebacivanje uključeno-isključeno koje
# buzzeru daje njegov najčišći ton.
buzzer = PWM(Pin(BUZZER_PIN))
SOUND_ON = 32768
SOUND_OFF = 0

# Počni s tihim buzzerom, da ne pravi buku prije nego je ijedna tipka pritisnuta.
buzzer.duty_u16(SOUND_OFF)


def play_note(frequency):
# Ovo je funkcija koju smo napisali sami. Pokreće notu i ostavlja je da svira.
# freq() postavlja koliko brzo pin prebacuje, što je visina tona, a duty_u16() zatim pokreće zvuk.
buzzer.freq(frequency)
buzzer.duty_u16(SOUND_ON)


def stop_note():
# Ova funkcija zaustavlja koji god zvuk je buzzer pravio, a to je ono što notu tjera da prestane onog trenutka kada
# pustiš tipku.
buzzer.duty_u16(SOUND_OFF)


while True:

# value() je funkcija koja čita vrijednost s pina, ili 1 (visoko) ili 0 (nisko). Zbog pull-up
# otpornika, pritisnuta tipka daje 0.
# Primijeti lanac "elif": pločica provjerava tipke po redu i zaustavlja se na prvoj koju nađe pritisnutu, pa
# pritisak dvije tipke odjednom svira samo notu koja dolazi prva u ovoj listi.
if btn1.value() == 0:
play_note(NOTE_C4)
elif btn2.value() == 0:
play_note(NOTE_D4)
elif btn3.value() == 0:
play_note(NOTE_E4)
elif btn4.value() == 0:
play_note(NOTE_F4)
else:

# Ako nijedna tipka nije pritisnuta, završimo ovdje, i buzzer utihne.
stop_note()

# time.sleep_ms() pauzira program za zadani broj milisekundi. Ova vrlo kratka pauza daje
# kontaktima tipke trenutak da se umire, što sprječava da se jedan pritisak pročita kao nekoliko.
time.sleep_ms(50)

Što bi trebao vidjeti

Pritisni Run. Ništa se ne događa dok ne pritisneš tipku. Buzzer je tih, i ništa se ne ispisuje, jer ova skripta nikada ne poziva print(). Jedini izlaz je zvuk.

Pritisni tipku najbližu pločici. Trebao bi čuti postojan ton koji traje točno onoliko dugo koliko je držiš, i prestaje onog trenutka kada je pustiš. Kreni prema vani i visina tona raste: C4, D4, E4, F4.

Prst pritišće jednu od četiri tipke na gotovom mini pianu
Držanje tipke pritisnutom: nota zvuči dokle god tvoj prst tamo ostaje

Stvari koje vrijedi probati kada radi:

  • Drži dvije tipke odjednom. Zvuči samo niža od dvije, zbog elif lanca.
  • Sviraj brzo. Kratka pauza u petlji znači da pločica tipke gleda samo 20 puta u sekundi, pa vrlo brzo sviranje djeluje malo tupo.
  • Promijeni frekvenciju. Uredi jednu od NOTE_ vrijednosti, pokreni ponovno, i ta je tipka preštimana.
ℹ️
Nema zvuka ni s jedne tipke? Provjeri prvo dvije žice mase: j30 do plave vodilice, i žicu koja spaja dvije plave vodilice. Bez te druge žice ništa na a–e rubu nije spojeno na masu, pa nijedna tipka ne može svoj pin povući u nisko stanje a buzzer nema povratni put. Jedna tipka tiha a ostale rade? Dvije žice te tipke vjerojatno su na istoj strani središnjeg kanala, ili su joj nožice sletjele u jedan red umjesto u dva.
ℹ️
Note u pogrešnom redoslijedu? Dvije od četiri signalne žice su zamijenjene. Sve su iste boje kada su na mjestu, pa ih prati natrag do pločice i provjeri da IO2 doseže tipku najbližu pločici a IO5 najdalju.
ℹ️
Nota koja nastavlja zvučati nakon što pritisneš Stop? Zaustavljanje skripte ostavlja PWM hardver točno kakav je bio, pa nota koja je svirala nastavlja. Pokreni ponovno i pusti tipke, ili resetiraj pločicu.

Cijeli primjer

Pogledaj cijeli kod primjera na linku ispod:

7.2_Mini_piano.py

Projekt koji pravi jednostavan piano pomoću 4 tipke i pasivnog buzzera. Svaka tipka proizvodi svoju notu.