Obsah:

AVR Assembler Tutorial 3: 9 Steps
AVR Assembler Tutorial 3: 9 Steps

Video: AVR Assembler Tutorial 3: 9 Steps

Video: AVR Assembler Tutorial 3: 9 Steps
Video: AVR Assembly Tutorial: Part 1 (Basic Commands) 2024, Júl
Anonim
Výučba montéra AVR 3
Výučba montéra AVR 3

Vitajte v návode číslo 3!

Predtým, ako začneme, chcem urobiť filozofickú poznámku. Nebojte sa experimentovať s obvodmi a kódom, ktorý v týchto tutoriáloch zostavujeme. Zmeňte káble, pridajte nové komponenty, vyberte komponenty, zmeňte riadky kódu, pridajte nové riadky, odstráňte riadky a uvidíte, čo sa stane! Je veľmi ťažké niečo zlomiť a ak áno, koho to zaujíma? Nič, čo používame, vrátane mikrokontroléra, nie je veľmi drahé a vždy je poučné zistiť, ako môžu veci zlyhať. Nielenže prídete na to, čo nabudúce nerobiť, ale čo je dôležitejšie, budete vedieť, prečo to neurobiť. Ak ste niečo ako ja, keď ste boli dieťa a dostali ste novú hračku, netrvalo dlho a rozkúskovali ste ju, aby ste zistili, prečo to tak dobre funguje? Niekedy hračka skončila nenapraviteľne poškodená, ale nič vážne. Umožniť dieťaťu preskúmať svoju zvedavosť až do bodu, keď sa mu zlomia hračky, to z neho urobí vedca alebo inžiniera, nie umývačku riadu.

Dnes zapojíme veľmi jednoduchý obvod a potom sa trochu začneme zaoberať teóriou. Ospravedlňujeme sa, ale potrebujeme nástroje! Sľubujem, že to vynahradíme v tutoriáli 4, kde budeme robiť serióznejšie budovanie okruhu a výsledok bude celkom cool. Spôsob, akým musíte všetky tieto návody vykonávať, je však veľmi pomalý, kontemplatívny. Ak sa len zorientujete, postavíte obvod, skopírujete a prilepíte kód a potom ho spustíte, určite to bude fungovať, ale nič sa nenaučíte. Na každý riadok sa musíte zamyslieť. Pauza. Experiment. Vynález. Ak to urobíte týmto spôsobom, do konca 5. tutoriálu prestanete stavať skvelé veci a už nebudete potrebovať žiadne doučovanie. Inak jednoducho len sledujete, než sa učíte a tvoríte.

V každom prípade dosť filozofie, začnime!

V tomto návode budete potrebovať:

  1. vaša prototypová doska
  2. LED dióda
  3. spojovacie vodiče
  4. odpor okolo 220 až 330 ohmov
  5. Návod na použitie: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. Dátový list: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. iný kryštálový oscilátor (voliteľný)

Tu je odkaz na kompletnú zbierku návodov:

Krok 1: Konštrukcia obvodu

Konštrukcia obvodu
Konštrukcia obvodu

Obvod v tomto návode je veľmi jednoduchý. V zásade napíšeme program „žmurknutie“, takže potrebujeme iba nasledujúce.

Pripojte LED k PD4, potom k odporu 330 ohmov a potom k zemi. t.j.

PD4 - LED - R (330) - GND

a to je všetko!

Teória bude ťažké drancovanie, aj keď …

Krok 2: Prečo potrebujeme komentáre a súbor M328Pdef.inc?

Myslím, že by sme mali začať tým, že ukážeme, prečo sú súbor zahrnutia a komentáre užitočné. Žiadny z nich nie je v skutočnosti potrebný a môžete bez nich písať, zostavovať a nahrávať kód rovnakým spôsobom a bude fungovať dobre (aj keď bez súboru na zahrnutie môžete od zostavovateľa dostať určité sťažnosti - ale žiadne chyby)

Tu je kód, ktorý dnes napíšeme, okrem toho, že som odstránil komentáre a súbor na zahrnutie:

.zariadenie 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 0x0b, 0x 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

celkom jednoduché nie? Haha. Ak ste zostavili a nahrali tento súbor, spôsobí blikanie LED diódy rýchlosťou 1 bliknutie za sekundu, pričom blikanie trvá 1/2 sekundy a prestávka medzi blikaniami trvá 1/2 sekundy.

Pohľad na tento kód je však sotva poučný. Ak by ste chceli písať kód takto a chceli by ste ho v budúcnosti upraviť alebo znova použiť, mali by ste to ťažké.

Poďme teda vložiť komentáre a zahrnúť súbor späť, aby sme tomu dali nejaký zmysel.

Krok 3: Blink.asm

Tu je kód, o ktorom budeme dnes diskutovať:

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

; napísal: 1o_o7; dátum:; verzia: 1.0; súbor uložený ako: blink.asm; pre AVR: atmega328p; taktovacia frekvencia: 16 MHz (voliteľné); *********************; Funkcia programu: ---------------------; odpočítava sekundy blikaním diódy LED;; PD4 - LED - R (330 ohmov) - GND;; --------------------------------------.nolist.include "./m328Pdef.inc".list; ===============; Deklarácie:.def temp = r16.def pretečie = r17.org 0x0000; pamäť (PC) umiestnenie obsluhy resetov rjmp Reset; jmp stojí 2 cykly procesora a rjmp stojí iba 1; pokiaľ teda nepotrebujete preskočiť viac ako 8 kB bajtov; potrebujete iba rjmp. Preto niektoré mikrokontroléry iba; majú rjmp a nie jmp.org 0x0020; umiestnenie pamäte obslužného programu pretečenia Timer0 rjmp overflow_handler; choďte sem, ak dôjde k prerušeniu pretečenia časovača; ============= Reset: ldi temp, 0b00000101 out TCCR0B, temp; nastavte bity selektora hodín CS00, CS01, CS02 na 101; tým sa Timer Counter0, TCNT0 prepne do režimu FCPU/1024; tak tiká pri CPU freq/1024 ldi temp, 0b00000001 sts TIMSK0, temp; nastavte bit Timer Overflow Interrupt Enable (TOIE0); registra masky prerušenia časovača (TIMSK0) sei; povoliť globálne prerušenia - ekvivalent „sbi SREG, I“clr temp out TCNT0, temp; inicializujte časovač/počítadlo na 0 sbi DDRD, 4; nastavte PD4 na výstup; ========================; Hlavná časť programu: blikanie: sbi PORTD, 4; zapnúť LED na PD4 oneskorenie vyvolania; oneskorenie bude 1/2 sekundy cbi PORTD, 4; vypnúť LED na PD4 oneskorenie vyvolávania; oneskorenie bude 1/2 sekundy blikať rjmp; slučka späť na oneskorenie štartu: CLR pretečie; nastaviť preteky na 0 sek_počet: pretečení cpi, 30; porovnať počet pretečení a 30 brne sec_count; vetva dozadu na sec_count, ak nie je rovnaká ret; ak sa vyskytlo 30 pretečení, vráťte sa k blikaniu overflow_handler: inc overflows; pridajte 1 k premennej pretečenia preteká cpi, 61; porovnaj s 61 brne PC+2; Program Counter + 2 (preskočiť nasledujúci riadok), ak nie je rovnaký, pretečie CLR; ak dôjde k 61 pretečeniam, vynulujte počítadlo na nulu reti; návrat z prerušenia

Ako vidíte, moje komentáre sú teraz o niečo stručnejšie. Keď vieme, aké príkazy v súbore inštrukcií sú, nepotrebujeme to vysvetľovať v komentároch. Potrebujeme iba vysvetliť, čo sa deje z pohľadu programu.

Budeme diskutovať o tom, čo to všetko robí, kúsok po kúsku, ale najskôr sa pokúsme získať globálny pohľad. Hlavná časť programu funguje nasledovne.

Najprv nastavíme bit 4 PORTDu pomocou „sbi PORTD, 4“, čím sa odošle 1 do PD4, čím sa napätie na tomto kolíku zvýši na 5V. Tým sa rozsvieti LED dióda. Potom skočíme na podprogram „oneskorenie“, ktorý odpočítava 1/2 sekundy (ako to bude fungovať, vysvetlíme neskôr). Potom sa vrátime k blikaniu a vymazaniu bitu 4 na PORTD, ktorý nastaví PD4 na 0V, a preto vypne LED. Potom zdržíme ďalšiu 1/2 sekundu a potom znova skočíme na začiatok blikania „blikaním rjmp“.

Mali by ste spustiť tento kód a zistiť, že robí to, čo má.

A tu to máte! To je všetko, čo tento kód fyzicky robí. Interná mechanika toho, čo mikrokontrolér robí, je o niečo viac zapojená, a preto robíme tento návod. Prediskutujme teda postupne každú sekciu.

Krok 4: Smernice.org Assembler

Už vieme, čo robia direktívy assembleru.nolist,.list,.include a.def z našich predchádzajúcich tutoriálov, takže sa najskôr pozrime na 4 riadky kódu, ktoré nasledujú:

.org 0x0000

jmp Reset.org 0x0020 jmp overflow_handler

Príkaz.org hovorí assembleru, kam v "Programovej pamäti" má vložiť nasledujúci príkaz. Keď sa váš program spustí, „Program Counter“(skrátene PC) obsahuje adresu aktuálneho vykonávaného riadka. Takže v tomto prípade, keď je počítač na 0x0000, uvidí príkaz „jmp Reset“, ktorý sa nachádza v tomto mieste pamäte. Dôvod, prečo chceme do tohto umiestnenia vložiť reset jmp, je ten, že keď sa program spustí alebo sa resetuje čip, počítač začne na tomto mieste vykonávať kód. Ako teda vidíme, práve sme jej povedali, aby okamžite „skočila“do sekcie označenej ako „Reset“. Prečo sme to urobili? To znamená, že posledné dva riadky vyššie sa iba preskakujú! Prečo?

No a práve tam začínajú byť veci zaujímavé. Teraz budete musieť otvoriť prehliadač PDF s úplným údajovým listom ATmega328p, na ktorý som poukázal na prvej stránke tohto tutoriálu (preto je to položka 4 v sekcii „Budete potrebovať“). Ak je vaša obrazovka príliš malá alebo máte už otvorených príliš veľa okien (ako je to u mňa), môžete urobiť to, čo robím, a dať to na Ereader alebo telefón s Androidom. Ak plánujete napísať kód zostavy, budete ho používať stále. Super je, že všetky mikrokontroléry sú organizované veľmi podobnými spôsobmi, a preto keď si zvyknete čítať údajové listy a kódovať z nich, bude pre vás takmer triviálne robiť to isté pre iný mikrokontrolér. Takže sa vlastne učíme, ako používať všetky mikrokontroléry v istom zmysle a nielen atmega328p.

Dobre, obráťte sa na stranu 18 v údajovom hárku a pozrite sa na obrázok 8-2.

Takto je nastavená programová pamäť v mikrokontroléri. Môžete vidieť, že začína adresou 0x0000 a je rozdelená na dve sekcie; sekcia Flash aplikácie a sekcia zavádzania Flash. Ak sa v stručnosti pozriete na stranu 277, tabuľka 27-14, uvidíte, že sekcia flash aplikácie zaberá miesta od 0x0000 do 0x37FF a sekcia bootovacej pamäte zaberá zvyšné polohy od 0x3800 do 0x3FFF.

Cvičenie 1: Koľko miest je v pamäti programu? Tj. previesť 3FFF na desatinné miesto a pridať 1, pretože začneme počítať na 0. Keďže každé miesto v pamäti je široké 16 bitov (alebo 2 bajty), aký je celkový počet bajtov pamäte? Teraz to preveďte na kilobajty, pričom pamätajte na to, že v kilobajte je 2^10 = 1024 bajtov. Sekcia bootovacej pamäte sa pohybuje od 0x3800 do 0x37FF, koľko je to kilobajtov? Koľko kilobajtov pamäte nám zostane na uloženie programu? Inými slovami, aký veľký môže byť náš program? Nakoniec, koľko riadkov kódu môžeme mať?

Dobre, teraz, keď vieme všetko o organizácii pamäte flash programu, pokračujme v našej diskusii o vyhláseniach.org. Vidíme, že prvé pamäťové miesto 0x0000 obsahuje naše inštrukcie na skok do našej sekcie, ktorú sme označili ako Reset. Teraz vidíme, čo robí vyhlásenie „.org 0x0020“. Hovorí, že chceme, aby boli pokyny na nasledujúcom riadku umiestnené na pamäťové miesto 0x0020. Inštrukcia, ktorú sme tam umiestnili, je skokom do sekcie v našom kóde, ktorú sme označili ako „overflow_handler“… prečo by sme sakra museli požadovať, aby bol tento skok umiestnený na pamäťové miesto 0x0020? Aby sme to zistili, v technickom liste sa obrátime na stranu 65 a pozrieme sa na tabuľku 12-6.

Tabuľka 12-6 je tabuľka „Reset a Interrupt Vectors“a presne ukazuje, kam pôjde počítač, keď dostane „prerušenie“. Ak sa napríklad pozriete na vektor číslo 1. „Zdroj“prerušenia je „RESET“, ktorý je definovaný ako „externý kolík, reset pri zapnutí, reset Brown-out a reset systému Watchdog“, čo znamená, ak existuje tieto veci sa dejú nášmu mikrokontroléru, počítač začne vykonávať náš program na mieste pamäte programu 0x0000. Čo potom s našou smernicou.org? Vložili sme príkaz na miesto pamäte 0x0020 a ak sa pozriete do tabuľky, uvidíte, že ak dôjde k pretečeniu časovača/počítadla (pochádzajúceho z TIMER0 OVF), vykoná čokoľvek, čo je na mieste 0x0020. Takže kedykoľvek sa to stane, počítač skočí na miesto, ktoré sme označili „overflow_handler“. Cool nie? O minútu uvidíte, prečo sme to urobili, ale najskôr tento krok tutoriálu ukončíme stranou.

Ak chceme, aby bol náš kód prehľadnejší a upravenejší, mali by sme skutočne nahradiť 4 riadky, o ktorých v súčasnosti diskutujeme, nasledujúcim (pozri stranu 66):

.org 0x0000

rjmp Reset; 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

Takže ak dôjde k danému prerušeniu, dôjde iba k „reti“, čo znamená „návrat z prerušenia“a nič iné sa nestane. Ak však tieto rôzne prerušenia nikdy „nepovolíme“, potom sa nepoužijú a do týchto miest môžeme vložiť programový kód. V našom súčasnom programe „blink.asm“povolíme iba prerušenie pretečenia timera0 (a samozrejme prerušenie resetovania, ktoré je vždy povolené), a preto sa nebudeme obťažovať ostatnými.

Ako potom „povolíme“prerušenie pretečenia timera0? … to je predmetom nášho ďalšieho kroku v tomto návode.

Krok 5: Časovač/počítadlo 0

Časovač/počítadlo 0
Časovač/počítadlo 0

Pozrite sa na vyššie uvedený obrázok. Toto je rozhodovací proces „PC“, keď nejaký vonkajší vplyv „preruší“tok nášho programu. Prvá vec, ktorú urobí, keď dostane signál zvonku, že došlo k prerušeniu, je, že skontroluje, či sme pre tento typ prerušenia nastavili bit „prerušenie povolenia“. Ak nie, potom pokračuje v vykonávaní nášho ďalšieho riadku kódu. Ak sme nastavili tento konkrétny bit na povolenie prerušenia (aby v tomto bitovom umiestnení bola 1 namiesto 0), potom skontroluje, či sme povolili „globálne prerušenia“alebo nie, ak nie, znova prejde na nasledujúci riadok kódu a pokračujte. Ak sme povolili aj globálne prerušenia, potom prejde do umiestnenia pamäte programu pre daný typ prerušenia (ako je uvedené v tabuľke 12-6) a vykoná akýkoľvek príkaz, ktorý sme tam vložili. Pozrime sa teda, ako sme to všetko implementovali do nášho kódu.

Časť resetovania označeného nášho kódu začína nasledujúcimi dvoma riadkami:

Resetovať:

ldi temp, 0b00000101 out TCCR0B, temp

Ako už vieme, toto sa načíta do teploty (t.j. R16) bezprostredne nasledujúceho čísla, ktoré je 0b00000101. Potom toto číslo zapíše do registra s názvom TCCR0B pomocou príkazu „von“. Čo je to za register? Prejdeme na stranu 614 údajového listu. Toto je uprostred tabuľky sumarizujúcej všetky registre. Na adrese 0x25 nájdete TCCR0B. (Teraz už viete, odkiaľ v mojej nekomentovanej verzii kódu pochádza riadok „von 0x25, r16“). Podľa segmentu kódu vyššie vidíme, že sme nastavili 0. bit a 2. bit a vymazali všetky ostatné. Pri pohľade na tabuľku vidíte, že to znamená, že sme nastavili CS00 a CS02. Teraz sa vráťme ku kapitole v technickom liste s názvom „8-bit Timer/Counter0 with PWM“. Prejdite najmä na stranu 107 tejto kapitoly. Uvidíte rovnaký popis registra "Register časovača/počítadla B" (TCCR0B), ktorý sme práve videli v súhrnnej tabuľke registrov (mohli sme teda prísť priamo sem, ale chcel som, aby ste videli, ako používať súhrnné tabuľky pre budúce použitie). Datasheet pokračuje v popise každého z bitov v tomto registri a toho, čo robí. To všetko zatiaľ preskočíme a otočíme stránku na tabuľku 15-9. Táto tabuľka zobrazuje „Popis bitov pre výber hodín“. Teraz sa pozrite do tabuľky, kým nenájdete riadok, ktorý zodpovedá bitom, ktoré sme v tomto registri práve nastavili. Riadok hovorí „clk/1024 (z predzápalca)“. Čo to znamená, že chceme, aby časovač/počítadlo0 (TCNT0) tikal rýchlosťou, ktorá je frekvenciou CPU delenou 1024. Pretože máme náš mikrokontrolér napájaný kryštálovým oscilátorom 16 MHz, znamená to, že rýchlosť, ktorou náš procesor vykonáva inštrukcie, je 16 miliónov inštrukcií za sekundu. Takže rýchlosť, ktorou bude počítadlo TCNT0 zaškrtnuté, je potom 16 miliónov/1024 = 15625 -krát za sekundu (vyskúšajte to s rôznymi bitmi výberu hodín a uvidíte, čo sa stane - pamätáte si našu filozofiu?). Ponechajme číslo 15625 v zadnej časti svojej mysle na neskôr a prejdeme na ďalšie dva riadky kódu:

ldi teplota, 0b00000001

ok TIMSK0, tepl

Tým sa nastaví 0 -ty bit registra s názvom TIMSK0 a vymaže sa zvyšok. Ak sa pozriete na stranu 109 v technickom liste, uvidíte, že TIMSK0 je skratka pre „Register časovača/počítadla prerušenia registra 0“a náš kód nastavil 0. bit, ktorý má názov TOIE0, čo znamená „Povolenie prerušenia pretečenia časovača/počítadla0“… tam! Teraz vidíte, o čo ide. Teraz máme „bit povolenia prerušenia“nastavený tak, ako sme chceli z prvého rozhodnutia na našom obrázku v hornej časti. Teraz teda stačí len povoliť „globálne prerušenia“a náš program bude schopný na tieto typy prerušení reagovať. Onedlho povolíme globálne prerušenia, ale skôr než to urobíme, vás môže niečo zmiasť.. prečo som sakra použil príkaz „sts“na skopírovanie do registra TIMSK0 namiesto obvyklého „out“?

Kedykoľvek ma uvidíte, použite pokyny, ktoré ste predtým nevideli, ako prvú vec, ktorú by ste mali urobiť, je obrátiť sa na stranu 616 v technickom liste. Toto je „Súhrn pokynov“. Teraz nájdite inštrukciu „STS“, ktorú som použil. Hovorí sa, že to vyžaduje číslo z registra R (použili sme R16) a umiestnenia k „Store direct to SRAM“(v našom prípade dané TIMSK0). Prečo sme teda museli na uloženie v TIMSK0 použiť „sts“, ktoré vyžadujú 2 hodinové cykly (pozri posledný stĺpec v tabuľke) a na uloženie do TCCR0B sme predtým potrebovali iba „out“, ktorý trvá iba jeden hodinový cyklus? Na zodpovedanie tejto otázky sa musíme vrátiť späť k našej súhrnnej tabuľke registrov na strane 614. Vidíte, že register TCCR0B je na adrese 0x25, ale aj na (0x45), nie? To znamená, že ide o register v SRAM, ale je to tiež určitý typ registra, ktorý sa nazýva „port“(alebo register I/O). Ak sa pozriete na súhrnnú tabuľku inštrukcií vedľa príkazu „von“, uvidíte, že preberá hodnoty z „pracovných registrov“ako R16 a odosiela ich na PORT. Pri písaní do TCCR0B teda môžeme použiť „von“a ušetriť si tak hodinový cyklus. Teraz však vyhľadajte TIMSK0 v tabuľke registrov. Vidíte, že má adresu 0x6e. To je mimo rozsah portov (ktoré sú iba prvými umiestneniami SRAM 0x3F), a preto sa musíte vrátiť k použitiu príkazu sts a vykonať dva cykly hodín CPU. Prečítajte si prosím poznámku 4 na konci súhrnnej tabuľky pokynov na strane 615. Všimnite si tiež, že všetky naše vstupné a výstupné porty, ako napríklad PORTD, sú umiestnené v spodnej časti tabuľky. Napríklad PD4 je bit 4 na adrese 0x0b (teraz vidíte, odkiaľ všetky veci 0x0b pochádzajú z môjho nekomentovaného kódu!).. ok, rýchla otázka: zmenili ste „očká“na „von“a uvidíte, čo stane sa? Pamätajte si našu filozofiu! zlom to! neber moje slovo len pre veci.

Dobre, než sa pohneme ďalej, na minútu sa obráťte na stranu 19 v technickom liste. Zobrazí sa obrázok dátovej pamäte (SRAM). Prvých 32 registrov v SRAM (od 0x0000 do 0x001F) sú „pracovné registre na všeobecné účely“R0 až R31, ktoré v našom kóde neustále používame ako premenné. Nasledujúcich 64 registrov sú vstupno-výstupné porty až do 0x005f (tj. Tie, o ktorých sme hovorili, ktoré majú v tabuľke registrov vedľa nich tie nezaradené adresy, ktoré môžeme použiť namiesto „sts“príkaz „out“) ďalšia časť SRAM obsahuje všetky ostatné registre v súhrnnej tabuľke až po adresu 0x00FF a nakoniec zvyšok je interný SRAM. Teraz rýchlo, vráťme sa na chvíľu na stranu 12. Tu vidíte tabuľku „univerzálnych pracovných registrov“, ktoré vždy používame ako premenné. Vidíte hrubú čiaru medzi číslami R0 až R15 a potom R16 až R31? Preto vždy používame R16 ako najmenší a trochu sa tomu venujem v nasledujúcom návode, kde budeme potrebovať aj tri 16-bitové registre nepriamych adries, X, Y a Z. Nebudem pustite sa do toho, aj keď, pretože to teraz nepotrebujeme a dosť sa tu zamotávame.

Prevráťte jednu stranu na stranu 11 listu s údajmi. Vpravo hore uvidíte diagram registra SREG? Vidíte, že bit 7 tohto registra sa nazýva „I“. Teraz choďte na stránku nadol a prečítajte si popis Bit 7 …. Jéj! Je to bit Global Interrupt Enable. To je to, čo musíme nastaviť, aby sme prešli druhým rozhodnutím v našom diagrame vyššie a umožnili prerušenia pretečenia časovača/počítadla v našom programe. Ďalší riadok nášho programu by teda mal znieť:

sbi SREG, I

ktorý nastavuje bit s názvom „I“v registri SREG. Namiesto toho sme však použili inštrukcie

sei

namiesto. Tento bit je v programoch nastavovaný tak často, že jednoducho urobili jednoduchší spôsob, ako to urobiť.

Dobre! Teraz máme pripravené prerušenia pretečenia, aby sa náš príkaz „jmp overflow_handler“vykonal vždy, keď k nemu dôjde.

Predtým, ako sa pohneme ďalej, sa rýchlo pozrite na register SREG (stavový register), pretože je veľmi dôležitý. Prečítajte si, čo jednotlivé vlajky predstavujú. Najmä mnoho z pokynov, ktoré používame, tieto vlajky neustále nastavuje a kontroluje. Napríklad neskôr budeme používať príkaz „CPI“, čo znamená „okamžite porovnať“. Pozrite sa na súhrnnú tabuľku týchto pokynov a všimnite si, koľko vlajok nastavuje v stĺpci „vlajky“. Toto sú všetko vlajky v SREG a náš kód ich bude nastavovať a neustále kontrolovať. Čoskoro uvidíte príklady. Nakoniec posledný bit tejto časti kódu je:

teplota clr

out TCNT0, temp sbi DDRD, 4

Posledný riadok je celkom zrejmý. Jednoducho nastaví 4. bit registra smeru údajov pre PortD, čo spôsobí, že PD4 bude VÝSTUPNÝ.

Prvý nastaví premennú temp na nulu a potom ju skopíruje do registra TCNT0. TCNT0 je náš časovač/počítadlo0. Tým sa nastaví na nulu. Hneď ako počítač spustí tento riadok, časovač 0 sa spustí na nule a každú sekundu bude počítať rýchlosťou 15625 -krát. Problém je v tomto: TCNT0 je „8-bitový“register, nie? Aké je teda najväčšie číslo, ktoré môže 8-bitový register pojať? 0b11111111 je to. Toto je číslo 0xFF. Čo je 255. Takže vidíte, čo sa stane? Časovač sa zapína 15625 -krát za sekundu a zakaždým, keď dosiahne 255, „pretečie“a vráti sa späť na 0. Súčasne s návratom na nulu vyšle signál prerušenia pretečenia časovača. Počítač to pochopí a už viete, čo robí? Jasné. Prejde na miesto pamäte programu 0x0020 a vykoná tam nájdené inštrukcie.

Skvelé! Ak si stále so mnou, si neúnavný superhrdina! Pokračujme…

Krok 6: Overflow Handler

Predpokladajme teda, že register časovača/počítadla0 práve pretekol. Teraz vieme, že program prijíma signál prerušenia a vykoná 0x0020, ktorý programovému počítadlu oznámi počítaču, aby preskočil na štítok „overflow_handler“, nasledujúci kód je kód, ktorý sme napísali za tento štítok:

overflow_handler:

inc preteká cpi preteká, 61 brne PC+2 clr preteká reti

Prvá vec, ktorú urobí, je zvýšenie premennej „pretečie“(čo je náš názov pre pracovný register R17 na všeobecné účely), potom „porovná“obsah pretečení s číslom 61. Inštrukcia cpi funguje tak, že jednoducho odpočíta dve čísla a ak je výsledok nula, nastaví príznak Z v registri SREG (povedal som vám, že tento register uvidíme stále). Ak sú tieto dve čísla rovnaké, príznak Z bude 1, ak tieto dve čísla nie sú rovnaké, bude to 0.

Nasledujúci riadok hovorí „brne PC+2“, čo znamená „vetva, ak nie je rovnaká“. V zásade kontroluje príznak Z v SREG a ak NIE je jedna (tj. Dve čísla nie sú rovnaké, ak by boli rovnaké, nastavil by sa nulový príznak), počítač sa rozvetví na PC+2, čo znamená, že preskočí nasledujúci riadok a prejde priamo na „reti“, ktorý sa po prerušení vráti z prerušenia na akékoľvek miesto, kde sa nachádzalo v kóde. Ak by inštrukcia brne našla 1 v bite nulového príznaku, nerozvetvila by sa a namiesto toho by pokračovala na nasledujúci riadok, ktorý by clr pretekol a resetoval by ho na 0.

Aký je čistý výsledok toho všetkého?

Vidíme, že zakaždým, keď dôjde k pretečeniu časovača, tento obslužný program zvýši hodnotu „pretečenia“o jeden. Premenná „pretečenie“teda počíta počet pretečení, ako k nim dôjde. Kedykoľvek číslo dosiahne 61, vynulujeme ho.

Prečo by sme to vo svete robili?

Pozrime sa. Pripomeňme si, že naša taktovacia frekvencia pre náš procesor je 16 MHz a „prescalovali“sme ju pomocou TCCR0B tak, aby časovač počítal iba s rýchlosťou 15625 impulzov za sekundu, však? A zakaždým, keď časovač dosiahne počet 255, pretečie. To znamená, že pretečie 15625/256 = 61,04 krát za sekundu. Sledujeme počet pretečení pomocou našej premennej „pretečenia“a porovnávame toto číslo s 61. Vidíme teda, že „pretečenia“sa budú rovnať 61 raz za sekundu! Náš obslužný program teda vynuluje „prepady“na nulu raz za sekundu. Ak by sme teda jednoducho sledovali premennú „pretečenia“a vzali na vedomie vždy, keď sa vynuluje, počítali by sme sekundu po sekunde v reálnom čase (Všimnite si, že v nasledujúcom návode ukážeme, ako získať presnejšie oneskorenie v milisekundách rovnakým spôsobom, akým funguje rutina „oneskorenia“Arduina).

Teraz sme „zvládli“prerušenie pretečenia časovača. Uistite sa, že rozumiete tomu, ako to funguje, a potom prejdite na ďalší krok, v ktorom túto skutočnosť využívame.

Krok 7: Oneskorenie

Teraz, keď sme videli, že naša rutina obsluhy prerušenia pretečenia časovača „overflow_handler“nastaví premennú „pretečenia“na nulu raz za sekundu, môžeme túto skutočnosť použiť na navrhnutie podprogramu „oneskorenia“.

Pozrite sa na nasledujúci kód z nášho oneskorenia: štítok

oneskorenie:

clr preteká sek_počet: preteká cpi, 30 brne sec_count ret

Tento podprogram zavoláme vždy, keď budeme potrebovať oneskorenie v programe. Funguje to tak, že najskôr nastaví premennú „pretečie“na nulu. Potom vstúpi do oblasti označenej „sec_count“a porovná pretečenie s 30, ak nie sú rovnaké, rozvetví sa späť na štítok sec_count a porovná znova a znova, atď., Kým si nie sú konečne rovné (pamätajte, že celý čas to pokračuje na našom obsluhe prerušenia časovača pokračuje v zvyšovaní premenných pretečenia, a tak sa mení vždy, keď ideme okolo. Keď sa pretečenie nakoniec rovná 30, dostane sa zo slučky a vráti sa tam, kde sme nazvali oneskorenie: od. Čistý výsledok je oneskorenie 1/2 sekundy

Cvičenie 2: Zmeňte rutinu overflow_handler na nasledujúcu:

overflow_handler:

inc preteká reti

a spustite program. Je nieco ine? Prečo áno alebo prečo nie?

Krok 8: Žmurknite

Nakoniec sa pozrime na rutinu žmurkania:

blikať:

sbi PORTD, 4 r oneskorenie volania cbi PORTD, 4 r oneskorenie volania rjmp bliká

Najprv zapneme PD4, potom vyvoláme náš podprogram oneskorenia. Používame rcall, takže keď sa PC dostane k príkazu „ret“, vráti sa na riadok nasledujúci po rcall. Potom sa rutina oneskorenia oneskorí o 30 číslic v premennej pretečenia, ako sme videli, a je to takmer presne 1/2 sekundy, potom vypneme PD4, oneskoríme ďalšiu 1/2 sekundu a potom sa znova vrátime na začiatok.

Čistým výsledkom je blikajúca LED dióda!

Myslím, že teraz súhlasíte s tým, že „blikanie“pravdepodobne nie je najlepším programom „ahoj sveta“v jazyku assembler.

Cvičenie 3: Zmeňte rôzne parametre v programe tak, aby LED dióda blikala rôznymi rýchlosťami, ako je sekunda alebo 4 -krát za sekundu, atď. Cvičenie 4: Zmeňte ju tak, aby sa dióda LED zapínala a vypínala rôzne dlho. Napríklad zapnuté na 1/4 sekundy a potom vypnuté na 2 sekundy alebo niečo podobné. Cvičenie 5: Zmeňte bity hodín TCCR0B na 100 a potom pokračujte v hre po stole. V ktorom bode sa stane nerozoznateľným od nášho programu „hello.asm“z tutoriálu 1? Cvičenie 6 (voliteľné): Ak máte iný kryštálový oscilátor, napríklad 4 MHz alebo 13,5 MHz alebo čokoľvek, vymeňte 16 MHz oscilátor. na svojom breadboarde za nový a zistite, ako to ovplyvňuje rýchlosť blikania diódy LED. Teraz by ste mali byť schopní prejsť presným výpočtom a presne predpovedať, ako to ovplyvní sadzbu.

Krok 9: Záver

Tí z vás, ktorí ste sa dostali až sem, gratulujeme!

Uvedomujem si, že je to dosť ťažké bičovanie, keď viac čítate a pozeráte hore, ako sa snažíte zapojiť a experimentovať, ale dúfam, že ste sa naučili nasledujúce dôležité veci:

  1. Ako funguje programová pamäť
  2. Ako funguje SRAM
  3. Ako vyhľadávať v registroch
  4. Ako vyhľadať pokyny a vedieť, čo robia
  5. Ako implementovať prerušenia
  6. Ako CP vykonáva kód, ako funguje SREG a čo sa deje počas prerušení
  7. Ako robiť slučky a skoky a odrážať sa v kóde
  8. Ako dôležité je prečítať si technický list!
  9. Ako raz budete vedieť, ako to všetko urobiť pre mikrokontrolér Atmega328p, bude relatívne ľahké sa zoznámiť s novými ovládačmi, ktoré vás zaujímajú.
  10. Ako zmeniť čas CPU na reálny čas a použiť ho v rutinách oneskorenia.

Teraz, keď máme veľa teórie mimo cesty, sme schopní písať lepší kód a ovládať zložitejšie veci. Takže nasledujúci tutoriál budeme robiť práve to. Postavíme komplikovanejší, zaujímavejší obvod a budeme ho ovládať zábavnými spôsobmi.

Cvičenie 7: „Rozbite“kód rôznymi spôsobmi a uvidíte, čo sa stane! Vedecká zvedavosť, dieťa! Niekto iný môže umývať riad správne? Cvičenie 8: Zostavte kód pomocou možnosti „-l“na vygenerovanie súboru so zoznamom. Tj. "avra -l blink.lst blink.asm" a pozrite sa na súbor zoznamu. Extra kredit: nekomentovaný kód, ktorý som uviedol na začiatku, a komentovaný kód, o ktorom budeme diskutovať neskôr, sa líšia! Existuje jeden riadok kódu, ktorý je odlišný. Dokážete to nájsť? Prečo na tom rozdiele nezáleží?

Dúfam, že ste sa pobavili! Uvidíme sa nabudúce…

Odporúča: