Stap 5: Timer/Counter 0
Neem een kijkje op de bovenstaande foto. Dit is het besluit-makend proces van de "PC" wanneer sommige buitenlandse invloed 'onderbroken' de stroom van onze programma. Het eerste ding het doet wanneer het wordt een signaal van buiten dat een interrupt is opgetreden is het controles om te zien als we hebben de "interrupt enable" bit voor dat type van onderbreken. Als we nog niet, dan blijft gewoon onze volgende lijn van code uit te voeren. Als wij dat bepaalde interrupt enable beetje hebt ingesteld (zodat er een 1 op die locatie bit in plaats van een 0) zal het dan controleren of wij "global interrupts" hebt ingeschakeld, zoniet het weer zal gaan naar de volgende coderegel en blijven. Als we mondiale interrupts ook hebt ingeschakeld, zal dan het gaat u naar de locatie van het programmageheugen van dat type interrupt (zoals aangegeven in tabel 12-6) en welke commando die we er hebben geplaatst. Dus laten we eens kijken hoe we dit alles in onze code hebt geïmplementeerd.
Het resetten van het label van de sectie van onze code begint met de volgende twee regels:
Reset: ldi temp, 0b00000101 out TCCR0B, temp
Zoals we al weten, laadt deze in temp (d.w.z. R16) het cijfer onmiddellijk na, die 0b00000101 is. Dan het schrijft dit nummer uit tot het register genaamd TCCR0B met behulp van de opdracht "out". Wat is dit register? Nou, laten we het hoofd over aan pagina 614 van het gegevensblad. Dit is in het midden van een tabel Samenvatting van alle van de registers. Op adres 0x25 vindt u TCCR0B. (Nu weet u waar de lijn "uit 0x25, r16" kwam uit in mijn un-commentaar versie van de code). We zien het codesegment boven die we hebben ingesteld de 0de bits en de 2de bit en gewist al de rest. Door te kijken naar de tabel kunt u zien dat dit betekent dat we hebben ingesteld CS00 en CS02. Laat nu hoofd over naar het hoofdstuk in het gegevensblad genaamd "8-bits Timer/Counter0 met PWM". In het bijzonder, ga naar pagina 107 van dat hoofdstuk. Ziet u dezelfde beschrijving van het register ' Timer/teller besturingselement registreren B' (TCCR0B) die we net in de register-samenvatting zagen tabel (dus we konden direct hier gekomen, maar ik wilde u om te zien hoe de samenvattende tabellen gebruiken voor toekomstig gebruik). Het gegevensblad blijft geven een beschrijving van elk van de bits in het register en wat ze doen. Wij zal overslaan dat alles voor nu en zet de pagina tot en met tabel 15-9. Deze tabel toont de "klok Bit Beschrijving selecteren". Nu kijken neer die tabel totdat u de regel die correspondeert met de bits die we net gesteld in dit register vindt. De lijn zegt "clk/1024 van prescaler)". Wat dit betekent is dat we Timer/Counter0 (TCNT0 willen) aan het kruis langs met een snelheid die de CPU-frequentie gedeeld door 1024. Omdat we onze microcontroller gevoed door een 16MHz kristal oscillator betekent dit dat de koers die onze CPU voert instructies is 16million instructies per seconde. Dus de koers die onze TCNT0 teller zal aankruisen is dan 16million/1024 = 15625 keer per seconde (proberen met verschillende klok select bits en zien wat er gebeurt - onze filosofie herinneren?). Laten we het aantal 15625 in ons achterhoofd houden voor later en ga naar de volgende twee coderegels:
ldi temp, 0b00000001 sts TIMSK0, temp
Dit stelt de 0de bit van een register genaamd TIMSK0 en al de rest wordt gewist. Als u een kijkje op pagina 109 in het gegevensblad nemen ziet u dat TIMSK0 voor "Timer/teller onderbreken masker Register 0 staat" en onze codeset heeft de 0de bit die heet TOIE0, wat voor "Timer/Counter0 Overflow Interrupt Enable staat"... Daar! Nu zie je wat dit is all about. We hebben nu de "interrupt enable-bit ingesteld" als we uit de eerste beslissing in onze foto boven wilden. Dus nu alles wat we moeten doen is "global interrupts" in staat stellen en ons programma zal kunnen inspelen op dit soort interrupts. We kunnen globale interrupts binnenkort, maar voordat we dat doen je kan hebben is in de war door iets... waarom de heck ik gebruikte de opdracht "St" kopiëren naar het register van de TIMSK0 in plaats van de gebruikelijke "out"?
Wanneer zie je me gebruiken een instructie die u nog niet voordat gezien is het eerste ding dat u moet doen ga naar pagina 616 in het gegevensblad. Dit is de "instructie Set samenvatting". Nu vinden de instructie "St", dat is degene die ik gebruikt. Het zegt dat het duurt een aantal uit een register van de R (wij gebruikten R16) en "Slaan direct naar SRAM" Locatie k (in ons geval gegeven door TIMSK0). Dus waarom hebben wij te gebruiken "St" waarin 2 klokcycli (zie laatste kolom in tabel) op te slaan TIMSK0 en we alleen nodig "out", waarin slechts één klokcyclus, in de TCCR0B alvorens op te slaan? Om deze vraag te beantwoorden moeten we teruggaan naar onze register samenvattende tabel op pagina 614. U ziet dat het TCCR0B-register op adres 0x25 maar ook op (0x45) recht? Dit betekent dat er een register in SRAM, maar het is ook een bepaald soort register "poort" genoemd (of i/o-register). Als je kijkt naar de instructie samenvattende tabel naast de "out"-opdracht u ziet dat het duurt van waarden uit de "werkende registers" zoals R16 en ze op een poort stuurt. Zo kunnen we gebruik "out" bij het schrijven naar TCCR0B en sla zelf een klokcyclus. Maar nu TIMSK0 opzoeken in de tabel register. Ziet u dat het adres 0x6e heeft. Dit valt buiten het bereik van poorten (die zijn alleen de eerste 0x3F locaties van SRAM) en dus je terugvallen moet op de St-opdracht en het nemen van twee cycli van CPU klok om het te doen. Lees Opmerking 4 aan het einde van de instructie samenvattende tabel op pagina 615 nu. Ook kunt u zien dat alle onze input en output poorten, zoals PORTD zich gelegen aan de onderkant van de tabel. Bijvoorbeeld, de PD4 is beetje 4 op adres 0x0b (nu u zien waar alle spullen van de 0x0b kwam uit in mijn un-commentaar code!)... Oke, vraagje: heb je het veranderen van de "St" tot "out" en zien wat er gebeurt? Vergeet niet onze filosofie! breken! nemen niet alleen mijn woord voor dingen.
Oke, alvorens verder te gaan, ga naar pagina 19 in het gegevensblad voor een minuut. U ziet een foto van het datageheugen (SRAM). De eerste 32 registers in SRAM (vanaf 0x0000 tot 0x001F) zijn de "general purpose werken registers" R0 via R31 die we de hele tijd als variabelen in onze code gebruiken. De volgende 64 registers zijn de I/O poorten tot 0x005f (d.w.z. we spraken over degenen die de VN-tussen haakjes adressen naast hen die in het register hebben tabel die we met de opdracht 'onvoldoende' in plaats van "St") ten slotte het volgende onderdeel van SRAM bevat alle andere registers in de samenvattingstabel tot adres 0x00FF, en tot slot de rest is interne SRAM. Snel, laten we nu naar pagina 12 voor een tweede. Daar zie je een tabel van de "general purpose werken registers" die we altijd als onze variabelen gebruiken. U ziet de dikke lijn tussen nummers R0 tot R15 en vervolgens R16 tot R31? Die lijn is de reden waarom we altijd R16 als de kleinste gebruiken en ik zal krijgen in het een beetje meer in de volgende tutorial waar we zullen ook moeten de drie indirecte adres van 16-bits registers, X, Y en Z. Ik zal niet krijgen in dat enkel nog wel omdat we nu niet nodig en wij zijn vast genoeg hier.
Spiegelen terug één pagina 11 van het gegevensblad. Hier ziet u een diagram van het register van de SREG rechts bovenaan? U ziet dat beetje 7 van het register wordt genoemd "I". Nu naar beneden de pagina en lees de beschrijving van de beetje 7... Yay! Het is het beetje Global Interrupt inschakelen. Dat is wat we moeten instellen om het passeren van de tweede beslissing in onze bovenstaande diagram en timer/teller overloop interrupts in ons programma toestaan. Zo moet de volgende regel van ons programma lezen:
sbi SREG, I
waarin de bit genaamd "I" in het SREG-register. Echter, in plaats van dit hebben we gebruikt de instructie
sei
in plaats daarvan. Dit stukje ligt zo vaak in de programma's dat ze zojuist een eenvoudigere manier om het te doen.
Oke! Nu hebben we de overloop interrupts klaar om te gaan zodat onze "jmp overflow_handler" zal worden uitgevoerd wanneer een voordoet.
Alvorens verder te gaan, neem een snelle blik op het SREG-register (Status Register) want het is zeer belangrijk. Lees wat elk van de vlaggen vertegenwoordigt. In het bijzonder, zullen veel van de instructies die we gebruiken instellen en controleer deze vlaggen hele tijd. Bijvoorbeeld, zullen later we worden met behulp van de opdracht "CPI" wat betekent "Vergelijk onmiddellijke". Neem een kijkje op de instructie-Overzichtstabel van deze instructie en merken hoeveel vlaggen daarin in de kolom "vlaggen". Dit zijn alle vlaggen in SREG en onze code zal hen te plaatsen en hen voortdurend controleren. Binnenkort zult u voorbeelden zien. Ten slotte is het laatste stukje van deze sectie van code:
clr temp out TCNT0, temp sbi DDRD,4
De laatste regel hier is vrij duidelijk. Het stelt enkel de 4de bit van het Register van de richting van de gegevens voor PortD veroorzaakt PD4 wordt uitgevoerd.
De eerste wordt de variabele temp ingesteld op nul en kopieert dat uit naar het TCNT0-register. TCNT0 is onze Timer/Counter0. Dit wordt het ingesteld op nul. Zodra de PC deze regel voert zal de timer0 beginnen bij nul en tellen met een snelheid van 15625 keer per seconde. Het probleem is dit: TCNT0 is een "8-bit" register terecht? Dus wat is het grootste getal dat een 8-bit register kan houden? Goed 0b11111111 is het. Dit is het nummer 0xFF. Die is 255. Zo zie je wat er gebeurt? De timer is zippen langs 15625 keer per seconde te verhogen en elke keer 255 bereikt het "overloop" en gaat terug naar 0 weer. Op hetzelfde moment als het gaat terug naar nul het signaal een Timer Overflow Interrupt. De PC krijgt dit en weet je wat het doet nu recht? Yep. Het gaat naar programmageheugen locatie 0x0020 en voert de instructie die het veld.
Geweldig! Bent u nog steeds met me dan bent u een onvermoeibare superheld! Laten we blijven gaan...