Kazalo:

Vadnica za zbiralnik AVR 3: 9 korakov
Vadnica za zbiralnik AVR 3: 9 korakov

Video: Vadnica za zbiralnik AVR 3: 9 korakov

Video: Vadnica za zbiralnik AVR 3: 9 korakov
Video: SKR PRO V1.1 TFT35 V2 2024, Julij
Anonim
Vadnica za sestavljalec AVR 3
Vadnica za sestavljalec AVR 3

Dobrodošli v vadnici številka 3!

Preden začnemo, želim povedati filozofsko. Ne bojte se eksperimentirati s vezji in kodo, ki jo ustvarjamo v teh vadnicah. Spremenite žice, dodajte nove komponente, odstranite komponente, spremenite vrstice kode, dodajte nove vrstice, izbrišite vrstice in poglejte, kaj se zgodi! Zelo težko je karkoli zlomiti in če to storite, koga briga? Nič, kar uporabljamo, vključno z mikrokrmilnikom, ni zelo drago in vedno je poučno videti, kako lahko stvari propadnejo. Ne samo, da boste naslednjič ugotovili, česa ne bi smeli storiti, ampak, kar je še pomembneje, vedeli boste, zakaj tega ne bi storili. Če ste kaj podobnega meni, ko ste bili otrok in ste dobili novo igračo, ni minilo dolgo, preden ste jo imeli v kosih, da vidite, kaj jo je odklenilo? Včasih je igrača na koncu nepopravljivo poškodovana, vendar nič hudega. Dovoljenje otroku, da raziskuje svojo radovednost celo do zlomljenih igrač, je tisto, kar ga spremeni v znanstvenika ali inženirja namesto v pomivalni stroj.

Danes bomo ožičili zelo preprosto vezje, nato pa se bomo nekoliko poglobili v teorijo. Oprostite, vendar potrebujemo orodja! Obljubim, da bomo to nadomestili v vadnici 4, kjer bomo delali resnejšo gradnjo vezja, rezultat pa bo precej kul. Vendar pa morate vse te vaje narediti zelo počasi in kontemplativno. Če samo plugate, sestavite vezje, kopirajte in prilepite kodo in jo nato zaženete, zagotovo bo delovalo, vendar se ne boste nič naučili. O vsaki vrstici morate razmišljati. Pavza. Poskusite. Izmisli. Če boste to storili tako, boste do konca 5. vadnice nehali graditi kul stvari in ne potrebujete več poučevanja. V nasprotnem primeru preprosto gledate in ne učite in ustvarjate.

Vsekakor dovolj filozofije, začnimo!

V tej vadnici boste potrebovali:

  1. svojo prototipno ploščo
  2. LED
  3. povezovalne žice
  4. upor okoli 220 do 330 ohmov
  5. Priročnik z navodili: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. Podatkovni list: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. drug kristalni oscilator (neobvezno)

Tukaj je povezava do celotne zbirke vadnic:

1. korak: Konstrukcija vezja

Sestavljanje vezja
Sestavljanje vezja

Vezje v tej vadnici je zelo preprosto. V bistvu bomo napisali "utripajoči" program, zato potrebujemo le naslednje.

Priključite LED na PD4, nato na 330 ohmski upor, nato na ozemljitev. tj.

PD4 - LED - R (330) - GND

in to je to!

Teorija pa bo zelo zahtevna …

2. korak: Zakaj potrebujemo komentarje in datoteko M328Pdef.inc?

Mislim, da bi morali začeti s prikazom, zakaj so datoteka include in komentarji v pomoč. Nobena od njih v resnici ni potrebna in kodo lahko napišete, sestavite in naložite na enak način brez njih in bo delovala popolnoma dobro (čeprav lahko brez datoteke za vključitev od asemblerja dobite nekaj pritožb - vendar brez napak)

Tukaj je koda, ki jo bomo napisali danes, le da sem odstranil komentarje in datoteko include:

.naprava ATmega328P

.org 0x0000 jmp a.org 0x0020 jmp ea: ldi r16, 0x05 out 0x25, r16 ldi r16, 0x01 sts 0x6e, r16 sei clr r16 out 0x26, r16 sbi 0x0a, 0x04 sbi 0x0b, 0x04 b: sbi 0x0c, 0 cbi 0x0b, 0x04 rcall c rjmp bc: clr r17 d: cpi r17, 0x1e brne d ret e: inc r17 cpi r17, 0x3d brne PC+2 clr r17 reti

precej preprosto kajne? Haha. Če ste to datoteko sestavili in naložili, bo LED utripala s hitrostjo 1 utripa na sekundo, pri čemer bo utripanje trajalo 1/2 sekunde, premor med utripanjem pa 1/2 sekunde.

Vendar pogled na to kodo ni razsvetljen. Če bi pisali tako kodo in bi jo želeli v prihodnosti spremeniti ali preurediti, bi imeli težave.

Zato dajmo komentarje in vključimo datoteko nazaj, da jo bomo lahko nekoliko razumeli.

3. korak: Blink.asm

Tukaj je koda, o kateri bomo danes razpravljali:

;************************************

; napisal: 1o_o7; datum:; različica: 1.0; datoteka shranjena kot: blink.asm; za AVR: atmega328p; frekvenca ure: 16MHz (neobvezno); **********************************; Funkcija programa: ---------------------; odšteva sekunde s utripanjem LED;; PD4 - LED - R (330 ohm) - GND;; --------------------------------------.nolist.include "./m328Pdef.inc".list; ==============; Izjave:.def temp = r16.def prelivi = r17.org 0x0000; pomnilnik (PC) lokacija upravljalnika ponastavitve rjmp Ponastavi; jmp stane 2 cikla procesorja, rjmp pa samo 1; torej razen če morate preskočiti več kot 8k bajtov; rabiš samo rjmp. Nekateri mikrokrmilniki torej samo; imeti rjmp in ne jmp.org 0x0020; pomnilniška lokacija upravljalnika pretoka Timer0 rjmp overflow_handler; pojdite sem, če pride do prekinitve prelivanja timer0; ============ Ponastavi: ldi temp, 0b00000101 ven TCCR0B, temp; nastavite bite za izbiro ure CS00, CS01, CS02 na 101; s tem se števec časovnika 0, TCNT0 preklopi v način FCPU/1024; zato tiktaka pri frekvenci CPU/1024 ldi temp, 0b00000001 sts TIMSK0, temp; nastavite bit Timie Overflow Interrupt Enable (TOIE0) Omogočanje prekinitve preklopa časovnika; registra časovne prekinitvene maske (TIMSK0) sei; omogoči globalne prekinitve - enakovredno "sbi SREG, I" clr temp out TCNT0, temp; inicializirajte časovnik/števec na 0 sbi DDRD, 4; nastavite PD4 na izhod; ======================; Glavni del programa: utripa: sbi PORTD, 4; vklopite LED na zakasnitvi klica PD4; zamuda bo 1/2 sekunde cbi PORTD, 4; izklopite LED pri zakasnitvi klica PD4; zakasnitev bo utripala 1/2 sekunde rjmp; zanka nazaj na zamudo pri zagonu: clr preplavi; nastavite prelive na 0 sec_count: cpi preliv, 30; primerjajte število prelivov in 30 brne sec_count; veja nazaj v sec_count, če ni enako ret; če je prišlo do 30 prelivov, se vrnite v utripajoči overflow_handler: inc preliv; spremenljivki overflows dodaj 1, cpi overflows, 61; primerjaj s 61 brne PC+2; Program Counter + 2 (preskoči naslednjo vrstico), če ni enakih prelivov clr; če je prišlo do 61 prelivov, ponastavite števec na nič reti; vrnitev iz prekinitve

Kot lahko vidite, so moji komentarji zdaj nekoliko krajši. Ko vemo, kakšni ukazi v naboru navodil, nam tega ni treba razlagati v komentarjih. Pojasniti moramo le, kaj se dogaja s stališča programa.

Komaj bomo razpravljali o tem, kaj vse to počne, a najprej poskusimo dobiti globalno perspektivo. Glavni del programa deluje na naslednji način.

Najprej nastavimo bit 4 PORTD z "sbi PORTD, 4", ki pošlje 1 na PD4, ki napetost na tem pinu postavi na 5V. S tem se prižge LED. Nato skočimo na podprogram "zakasnitev", ki šteje 1/2 sekunde (kako to počne, bomo razložili kasneje). Nato se vrnemo k utripanju in počistimo bit 4 na PORTD, ki nastavi PD4 na 0V in s tem ugasne LED. Nato zamudimo še 1/2 sekunde in nato znova skočimo nazaj na začetek utripanja z "rjmp utripanjem".

