7.6 Morseov kod
Svaki projekt do sada bio je jednosmjeran razgovor: pločica govori, ti gledaš. Ovaj sluša. Upišeš poruku u konzolu, pločica svako slovo potraži u tablici točaka i crtica, i izblinka ga na jednoj jedinoj LED-ici, koristeći isti kod koji je poruke nosio telegrafskim žicama stoljeće prije nego je itko imao računalo.
Krug je najjednostavniji u kitu: jedna LED-ica, jedan otpornik, tri žice. Sve zanimljivo je u programu.
U ovoj dokumentaciji naučit ćeš:
- Kako pročitati tekst koji upišeš u konzolu pomoću
input() - Što je rječnik (dictionary), i zašto pobjeđuje dugi lanac
ifizjava - Kako
get()nešto potraži bez rušenja kada toga nema - Kako pisati vlastite funkcije da dulji program ostane čitljiv
- Kako Morseov kod sve mjeri u jedinicama umjesto u milisekundama
Potreban hardver:
- 1x Soldered NULA MINI pločica
- 1x Breadboard
- 1x LED-ica (bilo koje boje)
- 1x otpornik od 330 Ω (narančasti-narančasti-smeđi)
- 3x Jumper žice
- 1x USB-C kabel
Spajanje komponenti
Ovaj projekt koristi jedan jedini pin: IO2, koji sjedi u redu 25 na f–j strani. Tijelo pločice prekriva stupce f–i, pa su j25 i j30 jedine rupice u koje na tom kraju stvarno možeš uvesti žicu. Sve ostalo odvija se dalje duž iste f–j strane, dobro odmaknuto od pločice.
IO2 na f–j strani ali TX na a–e strani. Broji redove na istoj strani na koju utiskuješ.1. Umetni NULA MINI pločicu na breadboard
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. Trebala bi zauzeti redove 25 do 30.

2. Napravi liniju mase i izvedi IO2
Ovdje ulaze dvije žice, jer su to dva kraja kruga koji ćeš između njih sagraditi.
Prvo jumper žica iz j30 (GND) do plave − vodilice. Ta vodilica postaje dijeljena linija mase, točno kao u svakom drugom projektu u ovom kitu.
Zatim jumper žica iz j25 (IO2) duž do j15. Ona nosi Morseov signal ispod pločice do reda do kojeg stvarno možeš doći.

3. Dodaj otpornik od 330 Ω
Utisni otpornik tako da premosti red 15 i red 13. Prstenovi mu se čitaju narančasti-narančasti-smeđi. Otpornik nema polaritet, pa je bilo koja strana ispravna.

4. Dodaj LED-icu
LED-ica ima polaritet. Njezina duža nožica je anoda, i ta ide u red 13, uz otpornik. Kraća nožica ide u red 11.

5. Spoji LED-icu na masu
Još jedna jumper žica, iz j11 do plave − vodilice. To zatvara krug: IO2 → otpornik → LED-ica → masa.

6. Spoji pločicu na računalo
Utisni USB-C kabel u pločicu i u računalo. Ljubičasta PWR LED-ica se upali; zelena LED-ica ostaje tamna, jer još ništa nije upisano.

Kako krug radi
Važna su samo tri reda, i sjede serijski, pa struja ima točno jedan put koji može slijediti:
| Red | Što je u njemu |
|---|---|
| 15 | jumper žica s IO2, i jedna nožica otpornika |
| 13 | druga nožica otpornika, i duga nožica LED-ice |
| 11 | kratka nožica LED-ice, i jumper žica do − vodilice |
Svih pet rupica u redu spojeno je unutar breadboarda, a to je ono što dopušta da se dvije različite komponente sretnu u jednom redu a da se ne dotiču. Zato i točni brojevi redova nisu važni: bilo koja tri slobodna reda rade, dokle god je redoslijed IO2 → otpornik → LED-ica → masa sačuvan.
Kada skripta pozove led.value(1), IO2 se dovede na 3.3 V, struja teče tim lancem i LED-ica se pali. led.value(0) vraća pin na 0 V i LED-ica se gasi. To je cijeli hardver. Sve ostalo na ovoj stranici je program.
Kako Morseov kod radi
Morseov kod svoje signale ne mjeri u milisekundama. Sve mjeri u jedinicama, gdje je jedna jedinica dužina točke, a svako drugo trajanje je njezin višekratnik:
| Dužina | |
|---|---|
| Točka | 1 jedinica svjetla |
| Crtica | 3 jedinice svjetla |
| Razmak između točaka i crtica unutar slova | 1 jedinica tišine |
| Razmak između slova | 3 jedinice tišine |
| Razmak između riječi | 7 jedinica tišine |
Zato skripta sadrži samo jedan pravi broj. DOT_DURATION je 300 ms a sve ostalo se iz njega izračunava:
DOT_DURATION = 300
DASH_DURATION = DOT_DURATION * 3
SYMBOL_GAP = DOT_DURATION
LETTER_GAP = DOT_DURATION * 3
WORD_GAP = DOT_DURATION * 7
Promijeni sam DOT_DURATION i cijeli se prijenos ubrza ili uspori a ostaje ispravan Morseov kod. Postavi ga na 100 i dobiješ brzog operatera; postavi ga na 600 i dobiješ sporog.
Tablica slova, kao rječnik
Skripta znak mora pretvoriti u niz točaka i crtica. Mogla bi to raditi s dvadeset i šest if izjava, ali umjesto toga koristi rječnik: tablicu parova gdje nešto potražiš imenujući to.
MORSE_TABLE = {
"A": ".-", "B": "-...", "C": "-.-.", "D": "-..", "E": ".",
...
" ": " ",
}
Svaki unos sparuje ključ, znak, s vrijednošću, kodom koji ga predstavlja. Traženje jednog svodi se na imenovanje ključa, a dodati vlastiti znak znači dodati jednu liniju ovdje i ne promijeniti ništa drugo. To je cijela prednost pred lancem if izjava.
struct da drži svaki par slova i koda, polje tih structova, prebrojavanje izračunato pomoću sizeof, i petlja da se kroz to traži. Python sve to ima ugrađeno, i zato je MicroPython verzija ovog projekta petnaest linija koda kraća od Arduino verzije.Posljednji unos sparuje razmak s razmakom, a tako skripta prepoznaje razmak između dvije riječi.
Sigurno traženje pomoću get()
def get_morse_code(character):
return MORSE_TABLE.get(character.upper(), "")
U toj jednoj liniji događaju se dvije stvari.
upper() malo slovo pretvara u veliko, pa upisivanje sos radi jednako dobro kao SOS, jer tablica drži samo velika slova.
get() je siguran način čitanja iz rječnika. Pisanje MORSE_TABLE["#"] za znak koji nije u tablici diže KeyError i zaustavlja program. get() prima drugi argument upravo za taj slučaj, a ovdje je to prazan tekst, pa nepoznat znak tiho proizvede ništa, a funkcija za prijenos ga preskoči.
get() cijela bi skripta pala na prvom takvom znaku.Dvije petlje kroz isti tekst
transmit_text() kroz tvoju poruku prolazi dvaput. Prvi prolaz skuplja prijevod i ispisuje ga da možeš pratiti; drugi prolaz izblinka istu stvar na LED-ici. Razdvajanje na dva je ono što dopušta da se cijeli prijevod pojavi na ekranu odmah, prije nego je LED-ica dovršila sricanje čak i prvog slova.
codes = []
for character in text:
codes.append(get_morse_code(character))
print("Morse: ", " ".join(codes))
" ".join(codes) lijepi listu dijelova u jedan string s razmakom između svakog para. To je Python način gradnje linije iz dijelova, i čita se bolje od sabiranja stringova jednog po jednog.U prolazu s blinkanjem razmak se ne blinka uopće. On je pauza. Kada petlja nađe jedan, čeka razmak riječi i pomoću continue preskače ostatak tog prolaza. Svakom drugom znaku simboli se izblinkaju jedan po jedan, a onda petlja čeka razmak slova prije nego nastavi.
for symbol in code: kroz string prolazi znak po znak, pa code od "..." daje tri prolaza s symbol koji je svaki put .. Stringovi se u Pythonu ponašaju kao liste znakova, što te poštedi ručnog indeksiranja.Razmaci su malo darežljivi
Prije nego počneš brojati blinkove, vrijedi znati jednu stvar. blink_symbol() svaki simbol završava jednom jedinicom tišine, a onda transmit_text() na to dodaje LETTER_GAP. Zato je razmak koji stvarno vidiš između dva slova 1 + 3 = 4 jedinice, a ne 3, a između dvije riječi 1 + 3 + 7 = 11 jedinica, a ne 7.
Pravi Morseov kod razmak simbola zamjenjuje, a ne dodaje na njega. Ta razlika poruku ne čini pogrešnom. Svaka točka i crtica su točno prave dužine, a razmaci se i dalje jasno razlikuju jedan od drugoga; prijenos je samo malo sporiji od standarda. Vrijedi to znati da se ono što brojiš poklapa s onim što očekuješ.
Kod
Ispod je cijeli kod primjera za ovaj projekt:
from machine import Pin
import time
# Ovo je varijabla kojoj predajemo broj pina na koji smo spojili LED-icu.
# NULA pločica ima logiku imenovanja pinova ovako: IO2, gdje je 2 broj koji dajemo varijabli.
#
# Zapamti da LED-ici treba otpornik od 330 ohma u seriji s njom. Taj otpornik ograničava koliko struje teče, a
# bez njega LED-ica vuče više nego što su ona ili pin građeni izdržati, pa se oboje može oštetiti.
LED_PIN = 2
# Morseov kod svoje signale ne mjeri u milisekundama nego u jedinicama, a svako drugo trajanje je višekratnik jedne
# jedinice. Zato je samo prva vrijednost ispod pravi broj a ostale se iz nje izračunavaju: promijeni sam
# DOT_DURATION i cijeli se prijenos ubrza ili uspori a ostaje ispravan Morseov kod.
DOT_DURATION = 300
DASH_DURATION = DOT_DURATION * 3
SYMBOL_GAP = DOT_DURATION
LETTER_GAP = DOT_DURATION * 3
WORD_GAP = DOT_DURATION * 7
# Ovo je naša tablica za traženje: sparuje svaki znak koji možemo poslati s točkama i crticama koje ga predstavljaju. U
# Pythonu se ovakva tablica zove rječnik, a potražiti nešto u njoj jednostavno je kao imenovati
# znak koji želiš.
# Posljednji unos sparuje razmak s razmakom, a tako prepoznajemo razmak između dvije riječi.
MORSE_TABLE = {
"A": ".-", "B": "-...", "C": "-.-.", "D": "-..", "E": ".",
"F": "..-.", "G": "--.", "H": "....", "I": "..", "J": ".---",
"K": "-.-", "L": ".-..", "M": "--", "N": "-.", "O": "---",
"P": ".--.", "Q": "--.-", "R": ".-.", "S": "...", "T": "-",
"U": "..-", "V": "...-", "W": ".--", "X": "-..-", "Y": "-.--",
"Z": "--..",
"1": ".----", "2": "..---", "3": "...--", "4": "....-", "5": ".....",
"6": "-....", "7": "--...", "8": "---..", "9": "----.", "0": "-----",
" ": " ",
}
# Ovdje stvaramo naš Pin objekt za LED-icu. Pin.OUT govori pločici da ovaj pin treba pisati vrijednost umjesto da je
# čita. Odmah nakon toga u njega pišemo 0, pa LED-ica počinje ugašena.
led = Pin(LED_PIN, Pin.OUT)
led.value(0)
def get_morse_code(character):
# Ovo je funkcija koju smo napisali sami. Prima znak i vraća točke i crtice koje ga predstavljaju.
# upper() malo slovo pretvara u veliko, tako da upisivanje "sos" radi jednako dobro kao "SOS".
# get() znak traži u našoj tablici, a druga vrijednost koju mu damo je ono što se vrati kada
# znaka uopće nema u tablici. Ovdje je to prazan tekst, koji funkcija za prijenos jednostavno preskoči.
return MORSE_TABLE.get(character.upper(), "")
def blink_symbol(symbol):
# Ova funkcija izblinka jednu točku ili crticu. Odabire pravo trajanje za simbol koji je dobila, pali
# LED-icu točno toliko dugo, a onda je gasi i čeka još jednu jedinicu, a to je tišina koja
# jedan simbol odvaja od sljedećeg.
if symbol == ".":
duration = DOT_DURATION
else:
duration = DASH_DURATION
led.value(1)
time.sleep_ms(duration)
led.value(0)
time.sleep_ms(SYMBOL_GAP)
def transmit_text(text):
# Ova funkcija prenosi cijeli komad teksta. Posao radi dvaput: prvo ispisuje prijevod u
# konzolu da možeš pratiti, a zatim istu stvar izblinka na LED-ici.
print()
print("--- TRANSMITTING ---")
print("Text: ", text)
# Ova prva petlja prolazi kroz tekst znak po znak. Za svaki od njih potražimo kod i
# skupimo ga, a join() zatim skupljene dijelove slijepi s razmakom između njih.
codes = []
for character in text:
codes.append(get_morse_code(character))
print("Morse: ", " ".join(codes))
print("--------------------")
# Ova druga petlja prolazi kroz taj isti tekst ponovno, ali ovaj put blinka umjesto da ispisuje.
# Razmak se ne blinka uopće, on je pauza, pa kada ga nađemo čekamo razmak riječi i preskačemo ostatak ovog
# prolaza pomoću continue. Inače unutarnja petlja izblinka simbole slova jedan po jedan, a kada su gotovi
# čekamo razmak slova prije nego nastavimo na sljedeće slovo.
for character in text:
code = get_morse_code(character)
if code == " ":
time.sleep_ms(WORD_GAP)
continue
for symbol in code:
blink_symbol(symbol)
time.sleep_ms(LETTER_GAP)
print()
print("Transmission complete!")
print()
# Pozovi korisnika da nešto upiše. Piši u konzolu svog editora i pritisni Enter.
print("Enter text to send via Morse code:")
while True:
# input() čeka dok ne upišeš liniju i pritisneš Enter, pa nam preda ono što si upisao. To je najjednostavniji način
# dobivanja informacije s računala u pločicu, i protuteža je print()-u koji smo cijelo vrijeme
# koristili u drugom smjeru.
text = input()
# strip() odstranjuje zalutale razmake ili zaostale znakove kraja linije s oba kraja, što vrijedi napraviti jer
# različiti sustavi svoje linije završavaju malo drugačije.
text = text.strip()
# Na kraju provjeravamo da je nakon odstranjivanja stvarno nešto ostalo, tako da pritisak na Enter u praznoj liniji ne
# pokrene prijenos, i tekst predajemo našoj funkciji iznad.
if len(text) > 0:
transmit_text(text)
Što bi trebao vidjeti
Pritisni Run. Pločica te pozdravi i onda čeka:
Enter text to send via Morse code:
Klikni u Shell, upiši poruku i pritisni Enter. Upiši je malim slovima, kao sos, da vidiš nešto korisno:
--- TRANSMITTING ---
Text: sos
Morse: ... --- ...
--------------------
Transmission complete!
Linija Text: vraća točno ono što si upisao, mala slova i sve, ali je linija Morse: ipak ispravna. To je upper() unutar get_morse_code() koji radi svoj posao: tablica drži samo velika slova, a svaki znak se pretvori prije nego ga se potraži. Prijevod se pojavljuje odjednom, sav, i tek onda LED-ica počinje blinkati.
input() čeka liniju iz konzole, a pritisci tipki upisani u polje editora idu u tvoju datoteku. Ako se ništa ne dogodi kada tipkaš, to je gotovo uvijek razlog.Linija Transmission complete! ne pojavljuje se dok LED-ica ne završi. To vrijedi primijetiti: cijeli transmit_text() izgrađen je iz time.sleep_ms(), pa dok poruka izlazi pločica ne radi ništa drugo uopće. Možeš tipkati tijekom prijenosa, ali se ništa neće dogoditi dok trenutni ne završi.
Pogledaj to jednom i tri se slova sama razdvajaju:
| Slovo | Kod | Što LED-ica radi |
|---|---|---|
| S | ... | tri kratka bljeska, blizu jedan drugom |
| O | --- | tri duga bljeska, blizu jedan drugom |
| S | ... | ponovno tri kratka bljeska |
Same bljeskove lako je razlikovati kada znaš što usporediti: crtica je upaljena tri puta dulje od točke. Razmaci rade ostatak posla: jedna jedinica tame između simbola unutar slova, i četiri jedinice između jednog slova i sljedećeg, što je dovoljno dugo da vidiš prekid ritma a da ništa ne brojiš.
SOS traje 9.9 sekundi od kraja do kraja, i to možeš izračunati na papiru. Tri točke, tri crtice i tri točke je 15 jedinica svjetla. Nakon svakog od devet simbola slijedi jedna jedinica tišine, a nakon svakog od tri slova još tri, što je 18 jedinica tišine. To je 33 jedinice ukupno, a 33 × 300 ms je 9.9 sekundi.
Kada se pojavi Transmission complete!, pločica je natrag u čekanju i možeš upisati nešto drugo. Probaj riječ s razmakom, kao HELLO WORLD, i pazi na dugu pauzu u sredini. To je razmak riječi, i daleko je najdulja tišina u bilo kojoj poruci.
hello. Točke nema u tablici, pa get() vraća prazan tekst i ona se jednostavno preskoči. Nema greške i nema rušenja, a ostatak poruke normalno se prenese.Ako se LED-ica nikada ne upali, skripta je gotovo sigurno u redu. Provjeri prvo polaritet LED-ice. Okreni je: njezina duga nožica pripada u red 13, s otpornikom, a LED-ica postavljena obrnuto ne provodi ništa, što izgleda točno kao mrtav krug. Ako konzola ispisuje prijevod a LED-ica ostaje tamna, program se ispravno izvršava i greška je definitivno u spajanju, što ju lijepo sužava.
Cijeli primjer
Pogledaj cijeli kod primjera na linku ispod:
7.6_Morse_code_transmitter.py
Projekt koji tekst koji upišeš u konzolu pretvara u Morseov kod i izblinka ga na jednoj LED-ici, koristeći rječnik kao tablicu za traženje i vlastite funkcije.