INHOUDSOPGAWE:

AVR -samestellingstudie 3: 9 -stappe
AVR -samestellingstudie 3: 9 -stappe

Video: AVR -samestellingstudie 3: 9 -stappe

Video: AVR -samestellingstudie 3: 9 -stappe
Video: Как устроена электрическая часть на бензиновом генераторе с AVR 2024, November
Anonim
AVR -samestelling -tutoriaal 3
AVR -samestelling -tutoriaal 3

Welkom by tutoriaal nommer 3!

Voordat ons begin, wil ek 'n filosofiese punt maak. Moenie bang wees om te eksperimenteer met die stroombane en die kode wat ons in hierdie tutoriale saamstel nie. Verander drade, voeg nuwe komponente by, haal komponente uit, verander kodelyne, voeg nuwe reëls by, verwyder lyne en kyk wat gebeur! Dit is baie moeilik om iets te breek, en as u dit doen, wie gee om? Niks wat ons gebruik nie, insluitend die mikrobeheerder, is baie duur en dit is altyd leersaam om te sien hoe dinge kan misluk. Nie net sal u uitvind wat u die volgende keer nie moet doen nie, maar belangriker nog, u sal weet hoekom u dit nie moet doen nie. As u net soos ek is, was dit nie lank nie, toe u 'n kind was en 'n nuwe speelding gekry het, om te sien wat dit reggekry het? Soms het die speelding onherstelbaar beskadig, maar dit is nie 'n groot probleem nie. Deur 'n kind toe te laat om sy nuuskierigheid te ondersoek, selfs tot die punt van stukkende speelgoed, word dit 'n wetenskaplike of 'n ingenieur in plaas van 'n skottelgoedwasser.

Vandag gaan ons 'n baie eenvoudige stroombaan bedrieg en dan 'n bietjie in die teorie beland. Jammer hieroor, maar ons het die gereedskap nodig! Ek belowe dat ons dit in tutoriaal 4 sal vergoed, waar ons 'n meer ernstige stroombaanbou gaan doen en die resultaat redelik gaaf sal wees. Die manier waarop u al hierdie tutoriale moet uitvoer, is egter baie stadig, nadenkend. As u net deurploeg, bou die kring, kopieer en plak die kode en voer dit dan uit, dit sal beslis werk, maar u sal niks leer nie. U moet aan elke reël dink. Pouse. Eksperimenteer. Uitvind. As u dit so doen, sal u aan die einde van die 5de tutoriaal goeie dinge bou en nie meer onderrig nodig hê nie. Anders kyk u eerder as om te leer en te skep.

In elk geval, genoeg filosofie, laat ons begin!

In hierdie tutoriaal benodig u:

  1. jou prototipe bord
  2. 'n LED
  3. drade verbind
  4. 'n weerstand rondom 220 tot 330 ohm
  5. Die handleiding vir instruksies: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. Die datablad: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. 'n ander kristal ossillator (opsioneel)

Hier is 'n skakel na die volledige versameling tutoriale:

Stap 1: Bou die stroombaan

Die bou van die kring
Die bou van die kring

Die kring in hierdie tutoriaal is uiters eenvoudig. Ons gaan in wese die 'knip' -program skryf, en al wat ons nodig het, is die volgende.

Koppel 'n LED aan PD4, dan aan 'n weerstand van 330 ohm, dan na die grond. m.a.w.

PD4 - LED - R (330) - GND

en dit is dit!

Die teorie gaan egter moeilik wees …

Stap 2: Waarom het ons die opmerkings en die M328Pdef.inc -lêer nodig?

Ek dink ons moet begin deur aan te dui waarom die insluit -lêer en die kommentaar nuttig is. Nie een van hulle is eintlik nodig nie, en u kan die kode op dieselfde manier skryf, bymekaarbring en oplaai, en dit sal perfek verloop (alhoewel u 'n paar klagtes van die versamelaar kan kry - maar geen foute nie)

Hier is die kode wat ons vandag gaan skryf, behalwe dat ek die kommentaar en die insluit -lêer verwyder het:

.toestel 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, 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

redelik eenvoudig reg? Haha. As u hierdie lêer saamgestel en opgelaai het, sal die LED met 'n flits van 1 knippie per sekonde laat flikker, met die knippie wat 1/2 sekonde duur en die pouse tussen die flitse van 1/2 sekonde.

Om na hierdie kode te kyk, is egter skaars verhelderend. As u 'n kode soos hierdie sou skryf, sou u dit in die toekoms wou verander of hergebruik, sou dit moeilik wees.

Laat ons dus die kommentaar plaas en die lêer terugsit, sodat ons 'n idee daarvan kan kry.

Stap 3: Knipoog

Hier is die kode wat ons vandag sal bespreek:

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

; geskryf deur: 1o_o7; datum:; weergawe: 1.0; lêer gestoor as: blink.asm; vir AVR: atmega328p; klokfrekwensie: 16MHz (opsioneel); *************************************; Program funksie: ---------------------; tel sekondes af deur 'n LED te knip;; PD4 - LED - R (330 ohm) - GND;; --------------------------------------.nolist. sluit "./m328Pdef.inc" in.list; ================; Deklarasies:.def temp = r16.def oorloop = r17.org 0x0000; geheue (rekenaar) ligging van reset handler rjmp Reset; jmp kos 2 cpu -siklusse en rjmp kos slegs 1; dus tensy u meer as 8k grepe moet spring; u benodig slegs rjmp. Sommige mikrobeheerders dus slegs; het rjmp en nie jmp.org 0x0020; geheue plek van Timer0 oorloop hanteerder rjmp overflow_handler; gaan hierheen as 'n timer0 oorloop onderbreking plaasvind; ============ Herstel: ldi temp, 0b00000101 out TCCR0B, temp; stel die Clock Selector Bits CS00, CS01, CS02 op 101; dit plaas Timer Counter0, TCNT0 in die FCPU/1024 -modus; dit merk dus by die CPU -frekwensie/1024 ldi temp, 0b00000001 st TIMSK0, temp; stel die Timer Overflow Interrupt Enable (TOIE0) -bit in; van die Timer Interrupt Mask Register (TIMSK0) sei; maak globale onderbrekings moontlik - gelykstaande aan "sbi SREG, I" clr temp out TCNT0, temp; initialiseer die timer/teller na 0 sbi DDRD, 4; stel PD4 op uitvoer; =========================; Hoofprogram: knipoog: sbi PORTD, 4; skakel LED aan op PD4 rcall delay; vertraging sal 1/2 sekonde cbi PORTD wees, 4; skakel LED aan PD4 rcall delay; vertraging sal 1/2 sekonde rjmp knip; loop terug na die beginvertraging: clr loop oor; stel oorloop na 0 sec_count: cpi loop oor, 30; vergelyk die aantal oorstromings en 30 brne sec_count; vertakking na agter na sec_count indien nie gelyk aan ret; as 30 oorstromings plaasgevind het, keer terug na blink overflow_handler: inc oorloop; voeg 1 by die oorloop veranderlike cpi oorloop, 61; vergelyk met 61 brne PC+2; Programteller + 2 (slaan volgende reël oor) indien nie gelyke clr -oorloë nie; stel 61 teller terug na zero reti; terugkeer van onderbreking

Soos u kan sien, is my kommentaar nou 'n bietjie meer kort. As ons eers weet wat die opdragte in die instruksieset is, hoef ons dit nie in die kommentaar te verduidelik nie. Ons hoef net uit die oogpunt van die program te verduidelik wat aangaan.

Ons sal bespreek wat dit alles stuk vir stuk doen, maar eers probeer ons 'n globale perspektief kry. Die hoofdeel van die program werk soos volg.

Eerstens het ons bietjie 4 van PORTD met "sbi PORTD, 4" gestel, dit stuur 'n 1 na PD4 wat die spanning op 5V op die pen plaas. Dit sal die LED aanskakel. Ons spring dan na die 'vertraging' -subroetine wat 1/2 'n sekonde tel (ons sal later verduidelik hoe dit dit doen). Ons keer dan terug om 'n bietjie te knip en bietjie 4 op PORTD te verwyder, wat PD4 op 0V stel en dus die LED afskakel. Ons vertraag dan nog 'n 1/2 sekonde en spring dan weer terug na die begin van die knip met "rjmp blink".

U moet hierdie kode uitvoer en kyk of dit doen wat dit moet.

En daar het jy dit! Dit is al wat hierdie kode fisies doen. Die interne meganika van wat die mikrobeheerder doen, is 'n bietjie meer betrokke, en daarom doen ons hierdie tutoriaal. Laat ons dus elke afdeling op sy beurt bespreek.

Stap 4:.org Assembler Directives

Ons weet reeds wat die.nolist,.list,.include en.def assembler -voorskrifte uit ons vorige tutoriale doen, dus kyk eers na die vier kode -reëls wat daarna kom:

.org 0x0000

jmp Herstel.org 0x0020 jmp overflow_handler

Die.org -verklaring sê vir die versamelaar waar in die "Programgeheue" die volgende stelling geplaas moet word. Terwyl u program uitgevoer word, bevat die "Programme teller" (afkorting as rekenaar) die adres van die huidige reël wat uitgevoer word. Dus, in hierdie geval, as die rekenaar op 0x0000 is, sal die opdrag "jmp Reset" in die geheue -ligging voorkom. Die rede waarom ons jmp Reset op die plek wil plaas, is omdat die rekenaar op hierdie plek begin met die uitvoering van die program wanneer die program begin of die chip herstel word. Dus, soos ons kan sien, het ons dit net gesê om onmiddellik na die afdeling met die naam "Herstel" te spring. Waarom het ons dit gedoen? Dit beteken dat die laaste twee reëls hierbo net oorgeslaan word! Hoekom?

Wel, dit is waar dinge interessant raak. U moet nou 'n pdf -kyker met die volledige ATmega328p -datablad oopmaak waarop ek op die eerste bladsy van hierdie tutoriaal gewys het (daarom is dit item 4 in die afdeling 'u benodig'). As u skerm te klein is, of as u al te veel vensters oopmaak (soos met my die geval is), kan u doen wat ek doen en dit op 'n Ereader of u Android -telefoon plaas. U sal dit altyd gebruik as u van plan is om die monteringskode te skryf. Die aangename ding is dat alle mikrobeheerders op baie soortgelyke maniere georganiseer is, en sodra u gewoond geraak het aan die lees van gegewensblaaie en die kodering daarvan, vind u dit amper triviaal om dieselfde vir 'n ander mikrobeheerder te doen. Ons leer dus eintlik hoe om alle mikrobeheerders in 'n sekere sin te gebruik, en nie net die atmega328p nie.

Gaan na bladsy 18 in die datablad en kyk na figuur 8-2.

Dit is hoe die programgeheue in die mikrobeheerder opgestel is. U kan sien dat dit met adres 0x0000 begin en in twee afdelings geskei is; 'n toepassingsflitsafdeling en 'n opstartflitsafdeling. As u kortliks na bladsy 277 tabel 27-14 verwys, sal u sien dat die toepassingsflitsafdeling die liggings van 0x0000 tot 0x37FF beslaan en die opstartflitsafdeling die oorblywende plekke van 0x3800 tot 0x3FFF opneem.

Oefening 1: Hoeveel plekke is daar in die programgeheue? D.w.s. skakel 3FFF om na desimale en voeg 1 by, aangesien ons begin tel by 0. Aangesien elke geheue -ligging 16 bis (of 2 grepe) breed is, wat is die totale aantal grepe geheue? Skakel dit nou om in kilobytes, onthou dat daar 2^10 = 1024 grepe in 'n kilobyte is. Die opstartflitsafdeling gaan van 0x3800 na 0x37FF, hoeveel kilobyte is dit? Hoeveel kilobytes geheue moet ons nog gebruik om ons program te stoor? Met ander woorde, hoe groot kan ons program wees? Laastens, hoeveel reëls kode kan ons hê?

Goed, noudat ons alles weet van die organisasie van die flash -programgeheue, laat ons voortgaan met ons bespreking van die.org -stellings. Ons sien dat die eerste geheue -plek 0x0000 ons instruksies bevat om na ons afdeling te gaan, wat ons as Reset gemerk het. Nou sien ons wat die '.org 0x0020' stelling doen. Dit sê dat ons wil hê dat die instruksie op die volgende reël op geheue -plek 0x0020 geplaas moet word. Die instruksie wat ons daar geplaas het, is 'n sprong na 'n gedeelte in ons kode wat ons as "overflow_handler" gemerk het … waarom sou ons dan vereis dat hierdie sprong op geheue plek 0x0020 geplaas word? Om dit uit te vind, gaan ons na bladsy 65 in die datablad en kyk na tabel 12-6.

Tabel 12-6 is 'n tabel met "Herstel- en onderbrekingsvektore" en dit wys presies waarheen die rekenaar gaan as dit 'n 'onderbreking' ontvang. As u byvoorbeeld na Vektornommer 1. kyk, is die 'bron' van die onderbreking 'RESET', wat gedefinieer word as 'External Pin, Power-on Reset, Brown-out Reset, and Watchdog system reset' betekenis, indien enige van as hierdie dinge met ons mikrobeheerder gebeur, begin die rekenaar ons program op die programgeheue 0x0000. Wat van ons.org -opdrag dan? Ons het 'n opdrag op geheue -plek 0x0020 geplaas, en as u in die tabel afkyk, sal u sien dat as 'n Timer/Counter0 -oorloop plaasvind (afkomstig van TIMER0 OVF), dit alles op die plek 0x0020 sal uitvoer. Dus, as dit gebeur, spring die rekenaar na die plek wat ons 'overflow_handler' genoem het. Cool reg? U sal binne 'n minuut sien hoekom ons dit gedoen het, maar laat ons eers hierdie stap van die tutoriaal afsonderlik voltooi.

As ons ons kode netjieser en netjieser wil maak, moet ons die 4 reëls wat ons tans bespreek, werklik vervang met die volgende (sien bladsy 66):

.org 0x0000

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

Sodat as 'n gegewe onderbreking plaasvind, dit net 'reti' beteken, wat 'terugkeer van onderbreking' beteken en niks anders gebeur nie. Maar as ons hierdie verskillende onderbrekings nooit 'aktiveer' nie, dan word dit nie gebruik nie en kan ons programkode op hierdie plekke plaas. In ons huidige 'blink.asm' -program gaan ons slegs die timer0 -oorlooponderbreking (en natuurlik die herstelonderbreking wat altyd aangeskakel is) moontlik maak, en daarom sal ons nie met die ander moeite doen nie.

Hoe kan ons dan die timer0 -oorlooponderbreking aktiveer? … dit is die onderwerp van ons volgende stap in hierdie tutoriaal.

Stap 5: Timer/Teller 0

Timer/toonbank 0
Timer/toonbank 0

Kyk na die prent hierbo. Dit is die besluitnemingsproses van die 'PC' wanneer 'n invloed van buite die vloei van ons program 'onderbreek'. Die eerste ding wat dit doen as dit van buite 'n sein kry dat 'n onderbreking plaasgevind het, is om te kyk of ons die 'onderbreek -inskakel' -bietjie vir die tipe onderbreking ingestel het. As ons dit nie gedoen het nie, gaan dit voort met die uitvoering van ons volgende reël kode. As ons die spesifieke onderbreek -inskakeling -bit gestel het (sodat daar 'n 1 in die bis -plek is in plaas van 'n 0), sal dit dan kontroleer of ons 'globale onderbrekings' moontlik gemaak het, indien nie, gaan dit weer na die volgende reël kode en gaan voort. As ons ook wêreldwye onderbrekings moontlik gemaak het, gaan dit na die programgeheue-plek van die tipe onderbreking (soos getoon in tabel 12-6) en voer die opdrag uit wat ons daar geplaas het. Kom ons kyk hoe ons dit alles in ons kode geïmplementeer het.

Die afdeling Herstel met die naam van ons kode begin met die volgende twee reëls:

Herstel:

ldi temp, 0b00000101 out TCCR0B, temp

Soos ons reeds weet, laai dit die getal onmiddellik daarna, wat 0b00000101 is, temp (dws R16). Dan skryf dit hierdie nommer uit na die register genaamd TCCR0B met die opdrag "uit". Wat is hierdie register? Kom ons gaan na bladsy 614 van die datablad. Dit is in die middel van 'n tabel wat 'n opsomming van al die registers bevat. By adres 0x25 vind u TCCR0B. (Nou weet u waar die lyn "uit 0x25, r16" vandaan kom in my weergawe van die kode sonder kommentaar). Ons sien aan die kodesegment hierbo dat ons die 0de bit en die 2de bit gestel het en al die res skoongemaak het. Deur na die tabel te kyk, kan u sien dat dit beteken dat ons CS00 en CS02 ingestel het. Gaan nou na die hoofstuk in die datablad met die naam "8-bis-timer/teller0 met PWM". Gaan veral na bladsy 107 van daardie hoofstuk. U sal dieselfde beskrywing sien van die "Timer/Counter Control Register B" (TCCR0B) -register wat ons pas in die registeropsommingstabel gesien het (sodat ons reguit hierheen kon kom, maar ek wou hê u moes sien hoe u die opsommingstabelle gebruik vir toekomstige verwysing). Die datablad gee steeds 'n beskrywing van elk van die bisse in die register en wat hulle doen. Ons sal dit alles vir eers oorslaan en die bladsy na tabel 15-9 keer. Hierdie tabel toon die 'Klokkies seleksie -beskrywing'. Kyk nou na die tabel totdat u die lyn vind wat ooreenstem met die stukkies wat ons pas in die register opgestel het. Die reël sê "clk/1024 (van voorverpakkingsmasjien)". Wat dit beteken, is dat ons wil hê dat Timer/Counter0 (TCNT0) moet tik teen 'n snelheid wat die frekwensie van die SVE gedeel is deur 1024. Aangesien ons mikrobeheerder gevoed word deur 'n 16MHz kristal ossillator, beteken dit dat die tempo wat ons SVE instruksies uitvoer, is. 16 miljoen instruksies per sekonde. Die tempo wat ons TCNT0 -teller sal merk, is dan 16 miljoen/1024 = 15625 keer per sekonde (probeer dit met verskillende stukkies klok en kyk wat gebeur - onthou ons filosofie?). Laat ons die nommer 15625 later in ons gedagtes hou en gaan na die volgende twee reëls kode:

ldi temp, 0b00000001

ste TIMSK0, temp

Dit stel die 0ste bietjie van 'n register met die naam TIMSK0 in en verwyder die res. As u na bladsy 109 in die datablad kyk, sal u sien dat TIMSK0 staan vir 'Timer/Counter Interrupt Mask Register 0' en ons kode het die 0de bis, met die naam TOIE0, wat staan vir 'Timer/Counter0 Overflow Interrupt Enable' gestel. … Daar! Nou sien u waaroor dit gaan. Ons het nou die 'onderbreek -inskakel -bitstel' soos ons wou van die eerste besluit in ons prentjie bo. Al wat ons hoef te doen is om 'globale onderbrekings' moontlik te maak, en ons program kan op hierdie tipe onderbrekings reageer. Ons sal binnekort globale onderbrekings moontlik maak, maar voordat ons dit doen, is u moontlik deur iets verwar. Waarom het ek die opdrag "sts" gebruik om na die TIMSK0 -register te kopieer in plaas van die gewone "uit"?

As u my sien, gebruik dan 'n instruksie wat u nog nie gesien het nie, en blaai na bladsy 616 in die datablad. Dit is die "Instruksiesetopsomming". Vind nou die instruksie "STS", wat ek gebruik het. Dit sê dat dit 'n nommer neem uit 'n R -register (ons het R16 gebruik) en 'Stoor direk op SRAM' plek k (in ons geval gegee deur TIMSK0). Waarom moes ons 'ste' gebruik, wat 2 kloksiklusse (sien laaste kolom in die tabel) neem om in TIMSK0 op te slaan, en ons het eers 'out' nodig gehad, wat slegs een kloksiklus neem? Om hierdie vraag te beantwoord, moet ons teruggaan na ons registeropsommingstabel op bladsy 614. U sien dat die TCCR0B -register op adres 0x25 is, maar ook by (0x45)? Dit beteken dat dit 'n register in SRAM is, maar dit is ook 'n sekere soort register wat 'n "poort" (of i/o -register) genoem word. As u na die instruksies opsommingstabel langs die opdrag "uit" kyk, sal u sien dat dit waardes uit die "werkregisters" soos R16 neem en dit na 'n PORT stuur. Ons kan dus 'out' gebruik as ons aan TCCR0B skryf en ons 'n kloksiklus bespaar. Maar kyk nou na TIMSK0 in die registertabel. U sien dat dit adres 0x6e het. Dit is buite die reeks hawens (wat slegs die eerste 0x3F -liggings van SRAM is), en u moet dus terugkeer na die gebruik van die sts -opdrag en twee CPU -kloksiklusse neem. Lees nou nota 4 aan die einde van die opsommingstabel op bladsy 615. Let ook op dat al ons invoer- en uitvoerpoort, soos PORTD, onderaan die tabel geleë is. Byvoorbeeld, PD4 is bit 4 by adres 0x0b (nou sien u waar al die 0x0b-dinge vandaan kom in my kode sonder kommentaar!).. oké, vinnige vraag: het u die "ste" in "out" verander en gesien wat gebeur? Onthou ons filosofie! breek dit! neem nie net my woord vir dinge nie.

Goed, voordat ons verder gaan, gaan vir 'n minuut na bladsy 19 in die datablad. U sien 'n prentjie van die data -geheue (SRAM). Die eerste 32 registers in SRAM (van 0x0000 tot 0x001F) is die "werkende registers vir algemene doeleindes" R0 tot en met R31 wat ons altyd as veranderlikes in ons kode gebruik. Die volgende 64 registers is die I/O-poorte tot 0x005f (dit wil sê diegene waaroor ons gepraat het, wat die on-bracket adresse langs hulle in die registertabel het, wat ons die "out" -opdrag in plaas van "sts" kan gebruik) Laastens die volgende afdeling van SRAM bevat al die ander registers in die opsommingstabel tot by 0x00FF, en laastens is die res interne SRAM. Kom ons blaai nou vinnig na bladsy 12. Daar sien u 'n tabel met die 'werkende registers vir algemene doeleindes' wat ons altyd as ons veranderlikes gebruik. Sien u die dik lyn tussen die syfers R0 tot R15 en dan R16 tot R31? Daarom gebruik ons altyd R16 as die kleinste, en ek sal dit in die volgende tutoriaal meer bespreek, waar ons ook die drie 16-bis indirekte adresregisters, X, Y en Z nodig het. kom nog net daaraan, aangesien ons dit nie nou nodig het nie en ons hier genoeg vasval.

Blaai een bladsy terug na bladsy 11 van die datablad. Regs bo sien u 'n diagram van die SREG -register? U sien dat stukkie 7 van die register 'ek' genoem word. Gaan nou af op die bladsy en lees die beskrywing van Bit 7 …. yay! Dit is die Global Interrupt Enable -bit. Dit is wat ons moet instel om die tweede besluit in ons diagram hierbo te kan deurloop en onderbrekings van timer/teenoorloop in ons program moontlik te maak. Die volgende reël van ons program moet dus lui:

sbi SREG, ek

wat die bietjie met die naam 'I' in die SREG -register stel. Maar eerder as hierdie het ons die instruksie gebruik

sei

in plaas daarvan. Hierdie bietjie word so gereeld in programme opgestel dat hulle dit net makliker gemaak het.

Goed! Nou het ons die oorlooponderbrekings gereed sodat ons 'jmp overflow_handler' uitgevoer kan word wanneer dit ook al gebeur.

Kyk vinnig na die SREG -register (statusregister) voordat dit verder gaan, want dit is baie belangrik. Lees wat elkeen van die vlae verteenwoordig. In die besonder sal baie van die instruksies wat ons gebruik, altyd hierdie vlae stel en nagaan. Byvoorbeeld, later gebruik ons die opdrag "CPI" wat beteken "vergelyk onmiddellik". Kyk na die opsommingstabel van die instruksies vir hierdie instruksie en let op hoeveel vlae dit in die kolom 'vlae' plaas. Dit is alles vlae in SREG, en ons kode stel dit voortdurend na en kontroleer dit. U sal binnekort voorbeelde sien. Uiteindelik is die laaste deel van hierdie gedeelte van die kode:

klr temp

uit TCNT0, temp sbi DDRD, 4

Die laaste reël hier is redelik duidelik. Dit stel net die vierde deel van die Data Direction Register vir PortD in, wat veroorsaak dat PD4 UITPUT is.

Die eerste stel die veranderlike temp op nul en kopieer dit dan na die TCNT0 -register. TCNT0 is ons tydopnemer/teller0. Dit stel dit op nul. Sodra die rekenaar hierdie lyn uitvoer, begin die timer0 op nul en tel 15625 keer per sekonde. Die probleem is: TCNT0 is 'n "8-bis" register, reg? So, wat is die grootste getal wat 'n 8-bis-register kan bevat? Wel, 0b11111111. Dit is die getal 0xFF. Wat is 255. So jy sien wat gebeur? Die timer rits 15625 keer per sekonde, en elke keer as dit 255 bereik, loop dit oor en gaan dit weer terug na 0. Terselfdertyd as dit terug gaan na nul, stuur dit 'n Timer Overflow Interrupt -sein uit. Die rekenaar kry dit, en u weet wat dit nou doen? Jip. Dit gaan na die programgeheue -plek 0x0020 en voer die instruksie uit wat dit daar vind.

Puik! As u nog steeds by my is, is u 'n onvermoeide superheld! Kom ons hou aan…

Stap 6: Oorloophanteerder

Laat ons dus aanvaar dat die timer/counter0 -register pas oorloop het. Ons weet nou dat die program 'n onderbrekingssein ontvang en 0x0020 uitvoer wat die programteller, rekenaar aanwys om na die etiket "overflow_handler" te spring, die volgende is die kode wat ons na die etiket geskryf het:

overflow_handler:

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

Die eerste ding wat dit doen, is om die veranderlike "oorloop" (wat ons naam is vir die algemene werkregister R17) te verhoog, dan "vergelyk" dit die inhoud van die oorloop met die getal 61. Die manier waarop die instruksie cpi werk, is dat dit eenvoudig aftrek die twee getalle en as die resultaat nul is, stel dit die Z -vlag in die SREG -register (ek het u gesê dat ons hierdie register die hele tyd sou sien). As die twee getalle gelyk is, sal die Z -vlag 'n 1 wees, as die twee getalle nie gelyk is nie, sal dit 'n 0 wees.

Die volgende reël sê "brne PC+2" wat beteken "vertakking indien nie gelyk nie". Dit kontroleer in wese die Z -vlag in SREG, en as dit NIE een is nie (dws die twee getalle is nie gelyk nie, as dit gelyk was, sou die nulvlag gestel word), vertak die rekenaar na PC+2, wat beteken dat dit die volgende slaan lyn en gaan reguit na "reti" wat van die onderbreking terugkeer na die plek waar dit in die kode was toe die onderbreking opgedaag het. As die brne -instruksie 'n 1 in die bits van die nulvlag gevind het, sou dit nie vertak word nie, maar dit sou net voortgaan na die volgende reël, wat die oorloop van die CLR sou herstel na 0.

Wat is die netto resultaat van dit alles?

Wel, ons sien dat elke keer as daar 'n timer -oorloop is, hierdie hanteerder die waarde van "oorstromings" met een verhoog. Die veranderlike "oorloop" tel dus die aantal oorstromings soos dit voorkom. Elke keer as die getal 61 bereik, stel ons dit terug op nul.

Nou waarom in die wêreld sou ons dit doen?

Kom ons kyk. Onthou ons dat ons kloksnelheid vir ons SVE 16MHz is en dat ons dit vooraf met TCCR0B 'voorskaal', sodat die timer slegs teen 'n snelheid van 15625 tellings per sekonde tel? En elke keer as die timer 'n telling van 255 bereik, loop dit oor. Dit beteken dus dat dit 15625/256 = 61,04 keer per sekonde oorloop. Ons hou die aantal oorstromings by met ons veranderlike "oorstromings" en vergelyk die getal met 61. Ons sien dus dat "oorstromings" 61 keer per sekonde gelyk sal wees! Ons hanteerder sal dus elke sekonde die "oorloop" na nul stel. Dus, as ons die veranderlike 'oorstromings' net sou monitor en let op elke keer dat dit op nul herstel word, tel ons intyds tweede vir sekonde (let op dat ons in die volgende tutoriaal sal wys hoe om 'n meer akkurate vertraging in millisekondes op dieselfde manier as wat die Arduino "vertraging" -roetine werk).

Nou het ons die onderbrekings van die timer -oorloop "hanteer". Maak seker dat u verstaan hoe dit werk en gaan dan verder met die volgende stap waar ons van hierdie feit gebruik maak.

Stap 7: Vertraag

Noudat ons gesien het dat ons 'overflow_handler' -roetine met die timer -oorlooponderbrekingshanterer die veranderlike' oorloop 'een keer per sekonde op nul sal stel, kan ons hierdie feit gebruik om 'n' vertraging' -subroutine te ontwerp.

Kyk na die volgende kode onder ons vertraging: etiket

vertraging:

clr oorloop sec_count: cpi loop oor, 30 brne sec_count ret

Ons gaan hierdie subroutine noem elke keer as ons 'n vertraging in ons program nodig het. Die manier waarop dit werk, is dat dit eers die veranderlike "oorloop" op nul stel. Dan betree dit 'n gebied met die naam 'sec_count' en vergelyk oorloop met 30, as dit nie gelyk is nie, vertak dit terug na die label sec_count en vergelyk dit weer, en weer, ens. Totdat dit uiteindelik gelyk is (onthou dat dit die hele tyd gaan op ons timer onderbreek hanteerder steeds om die veranderlike oorloop te verhoog en dit verander dus elke keer as ons hier rondloop. vertraging van 1/2 sekonde

Oefening 2: Verander die overflow_handler -roetine na die volgende:

overflow_handler:

inc oorloop reti

en voer die program uit. Is iets anders? Hoekom of hoekom nie?

Stap 8: Knipoog

Laastens kyk ons na die oogwenkroetine:

knip:

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

Eers skakel ons PD4 aan, dan bel ons ons vertragingsonderroetine. Ons gebruik rcall sodat wanneer die rekenaar 'n "ret" -verklaring kry, dit na die oproep na rcall terugkeer. Dan vertraag die vertragingsroetine vir 30 tellings in die oorloopveranderlike soos ons gesien het, en dit is amper presies 1/2 sekonde, dan skakel ons PD4 uit, vertraag nog 'n 1/2 sekonde en keer dan weer terug na die begin.

Die netto resultaat is 'n knipperende LED!

Ek dink u sal nou saamstem dat 'knipoog' waarskynlik nie die beste 'hallo wêreld' -program in die samestelling is nie.

Oefening 3: Verander die verskillende parameters in die program sodat die LED met verskillende snelhede soos 'n sekonde of 4 keer per sekonde, ens. Byvoorbeeld, vir 1/4 sekonde aan en dan af vir 2 sekondes of iets dergeliks. Oefening 5: Verander die TCCR0B -horlosie, kies stukkies na 100 en gaan dan verder op die tafel. Op watter punt kan dit nie onderskei word van ons 'hello.asm' -program uit tutoriaal 1 nie? op u broodbord vir die nuwe een en kyk hoe dit die knippertempo van die LED beïnvloed. U moet nou deur die presiese berekening kan gaan en presies kan voorspel hoe dit die koers sal beïnvloed.

Stap 9: Gevolgtrekking

Vir die van julle wat so ver gekom het, baie geluk!

Ek besef dat dit redelik moeilik is as u meer lees en opkyk as wat u bedrieg en eksperimenteer, maar ek hoop dat u die volgende belangrike dinge geleer het:

  1. Hoe programgeheue werk
  2. Hoe SRAM werk
  3. Hoe om registers op te soek
  4. Hoe om instruksies op te soek en te weet wat hulle doen
  5. Hoe om onderbrekings te implementeer
  6. Hoe die CP die kode uitvoer, hoe die SREG werk en wat gebeur tydens onderbrekings
  7. Hoe om lusse en spronge te doen en in die kode rond te spring
  8. Hoe belangrik is dit om die datablad te lees!
  9. Hoe u eers weet hoe u dit alles vir die Atmega328p -mikrobeheerder moet doen, is 'n relatiewe koekwandeling om nuwe beheerders te leer waarin u belangstel.
  10. Hoe om die SVE -tyd in reële tyd te verander en dit in vertragingsroetines te gebruik.

Noudat ons baie teorieë uit die weg geruim het, kan ons beter kode skryf en meer ingewikkelde dinge beheer. Die volgende tutoriaal doen ons dus. Ons sal 'n meer ingewikkelde, meer interessante kring bou en dit op 'n prettige manier beheer.

Oefening 7: "Breek" die kode op verskillende maniere en kyk wat gebeur! Wetenskaplike nuuskierigheid skat! Iemand anders kan die skottelgoed reg was? Oefening 8: Stel die kode saam met die '-l' opsie om 'n lyslêer te genereer. D.w.s. "avra -l blink.lst blink.asm" en kyk na die lyslêer. Ekstra krediet: die kode sonder kommentaar wat ek aan die begin gegee het en die kode wat ons later bespreek, verskil! Daar is een reël kode wat anders is. Kan jy dit vind? Waarom maak die verskil nie saak nie?

Hoop jy het pret gehad! Sien jou volgende keer …