To kodo morate zagnati in preveriti, ali deluje tako, kot mora.

In tu ste! To je vse, kar ta koda fizično počne. Notranja mehanika tega, kar počne mikrokrmilnik, je nekoliko bolj vpletena in zato delamo to vadnico. Pogovorimo se torej o vsakem odseku.

4. korak:.org Direktive o sestavljanju

Že vemo, kaj počnejo direktive sestavljalcev.nolist,.list,.include in.def iz prejšnjih vadnic, zato si najprej oglejmo 4 vrstice kode, ki sledijo za tem:

.org 0x0000

jmp Ponastavi.org 0x0020 jmp overflow_handler

Stavek.org pove asemblerju, kam v "Program Memory" naj postavi naslednji stavek. Med izvajanjem programa "Števec programov" (skrajšano kot PC) vsebuje naslov trenutne vrstice, ki se izvaja. Torej, v tem primeru, ko je računalnik pri 0x0000, bo na tem pomnilniškem mestu prikazan ukaz "jmp Reset". Razlog, zakaj želimo postaviti jmp Reset na to mesto, je, ker računalnik ob zagonu programa ali ponastavitvi čipa začne izvajati kodo na tem mestu. Kot smo videli, smo mu pravkar povedali, naj takoj "skoči" na razdelek z oznako "Ponastavi". Zakaj smo to storili? To pomeni, da sta zadnji dve zgornji vrstici zgolj preskočeni! Zakaj?

No, tam stvari postanejo zanimive. Zdaj boste morali odpreti pregledovalnik PDF s celotnim podatkovnim listom ATmega328p, na katerega sem opozoril na prvi strani te vadnice (zato je to 4. točka v razdelku »potrebovali boste«). Če je vaš zaslon premajhen ali imate že preveč odprtih oken (tako je pri meni), lahko naredite to, kar počnem, in ga postavite na Ereader ali telefon Android. Če nameravate napisati montažno kodo, jo boste uporabljali ves čas. Super stvar je, da so vsi mikrokrmilniki organizirani na zelo podobne načine, zato se vam bo, ko se boste navadili brati podatkovne liste in kodirali iz njih, skoraj nepomembno, da to storite za drug mikrokrmilnik. Tako se dejansko učimo uporabljati vse mikrokrmilnike v nekem smislu in ne le atmega328p.

V redu, pojdite na stran 18 v podatkovnem listu in si oglejte sliko 8-2.

Tako je nastavljen programski pomnilnik v mikrokrmilniku. Vidite lahko, da se začne z naslovom 0x0000 in je ločen v dva dela; razdelek bliskavice aplikacij in razdelek zagonskega bliskavice. Če na kratko pogledate stran 277 tabele 27-14, boste videli, da razdelek bliskavice aplikacij zavzame lokacije od 0x0000 do 0x37FF, razdelek zagonskega bliskavice pa zavzame preostale lokacije od 0x3800 do 0x3FFF.

Vaja 1: Koliko lokacij je v pomnilniku programa? Tj. pretvorimo 3FFF v decimalno vrednost in dodamo 1, saj začnemo šteti pri 0. Ker je vsako pomnilniško mesto široko 16 bitov (ali 2 bajta), koliko je skupno število bajtov pomnilnika? Zdaj to pretvorite v kilobajte, pri tem pa ne pozabite, da je v kilobajtu 2^10 = 1024 bajtov. Odsek zagonskega bliskavice sega od 0x3800 do 0x37FF, koliko kilobajtov je to? Koliko kilobajtov pomnilnika nam ostane za shranjevanje našega programa? Z drugimi besedami, kako velik je lahko naš program? Končno, koliko vrstic kode lahko imamo?

V redu, zdaj, ko vemo vse o organizaciji pomnilnika flash programa, nadaljujmo z razpravo o izjavah.org. Vidimo, da prva pomnilniška lokacija 0x0000 vsebuje naše navodilo za skok na naš razdelek, ki smo ga poimenovali Ponastavi. Zdaj vidimo, kaj počne stavek ".org 0x0020". Piše, da želimo, da se navodilo v naslednji vrstici postavi na pomnilniško mesto 0x0020. Navodilo, ki smo ga tam postavili, je skok na razdelek v naši kodi, ki smo ga označili z "overflow_handler" … zakaj bi za vraga zahtevali, da se ta skok postavi na pomnilniško mesto 0x0020? Če želite izvedeti, se obrnemo na stran 65 v podatkovnem listu in si oglejmo tabelo 12-6.

Tabela 12-6 je tabela "Ponastavi in prekini vektorje" in natančno prikazuje, kam bo šel računalnik, ko prejme "prekinitev". Na primer, če pogledate vektorsko številko 1. "Vir" prekinitve je "RESET", ki je opredeljen kot "zunanji pin, ponastavitev ob vklopu, ponastavitev rjave barve in ponastavitev nadzornega sistema", kar pomeni, če ko se to zgodi z našim mikrokrmilnikom, bo računalnik začel izvajati naš program na mestu pomnilnika programa 0x0000. Kaj pa naša direktiva.org? No, ukaz smo postavili na pomnilniško mesto 0x0020 in če pogledate navzdol v tabelo, boste videli, da bo, če pride do prelivanja Timer/Counter0 (prihaja iz TIMER0 OVF), izvedel vse, kar je na lokaciji 0x0020. Torej, kadar koli se to zgodi, bo računalnik skočil na mesto, ki smo ga označili kot "overflow_handler". Kul, kajne? Čez minuto boste videli, zakaj smo to storili, vendar najprej zaključimo ta korak vadnice ob strani.

Če želimo narediti našo kodo bolj čisto in urejeno, bi morali res zamenjati 4 vrstice, o katerih trenutno razpravljamo, z naslednjimi (glejte stran 66):

.org 0x0000

rjmp Ponastavi; PC = 0x0000 reti; PC = 0x0002 reti; PC = 0x0004 reti; PC = 0x0006 reti; PC = 0x0008 reti; PC = 0x000A… reti; PC = 0x001E jmp overflow_handler: PC = 0x0020 reti: PC = 0x0022… reti; PC = 0x0030 reti; PC = 0x0032

Tako da, če se pojavi določena prekinitev, se bo samo "reti", kar pomeni "vrnitev iz prekinitve", in nič drugega se ne bo zgodilo. Če teh različnih prekinitev nikoli ne "omogočimo", potem ne bodo uporabljeni in programsko kodo lahko postavimo na ta mesta. V našem trenutnem programu "blink.asm" bomo omogočili le prekinitev pretoka timer0 (in seveda prekinitev ponastavitve, ki je vedno omogočena), zato se ne bomo obremenjevali z drugimi.

Kako potem "omogočimo" prekinitev prelivanja timer0? … to je tema našega naslednjega koraka v tej vadnici.

5. korak: Časovnik/števec 0

Časovnik/števec 0
Časovnik/števec 0

Oglejte si zgornjo sliko. To je proces odločanja "računalnika", ko nekateri zunanji vplivi "prekinejo" tok našega programa. Prva stvar, ki jo naredi, ko od zunaj prejme signal, da je prišlo do prekinitve, je, da preveri, ali smo za to vrsto prekinitve nastavili bit za omogočanje prekinitve. Če nismo, potem nadaljuje z izvajanjem naše naslednje vrstice kode. Če smo določili ta bit za omogočanje prekinitve (tako da je na tem mestu bita 1 namesto 0), bo nato preveril, ali smo omogočili »globalne prekinitve«, če ne, pa bo spet šel v naslednjo vrstico kode in nadaljujte. Če smo omogočili tudi globalne prekinitve, bo šel na lokacijo programskega pomnilnika te vrste prekinitve (kot je prikazano v tabeli 12-6) in izvedel vse ukaze, ki smo jih tam postavili. Pa poglejmo, kako smo vse to implementirali v našo kodo.

Oddelek z oznako Ponastavi naše kode se začne z naslednjima dvema vrsticama:

Ponastaviti:

ldi temp, 0b00000101 out TCCR0B, temp

Kot že vemo, se v temp (tj. R16) naloži številka, ki sledi, to je 0b00000101. Nato to številko izpiše v register, imenovan TCCR0B, z ukazom "out". Kaj je ta register? No, pojdimo na stran 614 podatkovnega lista. To je sredi tabele, ki povzema vse registre. Na naslovu 0x25 boste našli TCCR0B. (Zdaj veste, od kod prihaja vrstica "out 0x25, r16" v moji različici kode brez komentarjev). Po zgornjem segmentu kode vidimo, da smo nastavili 0. bit in 2. bit, ter počistili vse ostalo. Če pogledate tabelo, lahko vidite, da to pomeni, da smo nastavili CS00 in CS02. Zdaj pa pojdimo na poglavje v podatkovnem listu, imenovano "8-bitni časovnik/števec0 s PWM". Pojdite zlasti na stran 107 tega poglavja. Videli boste enak opis registra "Timer/Counter Control Register B" (TCCR0B), ki smo ga pravkar videli v tabeli povzetka registra (torej bi lahko prišli naravnost sem, vendar sem želel, da vidite, kako uporabljati tabele povzetka za prihodnjo uporabo). Na podatkovnem listu je še naprej opisan vsak bit v tem registru in kaj počnejo. Vse to bomo za zdaj preskočili in stran obrnili na tabelo 15-9. Ta tabela prikazuje "Opis ure za izbiro ure". Zdaj poglejte navzdol po tabeli, dokler ne najdete vrstice, ki ustreza bitom, ki smo jih pravkar nastavili v tem registru. Vrstica pravi "clk/1024 (iz predkalerja)". To pomeni, da želimo, da se Timer/Counter0 (TCNT0) označuje skupaj s hitrostjo, ki je frekvenca CPU -ja, deljena z 1024. Ker imamo mikrokrmilnik krmiljen s 16MHz kristalnim oscilatorjem, to pomeni, da je hitrost, da naš CPU izvaja navodila 16 milijonov navodil na sekundo. Torej je stopnja, ki jo bo naš števec TCNT0 označil, 16 milijonov/1024 = 15625 krat na sekundo (poskusite z različnimi bitnimi urami in poglejte, kaj se zgodi - se spomnite naše filozofije?). Zapomnimo si številko 15625 za pozneje in pojdimo na naslednji dve vrstici kode:

ldi temp., 0b00000001

sts TIMSK0, temp

S tem nastavite 0 -ti bit registra, imenovanega TIMSK0, in počistite vse ostalo. Če pogledate stran 109 v podatkovnem listu, boste videli, da TIMSK0 pomeni "Timer/Counter Interrupt Mask Register 0" in naša koda je nastavila 0 -ti bit z imenom TOIE0, ki pomeni "Timer/Counter0 Overflow Interrupt Enable" … Tam! Zdaj vidite, za kaj gre. Zdaj imamo nastavljen "bit za omogočanje prekinitve", kot smo želeli od prve odločitve na naši sliki na vrhu. Zdaj moramo le še omogočiti »globalne prekinitve« in naš program se bo lahko odzval na tovrstne prekinitve. Kmalu bomo omogočili globalne prekinitve, vendar preden ste to storili, vas je morda nekaj zmotilo. Zakaj sem za vraga uporabil ukaz "sts" za kopiranje v register TIMSK0 namesto običajnega "out"?

Kadar koli me vidite, uporabim navodila, ki jih prej niste videli, se najprej obrnite na stran 616 v podatkovnem listu. To je "Povzetek nabora navodil". Zdaj poiščite navodilo "STS", ki sem ga uporabil. Piše, da vzame številko iz registra R (uporabili smo R16) in lokacije »Shrani neposredno v SRAM« k (v našem primeru poda TIMSK0). Zakaj smo torej morali za shranjevanje v TIMSK0 uporabiti "sts", ki traja 2 cikla ure (glej zadnji stolpec v tabeli), za shranjevanje v TCCR0B pa smo potrebovali le "out", ki traja le en cikel ure? Če želite odgovoriti na to vprašanje, se moramo vrniti v tabelo povzetka registra na strani 614. Vidite, da je register TCCR0B na naslovu 0x25, pa tudi na (0x45), kajne? To pomeni, da gre za register v SRAM -u, je pa tudi za določeno vrsto registra, imenovano "vrata" (ali i/o register). Če pogledate tabelo povzetka navodil poleg ukaza "out", boste videli, da vzame vrednosti iz "delovnih registrov", kot je R16, in jih pošlje v PORT. Tako lahko pri pisanju v TCCR0B uporabimo »out« in si prihranimo cikel ure. Zdaj pa poiščite TIMSK0 v tabeli registra. Vidite, da ima naslov 0x6e. To je izven obsega vrat (to so le prve lokacije 0x3F SRAM -a), zato se morate vrniti k uporabi ukaza sts in za to vzeti dva cikla procesorja. Prosimo, preberite opombo 4 na koncu tabele povzetka navodil na strani 615. Upoštevajte tudi, da so vsa naša vhodna in izhodna vrata, na primer PORTD, na dnu tabele. Na primer, PD4 je bit 4 na naslovu 0x0b (zdaj vidite, od kod prihajajo vse stvari 0x0b v moji komentirani komenti!).. v redu, hitro vprašanje: ali ste spremenili "sts" v "out" in poglejte, kaj se zgodi? Spomnite se naše filozofije! polomi! ne verjemite mi samo na besedo.

V redu, preden nadaljujemo, se za minuto obrnemo na stran 19 v podatkovnem listu. Prikaže se slika podatkovnega pomnilnika (SRAM). Prvih 32 registrov v SRAM -u (od 0x0000 do 0x001F) so "splošni delovni registri" R0 do R31, ki jih ves čas uporabljamo kot spremenljivke v naši kodi. Naslednjih 64 registrov so vhodno/izhodna vrata do 0x005f (tj. Tisti, o katerih smo govorili, ki imajo v registrski tabeli zraven tiste naslove brez oklepajev, ki jih lahko uporabimo z ukazom "out" namesto "sts") Končno naslednji odsek SRAM -a vsebuje vse druge registre v zbirni tabeli do naslova 0x00FF, nazadnje pa preostali notranji SRAM. Zdaj pa se na kratko obrnimo na stran 12. Tam vidite tabelo "delovnih registrov splošnega namena", ki jih vedno uporabljamo kot spremenljivke. Vidite debelo črto med številkami R0 do R15 in nato R16 do R31? To je razlog, zakaj vedno uporabljamo R16 kot najmanjšega in v to se bom nekoliko poglobil v naslednji vadnici, kjer bomo potrebovali tudi tri 16-bitne registre posrednih naslovov, X, Y in Z. Ne bom vstopite v to, čeprav tega zdaj ne potrebujemo in smo dovolj zasuti.

Zavrtite eno stran nazaj na stran 11 podatkovnega lista. V zgornjem desnem kotu boste videli diagram registra SREG? Vidite, da se bit 7 tega registra imenuje "I". Zdaj pojdite navzdol po strani in preberite opis Bit 7…. Juhu! To je bit za omogočanje globalnega prekinitve. To je tisto, kar moramo nastaviti, da preidemo skozi drugo odločitev v zgornjem diagramu in omogočimo prekinitve časovnega/številskega prelivanja v našem programu. Naslednja vrstica našega programa bi se morala glasiti:

sbi SREG, I

ki v registru SREG nastavi bit z imenom "I". Vendar smo namesto tega uporabili navodila

sei

namesto tega. Ta del je v programih tako pogosto nastavljen, da so naredili preprostejši način.

V redu! Zdaj imamo pripravljene prekinitve prelivanja, tako da se bo naš "jmp overflow_handler" izvedel, kadar koli se pojavi.

Preden nadaljujemo, si na hitro oglejte register SREG (Status Status Register), ker je zelo pomemben. Preberite, kaj predstavlja vsaka od zastav. Zlasti številna navodila, ki jih uporabljamo, bodo te zastavice ves čas nastavljala in preverjala. Na primer, kasneje bomo uporabili ukaz "CPI", kar pomeni "primerjaj takoj". Oglejte si povzetek tabel z navodili za to navodilo in opazite, koliko zastavic nastavi v stolpcu »zastave«. Vse to so zastavice v SREG -u in naša koda jih bo nastavila in nenehno preverjala. Kmalu boste videli primere. Končno je zadnji del tega dela kode:

clr temp

izhod TCNT0, temp sbi DDRD, 4

Zadnja vrstica tukaj je precej očitna. Samo nastavi 4. bit registra podatkovnih smeri za PortD, zaradi česar je PD4 IZHOD.

Prvi nastavi spremenljivko temp na nič in jo nato kopira v register TCNT0. TCNT0 je naš časomer/števec0. S tem se nastavi na nič. Takoj, ko osebni računalnik izvede to vrstico, se bo timer0 zagnal pri ničli in vsako sekundo štel 15625 -krat. Težava je v tem: TCNT0 je "8-bitni" register, kajne? Kaj je torej največje število, ki ga lahko vsebuje 8-bitni register? No, 0b11111111 je to. To je številka 0xFF. Kar je 255. Torej vidite, kaj se zgodi? Časovnik se premika skupaj 15625 -krat na sekundo in vsakič, ko doseže 255, se "preliva" in se spet vrne na 0. Hkrati, ko se vrne na nič, pošlje signal prekinitve preklopa časovnika. Računalnik to razume in veste, kaj zdaj počne, kajne? Ja. Gre na lokacijo programskega pomnilnika 0x0020 in izvede navodila, ki jih tam najde.

Super! Če ste še vedno z mano, ste neutrudni superjunak! Nadaljujmo…

6. korak: Obdelovalec prelivanja

Predpostavimo torej, da se je register timer/counter0 ravno prepolnil. Sedaj vemo, da program prejme signal prekinitve in izvede 0x0020, ki pove, da števec programov, računalnik skoči na oznako "overflow_handler", je naslednja koda, ki smo jo napisali za to oznako:

overflow_handler:

inc preliv cpi preliv, 61 brne PC+2 clr preliv reti

Najprej naredi povečanje spremenljivke "overflows" (kar je naše ime za splošni delovni register R17), nato "primerja" vsebino prelivov s številko 61. Način cpi deluje tako, da preprosto odšteje dve številki in če je rezultat nič, nastavi zastavico Z v registru SREG (rekel sem vam, da bomo ta register videli ves čas). Če sta dve številki enaki, bo zastavica Z 1, če dve številki nista enaki, pa 0.

V naslednji vrstici piše "brne PC+2", kar pomeni "podružnica, če ni enaka". V bistvu preveri zastavo Z v SREG -u in če NI ena (tj. Dve številki nista enaki, če bi bili enaki, bi bila nastavljena ničelna zastavica), se PC razveja na PC+2, kar pomeni, da preskoči naslednjo vrstico in gre naravnost v "reti", ki se vrne iz prekinitve na katero koli mesto v kodi, ko je prekinitev prispela. Če bi navodilo brne našlo 1 v ničelnem bitu zastavice, se ne bi razvejalo in bi namesto tega nadaljevalo v naslednjo vrstico, ki bi clr overflows ponastavila na 0.

Kakšen je neto rezultat vsega tega?

Vidimo, da vsakič, ko pride do prelivanja časovnika, ta rokovalnik poveča vrednost "prelivov" za eno. Torej spremenljivka "prelivi" šteje število prelivov, ko se pojavijo. Kadar koli število doseže 61, ga ponastavimo na nič.

Zakaj bi zdaj na svetu to storili?

Pa poglejmo. Spomnite se, da je takt našega CPU -ja 16MHz in da smo ga "prednamenili" z uporabo TCCR0B, tako da časovnik šteje le s hitrostjo 15625 točk na sekundo, kajne? Vsakič, ko časovnik doseže število 255, se preplavi. To pomeni, da se preliva 15625/256 = 61,04 krat na sekundo. S spremenljivko "overflows" spremljamo število prelivov in to število primerjamo s 61. Tako vidimo, da bodo "prelivi" enaki 61 enkrat na sekundo! Tako bo naš upravljavec enkrat vsako sekundo ponastavil "prelive" na nič. Če bi torej preprosto spremljali spremenljivko "overflows" in upoštevali vsakič, ko se ponastavi na nič, bi šteli sekundo za sekundo v realnem času (upoštevajte, da bomo v naslednji vadnici pokazali, kako priti do natančnejše natančnosti zamik v milisekundah na enak način, kot deluje Arduino "delay" rutina).

Zdaj smo "obdelali" prekinitve pretoka časovnika. Prepričajte se, da razumete, kako to deluje, nato pa pojdite na naslednji korak, kjer to dejstvo izkoristimo.

7. korak: Zamuda

Zdaj, ko smo videli, da bo naša rutina za prekinitve prekinitve časovnika "overflow_handler" določila spremenljivko "overflows" na nič enkrat na sekundo, lahko to dejstvo uporabimo za oblikovanje podprograma "delay".

Oglejte si naslednjo kodo iz naše zamude: label

zamuda:

clr preliv sec_count: cpi preliv, 30 brne sec_count ret

To podprogram bomo poklicali vsakič, ko bomo potrebovali zamudo v našem programu. Način delovanja je, da spremenljivko "overflows" najprej nastavi na nič. Nato vstopi v območje z oznako "sec_count" in primerja prelive s 30, če niso enaki, se odcepi nazaj na oznako sec_count in primerja znova in znova itd., Dokler niso končno enaki (ne pozabite, da bo to ves čas na našem upravljalniku prekinitev časovnika še naprej povečuje spremenljivke, ki se prelivajo, zato se vsakič, ko gremo tukaj, spreminja. Ko je prelivanje končno enako 30, izstopi iz zanke in se vrne tja, kjer smo poklicali zamik: od. Neto rezultat je zamuda 1/2 sekunde

2. vaja: spremenite rutino overflow_handler na naslednje:

overflow_handler:

inc preliva reti

in zaženite program. Je kaj drugače? Zakaj ali zakaj ne?

8. korak: Utripajte

Na koncu poglejmo še utripajočo rutino:

utripa:

sbi PORTD, 4 rcall delay cbi PORTD, 4 rcall delay rjmp utripa

Najprej vklopimo PD4, nato prikličemo svojo podprogram zakasnitve. Rcall uporabljamo tako, da se računalnik, ko pride do stavka "ret", vrne v vrstico, ki sledi rcall. Nato zamudne rutinske zamude za 30 štetj v spremenljivki prelivanja, kot smo videli, in to je skoraj točno 1/2 sekunde, nato izklopimo PD4, zamudimo še 1/2 sekunde in se nato spet vrnemo na začetek.

Neto rezultat je utripajoča LED!

Mislim, da se boste zdaj strinjali, da "utripanje" verjetno ni najboljši program "hello world" v zbirnem jeziku.

3. vaja: spremenite različne parametre v programu, tako da LED utripa z različnimi hitrostmi, na primer sekundo ali 4 -krat na sekundo itd. Na primer, vklopite za 1/4 sekunde in nato za 2 sekundi izklopite ali kaj podobnega. Vaja 5: spremenite nastavitve bitov ure TCCR0B na 100 in nato nadaljujte po tabeli. Kdaj se od našega programa "hello.asm" iz vadnice 1 ne razlikuje več? Vaja 6 (izbirno): Če imate drugačen kristalni oscilator, na primer 4 MHz ali 13,5 MHz ali karkoli drugega, zamenjajte svoj 16 MHz oscilator na tleh za novo in si oglejte, kako to vpliva na hitrost utripanja LED. Zdaj bi morali natančno izračunati in natančno predvideti, kako bo to vplivalo na obrestno mero.

9. korak: Zaključek

Tistim, ki ste trdi, ki ste prišli tako daleč, čestitamo!

Zavedam se, da je precej naporno, ko bereš in gledaš navzgor, kot pa ožičenje in eksperimentiranje, vendar upam, da ste se naučili naslednjih pomembnih stvari:

  1. Kako deluje programski pomnilnik
  2. Kako deluje SRAM
  3. Kako poiskati registre
  4. Kako poiskati navodila in vedeti, kaj počnejo
  5. Kako izvajati prekinitve
  6. Kako CP izvaja kodo, kako deluje SREG in kaj se zgodi med prekinitvami
  7. Kako narediti zanke in skoke ter se premikati po kodi
  8. Kako pomembno je prebrati podatkovni list!
  9. Ko boste vedeli, kako vse to narediti za mikrokrmilnik Atmega328p, se boste lahko relativno naučili novih krmilnikov, ki vas zanimajo.
  10. Kako spremeniti čas CPE -ja v realni čas in ga uporabiti pri rutinah zamika.

Zdaj, ko imamo veliko teorije, ne moremo napisati boljše kode in nadzorovati bolj zapletene stvari. V naslednji vadnici bomo naredili prav to. Zgradili bomo bolj zapleteno, bolj zanimivo vezje in ga na zabaven način nadzirali.

Vaja 7: "Razbijte" kodo na različne načine in poglejte, kaj se zgodi! Znanstvena radovednost dojenček! Ali lahko kdo drug opere posodo? Vaja 8: Sestavite kodo z možnostjo "-l", da ustvarite datoteko s seznamom. Tj. "avra -l blink.lst blink.asm" in si oglejte datoteko s seznamom. Dodatni kredit: Koda brez komentarja, ki sem jo dala na začetku, in koda s komentarjem, o kateri bomo razpravljali kasneje, se razlikujeta! Obstaja ena vrstica kode, ki je drugačna. Ga lahko najdete? Zakaj ta razlika ni pomembna?

Upam, da ste se zabavali! Se vidimo naslednjič…

Priporočena: