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, Červenec
Anonim
AVR Assembler Tutorial 3
AVR Assembler Tutorial 3

Vítejte v tutoriálu číslo 3!

Než začneme, chci uvést filozofickou poznámku. Nebojte se experimentovat s obvody a kódem, který vytváříme v těchto výukových programech. Změňte dráty, přidejte nové součásti, vyjměte součásti, změňte řádky kódu, přidejte nové řádky, odstraňte řádky a uvidíte, co se stane! Je velmi těžké něco zlomit, a pokud ano, koho to zajímá? Nic, co používáme, včetně mikrokontroléru, není příliš drahé a vždy je poučné sledovat, jak věci mohou selhat. Nejen, že příště zjistíte, co nedělat, ale co je důležitější, budete vědět, proč to nedělat. Pokud jste něco jako já, když jste byli malí a dostali jste novou hračku, netrvalo dlouho, než jste ji rozdělili na kousky, abyste zjistili, co ji přimělo táhnout správně? Někdy skončila hračka nenapravitelně poškozená, ale nic vážného. Umožnit dítěti prozkoumat jeho zvědavost dokonce až k rozbitým hračkám je to, co z něj udělá vědce nebo inženýra místo myčky.

Dnes zapojíme velmi jednoduchý obvod a poté se trochu začleníme do teorie. Omlouváme se, ale potřebujeme nástroje! Slibuji, že to vynahradíme v tutoriálu 4, kde budeme dělat vážnější stavbu obvodů a výsledek bude docela cool. Způsob, jakým musíte všechny tyto výukové programy provádět, je však velmi pomalý a rozjímavý. Pokud jen projedete, postavíte obvod, zkopírujete a vložíte kód a spustíte ho, určitě to bude fungovat, ale nic se nenaučíte. Musíte přemýšlet o každém řádku. Pauza. Experiment. Vymyslet. Pokud to uděláte tímto způsobem, pak do konce 5. tutoriálu přestanete stavět skvělé věci a nepotřebujete žádné další doučování. Jinak se prostě díváte, než se učíte a tvoříte.

V každém případě dost filozofie, pojďme začít!

V tomto kurzu budete potřebovat:

  1. vaše prototypovací deska
  2. LED
  3. spojovací vodiče
  4. odpor kolem 220 až 330 ohmů
  5. Návod k použití: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. Datasheet: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. jiný krystalový oscilátor (volitelný)

Zde je odkaz na kompletní sbírku návodů:

Krok 1: Konstrukce obvodu

Stavba obvodu
Stavba obvodu

Obvod v tomto kurzu je extrémně jednoduchý. V podstatě budeme psát program „mrknutí“, takže vše, co potřebujeme, je následující.

Připojte LED k PD4, pak k odporu 330 ohmů, pak k zemi. tj.

PD4 - LED - R (330) - GND

a je to!

Teorie bude těžké drancování, i když…

Krok 2: Proč potřebujeme komentáře a soubor M328Pdef.inc?

Myslím, že bychom měli začít tím, že ukážeme, proč jsou soubor pro zahrnutí a komentáře užitečné. Žádný z nich není ve skutečnosti nezbytný a můžete bez něj psát, sestavovat a nahrávat kód stejným způsobem a bude fungovat dobře (i když bez zahrnutého souboru můžete mít nějaké stížnosti od assembleru - ale žádné chyby)

Zde je kód, který dnes napíšeme, kromě toho, že jsem odstranil komentáře a soubor include:

.zařízení 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

docela jednoduché ne? Haha. Pokud jste sestavili a nahráli tento soubor, způsobíte, že LED bude blikat rychlostí 1 bliknutí za sekundu, přičemž blikání trvá 1/2 sekundy a pauza mezi blikáním trvá 1/2 sekundy.

Pohled na tento kód je však stěží poučný. Pokud byste chtěli napsat kód takto a chtěli byste jej v budoucnu upravit nebo znovu použít, měli byste to těžké.

Pojďme tedy vložit komentáře a zahrnout soubor zpět, abychom tomu mohli rozumět.

Krok 3: Blink.asm

Zde je kód, o kterém budeme dnes diskutovat:

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

; napsal: 1o_o7; datum:; verze: 1.0; soubor uložen jako: blink.asm; pro AVR: atmega328p; taktovací frekvence: 16 MHz (volitelně); ***********************; Funkce programu: ---------------------; odpočítává sekundy blikáním LED;; PD4 - LED - R (330 ohmů) - GND;; --------------------------------------.nolist.include "./m328Pdef.inc".list; ===============; Deklarace:.def temp = r16.def přetečení = r17.org 0x0000; paměť (PC) umístění obslužné rutiny resetu rjmp Reset; jmp stojí 2 cykly CPU a rjmp stojí pouze 1; pokud tedy nepotřebujete přeskočit více než 8 kB bytů; potřebujete pouze rjmp. Některé mikrokontroléry proto pouze; mít rjmp a ne jmp.org 0x0020; umístění paměti obsluhy přetečení Timer0 rjmp overflow_handler; jděte sem, pokud dojde k přetečení časovače0; ============= Reset: ldi temp, 0b00000101 out TCCR0B, temp; nastavte bity voliče hodin CS00, CS01, CS02 na 101; tím se časovač Counter0, TCNT0 přepne do režimu FCPU/1024; tak to tiká na CPU freq/1024 ldi temp, 0b00000001 sts TIMSK0, temp; nastavit bit Timer Overflow Interrupt Enable (TOIE0) bit; registru Timer Interrupt Mask Register (TIMSK0) sei; povolit globální přerušení - ekvivalent "sbi SREG, I" clr temp out TCNT0, temp; inicializujte časovač/čítač na 0 sbi DDRD, 4; nastavit PD4 na výstup; ========================; Hlavní část programu: blikání: sbi PORTD, 4; zapnout LED na PD4 rcall zpoždění; zpoždění bude 1/2 sekundy cbi PORTD, 4; vypnout LED na PD4 zpoždění zpětného volání; zpoždění bude blikat rjmp 1/2 sekundy; smyčka zpět na zpoždění startu: přetečení clr; nastavit přetečení na 0 sec_count: cpi přetečení, 30; porovnat počet přetečení a 30 brne sec_count; větev zpět na sec_count, pokud není stejná ret; pokud došlo k 30 přetečení, vraťte se k blikání overflow_handler: inc overflows; přidejte 1 k proměnné přetečení cpi přetečení, 61; porovnat s 61 brne PC+2; Program Counter + 2 (přeskočit další řádek), pokud není stejný, přeteče clr; pokud došlo k 61 přetečení, resetujte čítač na nulu reti; návrat z přerušení

Jak vidíte, mé komentáře jsou nyní trochu stručnější. Jakmile víme, jaké příkazy v sadě instrukcí nepotřebujeme, musíme to vysvětlovat v komentářích. Stačí nám vysvětlit, co se děje z pohledu programu.

Budeme diskutovat, co to všechno dělá, kousek po kousku, ale nejprve se pokusme získat globální perspektivu. Hlavní část programu funguje následovně.

Nejprve nastavíme bit 4 PORTD pomocí „sbi PORTD, 4“, který odešle 1 do PD4, čímž se napětí na tomto pinu nastaví na 5V. Tím se rozsvítí LED. Poté skočíme na podprogram „zpoždění“, který odpočítává 1/2 sekundy (jak to udělá, vysvětlíme později). Poté se vrátíme k blikání a vymazání bitu 4 na PORTD, který nastaví PD4 na 0V, a proto vypne LED. Poté zpozdíme další 1/2 sekundy a poté skočíme zpět na začátek blikání pomocí „blikání rjmp“.

Měli byste spustit tento kód a zjistit, že dělá to, co by měl.

A tady to máte! To je vše, co tento kód fyzicky dělá. Interní mechanika toho, co mikrokontrolér dělá, je trochu více zapojena, a proto děláme tento tutoriál. Pojďme tedy probrat každou sekci postupně.

Krok 4: Směrnice.org Assembler

Už víme, co dělají direktiva assembleru.nolist,.list,.include a.def z našich předchozích tutoriálů, pojďme se tedy nejprve podívat na 4 řádky kódu, které následují:

.org 0x0000

jmp Reset.org 0x0020 jmp overflow_handler

Příkaz.org říká assembleru, kam v "Programové paměti" má vložit další příkaz. Jak se váš program spouští, „Počitadlo programů“(zkráceně PC) obsahuje adresu aktuálního prováděného řádku. Takže v tomto případě, když je počítač na 0x0000, uvidí příkaz "jmp Reset", který je umístěn v tomto paměťovém místě. Důvod, proč chceme do tohoto umístění vložit jmp Reset, je ten, že když program začne nebo se resetuje čip, počítač začne v tomto místě spouštět kód. Takže, jak vidíme, právě jsme mu řekli, aby okamžitě „skočil“do sekce označené „Reset“. Proč jsme to udělali? To znamená, že poslední dva řádky výše jsou právě přeskočeny! Proč?

No a tam věci začínají být zajímavé. Nyní budete muset otevřít prohlížeč PDF s úplným datovým listem ATmega328p, na který jsem ukázal na první stránce tohoto tutoriálu (proto je to položka 4 v sekci „budete potřebovat“). Pokud je vaše obrazovka příliš malá nebo již máte otevřeno příliš mnoho oken (jako je tomu u mě), můžete udělat to, co já, a dát to na Ereader nebo na váš telefon Android. Pokud plánujete napsat kód sestavy, budete ho používat pořád. Skvělé je, že všechny mikrokontroléry jsou organizovány velmi podobnými způsoby, a tak jakmile si zvyknete číst datové listy a kódovat z nich, bude pro vás téměř triviální dělat totéž pro jiný mikrokontrolér. Takže se vlastně učíme, jak používat všechny mikrokontroléry v určitém smyslu a ne jen atmega328p.

Dobře, přejděte na stránku 18 v datovém listu a podívejte se na obrázek 8-2.

Takto je nastavena paměť programu v mikrokontroléru. Vidíte, že začíná adresou 0x0000 a je rozděleno na dvě části; sekce flash aplikace a sekce boot flash. Pokud se krátce podíváte na stranu 277, tabulka 27-14, uvidíte, že část aplikace Flash zabírá místa od 0x0000 do 0x37FF a část boot flash zabírá zbývající místa od 0x3800 do 0x3FFF.

Cvičení 1: Kolik míst je v paměti programu? Tj. převést 3FFF na desítkové a přidat 1, protože začneme počítat na 0. Protože každé místo v paměti je široké 16 bitů (nebo 2 bajtů), jaký je celkový počet bajtů paměti? Nyní to převeďte na kilobajty a pamatujte, že v kilobajtu je 2^10 = 1024 bajtů. Sekce zaváděcího flash se pohybuje od 0x3800 do 0x37FF, kolik je to kilobajtů? Kolik kilobajtů paměti nám zbývá použít k uložení programu? Jinými slovy, jak velký může být náš program? Nakonec, kolik řádků kódu můžeme mít?

Dobře, teď, když víme vše o organizaci paměti flash programu, pokračujme v diskusi o příkazech.org. Vidíme, že první paměťové místo 0x0000 obsahuje naši instrukci ke skoku do naší sekce, kterou jsme označili Reset. Nyní vidíme, co prohlášení „.org 0x0020“dělá. Říká, že chceme, aby instrukce na dalším řádku byla umístěna na paměťové místo 0x0020. Instrukce, kterou jsme tam umístili, je skok do části v našem kódu, kterou jsme označili „overflow_handler“… proč bychom sakra požadovali, aby byl tento skok umístěn na paměťové místo 0x0020? Abychom to zjistili, otočíme se na stránku 65 v datovém listu a podíváme se na tabulku 12-6.

Tabulka 12-6 je tabulka „Reset a Interrupt Vectors“a přesně ukazuje, kam PC půjde, když obdrží „přerušení“. Pokud se například podíváte na Vektor číslo 1. „Zdrojem“přerušení je „RESET“, který je definován jako „Externí pin, Reset při zapnutí, Reset zhnědnutí a Reset systému Watchdog“, což znamená, pokud existuje tyto věci se stávají našemu mikrokontroléru, PC začne spouštět náš program v paměti programu 0x0000. Co pak naše směrnice.org? Vložili jsme příkaz na paměťové místo 0x0020 a když se podíváte dolů do tabulky, uvidíte, že pokud dojde k přetečení časovače/čítače (pocházející z TIMER0 OVF), provede to, co je v umístění 0x0020. Takže kdykoli se to stane, počítač skočí na místo, které jsme označili „overflow_handler“. Skvělé, že? Za minutu uvidíte, proč jsme to udělali, ale nejprve dokončíme tento krok tutoriálu stranou.

Pokud chceme, aby byl náš kód přehlednější a uklizenější, měli bychom skutečně nahradit 4 řádky, o kterých právě diskutujeme, následujícím (viz strana 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 pokud dojde k danému přerušení, dojde pouze k „reti“, což znamená „návrat z přerušení“a nic jiného se nestane. Pokud ale tato různá přerušení nikdy „nepovolíme“, pak nebudou použita a do těchto míst můžeme vložit programový kód. V našem aktuálním programu "blink.asm" povolíme pouze přerušení přetečení timeru0 (a samozřejmě přerušení resetování, které je vždy povoleno), a tak se nebudeme obtěžovat s ostatními.

Jak tedy „povolíme“přetečení timeru0? … To je předmětem našeho dalšího kroku v tomto tutoriálu.

Krok 5: Časovač/čítač 0

Časovač/čítač 0
Časovač/čítač 0

Podívejte se na výše uvedený obrázek. Toto je rozhodovací proces „PC“, když nějaký vnější vliv „přeruší“tok našeho programu. První věc, kterou udělá, když dostane signál zvenčí, že došlo k přerušení, je zkontrolovat, zda jsme pro tento typ přerušení nastavili bit „přerušení povolit“. Pokud ne, pokračuje se v provádění našeho dalšího řádku kódu. Pokud jsme nastavili konkrétní bit pro povolení přerušení (takže v tomto bitovém umístění je 1 místo 0), pak zkontroluje, zda jsme povolili „globální přerušení“, pokud ne, znovu přejde na další řádek kódu a pokračujte. Pokud jsme také povolili globální přerušení, přejde do umístění paměti programu pro tento typ přerušení (jak ukazuje Tabulka 12-6) a provede jakýkoli příkaz, který jsme tam vložili. Pojďme se tedy podívat, jak jsme to všechno implementovali do našeho kódu.

Sekce Obnovit označené v našem kódu začíná následujícími dvěma řádky:

Resetovat:

ldi temp, 0b00000101 out TCCR0B, temp

Jak již víme, načte se do temp (tj. R16) číslo bezprostředně následující, což je 0b00000101. Poté toto číslo zapíše do registru s názvem TCCR0B pomocí příkazu „out“. Co je to za registr? Přejdeme na stránku 614 datového listu. Toto je uprostřed tabulky shrnující všechny registry. Na adrese 0x25 najdete TCCR0B. (Nyní víte, odkud pochází řádek „out 0x25, r16“v mé nekomentované verzi kódu). Podle segmentu kódu výše vidíme, že jsme nastavili 0. bit a 2. bit a vymazali všechny ostatní. Při pohledu na tabulku vidíte, že to znamená, že jsme nastavili CS00 a CS02. Nyní přejdeme ke kapitole v datovém listu s názvem „8-bit Timer/Counter0 with PWM“. Zejména přejděte na stranu 107 této kapitoly. Uvidíte stejný popis registru „Regulátor časovače/čítače řízení B“(TCCR0B), který jsme právě viděli v souhrnné tabulce registru (mohli jsme tedy přijít přímo sem, ale chtěl jsem, abyste viděli, jak používat souhrnné tabulky pro budoucí reference). Datový list pokračuje v popisu každého z bitů v tomto registru a toho, co dělají. To vše prozatím přeskočíme a stránku otočíme k tabulce 15-9. Tato tabulka ukazuje "Popis bitů pro výběr hodin". Nyní se podívejte dolů do tabulky, dokud nenajdete řádek, který odpovídá bitům, které jsme právě nastavili v tomto registru. Na řádku je uvedeno „clk/1024 (z předzápalce)“. To znamená, že chceme, aby časovač/čítač0 (TCNT0) škrtal rychlostí, která je frekvencí CPU dělenou 1024. Protože máme náš mikrokontrolér napájený krystalovým oscilátorem 16 MHz, znamená to, že rychlost, kterou náš procesor vykonává, je 16 milionů instrukcí za sekundu. Takže míra, že náš čítač TCNT0 bude tikat, je 16 milionů/1024 = 15625krát za sekundu (zkuste to s různými bity pro výběr hodin a uvidíte, co se stane - pamatujete si naši filozofii?). Ponechme si číslo 15625 v zadní části mysli na později a přejdeme k dalším dvěma řádkům kódu:

ldi teplota, 0b00000001

ok TIMSK0, tepl

Tím se nastaví 0. bit registru s názvem TIMSK0 a smaže se všechny ostatní. Pokud se podíváte na stránku 109 v datovém listu, uvidíte, že TIMSK0 je zkratka pro „Register Timer/Counter Interrupt Mask Register 0“a náš kód nastavil 0. bit, který se jmenuje TOIE0, což znamená „Timer/Counter0 Overflow Interrupt Enable“… Tam! Nyní vidíte, o co jde. Nyní máme „bit umožňující přerušení nastavený“, jak jsme chtěli od prvního rozhodnutí na našem obrázku nahoře. Nyní tedy vše, co musíme udělat, je povolit „globální přerušení“a náš program bude schopen na tyto typy přerušení reagovat. Brzy povolíme globální přerušení, ale než to uděláme, možná vás něco zmátlo.. proč jsem sakra použil příkaz „sts“ke zkopírování do registru TIMSK0 místo obvyklého „out“?

Kdykoli mě uvidíte, použijte instrukci, kterou jste předtím neviděli, a první věc, kterou byste měli udělat, je obrátit se na stránku 616 v datovém listu. Toto je „Shrnutí sady instrukcí“. Nyní najděte instrukci „STS“, kterou jsem použil. Říká, že to vyžaduje číslo z registru R (použili jsme R16) a umístění k „Store direct to SRAM“k (v našem případě dané TIMSK0). Proč jsme tedy museli použít „sts“, což vyžaduje 2 hodinové cykly (viz poslední sloupec v tabulce) k uložení do TIMSK0 a k uložení do TCCR0B jsme předtím potřebovali pouze „out“, který trvá pouze jeden hodinový cyklus? Abychom na tuto otázku odpověděli, musíme se vrátit zpět do naší souhrnné tabulky registrů na straně 614. Vidíte, že registr TCCR0B je na adrese 0x25, ale také na (0x45), že? To znamená, že jde o registr v SRAM, ale je to také určitý typ registru nazývaný „port“(nebo i/o registr). Když se podíváte na souhrnnou tabulku instrukcí vedle příkazu „out“, uvidíte, že přebírá hodnoty z „pracovních registrů“jako R16 a odesílá je na PORT. Můžeme tedy použít „out“při zápisu do TCCR0B a ušetřit si tak hodinový cyklus. Nyní však vyhledejte TIMSK0 v registrační tabulce. Vidíte, že má adresu 0x6e. To je mimo rozsah portů (což jsou pouze první 0x3F umístění SRAM), a tak se musíte vrátit k použití příkazu sts a provedení dvou taktovacích cyklů CPU. Přečtěte si nyní poznámku 4 na konci souhrnné tabulky pokynů na straně 615. Všimněte si také, že všechny naše vstupní a výstupní porty, jako je PORTD, jsou umístěny ve spodní části tabulky. Například PD4 je bit 4 na adrese 0x0b (nyní vidíte, odkud v mém nekomentovaném kódu pocházely všechny věci 0x0b!).. dobře, rychlá otázka: změnili jste „sts“na „out“a uvidíte, co se děje? Pamatujte na naši filozofii! Rozbij to! neber moje slova jen pro věci.

Dobře, než budeme pokračovat, na minutu přejděte na stránku 19 v datovém listu. Zobrazí se obrázek datové paměti (SRAM). Prvních 32 registrů v SRAM (od 0x0000 do 0x001F) jsou „obecné pracovní registry“R0 až R31, které v našem kódu používáme neustále jako proměnné. Dalších 64 registrů jsou I/O porty až 0x005f (tj. Ty, o kterých jsme mluvili, které mají v tabulce registrů vedle sebe ty nesestavené adresy, které můžeme použít místo „sts“příkaz „out“) další část SRAM obsahuje všechny ostatní registry v souhrnné tabulce až po adresu 0x00FF a nakonec zbytek je interní SRAM. Nyní rychle, pojďme na vteřinu přejít na stranu 12. Zde vidíte tabulku „univerzálních pracovních registrů“, které vždy používáme jako proměnné. Vidíte tlustou čáru mezi čísly R0 až R15 a poté R16 až R31? To je důvod, proč vždy používáme R16 jako nejmenší a budu se tomu věnovat trochu v dalším tutoriálu, kde budeme také potřebovat tři 16bitové nepřímé registry adres, X, Y a Z. Nebudu přesto se do toho pusťte, protože to teď nepotřebujeme a dost se tu motáme.

Otočte jednu stránku zpět na stranu 11 datového listu. Vpravo nahoře uvidíte diagram registru SREG? Vidíte, že bit 7 tohoto registru se nazývá „I“. Nyní přejděte dolů na stránku a přečtěte si popis Bit 7 …. jé! Je to bit Global Interrupt Enable bit. To je to, co musíme nastavit, abychom mohli projít druhým rozhodnutím v našem diagramu výše a umožnit přerušení přetečení časovače/čítače v našem programu. Další řádek našeho programu by tedy měl znít:

sbi SREG, I

který nastavuje bit s názvem „I“v registru SREG. Místo toho jsme však použili instrukci

sei

namísto. Tento bit je v programech nastaven tak často, že právě udělali jednodušší způsob, jak to udělat.

Dobře! Nyní máme přerušení přetečení připraveno, takže náš „jmp overflow_handler“bude spuštěn, kdykoli k němu dojde.

Než půjdeme dál, podívejte se rychle na registr SREG (Status Register), protože je velmi důležitý. Přečtěte si, co každý z příznaků představuje. Zejména mnoho z pokynů, které používáme, nastaví a zkontroluje tyto příznaky po celou dobu. Například později budeme používat příkaz „CPI“, což znamená „okamžitě porovnat“. Podívejte se na souhrnnou tabulku instrukcí pro tuto instrukci a všimněte si, kolik příznaků nastavuje ve sloupci "příznaky". Toto jsou všechny příznaky v SREG a náš kód je bude nastavovat a neustále kontrolovat. Brzy uvidíte příklady. Nakonec poslední bit této části kódu je:

teplota clr

výstup TCNT0, teplota sbi DDRD, 4

Poslední řádek zde je docela zřejmý. Prostě nastaví 4. bit registru Data Direction Register pro PortD, což způsobí, že PD4 bude VÝSTUP.

První nastaví proměnnou temp na nulu a poté ji zkopíruje do registru TCNT0. TCNT0 je náš časovač/čítač0. Tím se nastaví na nulu. Jakmile počítač spustí tento řádek, časovač 0 začne na nule a každou sekundu bude počítat rychlostí 15625krát. Problém je v tom: TCNT0 je "8bitový" registr, že? Jaké je tedy největší číslo, které může 8bitový registr pojmout? No 0b11111111 je to. Toto je číslo 0xFF. Což je 255. Takže vidíte, co se stane? Časovač se zvětšuje 15625krát za sekundu a pokaždé, když dosáhne 255, „přeteče“a vrátí se zpět na 0. Současně s návratem na nulu vyšle signál přerušení přetečení časovače. Počítač to pochopil a víte, co teď dělá, že? Ano. Přejde do umístění paměti programu 0x0020 a provede tam instrukci, kterou najde.

Skvělý! Pokud jsi stále se mnou, jsi neúnavný superhrdina! Pokračujme…

Krok 6: Overflow Handler

Předpokládejme tedy, že registr časovače/čítače0 právě přetekl. Nyní víme, že program obdrží signál přerušení a provede 0x0020, který řekne čítači programu, PC, aby přeskočil na popisek „overflow_handler“, následující je kód, který jsme napsali za tento štítek:

overflow_handler:

včetně přetečení cpi přetečení, 61 brne PC+2 clr přetečení reti

První věc, kterou udělá, je zvýšení proměnné „přetečení“(což je náš název pro pracovní registr R17 pro obecné účely), poté „porovná“obsah přetečení s číslem 61. Způsob, jakým funguje instrukce cpi, je, že jednoduše odečte ta dvě čísla a pokud je výsledek nula, nastaví příznak Z v registru SREG (řekl jsem vám, že tento registr budeme vidět pořád). Pokud jsou obě čísla stejná, pak příznak Z bude 1, pokud nejsou dvě čísla stejná, bude to 0.

Další řádek říká „brne PC+2“, což znamená „větev, pokud není stejná“. V zásadě kontroluje příznak Z v SREG a pokud NENÍ jedničkou (tj. Dvě čísla nejsou stejná, pokud by byla stejná, byl by nastaven nulový příznak), PC se větví na PC+2, což znamená, že přeskočí další řádek a jde přímo do „reti“, který se vrací z přerušení na jakékoli místo, kde bylo v kódu, když přerušení dorazilo. Pokud by instrukce brne nalezla 1 v bitu nulového příznaku, nerozvětvila by se a místo toho by pokračovala na další řádek, který by přetečení clr resetoval na 0.

Jaký je čistý výsledek toho všeho?

Vidíme, že pokaždé, když dojde k přetečení časovače, tento obslužný program zvýší hodnotu „přetečení“o jeden. Proměnná „přetečení“tedy počítá počet přetečení tak, jak k nim dochází. Kdykoli číslo dosáhne 61, vynulujeme ho na nulu.

Proč bychom to tedy ve světě dělali?

Uvidíme. Připomeňme si, že naše taktovací frekvence pro náš procesor je 16 MHz a „předškálovali“jsme ji pomocí TCCR0B, aby časovač počítal pouze rychlostí 15625 počtů za sekundu, že? A pokaždé, když časovač dosáhne počtu 255, přeteče. To tedy znamená, že přetéká 15625/256 = 61,04krát za sekundu. Sledujeme počet přetečení pomocí naší proměnné „přetečení“a porovnáváme toto číslo s 61. Vidíme tedy, že „přetečení“se bude rovnat 61 jednou za sekundu! Náš obslužný program tedy jednou za sekundu resetuje „přetečení“na nulu. Pokud bychom tedy měli jednoduše sledovat proměnnou „přetečení“a vzít si na vědomí každé její resetování na nulu, počítali bychom sekundu po vteřině v reálném čase (Všimněte si, že v příštím tutoriálu ukážeme, jak získat přesnější zpoždění v milisekundách stejným způsobem, jako funguje rutina „zpoždění“Arduina).

Nyní jsme „zvládli“přetečení časovače. Ujistěte se, že rozumíte tomu, jak to funguje, a poté přejděte k dalšímu kroku, kde tuto skutečnost využíváme.

Krok 7: Zpoždění

Nyní, když jsme viděli, že naše rutina přerušení přetečení časovače „overflow_handler“nastaví proměnnou „přetečení“na nulu jednou za sekundu, můžeme tuto skutečnost použít k návrhu podprogramu „zpoždění“.

Podívejte se na následující kód zpod našeho zpoždění: štítek

zpoždění:

přetečení clr sec_count: přetečení cpi, 30 brne sec_count ret

Zavoláme tento podprogram pokaždé, když budeme potřebovat zpoždění v našem programu. Funguje to tak, že nejprve nastaví proměnnou „přetečení“na nulu. Poté zadá oblast označenou „sec_count“a porovná přetečení s 30, pokud si nejsou rovna, rozvětví se zpět na štítek sec_count a porovnává znovu a znovu atd., Dokud si nejsou konečně rovni (pamatujte, že po celou dobu to probíhá na naší obsluze přerušení časovače pokračuje ve zvyšování přetečení proměnné, a tak se mění pokaždé, když jdeme kolem. Když se přetečení nakonec rovná 30, dostane se ze smyčky a vrátí se kamkoli jsme nazvali zpoždění: od. Čistý výsledek je zpoždění 1/2 sekundy

Cvičení 2: Změňte rutinu overflow_handler na následující:

overflow_handler:

inc přetoky reti

a spusťte program. Je něco jiného? Proč nebo proč ne?

Krok 8: Mrkněte

Nakonec se podívejme na rutinu mrknutí:

blikat:

sbi PORTD, 4 rcall delay cbi PORTD, 4 rcall delay rjmp bliká

Nejprve zapneme PD4, poté vyvoláme podprogram zpoždění. Používáme rcall, takže když se PC dostane k příkazu „ret“, vrátí se na řádek následující po rcall. Potom se zpožďovací rutina prodlouží o 30 počtů v proměnné přetečení, jak jsme viděli, a to je téměř přesně 1/2 sekundy, poté vypneme PD4, zdržíme další 1/2 sekundy a pak se vrátíme zpět na začátek.

Výsledkem je blikající LED!

Myslím, že teď budete souhlasit, že „blink“pravděpodobně není nejlepší program „hello world“v jazyce Assembly.

Cvičení 3: Změňte různé parametry v programu tak, aby LED blikala různou rychlostí jako sekunda nebo 4krát za sekundu atd. Cvičení 4: Změňte ji tak, aby LED svítila a zhasínala po různě dlouhou dobu. Například zapnuto na 1/4 sekundy a poté vypnuto na 2 sekundy nebo něco podobného. Cvičení 5: Změňte hodiny TCCR0B, vyberte bity na 100 a pak pokračujte v pohybu po stole. V jakém okamžiku se stane nerozeznatelným od našeho programu „hello.asm“z tutoriálu 1? Cvičení 6 (volitelně): Pokud máte jiný krystalový oscilátor, například 4 MHz nebo 13,5 MHz nebo cokoli jiného, změňte oscilátor 16 MHz na vašem prkénku pro nový a podívejte se, jak to ovlivňuje rychlost blikání LED. Nyní byste měli být schopni projít přesným výpočtem a přesně předpovědět, jak to ovlivní sazbu.

Krok 9: Závěr

Těm z vás, kteří jste se dostali tak daleko, gratulujeme!

Uvědomuji si, že je docela těžké bičovat, když více čtete a vzhlížíte, než zapojujete a experimentujete, ale doufám, že jste se naučili následující důležité věci:

  1. Jak funguje paměť programu
  2. Jak SRAM funguje
  3. Jak vyhledat registry
  4. Jak vyhledat pokyny a vědět, co dělají
  5. Jak implementovat přerušení
  6. Jak CP provádí kód, jak funguje SREG a co se děje během přerušení
  7. Jak dělat smyčky a skoky a odrážet se v kódu
  8. Jak důležité je přečíst si datasheet!
  9. Jak jednou budete vědět, jak to vše udělat pro mikrokontrolér Atmega328p, bude to relativní procházka, ve které se naučíte nové ovladače, které vás zajímají.
  10. Jak změnit čas CPU na reálný čas a použít jej v rutinách zpoždění.

Nyní, když máme spoustu teorie z cesty, jsme schopni psát lepší kód a ovládat složitější věci. Takže příští tutoriál budeme dělat právě to. Postavíme složitější, zajímavější obvod a budeme jej ovládat zábavnými způsoby.

Cvičení 7: „Rozbijte“kód různými způsoby a uvidíte, co se stane! Vědecká zvědavost, zlato! Někdo jiný může umýt nádobí, ne? Cvičení 8: Sestavte kód pomocí možnosti „-l“a vygenerujte soubor seznamu. Tj. "avra -l blink.lst blink.asm" a podívejte se na soubor seznamu. Extra kredit: Nezkomentovaný kód, který jsem dal na začátku, a komentovaný kód, který probereme později, se liší! Existuje jeden řádek kódu, který je odlišný. Dokážete to najít? Proč na tom rozdílu nezáleží?

Doufám, že jste se pobavili! Uvidíme se příště…

Doporučuje: