Turinys:

AVR surinkėjo pamoka 3: 9 žingsniai
AVR surinkėjo pamoka 3: 9 žingsniai

Video: AVR surinkėjo pamoka 3: 9 žingsniai

Video: AVR surinkėjo pamoka 3: 9 žingsniai
Video: Arduino pamoka Nr. 5: Spaudžiame mygtukus 2024, Liepa
Anonim
AVR surinkėjo pamoka 3
AVR surinkėjo pamoka 3

Sveiki atvykę į pamoką Nr. 3!

Prieš pradėdami noriu pasakyti filosofinį dalyką. Nebijokite eksperimentuoti su grandinėmis ir kodu, kurį mes kuriame šiose pamokose. Pakeiskite laidus, pridėkite naujų komponentų, išimkite komponentus, pakeiskite kodo eilutes, pridėkite naujų eilučių, ištrinkite eilutes ir pažiūrėkite, kas atsitiks! Labai sunku ką nors sulaužyti ir, jei tai padarysi, kam tai rūpi? Niekas, ką naudojame, įskaitant mikrovaldiklį, nėra labai brangus ir visada yra mokomoji, kaip viskas gali nepavykti. Kitą kartą ne tik sužinosite, ko nedaryti, bet dar svarbiau - žinosite, kodėl to nedaryti. Jei esate kažkas panašaus į mane, kai buvote vaikas ir įsigijote naują žaislą, netrukus turėjote jį gabalėliais, kad pamatytumėte, kodėl jis teisingai pažymėjo? Kartais žaislas buvo nepataisomai sugadintas, tačiau tai nebuvo didelė problema. Leisti vaikui ištirti savo smalsumą net iki sulaužytų žaislų - tai paverčia jį mokslininku ar inžinieriumi, o ne indaplove.

Šiandien mes prijungsime labai paprastą grandinę ir tada šiek tiek įsitrauksime į teoriją. Atsiprašome, bet mums reikia įrankių! Pažadu, kad tai kompensuosime 4 pamokoje, kurioje atliksime rimtesnę grandinės statybą ir rezultatas bus gana šaunus. Tačiau tai, kaip jums reikia atlikti visas šias pamokas, vyksta labai lėtai, kontempliatyviai. Jei tik ariate, sukuriate grandinę, nukopijuojate ir įklijuojate kodą ir paleidžiate, tada tikrai veiks, bet nieko neišmoksite. Turite galvoti apie kiekvieną eilutę. Pauzė. Eksperimentuokite. Išrasti. Jei tai padarysite taip, tada iki 5 -osios pamokos pabaigos nebegalėsite kurti įdomių dalykų ir jums nebereikės mokyti. Priešingu atveju jūs tiesiog žiūrite, o ne mokotės ir kuriate.

Bet kokiu atveju, pakankamai filosofijos, pradėkime!

Šioje pamokoje jums reikės:

  1. jūsų prototipų lenta
  2. šviesos diodas
  3. jungiamieji laidai
  4. rezistorius apie 220–330 omų
  5. Instrukcijų rinkinio vadovas: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. Duomenų lapas: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. kitas kristalų osciliatorius (neprivaloma)

Čia yra nuoroda į visą vadovėlių kolekciją:

1 žingsnis: Sukurkite grandinę

Grandinės konstravimas
Grandinės konstravimas

Šios pamokos grandinė yra labai paprasta. Mes iš esmės rašysime „mirksėjimo“programą, todėl viskas, ko mums reikia, yra tokia.

Prijunkite šviesos diodą prie PD4, tada prie 330 omų rezistoriaus, tada įžeminkite. t.y.

PD4 - LED - R (330) - GND

ir tiek!

Tačiau teorija bus sunki …

2 žingsnis: Kodėl mums reikia komentarų ir failo M328Pdef.inc?

Manau, kad pirmiausia turėtume parodyti, kodėl įtraukimo failas ir komentarai yra naudingi. Nė vienas iš jų nėra būtinas, be to, galite rašyti, surinkti ir įkelti kodą be jų, ir jis veiks puikiai (nors be įtraukimo failo galite gauti surinkėjo skundų, bet jokių klaidų)

Štai kodas, kurį šiandien rašysime, išskyrus tai, kad pašalinau komentarus ir įtraukimo failą:

. prietaisas 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, cxx 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

gana paprasta tiesa? Haha. Jei surinkote ir įkėlėte šį failą, šviesos diodas mirksės 1 mirksėjimo per sekundę greičiu, mirksėjimas truks 1/2 sekundės, o pauzė tarp mirksėjimų - 1/2 sekundės.

Tačiau pažvelgti į šį kodą vargu ar nušviečia. Jei rašytumėte tokį kodą ir norėtumėte jį pakeisti ar panaudoti ateityje, jums būtų sunku.

Taigi įdėkime komentarus ir įtraukime failą atgal, kad galėtume tai suprasti.

3 žingsnis: Blink.asm

Štai kodas, kurį šiandien aptarsime:

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

; parašė: 1o_o7; data:; versija: 1.0; failas išsaugotas kaip: blink.asm; AVR: atmega328p; laikrodžio dažnis: 16MHz (neprivaloma); ***********************************; Programos funkcija: ---------------------; mirksi šviesos diodas, skaičiuoja sekundes;; PD4 - LED - R (330 omų) - GND;; --------------------------------------.nolist.include "./m328Pdef.inc".list; ==============; Deklaracijos:.def temp = r16.def overflows = r17.org 0x0000; atminties (kompiuterio) atstatymo tvarkyklės vieta rjmp Reset; jmp kainuoja 2 procesoriaus ciklus, o rjmp - tik 1; taigi nebent reikia šokinėti daugiau nei 8 k baitų; jums reikia tik rjmp. Todėl tik kai kurie mikrovaldikliai; turėti rjmp, o ne jmp.org 0x0020; „Timer0“perpildymo tvarkyklės atminties vieta rjmp overflow_handler; eikite čia, jei įvyksta laikmačio0 perpildymo pertrauka; ============ Atstatyti: ldi temp, 0b00000101 iš TCCR0B, temp; nustatykite laikrodžio parinkimo bitus CS00, CS01, CS02 į 101; tai įjungia laikmačio skaitiklį0, TCNT0 į FCPU/1024 režimą; taigi jis tiksi prie CPU dažnio/1024 ldi temp, 0b00000001 sts TIMSK0, temp; nustatyti laikmačio perpildymo pertraukos įjungimo (TOIE0) bitą; laikmačio pertraukimo kaukių registro (TIMSK0) sei; įjungti visuotinius pertraukimus - atitinka „sbi SREG, I“clr temp out TCNT0, temp; inicijuokite laikmatį/skaitiklį į 0 sbi DDRD, 4; nustatykite PD4 į išvestį; ======================; Pagrindinis programos elementas: mirksi: sbi PORTD, 4; įjungti šviesos diodą PD4 rcall delay; vėlavimas bus 1/2 sekundės cbi PORTD, 4; išjungti šviesos diodą PD4 rcall delay; delsimas bus 1/2 sekundės rjmp mirksėjimas; grįžti į pradžios vėlavimą: clr perpildo; nustatyti perpildymus iki 0 sek.: cpi perpildymai, 30; palyginti perpildymų skaičių ir 30 brne sec_count; šakotis atgal į sec_count, jei nėra lygus ret; jei įvyko 30 perpildymų, grįžkite į mirksėjimą overflow_handler: inc overflows; pridėti 1 prie perpildymų kintamųjų cpi perpildymų, 61; palyginti su 61 brne PC+2; Programos skaitiklis + 2 (praleisti kitą eilutę), jei ne lygūs klr perpildymai; jei įvyko 61 perpildymas, iš naujo nustatykite skaitiklį į nulį reti; grįžti iš pertraukos

Kaip matote, mano komentarai dabar yra šiek tiek trumpesni. Kai žinome, kokios instrukcijų rinkinio komandos mums nereikia to paaiškinti komentaruose. Mums reikia tik paaiškinti, kas vyksta programos požiūriu.

Mes diskutuosime, ką visa tai daro, po truputį, bet pirmiausia pabandykime gauti pasaulinę perspektyvą. Pagrindinis programos turinys veikia taip.

Pirmiausia nustatome PORTD 4 bitą su „sbi PORTD, 4“, tai siunčia 1 į PD4, kuris to kaiščio įtampą padidina iki 5 V. Tai įjungs šviesos diodą. Tada pereiname prie „atidėjimo“paprogramės, kuri skaičiuojama 1/2 sekundės (vėliau paaiškinsime, kaip tai daroma). Tada grįžtame prie PORTD mirksėjimo ir išvalymo 4 bitų, kuris nustato PD4 į 0V ir taip išjungia šviesos diodą. Tada atidėliojame dar 1/2 sekundės, o tada vėl grįžtame į mirksėjimo pradžią „rjmp mirksėjimas“.

Turėtumėte paleisti šį kodą ir pamatyti, kad jis daro tai, ką turėtų.

Ir štai tu turi! Tai viskas, ką šis kodas daro fiziškai. Vidinė mikrovaldiklio veikimo mechanika yra šiek tiek labiau įtraukta, todėl mes atliekame šią pamoką. Taigi aptarkime kiekvieną skyrių paeiliui.

4 žingsnis:.org surinkėjų direktyvos

Mes jau žinome, ką daro.nolist,.list,.include ir.def surinkėjų direktyvos iš ankstesnių vadovėlių, todėl pirmiausia pažvelkime į keturias po to einančias kodo eilutes:

.org 0x0000

jmp Iš naujo nustatyti.org 0x0020 jmp overflow_handler

. Org pareiškimas liepia surinkėjui, kur „Programos atmintyje“įdėti kitą teiginį. Vykdant jūsų programą, „Programų skaitiklis“(sutrumpintai kaip kompiuteris) turi dabartinės vykdomos eilutės adresą. Taigi šiuo atveju, kai kompiuteris yra 0x0000, jis pamatys komandą „jmp Reset“, esančią toje atminties vietoje. Priežastis, kodėl mes norime įdėti „jmp Reset“į tą vietą, yra ta, kad paleidus programą arba iš naujo nustatant lustą, kompiuteris pradeda vykdyti kodą šioje vietoje. Taigi, kaip matome, ką tik liepėme nedelsiant „peršokti“į skyrių, pavadintą „Atstatyti“. Kodėl mes tai padarėme? Tai reiškia, kad paskutinės dvi eilutės aukščiau yra tiesiog praleidžiamos! Kodėl?

Na, čia viskas tampa įdomu. Dabar turėsite atidaryti pdf peržiūros programą naudodami visą ATmega328p duomenų lapą, kurį nurodžiau pirmame šios mokymo programos puslapyje (todėl tai yra 4 punktas skyriuje „jums reikės“). Jei jūsų ekranas yra per mažas arba turite per daug atidarytų langų (kaip ir man), galite padaryti tai, ką aš darau, ir įdėti jį į „Ereader“arba „Android“telefoną. Jį naudosite visą laiką, jei planuojate rašyti surinkimo kodą. Šaunus dalykas yra tai, kad visi mikrovaldikliai yra organizuojami labai panašiai, todėl pripratę skaityti duomenų lapus ir koduoti iš jų, pastebėsite, kad beveik nerealu tą patį padaryti kitam mikrovaldikliui. Taigi mes iš tikrųjų mokomės tam tikra prasme naudoti visus mikrovaldiklius, o ne tik „atmega328p“.

Gerai, peržiūrėkite duomenų lapo 18 puslapį ir pažiūrėkite į 8-2 paveikslą.

Taip nustatoma mikrovaldiklio programos atmintis. Matote, kad jis prasideda adresu 0x0000 ir yra padalintas į dvi dalis; programos blykstės skyrius ir įkrovos blykstės skyrius. Jei trumpai perskaitysite 277 psl. 27-14 lentelę, pamatysite, kad programos blykstės skyrius užima vietas nuo 0x0000 iki 0x37FF, o įkrovos blykstės skyrius užima likusias vietas nuo 0x3800 iki 0x3FFF.

1 pratimas: kiek vietų yra programos atmintyje? T.y. konvertuokite 3FFF į dešimtainius ir pridėkite 1, nes pradedame skaičiuoti nuo 0. Kadangi kiekviena atminties vieta yra 16 bitų (arba 2 baitų) pločio, koks yra bendras atminties baitų skaičius? Dabar konvertuokite tai į kilobaitus, prisimindami, kad kilobaite yra 2^10 = 1024 baitai. Įkrovos blykstės sekcija yra nuo 0x3800 iki 0x37FF, kiek tai yra kilobaitų? Kiek kilobaitų atminties turime panaudoti savo programai saugoti? Kitaip tariant, kokia gali būti mūsų programa? Galiausiai, kiek kodo eilučių galime turėti?

Gerai, dabar, kai žinome viską apie „flash“programos atminties organizavimą, tęskime diskusiją apie.org pareiškimus. Matome, kad pirmoje atminties vietoje 0x0000 yra mūsų nurodymas pereiti į mūsų skyrių, pavadintą „Atstatyti“. Dabar matome, ką daro „.org 0x0020“teiginys. Jame sakoma, kad norime, kad instrukcija kitoje eilutėje būtų patalpinta atminties vietoje 0x0020. Instrukcija, kurią mes įdėjome, yra perėjimas prie mūsų kodo skilties, kurią pavadinome „overflow_handler“… o kodėl, po velnių, mes reikalaujame, kad šis šuolis būtų pateiktas atminties vietoje 0x0020? Norėdami tai sužinoti, pereiname prie duomenų lapo 65 puslapio ir pažvelkime į 12-6 lentelę.

12-6 lentelė yra lentelė „Vektorų nustatymas iš naujo ir pertraukimas“ir tiksliai parodo, kur kompiuteris eis, kai gaus „pertraukimą“. Pvz., Jei pažvelgsite į vektoriaus numerį 1. Nutraukimo „šaltinis“yra „RESET“, kuris apibrėžiamas kaip „Išorinis kaištis, įjungimo iš naujo nustatymas,„ Brown-out Reset “ir„ Watchdog “sistemos atstatymas“, tai reiškia, jei jei tai atsitiks mūsų mikrovaldikliui, kompiuteris pradės vykdyti mūsų programą programos atminties vietoje 0x0000. O kaip tada su mūsų.org direktyva? Na, mes įdėjome komandą atminties vietoje 0x0020 ir jei pažvelgsite žemyn į lentelę, pamatysite, kad jei įvyks laikmačio/skaitiklio0 perpildymas (kilęs iš TIMER0 OVF), jis vykdys viską, kas yra 0x0020 vietoje. Taigi, kai tai atsitiks, kompiuteris pereis į vietą, kurią pavadinome „overflow_handler“. Šaunu tiesa? Per minutę pamatysite, kodėl mes tai padarėme, bet pirmiausia užbaigkime šį vadovėlio žingsnį nuošalyje.

Jei norime, kad mūsų kodas būtų gražesnis ir tvarkingesnis, iš tikrųjų turėtume pakeisti 4 šiuo metu aptariamas eilutes taip: (žr. 66 psl.):

.org 0x0000

rjmp Atstatyti; 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; Kompiuteris = 0x0032

Taigi, jei tam tikras pertraukimas įvyks, jis tiesiog „pasitrauks“, o tai reiškia „grįžimas iš pertraukos“, ir nieko daugiau neįvyks. Bet jei mes niekada „neįgalinsime“šių įvairių pertraukimų, jie nebus naudojami ir mes galime įdėti programos kodą į šias vietas. Dabartinėje „blink.asm“programoje mes tik įjungsime „timer0“perpildymo pertraukimą (ir, žinoma, iš naujo nustatytą pertraukimą, kuris visada įjungtas), todėl nesivarginsime su kitais.

Kaip tada „įjungti“„timer0“perpildymo pertrauką? … tai yra mūsų kito žingsnio šioje pamokoje tema.

5 žingsnis: Laikmatis/skaitiklis 0

Laikmatis/skaitiklis 0
Laikmatis/skaitiklis 0

Pažvelkite į aukščiau pateiktą paveikslėlį. Tai yra „kompiuterio“sprendimų priėmimo procesas, kai kokia nors išorinė įtaka „nutraukia“mūsų programos srautą. Pirmas dalykas, kurį ji daro, kai iš išorės gauna signalą, kad įvyko pertrauka, yra patikrinti, ar mes nustatėme tokio tipo pertraukos bitą „pertraukos įgalinimas“. Jei to nepadarėme, ji tiesiog toliau vykdo kitą mūsų kodo eilutę. Jei nustatėme tam tikrą pertraukimo įjungimo bitą (kad toje bitų vietoje būtų 1, o ne 0), jis patikrins, ar mes įgalinome „visuotinius pertraukimus“, jei ne, tai vėl pereis į kitą eilutę kodą ir tęskite. Jei mes taip pat įgalinome visuotinius pertraukimus, jis pateks į tokio tipo pertraukos programos atminties vietą (kaip parodyta 12-6 lentelėje) ir vykdys bet kokią ten pateiktą komandą. Taigi pažiūrėkime, kaip visa tai įgyvendinome savo kodekse.

Mūsų kodo skiltis „Iš naujo pažymėta“prasideda šiomis dviem eilutėmis:

Iš naujo nustatyti:

ldi temp, 0b00000101 iš TCCR0B, temp

Kaip jau žinome, į temp (pvz., R16) įkeliamas iškart po jo esantis skaičius, kuris yra 0b00000101. Tada jis įrašo šį numerį į registrą, vadinamą TCCR0B, naudodami komandą „out“. Kas yra šis registras? Na, pereikime prie duomenų lapo 614 puslapio. Tai lentelės, kurioje apibendrinami visi registrai, viduryje. Adresu 0x25 rasite TCCR0B. (Dabar jūs žinote, iš kur atsirado eilutė „out 0x25, r16“mano nekomentuojamoje kodo versijoje). Iš aukščiau esančio kodo segmento matome, kad nustatėme 0 -ąjį ir 2 -ąjį bitus ir pašalinome visus likusius. Žvelgdami į lentelę galite pamatyti, kad tai reiškia, kad nustatėme CS00 ir CS02. Dabar pereikime prie duomenų lapo skyriaus „8 bitų laikmatis/skaitiklis0 su PWM“. Visų pirma, eikite į to skyriaus 107 puslapį. Pamatysite tą patį „Laikmačio/skaitiklio valdymo registro B“(TCCR0B) registro aprašymą, kurį ką tik matėme registrų suvestinės lentelėje (taigi galėjome atvykti tiesiai čia, bet norėjau, kad pamatytumėte, kaip naudotis suvestinėmis lentelėmis). ateičiai). Duomenų lape ir toliau aprašomas kiekvienas to registro bitas ir ką jie daro. Kol kas visa tai praleisime ir atsiversime puslapį į 15-9 lentelę. Šioje lentelėje rodomas „Laikrodžio pasirinkimo bitų aprašymas“. Dabar pažvelkite į lentelę žemyn, kol rasite eilutę, atitinkančią bitus, kuriuos ką tik nustatėme tame registre. Eilutėje rašoma „clk/1024 (iš prescaler)“. Tai reiškia, kad norime, kad laikmatis/skaitiklis0 (TCNT0) pažymėtų greitį, kuris yra procesoriaus dažnis, padalytas iš 1024. Kadangi mūsų mikrovaldiklį maitina 16MHz kristalų osciliatorius, tai reiškia, kad mūsų procesoriaus vykdomas greitis yra 16 milijonų nurodymų per sekundę. Taigi greitis, kurį pažymės mūsų TCNT0 skaitiklis, yra 16 milijonų/1024 = 15625 kartų per sekundę (pabandykite jį su skirtingais laikrodžio pasirinkimo bitais ir pažiūrėkite, kas atsitiks - prisiminkite mūsų filosofiją?). Pasilikime numerį 15625 galvoje vėliau ir pereikime prie kitų dviejų kodo eilučių:

ldi temp, 0b00000001

sts TIMSK0, temp

Tai nustato 0 -ąjį registro bitą, pavadintą TIMSK0, ir pašalina visus likusius. Jei pažvelgsite į duomenų lapo 109 puslapį, pamatysite, kad TIMSK0 reiškia „Laikmačio/skaitiklio pertraukimo kaukės registras 0“, o mūsų kodas nustatė 0 -ąjį bitą, pavadintą TOIE0, kuris reiškia „Timer/Counter0 Overflow Interrupt Enable“. … Ten! Dabar matai, apie ką visa tai. Dabar turime „pertraukimo įjungimo bitų rinkinį“, kaip norėjome nuo pirmojo sprendimo mūsų paveikslėlyje viršuje. Taigi dabar mums tereikia įjungti „pasaulinius pertraukimus“ir mūsų programa galės reaguoti į tokio tipo pertraukas. Netrukus įjungsime visuotinius pertraukimus, tačiau prieš tai darydami galbūt jus kažkas supainiojo.. kodėl, po velnių, aš naudoju komandą „sts“, norėdamas nukopijuoti į TIMSK0 registrą, o ne įprastą „out“?

Kai tik pamatysite mane, naudokite instrukciją, kurios anksčiau nematėte, pirmiausia turėtumėte pereiti prie duomenų lapo 616 puslapio. Tai yra „Instrukcijų rinkinio suvestinė“. Dabar raskite instrukciją „STS“, kurią aš naudojau. Jame sakoma, kad reikia skaičiaus iš R registro (mes naudojome R16) ir „Saugoti tiesiai į SRAM“vietą k (mūsų atveju nurodė TIMSK0). Taigi kodėl mes turėjome naudoti „sts“, kuris užtrunka 2 laikrodžio ciklus (žr. Paskutinį lentelės stulpelį), kad išsaugotume TIMSK0, o mums reikėjo tik „out“, kuris užtrunka tik vieną laikrodžio ciklą, kad išsaugotume TCCR0B anksčiau? Norėdami atsakyti į šį klausimą, turime grįžti prie registro suvestinės lentelės, esančios 614. puslapyje. Matote, kad TCCR0B registras yra adresu 0x25, bet taip pat (0x45)? Tai reiškia, kad tai yra SRAM registras, bet taip pat tam tikro tipo registras, vadinamas „uostu“(arba i/o registru). Jei pažvelgsite į instrukcijų suvestinės lentelę šalia komandos „out“, pamatysite, kad ji paima reikšmes iš „darbo registrų“, tokių kaip R16, ir siunčia jas į uostą. Taigi mes galime naudoti „out“rašydami į TCCR0B ir sutaupyti laikrodžio ciklą. Bet dabar registrų lentelėje ieškokite TIMSK0. Matote, kad jo adresas yra 0x6e. Tai nepatenka į prievadų diapazoną (tai tik pirmosios SRAM 0x3F vietos), todėl jūs turite grįžti prie komandos sts naudojimo ir atlikti du procesoriaus laikrodžio ciklus. Šiuo metu perskaitykite 4 pastabą instrukcijų santraukos lentelės pabaigoje, 615 puslapyje. Taip pat atkreipkite dėmesį, kad visi įvesties ir išvesties prievadai, pvz., PORTD, yra lentelės apačioje. Pavyzdžiui, PD4 yra 4 bitas adresu 0x0b (dabar matote, iš kur atsirado visi 0x0b dalykai mano nekomentuojamame kode!) atsitinka? Prisimink mūsų filosofiją! Sulaužyk tai! neimk mano žodžio tik dėl dalykų.

Gerai, prieš tęsdami, minutėlę peržiūrėkite duomenų lapo 19 puslapį. Matote duomenų atminties (SRAM) paveikslėlį. Pirmieji 32 SRAM registrai (nuo 0x0000 iki 0x001F) yra „bendrosios paskirties darbo registrai“nuo R0 iki R31, kuriuos mes visą laiką naudojame kaip savo kodo kintamuosius. Kiti 64 registrai yra įvesties/išvesties prievadai iki 0x005f (ty tie, apie kuriuos mes kalbėjome ir kurių registrų lentelėje yra tie adresai be skliaustų, kuriuos galime naudoti „out“, o ne „sts“) kitame SRAM skyriuje yra visi kiti suvestinės lentelės registrai iki adreso 0x00FF, o galiausiai likusi dalis yra vidinė SRAM. Dabar greitai pereikime prie 12 puslapio sekundei. Ten matote „bendrosios paskirties darbo registrų“lentelę, kurią visada naudojame kaip kintamuosius. Matote storą liniją tarp skaičių R0 – R15, o po to nuo R16 iki R31? Dėl šios linijos mes visada naudojame R16 kaip mažiausią, ir aš šiek tiek daugiau į jį pateksiu kitoje pamokoje, kur mums taip pat reikės trijų 16 bitų netiesioginių adresų registrų, X, Y ir Z. įsitraukite į tai dar, nors mums to dabar nereikia ir mes čia pakankamai įstrigome.

Apverskite vieną puslapį į duomenų lapo 11 puslapį. Viršuje dešinėje pamatysite SREG registro schemą? Matote, kad to registro 7 bitas vadinamas „aš“. Dabar eikite žemyn puslapiu ir perskaitykite 7 bitų aprašymą…. Valio! Tai visuotinio pertraukimo įjungimo bitas. Tai turime nustatyti, kad galėtume priimti antrą sprendimą aukščiau esančioje diagramoje ir leisti mūsų programoje pertraukti laikmačio/skaitiklio perteklių. Taigi kita mūsų programos eilutė turėtų būti tokia:

sbi SREG, I

kuris nustato bitą, vadinamą „aš“SREG registre. Tačiau vietoj to mes panaudojome instrukciją

sei

vietoj to. Šis bitas programose nustatytas taip dažnai, kad jie tiesiog padarė paprastesnį būdą tai padaryti.

Gerai! Dabar mes paruošėme pertekliaus pertraukas, kad mūsų „jmp overflow_handler“būtų vykdomas kiekvieną kartą, kai tai įvyks.

Prieš tęsdami, greitai pažvelkime į SREG registrą (būsenos registrą), nes jis yra labai svarbus. Perskaitykite, ką simbolizuoja kiekviena vėliava. Visų pirma, daugelis mūsų naudojamų instrukcijų nustatys ir tikrins šias vėliavas. Pavyzdžiui, vėliau mes naudosime komandą „VKI“, o tai reiškia „nedelsiant palyginti“. Pažvelkite į šios instrukcijos santraukų lentelę ir pastebėkite, kiek vėliavų ji nustato stulpelyje „vėliavos“. Tai visos SREG vėliavos ir mūsų kodas jas nustatys ir nuolat tikrins. Netrukus pamatysite pavyzdžių. Galiausiai paskutinis šio kodo skyriaus fragmentas yra:

clr temp

iš TCNT0, temp sbi DDRD, 4

Paskutinė eilutė čia yra gana akivaizdi. Tai tik nustato ketvirtąjį „PortD“duomenų krypčių registro bitą, dėl kurio PD4 yra išvestis.

Pirmasis nustato kintamąją temperatūrą iki nulio ir nukopijuoja ją į TCNT0 registrą. TCNT0 yra mūsų laikmatis/skaitiklis0. Tai nustato jį iki nulio. Kai tik kompiuteris įvykdys šią eilutę, laikmatis0 prasidės nuo nulio ir skaičiuos 15625 kartus per sekundę. Problema yra tokia: TCNT0 yra „8 bitų“registras? Taigi koks yra didžiausias skaičius, kurį gali turėti 8 bitų registras? Na 0b11111111 tai. Tai skaičius 0xFF. Kuris yra 255. Taigi matai, kas atsitinka? Laikmatis sukasi 15625 kartus per sekundę ir kiekvieną kartą pasiekus 255 „perpildo“ir vėl grįžta prie 0. Tuo pačiu metu, kai grįžta į nulį, jis siunčia laikmačio perpildymo pertraukimo signalą. Kompiuteris tai supranta ir jūs jau žinote, ką jis daro? Taip. Jis eina į programos atminties vietą 0x0020 ir vykdo ten rastas instrukcijas.

Puiku! Jei vis dar esi su manimi, tu esi nenuilstantis superherojus! Tęskime…

6 žingsnis: perpildymo tvarkyklė

Taigi tarkime, kad laikmačio/skaitiklio registras ką tik perpildytas. Dabar mes žinome, kad programa gauna pertraukimo signalą ir vykdo 0x0020, kuris nurodo kompiuterio skaitikliui, kompiuteriui, pereiti prie etiketės „overflow_handler“, tai yra kodas, kurį parašėme po šios etiketės:

overflow_handler:

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

Pirmas dalykas, kurį jis daro, yra padidinti kintamąjį „perpildymas“(kuris yra mūsų bendrosios paskirties darbo registro R17 pavadinimas), tada „palygina“perpildymų turinį su skaičiumi 61. Instrukcija cpi veikia taip, kad ji tiesiog atima du skaičiai, o jei rezultatas lygus nuliui, jis nustato Z vėliavą SREG registre (sakiau, kad šį registrą matysime visą laiką). Jei du skaičiai yra lygūs, Z vėliava bus 1, jei du skaičiai nėra lygūs, tai bus 0.

Kitoje eilutėje rašoma „brne PC+2“, o tai reiškia „šaka, jei ne lygi“. Iš esmės jis patikrina Z vėliavą SREG ir jei jis nėra vienas (ty du skaičiai nėra lygūs, jei jie būtų lygūs, būtų nustatyta nulinė vėliava), kompiuteris atšako į PC+2, o tai reiškia, kad jis praleidžia kitą liniją ir eina tiesiai į „reti“, kuri grįžta iš pertraukos į bet kurią vietą, kurioje buvo kodas, kai atvyko pertrauka. Jei brne instrukcija rastų 1 nulinės vėliavos bite, ji nesišakotų, o vietoj to tiesiog tęstų iki kitos eilutės, kuri užblokuotų perpildymus ir grąžintų ją į 0.

Koks yra viso to grynasis rezultatas?

Mes matome, kad kiekvieną kartą, kai yra laikmačio perpildymas, šis tvarkytojas padidina „perpildymo“vertę vienu. Taigi kintamasis „perpildymas“skaičiuoja perpildymų skaičių, kai jie atsiranda. Kai skaičius pasiekia 61, nustatome jį į nulį.

Dabar kodėl pasaulyje mes tai darytume?

Pažiūrėkime. Prisiminkite, kad mūsų procesoriaus laikrodžio greitis yra 16MHz ir mes jį „iš anksto nustatėme“naudodami TCCR0B, kad laikmatis skaičiuotų tik 15625 skaičių per sekundę greičiu? Ir kiekvieną kartą, kai laikmatis pasiekia 255 skaičių, jis perpildomas. Tai reiškia, kad perpildo 15625/256 = 61,04 karto per sekundę. Mes stebime perpildymų skaičių naudodami savo kintamąjį „perpildymai“ir palyginame tą skaičių su 61. Taigi matome, kad „perpildymai“bus 61 kartą per sekundę! Taigi mūsų valdytojas kartą per sekundę nustatys „perpildymus“į nulį. Taigi, jei mes tiesiog stebėtume kintamąjį „perpildymai“ir atkreiptume dėmesį į kiekvieną kartą, kai jis atstatomas į nulį, mes skaičiuosime sekundę po sekundės realiuoju laiku (atkreipkite dėmesį, kad kitoje pamokoje parodysime, kaip gauti tikslesnį vėlavimas milisekundėmis taip pat, kaip veikia „Arduino“„atidėjimo“rutina).

Dabar mes „tvarkėme“laikmačio perpildymo pertraukas. Įsitikinkite, kad suprantate, kaip tai veikia, ir pereikite prie kito žingsnio, kuriame mes naudojame šį faktą.

7 žingsnis: atidėjimas

Dabar, kai pamatėme, kad mūsų laikmačio perpildymo pertraukimo tvarkyklė „overflow_handler“įprastai nustatys kintamąjį „perpildymai“į nulį kartą per sekundę, galime panaudoti šį faktą kurdami „uždelsimo“paprogramę.

Pažvelkite į šį kodą iš mūsų uždelsimo: etiketė

delsimas:

clr perpildymai sec_count: cpi perpildymai, 30 brne sec_count ret

Šią paprogramę vadinsime kiekvieną kartą, kai prireiks atidėti mūsų programą. Kaip tai veikia, jis pirmiausia nustato kintamąjį „perpildymas“į nulį. Tada jis patenka į sritį, pažymėtą kaip „sec_count“, ir lygina perpildymus su 30, jei jie nėra lygūs, jis atšoka į etiketę sec_count ir vėl lygina, ir vėl, ir tt, kol jie pagaliau yra lygūs (atminkite, kad visą laiką mūsų laikmačio pertraukimo tvarkytojas toliau didina kintamojo perpildymus, todėl jis keičiasi kiekvieną kartą, kai čia einame. Kai perpildymai pagaliau yra 30, jie išeina iš ciklo ir grįžta į bet kur, kur vadinome vėlavimą: iš. Grynasis rezultatas yra 1/2 sekundės vėlavimas

2 pratimas: pakeiskite „overflow_handler“procedūrą taip:

overflow_handler:

inc perpildymai pens

ir paleiskite programą. Ar kas nors kitaip? Kodėl ar kodėl ne?

8 žingsnis: mirksi

Galiausiai pažvelkime į mirksėjimo rutiną:

mirksi:

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

Pirmiausia įjungiame PD4, tada paskambiname savo uždelsimo paprogramei. Mes naudojame rcall, kad kai kompiuteris pateiks „ret“teiginį, jis grįš į eilutę po „rcall“. Tada, kaip matėme, atidėjimo rutina vėluoja 30 kartų perpildymo kintamajame ir tai yra beveik lygiai 1/2 sekundės, tada išjungiame PD4, vėluojame dar 1/2 sekundės ir vėl grįžtame į pradžią.

Rezultatas yra mirksintis šviesos diodas!

Manau, dabar sutiksite, kad „mirksėjimas“tikriausiai nėra pati geriausia „labas pasaulis“programa surinkimo kalba.

3 pratimas: pakeiskite įvairius programos parametrus, kad šviesos diodas mirksėtų skirtingu greičiu, pavyzdžiui, sekundę arba 4 kartus per sekundę ir pan. Pvz., Įjunkite 1/4 sekundės, tada išjunkite 2 sekundes ar panašiai. Kada jis tampa niekuo nesiskiriantis nuo mūsų „hello.asm“programos iš 1 pamokos? 6 pratimas (neprivaloma): Jei turite kitą kristalų osciliatorių, pvz., 4 MHz arba 13,5 MHz ar bet ką, pakeiskite 16 MHz generatorių savo naujos kartos duonos lentelėje ir pažiūrėkite, kaip tai veikia šviesos diodo mirksėjimo dažnį. Dabar turėtumėte sugebėti tiksliai apskaičiuoti ir tiksliai numatyti, kaip tai paveiks normą.

9 žingsnis: Išvada

Tiems iš jūsų, kuriems pavyko taip toli, sveikiname!

Suprantu, kad skaityti ir žiūrėti aukštyn yra gana sunku, nei laidai ir eksperimentai, bet tikiuosi, kad sužinojai šiuos svarbius dalykus:

  1. Kaip veikia programos atmintis
  2. Kaip veikia SRAM
  3. Kaip ieškoti registrų
  4. Kaip ieškoti instrukcijų ir žinoti, ką jos daro
  5. Kaip įgyvendinti pertraukas
  6. Kaip CP vykdo kodą, kaip veikia SREG ir kas vyksta pertraukų metu
  7. Kaip atlikti kilpas ir šuolius bei atšokti kodu
  8. Kaip svarbu perskaityti duomenų lapą!
  9. Kai žinosite, kaip visa tai padaryti naudojant „Atmega328p“mikrovaldiklį, tai bus santykinis pasivaikščiojimas, kad sužinotumėte apie visus naujus jus dominančius valdiklius.
  10. Kaip pakeisti procesoriaus laiką į realų laiką ir panaudoti jį delsiant.

Dabar, kai turime daug teorijos, mes galime parašyti geresnį kodą ir valdyti sudėtingesnius dalykus. Taigi kitoje pamokoje mes tai darysime. Mes sukursime sudėtingesnę, įdomesnę grandinę ir linksmai ją valdysime.

7 pratimas: „Sulaužykite“kodą įvairiais būdais ir pažiūrėkite, kas atsitiks! Mokslinis smalsumas, vaikeli! Ar kas nors kitas gali tinkamai plauti indus? 8 pratimas: surinkite kodą naudodami parinktį „-l“, kad sukurtumėte sąrašo failą. T.y. "avra -l blink.lst blink.asm" ir pažiūrėkite į sąrašo failą. Papildomas kreditas: pradžioje pateiktas nekomentuotas kodas ir vėliau aptariamas komentuojamas kodas skiriasi! Yra viena kodo eilutė, kuri skiriasi. Ar galite jį rasti? Kodėl tas skirtumas nėra svarbus?

Tikiuosi, jums buvo smagu! Iki kito karto…

Rekomenduojamas: