Satura rādītājs:

AVR Assembler apmācība 3: 9 soļi
AVR Assembler apmācība 3: 9 soļi

Video: AVR Assembler apmācība 3: 9 soļi

Video: AVR Assembler apmācība 3: 9 soļi
Video: СБОРКА И ЗАПУСК 16-ЛИТРОВОГО V8 ДВИГАТЕЛЯ SCANIA. ПРОБЕГ 1.6 МЛН КМ. DC16 PDE 2024, Jūlijs
Anonim
AVR montētāja apmācība 3
AVR montētāja apmācība 3

Laipni lūdzam apmācības numurā 3!

Pirms mēs sākam, es vēlos izteikt filozofisku punktu. Nebaidieties eksperimentēt ar shēmām un kodu, ko mēs veidojam šajās apmācībās. Mainiet vadus, pievienojiet jaunus komponentus, izņemiet komponentus, mainiet koda rindas, pievienojiet jaunas rindas, dzēsiet rindas un redziet, kas notiek! Ir ļoti grūti kaut ko salauzt, un, ja jūs to darāt, kam tas interesē? Nekas, ko mēs izmantojam, ieskaitot mikrokontrolleru, nav ļoti dārgs, un vienmēr ir izglītojoši redzēt, kā lietas var neizdoties. Jūs ne tikai uzzināsit, ko nākamreiz nedarīt, bet, vēl svarīgāk, jūs zināt, kāpēc to nedarīt. Ja jūs esat kaut kas līdzīgs man, tad, kad bijāt bērns un iegādājāties jaunu rotaļlietu, nepagāja ilgs laiks, pirms jūs to sagriezāt gabalos, lai redzētu, kas lika tai tikties? Dažreiz rotaļlieta tika sabojāta neatgriezeniski, taču tas nebija nekas īpašs. Ļaujot bērnam izpētīt savu ziņkārību pat līdz salauztām rotaļlietām, tas viņu padara par zinātnieku vai inženieri, nevis trauku mazgājamo mašīnu.

Šodien mēs ieslēgsim ļoti vienkāršu ķēdi un pēc tam mazliet iedziļināsimies teorijā. Atvainojiet par to, bet mums ir nepieciešami rīki! Es apsolu, ka mēs to kompensēsim 4. apmācībā, kur mēs veiksim nopietnāku ķēdes veidošanu, un rezultāts būs diezgan foršs. Tomēr veids, kā veikt visas šīs apmācības, notiek ļoti lēni, pārdomāti. Ja jūs vienkārši uzart, izveidojat ķēdi, nokopējiet un ielīmējiet kodu un palaidiet to, tad, protams, tas darbosies, bet jūs neko neuzzināsit. Jums ir jādomā par katru rindu. Pauze. Eksperimentējiet. Izgudrot. Ja jūs to darāt šādā veidā, tad piektās apmācības beigās jūs vairs neveidosit interesantas lietas, un jums vairs nav nepieciešama apmācība. Pretējā gadījumā jūs vienkārši skatāties, nevis mācāties un veidojat.

Jebkurā gadījumā pietiek ar filozofiju, sāksim!

Šajā apmācībā jums būs nepieciešams:

  1. jūsu prototipēšanas dēlis
  2. LED
  3. savienojošie vadi
  4. rezistors ap 220 līdz 330 omi
  5. Instrukciju komplekta rokasgrāmata: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. Datu lapa: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. cits kristāla oscilators (pēc izvēles)

Šeit ir saite uz visu apmācību kolekciju:

1. darbība: shēmas izveide

Ķēdes konstruēšana
Ķēdes konstruēšana

Šīs apmācības shēma ir ārkārtīgi vienkārša. Mēs būtībā rakstīsim "mirgošanas" programmu, tāpēc viss, kas mums nepieciešams, ir šāds.

Pievienojiet gaismas diodi pie PD4, pēc tam pie 330 omu rezistora, pēc tam pie zemes. i.

PD4 - LED - R (330) - GND

un tā tas ir!

Teorija tomēr būs grūta kļūda …

2. darbība. Kāpēc mums nepieciešami komentāri un fails M328Pdef.inc?

Es domāju, ka mums vajadzētu sākt, parādot, kāpēc iekļaušanas fails un komentāri ir noderīgi. Neviens no tiem faktiski nav nepieciešams, un jūs varat rakstīt, apkopot un augšupielādēt kodu tādā pašā veidā bez tiem, un tas darbosies perfekti (lai gan bez iekļaušanas faila jūs varat saņemt dažas sūdzības no montētāja, bet bez kļūdām)

Šeit ir kods, kuru mēs šodien rakstīsim, izņemot to, ka esmu noņēmis komentārus un iekļaušanas failu:

.ierīce 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

diezgan vienkārši, vai ne? Haha. Ja apkopojāt un augšupielādējāt šo failu, gaismas diode mirgos ar 1 mirgošanas ātrumu sekundē, mirgošanas ilgums - 1/2 sekundes un pauze starp mirgošanu - 1/2 sekundi.

Tomēr, skatoties uz šo kodu, tas diez vai ir apgaismojošs. Ja jūs rakstītu šādu kodu un vēlaties to modificēt vai atkārtoti izmantot nākotnē, jums būtu grūti.

Tāpēc ieliksim komentārus un iekļausim failu atpakaļ, lai mēs varētu no tā kaut ko saprast.

3. darbība. Blink.asm

Šeit ir kods, kuru mēs šodien apspriedīsim:

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

; rakstīja: 1o_o7; datums:; versija: 1.0; fails saglabāts kā: blink.asm; AVR: atmega328p; pulksteņa frekvence: 16MHz (pēc izvēles); ************************************ Programmas funkcija: ---------------------; mirgo LED, skaitot sekundes;; PD4 - LED - R (330 omi) - GND;; --------------------------------------.nolist.include "./m328Pdef.inc".saraksts; ==============; Deklarācijas:.def temp = r16.def pārplūst = r17.org 0x0000; atmiņas (datora) atiestatīšanas apstrādātāja atrašanās vieta rjmp Reset; jmp maksā 2 CPU ciklus un rjmp maksā tikai 1; tāpēc, ja vien jums nav nepieciešams pārlēkt vairāk par 8 k baitiem; vajag tikai rjmp. Tāpēc tikai daži mikrokontrolleri; ir rjmp, nevis jmp.org 0x0020; Timer0 pārpildes apstrādātāja atmiņas atrašanās vieta rjmp overflow_handler; dodieties šeit, ja notiek taimera0 pārplūdes pārtraukums; ============ Atiestatīt: ldi temp, 0b00000101 out TCCR0B, temp; iestatiet pulksteņa izvēles bitus CS00, CS01, CS02 uz 101; tas ieslēdz taimera skaitītāju0, TCNT0 FCPU/1024 režīmā; tāpēc tas atzīmē CPU frekvenci/1024 ldi temp, 0b00000001 sts TIMSK0, temp; iestatiet bitu Taimera pārpildes pārtraukšanas iespējošana (TOIE0); taimera pārtraukšanas masku reģistra (TIMSK0) sei; iespējot globālos pārtraukumus - līdzvērtīgi "sbi SREG, I" clr temp out TCNT0, temp; inicializējiet taimeri/skaitītāju uz 0 sbi DDRD, 4; iestatiet PD4 uz izvadi; ======================; Programmas galvenā daļa: mirgo: sbi PORTD, 4; ieslēdziet LED uz PD4 rcall delay; kavēšanās būs 1/2 sekundes cbi PORTD, 4; izslēdziet LED uz PD4 rcall delay; kavēšanās būs 1/2 sekundes rjmp mirgo; cilpa atpakaļ uz sākuma aizkavi: clr pārplūst; iestatīt pārplūdes uz 0 sec_count: cpi pārpildes, 30; salīdzināt pārpildījumu skaitu un 30 brne sec_count; atzarojums atpakaļ uz sec_count, ja nav vienāds ret; ja ir notikušas 30 pārplūdes, atgriežas pie mirgošanas overflow_handler: inc pārplūdes; pievienot 1 pārpildēm mainīgajiem cpi pārpildījumiem, 61; saldzint ar 61 brne PC+2; Programmas skaitītājs + 2 (izlaist nākamo rindu), ja nav vienāds clr pārplūdums; ja notika 61 pārplūde, atiestatiet skaitītāju uz nulli reti; atgriezties no pārtraukuma

Kā redzat, mani komentāri tagad ir nedaudz īsāki. Kad mēs zinām, kādas ir instrukciju kopas komandas, mums tas nav jāpaskaidro komentāros. Mums tikai jāpaskaidro notiekošais no programmas viedokļa.

Mēs apspriedīsim, ko tas viss dara pa gabalu, bet vispirms mēģināsim iegūt globālu skatījumu. Programmas galvenā daļa darbojas šādi.

Vispirms mēs iestatījām PORTD 4. bitu ar "sbi PORTD, 4", tas nosūta 1 uz PD4, kas spriegumu uz šo tapu ievieto līdz 5 V. Tas ieslēgs LED. Pēc tam mēs pārietam uz "kavēšanās" apakšprogrammu, kas ir 1/2 sekunde (mēs paskaidrosim, kā tas tiek darīts vēlāk). Pēc tam mēs atgriežamies pie PORTD mirgošanas un dzēšanas 4. bita, kas nosaka PD4 uz 0V un tādējādi izslēdz LED. Pēc tam mēs aizkavējam vēl 1/2 sekundi un pēc tam atkal atgriežamies mirgošanas sākumā ar "rjmp mirgo".

Jums vajadzētu palaist šo kodu un redzēt, ka tas dara to, ko vajadzētu.

Un tur jums tas ir! Tas ir viss, ko šis kods dara fiziski. Mikrokontrollera iekšējā mehānika ir nedaudz vairāk iesaistīta, un tāpēc mēs veicam šo apmācību. Tāpēc apspriedīsim katru sadaļu pēc kārtas.

4. solis:.org montētāju direktīvas

Mēs jau zinām, ko direktīvas.nolist,.list,.include un.def montāža dara no mūsu iepriekšējām apmācībām, tāpēc vispirms apskatīsim četras koda rindiņas, kas nāk pēc tam:

.org 0x0000

jmp Atiestatīt.org 0x0020 jmp overflow_handler

Paziņojums.org norāda montētājam, kur "Programmas atmiņā" ievietot nākamo paziņojumu. Programmas izpildes laikā "Programmu skaitītājs" (saīsināti kā dators) satur pašreizējās izpildāmās rindas adresi. Tātad šajā gadījumā, kad dators ir pie 0x0000, tas redzēs komandu "jmp Reset", kas atrodas šajā atmiņas vietā. Iemesls, kāpēc mēs vēlamies ievietot jmp Reset šajā vietā, ir tas, ka tad, kad programma sākas vai mikroshēma tiek atiestatīta, dators sāk izpildīt kodu šajā vietā. Tātad, kā mēs redzam, mēs tikko teicām, ka nekavējoties "jāpāriet" uz sadaļu ar nosaukumu "Atiestatīt". Kāpēc mēs to darījām? Tas nozīmē, ka pēdējās divas rindas iepriekš tiek vienkārši izlaistas! Kāpēc?

Nu tur jau lietas kļūst interesantas. Tagad jums būs jāatver pdf skatītājs ar pilnu ATmega328p datu lapu, uz kuru es norādīju šīs apmācības pirmajā lapā (tāpēc tas ir 4. punkts sadaļā "jums būs nepieciešams"). Ja jūsu ekrāns ir pārāk mazs vai jums jau ir atvērts pārāk daudz logu (kā tas ir manā gadījumā), jūs varat darīt to, ko es daru, un ievietot to Ereader vai savā Android tālrunī. Jūs to izmantosit visu laiku, ja plānojat rakstīt montāžas kodu. Forši ir tas, ka visi mikrokontroleri ir sakārtoti ļoti līdzīgos veidos, un tāpēc, kad būsiet pieradis lasīt datu lapas un kodēt no tām, jums būs gandrīz triviāli darīt to pašu citam mikrokontrolleram. Tātad mēs faktiski mācāmies izmantot visus mikrokontrollerus savā ziņā, nevis tikai atmega328p.

Labi, atgriezieties datu lapas 18. lappusē un apskatiet 8-2. Attēlu.

Šādi tiek iestatīta programmas atmiņa mikrokontrollerī. Jūs varat redzēt, ka tas sākas ar adresi 0x0000 un ir sadalīts divās sadaļās; lietojumprogrammas zibspuldzes sadaļa un sāknēšanas zibspuldzes sadaļa. Ja īsumā atsaucaties uz 277. lappusi, 27.-14. Tabulu, jūs redzēsit, ka lietojumprogrammas zibspuldzes sadaļa aizņem vietas no 0x0000 līdz 0x37FF, un sāknēšanas zibspuldzes sadaļa aizņem pārējās vietas no 0x3800 līdz 0x3FFF.

1. uzdevums: Cik vietu ir programmas atmiņā? T.i. pārvērst 3FFF par decimālo skaitli un pievienot 1, jo mēs sākam skaitīt ar 0. Tā kā katra atmiņas vieta ir 16 bitu (vai 2 baitu) plata, kāds ir kopējais atmiņas baitu skaits? Tagad konvertējiet to uz kilobaitiem, atceroties, ka kilobaitos ir 2^10 = 1024 baiti. Sāknēšanas zibspuldzes sadaļa ir no 0x3800 līdz 0x37FF, cik kilobaitu tas ir? Cik kilobaitu atmiņas mēs varam izmantot, lai saglabātu savu programmu? Citiem vārdiem sakot, cik liela var būt mūsu programma? Visbeidzot, cik koda rindu mums var būt?

Labi, tagad, kad mēs zinām visu par zibatmiņas programmas atmiņas organizāciju, turpināsim diskusiju par.org paziņojumiem. Mēs redzam, ka pirmajā atmiņas vietā 0x0000 ir mūsu norādījumi pāriet uz mūsu sadaļu, ko mēs apzīmējām kā Atiestatīt. Tagad mēs redzam, ko dara paziņojums ".org 0x0020". Tajā teikts, ka mēs vēlamies, lai instrukcija nākamajā rindā tiktu ievietota atmiņas vietā 0x0020. Norādījumi, ko mēs tur ievietojām, ir pārlēkšana uz mūsu koda sadaļu, ko esam apzīmējuši ar nosaukumu "overflow_handler" … kāpēc tad, pie velna, mēs pieprasītu šo lēcienu novietot atmiņas vietā 0x0020? Lai to uzzinātu, mēs atgriežamies datu lapas 65. lappusē un apskatām 12.-6. Tabulu.

Tabula 12-6 ir tabula ar "Atiestatīt un pārtraukt vektorus", un tā precīzi parāda, kur dators dosies, kad saņems "pārtraukumu". Piemēram, ja paskatās uz vektora numuru 1. Pārtraukuma "avots" ir "RESET", kas tiek definēts kā "Ārējā tapa, ieslēgšanas atiestatīšana, atiestatīšana no izejas un sargsuņu sistēmas atiestatīšana", kas nozīmē, ja tāds ir ja šīs lietas notiek ar mūsu mikrokontrolleri, dators sāks izpildīt mūsu programmu programmas atmiņas vietā 0x0000. Kā tad ar mūsu.org direktīvu? Mēs ievietojām komandu atmiņas vietā 0x0020, un, paskatoties uz leju tabulā, jūs redzēsit, ka, ja notiks taimera/skaitītāja0 pārplūde (nāk no TIMER0 OVF), tā izpildīs visu, kas atrodas vietā 0x0020. Tātad, kad tas notiks, dators pārlēks uz vietu, ko mēs apzīmējām ar nosaukumu "overflow_handler". Forši, vai ne? Pēc minūtes jūs redzēsit, kāpēc mēs to izdarījām, bet vispirms pabeigsim šo apmācības soli ar maliņu.

Ja mēs vēlamies padarīt savu kodu glītāku un sakoptāku, mums tiešām jāaizstāj četras pašreiz apspriestās rindas ar šādām (skatīt 66. lpp.):

.org 0x0000

rjmp Atiestatīt; 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

Tātad, ja notiek konkrēts pārtraukums, tas vienkārši “atkāpjas”, kas nozīmē “atgriešanās no pārtraukuma”, un nekas cits nenotiek. Bet, ja mēs nekad "neiespēsim" šos dažādus pārtraukumus, tad tie netiks izmantoti, un mēs varam ievietot programmas kodu šajos punktos. Mūsu pašreizējā programmā "blink.asm" mēs tikai iespējosim timer0 pārplūdes pārtraukumu (un, protams, atiestatīšanas pārtraukumu, kas vienmēr ir iespējots), un tāpēc mēs netraucēsim citiem.

Kā tad "iespējot" taimera0 pārplūdes pārtraukumu? … Tas ir mūsu nākamā šīs apmācības soļa priekšmets.

5. darbība: taimeris/skaitītājs 0

Taimeris/skaitītājs 0
Taimeris/skaitītājs 0

Apskatiet iepriekš redzamo attēlu. Tas ir "PC" lēmumu pieņemšanas process, kad kāda ārēja ietekme "pārtrauc" mūsu programmas plūsmu. Pirmā lieta, ko tā dara, saņemot signālu no ārpuses, ka ir noticis pārtraukums, ir pārbaudīt, vai mēs esam iestatījuši “pārtraukuma iespējošanas” bitu šāda veida pārtraukumam. Ja mēs to neesam izdarījuši, tas vienkārši turpina izpildīt mūsu nākamo koda rindu. Ja mēs esam iestatījuši šo konkrēto pārtraukšanas iespējošanas bitu (lai šajā bitu vietā būtu 1, nevis 0), tas pārbaudīs, vai esam iespējojuši "globālos pārtraukumus", ja ne, tas atkal pāries uz nākamo rindu kodu un turpiniet. Ja mēs esam iespējojuši arī globālos pārtraukumus, tas nonāks šāda veida pārtraukuma programmas atmiņas vietā (kā parādīts 12.-6. Tabulā) un izpildīs jebkuru komandu, kuru esam tur ievietojuši. Tātad, redzēsim, kā mēs to visu esam ieviesuši savā kodā.

Mūsu koda sadaļa Atiestatīt ar iezīmi sākas ar šādām divām rindām:

Atiestatīt:

ldi temp, 0b00000101 izeja TCCR0B, temp

Kā mēs jau zinām, tas tempā (t.i., R16) ielādē skaitli, kas seko tūlīt, kas ir 0b00000101. Tad tas izraksta šo numuru reģistrā ar nosaukumu TCCR0B, izmantojot komandu "out". Kas ir šis reģistrs? Pāriesim uz datu lapas 614 lappusi. Tas ir tabulas vidū, kurā apkopoti visi reģistri. Pēc adreses 0x25 jūs atradīsit TCCR0B. (Tagad jūs zināt, no kurienes manā nekomentētajā koda versijā radās rindiņa "out 0x25, r16"). Iepriekš redzamajā koda segmentā mēs redzam, ka esam iestatījuši 0. bitu un 2. bitu un notīrījuši visu pārējo. Aplūkojot tabulu, jūs varat redzēt, ka tas nozīmē, ka esam iestatījuši CS00 un CS02. Tagad pāriesim pie nodaļas datu lapā ar nosaukumu "8 bitu taimeris/skaitītājs0 ar PWM". Jo īpaši dodieties uz šīs nodaļas 107. lpp. Jūs redzēsit to pašu reģistra "Taimeris/skaitītāja kontroles reģistrs B" (TCCR0B) aprakstu, ko mēs tikko redzējām reģistra kopsavilkuma tabulā (tāpēc mēs būtu varējuši ierasties tieši šeit, bet es vēlējos, lai jūs redzētu, kā izmantot kopsavilkuma tabulas turpmākai uzziņai). Datu lapa turpina sniegt aprakstu par katru reģistra bitu un to darbību. Pagaidām mēs to visu izlaidīsim un pāršķirsim lapu līdz 15.-9. Šajā tabulā ir parādīts pulksteņa atlases bitu apraksts. Tagad paskatieties uz šo tabulu, līdz atrodat līniju, kas atbilst bitiem, kurus mēs tikko iestatījām šajā reģistrā. Līnija saka "clk/1024 (no prescaler)". Tas nozīmē, ka mēs vēlamies, lai taimeris/skaitītājs0 (TCNT0) atzīmētos ar ātrumu, kas ir CPU frekvence, dalīta ar 1024. Tā kā mūsu mikrokontrolleri baro 16 MHz kristāla oscilators, tas nozīmē, ka mūsu CPU izpildes ātrums ir 16 miljoni instrukciju sekundē. Tātad ātrums, ko atzīmēs mūsu TCNT0 skaitītājs, ir 16 miljoni/1024 = 15625 reizes sekundē (izmēģiniet to ar dažādiem pulksteņa atlases bitiem un redziet, kas notiek - atcerieties mūsu filozofiju?). Paturēsim numuru 15625 prātā vēlākam laikam un pāriesim pie nākamajām divām koda rindām:

ldi temp, 0b00000001

sts TIMSK0, temp

Tas nosaka reģistra 0. bitu ar nosaukumu TIMSK0 un notīra visu pārējo. Ja paskatīsities datu lapas 109. lappusi, jūs redzēsit, ka TIMSK0 apzīmē "Taimera/skaitītāja pārtraukuma maskas reģistrs 0" un mūsu kods ir iestatījis 0. Bitu, kura nosaukums ir TOIE0, kas nozīmē "Taimeris/Counter0 pārpildes pārtraukšanas iespējošana" … Tur! Tagad jūs redzat, par ko ir runa. Tagad mums ir "pārtraukšanas iespējošanas bitu komplekts", kā mēs vēlējāmies no pirmā lēmuma mūsu attēlā augšpusē. Tagad mums atliek tikai iespējot “globālos pārtraukumus”, un mūsu programma varēs reaģēt uz šāda veida pārtraukumiem. Mēs drīz iespējosim globālos pārtraukumus, bet pirms mēs to darām, iespējams, jūs kaut kas mulsināja.. kāpēc, heck, es izmantoju komandu "sts", lai kopētu TIMSK0 reģistrā, nevis parasto "out"?

Ikreiz, kad redzat mani, izmantojiet instrukciju, kuru iepriekš neesat redzējis. Pirmā lieta, kas jums jādara, ir datu lapas lapas 616 lappuse. Šis ir "instrukciju kopuma kopsavilkums". Tagad atrodiet instrukciju "STS", kuru es izmantoju. Tajā teikts, ka ir nepieciešams skaitlis no R reģistra (mēs izmantojām R16) un “Saglabāt tieši uz SRAM” atrašanās vietu k (mūsu gadījumā to ir norādījis TIMSK0). Tātad, kāpēc mums bija jāizmanto "sts", kas prasa 2 pulksteņa ciklus (sk. Tabulas pēdējo sleju), lai tos uzglabātu TIMSK0, un mums iepriekš vajadzēja tikai "out", kas aizņem tikai vienu pulksteņa ciklu, lai saglabātu TCCR0B? Lai atbildētu uz šo jautājumu, mums jāatgriežas pie mūsu reģistra kopsavilkuma tabulas 61. lpp. Jūs redzat, ka TCCR0B reģistra adrese ir 0x25, bet arī (0x45)? Tas nozīmē, ka tas ir reģistrs SRAM, bet tas ir arī noteikta veida reģistrs, ko sauc par "ostu" (vai i/o reģistru). Ja paskatāties uz instrukciju kopsavilkuma tabulu blakus komandai "ārā", jūs redzēsit, ka tā ņem vērtības no "darba reģistriem", piemēram, R16, un nosūta tās uz ostu. Tātad, rakstot uz TCCR0B, mēs varam izmantot “out” un ietaupīt sev pulksteņa ciklu. Bet tagad reģistra tabulā meklējiet TIMSK0. Jūs redzat, ka tā adrese ir 0x6e. Tas ir ārpus portu diapazona (kas ir tikai pirmās SRAM 0x3F atrašanās vietas), un tāpēc jums ir jāatgriežas pie komandas sts izmantošanas un jāveic divi CPU pulksteņa cikli. Lūdzu, izlasiet 4. piezīmi instrukciju kopsavilkuma tabulas beigās 615. lappusē. Ņemiet vērā arī to, ka visi mūsu ievades un izvades porti, piemēram, PORTD, atrodas tabulas apakšā. Piemēram, PD4 ir 4. bits adresē 0x0b (tagad jūs redzat, no kurienes visi 0x0b materiāli ir iegūti manā nekomentētajā kodā!).. labi, ātrs jautājums: vai jūs mainījāt "sts" uz "out" un redzat, kas notiek? Atcerieties mūsu filozofiju! saplēs to! neuztver tikai manu vārdu par lietām.

Labi, pirms mēs turpinām, uz minūti atgriezieties datu lapas 19. lappusē. Jūs redzat datu atmiņas (SRAM) attēlu. Pirmie 32 reģistri SRAM (no 0x0000 līdz 0x001F) ir "vispārējas nozīmes darba reģistri" R0 līdz R31, kurus mēs visu laiku izmantojam kā mainīgos savā kodā. Nākamie 64 reģistri ir I/O porti līdz 0x005f (ti, tie, par kuriem mēs runājām un kuriem reģistra tabulā blakus ir tās bezkronšteina adreses, kuras mēs varam izmantot komandu "out", nevis "sts") nākamajā SRAM sadaļā ir visi pārējie reģistri kopsavilkuma tabulā līdz adresei 0x00FF, un visbeidzot pārējais ir iekšējais SRAM. Tagad ātri, uz sekundi pievērsīsimies 12. lappusei. Tur jūs redzat tabulu ar "vispārējas nozīmes darba reģistriem", kurus mēs vienmēr izmantojam kā mainīgos. Vai redzat biezo līniju starp cipariem R0 līdz R15 un pēc tam R16 līdz R31? Šī līnija ir iemesls, kāpēc mēs vienmēr izmantojam R16 kā mazāko, un es mazliet vairāk iedziļināšos nākamajā apmācībā, kur mums būs nepieciešami arī trīs 16 bitu netiešo adrešu reģistri, X, Y un Z. vēl tikai iedziļinieties tajā, jo mums tas tagad nav vajadzīgs un mēs šeit pietiekami aizķeramies.

Atgrieziet vienu lapu atpakaļ uz datu lapas 11. lapu. Augšējā labajā stūrī redzēsit SREG reģistra diagrammu? Jūs redzat, ka šī reģistra 7. bitu sauc par "es". Tagad dodieties lejup pa lapu un izlasiet 7. bita aprakstu…. jā! Tas ir globālās pārtraukšanas iespējošanas bits. Tas mums ir jāiestata, lai iepriekšējā diagrammā pieņemtu otro lēmumu un mūsu programmā atļautu taimera/skaitītāja pārplūdes pārtraukumus. Tātad mūsu programmas nākamajā rindā vajadzētu lasīt:

sbi SREG, es

kas SREG reģistrā nosaka bitu ar nosaukumu "I". Tomēr tā vietā mēs izmantojām instrukciju

sei

tā vietā. Šis bits programmās ir iestatīts tik bieži, ka viņi vienkārši ir izveidojuši vienkāršāku veidu, kā to izdarīt.

Labi! Tagad mēs esam sagatavojuši pārplūdes pārtraukumus, lai mūsu "jmp overflow_handler" tiktu izpildīts ikreiz, kad tas notiek.

Pirms mēs turpinām, apskatiet SREG reģistru (statusa reģistru), jo tas ir ļoti svarīgi. Izlasiet, ko attēlo katrs no karogiem. Jo īpaši daudzi no mūsu izmantotajiem norādījumiem visu laiku iestatīs un pārbaudīs šos karodziņus. Piemēram, vēlāk mēs izmantosim komandu "PCI", kas nozīmē "nekavējoties salīdzināt". Apskatiet šīs instrukcijas kopsavilkuma tabulu un ievērojiet, cik karodziņu tā ir iestatījusi slejā "karogi". Tie visi ir karogi SREG, un mūsu kods tos iestatīs un pastāvīgi pārbaudīs. Drīz jūs redzēsit piemērus. Visbeidzot, šīs koda sadaļas pēdējais bits ir šāds:

clr temp

izeja TCNT0, temp sbi DDRD, 4

Pēdējā rinda šeit ir diezgan acīmredzama. Tas tikai nosaka PortD datu virzienu reģistra 4. bitu, izraisot PD4 izvadi.

Pirmais noregulē mainīgo temperatūru uz nulli un pēc tam kopē to TCNT0 reģistrā. TCNT0 ir mūsu taimeris/skaitītājs0. Tas nosaka to līdz nullei. Tiklīdz dators izpildīs šo līniju, taimeris0 sāksies ar nulli un skaitīsies ar ātrumu 15625 reizes katru sekundi. Problēma ir šāda: TCNT0 ir "8 bitu" reģistrs, vai ne? Tātad, kāds ir lielākais skaitlis, ko var turēt 8 bitu reģistrs? Nu tas ir 0b11111111. Šis ir skaitlis 0xFF. Kurš ir 255. Tātad jūs redzat, kas notiek? Taimeris rāvējslēdzēja ātrumā palielinās 15625 reizes sekundē, un katru reizi, kad tas sasniedz 255, tas "pārplūst" un atkal atgriežas pie 0. Tajā pašā laikā, atgriežoties pie nulles, tas izsūta taimera pārplūdes pārtraukuma signālu. Dators to saņem, un jūs zināt, ko tas dara līdz šim? Jā. Tas dodas uz programmas atmiņas vietu 0x0020 un izpilda tur atrasto instrukciju.

Lieliski! Ja jūs joprojām esat ar mani, tad jūs esat nenogurstošs supervaronis! Turpināsim…

6. darbība. Pārplūdes apstrādātājs

Tātad pieņemsim, ka taimera/skaitītāja0 reģistrs ir tikko pārpildīts. Tagad mēs zinām, ka programma saņem pārtraukuma signālu un izpilda 0x0020, kas liek programmas skaitītājam, personālajam datoram, pāriet uz etiķeti "overflow_handler", ko mēs uzrakstījām pēc šīs etiķetes:

overflow_handler:

inc pārplūdes cpi pārpildes, 61 brne PC+2 clr pārplūdes pens

Pirmā lieta, ko tā dara, ir palielināt mainīgo "pārpildes" (tas ir mūsu nosaukums vispārējam darba reģistram R17), pēc tam tas "salīdzina" pārplūdes saturu ar skaitli 61. Instrukcija cpi darbojas tā, ka tā vienkārši atņem divi skaitļi, un, ja rezultāts ir nulle, tas SREG reģistrā nosaka Z karogu (es jums teicu, ka mēs visu laiku redzēsim šo reģistru). Ja abi skaitļi ir vienādi, tad Z karogs būs 1, ja abi skaitļi nav vienādi, tas būs 0.

Nākamajā rindā teikts "brne PC+2", kas nozīmē "zars, ja nav vienāds". Būtībā tas pārbauda Z karogu SREG, un, ja tas NAV viens (ti, divi skaitļi nav vienādi, ja tie būtu vienādi, tiktu iestatīts nulles karogs), dators atzaro uz PC+2, kas nozīmē, ka tas izlaiž nākamo līniju un iet taisni uz "reti", kas no pārtraukuma atgriežas jebkurā vietā, kas bija kodā, kad ieradās pārtraukums. Ja brne instrukcija nulles karoga bitā atrastu 1, tā nesazarotos un tā vietā turpinātu uz nākamo rindu, kas pārplūstu, atiestatot to uz 0.

Kāds ir tā visa neto rezultāts?

Mēs redzam, ka katru reizi, kad ir taimera pārpilde, šis apstrādātājs palielina "pārplūdes" vērtību par vienu. Tātad mainīgais "pārplūdes" skaita pārplūdes to rašanās brīdī. Kad skaitlis sasniedz 61, mēs to atiestatām uz nulli.

Kāpēc tad pasaulē mēs to darītu?

Paskatīsimies. Atcerieties, ka mūsu CPU pulksteņa ātrums ir 16 MHz, un mēs to "iepriekš palielinājām", izmantojot TCCR0B, lai taimeris tiktu skaitīts tikai ar ātrumu 15625 skaitļi sekundē? Un katru reizi, kad taimeris sasniedz 255, tas pārplūst. Tas nozīmē, ka tas pārplūst 15625/256 = 61,04 reizes sekundē. Mēs izsekojam pārpildījumu skaitam ar mūsu mainīgo "pārplūdi" un salīdzinām šo skaitli ar 61. Tātad mēs redzam, ka "pārplūdes" būs vienādas ar 61 reizi sekundē! Tātad mūsu apstrādātājs reizi sekundē atiestatīs "pārplūdes" uz nulli. Tātad, ja mēs vienkārši uzraudzītu mainīgo "pārplūdes" un ņemtu vērā katru reizi, kad tas tiek atiestatīts uz nulli, mēs reāllaikā skaitītu katru sekundi (ņemiet vērā, ka nākamajā apmācībā mēs parādīsim, kā iegūt precīzāku aizkavēšanās milisekundēs tādā pašā veidā, kā darbojas Arduino “kavēšanās” rutīna).

Tagad mēs esam "apstrādājuši" taimera pārplūdes pārtraukumus. Pārliecinieties, ka saprotat, kā tas darbojas, un pēc tam pārejiet pie nākamās darbības, kurā mēs izmantojam šo faktu.

7. solis: kavēšanās

Tagad, kad esam redzējuši, ka mūsu taimera pārplūdes pārtraukšanas apstrādātāja "overflow_handler" rutīna mainīgo "pārplūdes" iestatīs uz nulli reizi sekundē, mēs varam izmantot šo faktu, lai izstrādātu "kavēšanās" apakšprogrammu.

Apskatiet šo kodu no mūsu aizkaves: etiķete

kavēšanās:

clr overflows sec_count: cpi pārpildes, 30 brne sec_count ret

Mēs šo apakšprogrammu izsauksim katru reizi, kad mūsu programmā būs nepieciešama aizkavēšanās. Tas darbojas tā, ka vispirms mainīgo "pārplūst" nosaka uz nulli. Pēc tam tas nonāk apgabalā ar nosaukumu "sec_count" un salīdzina pārplūdes ar 30, ja tie nav vienādi, tas atzarojas atpakaļ uz etiķetes sec_count un salīdzina vēlreiz, un atkal utt., Līdz tie beidzot ir vienādi (atcerieties, ka visu šo laiku) mūsu taimera pārtraukšanas apstrādātājs turpina palielināt mainīgo pārplūdi, un tāpēc tas mainās katru reizi, kad mēs ejam apkārt. Kad pārplūdes beidzot ir 30, tas iziet no cilpas un atgriežas visur, kur mēs saucām par kavēšanos: no. Neto rezultāts ir kavēšanās 1/2 sekundes

2. vingrinājums: mainiet pārpildes apstrādātāja kārtību uz šādu:

overflow_handler:

inc pārplūdes pens

un palaidiet programmu. Vai ir kas cits? Kāpēc vai kāpēc ne?

8. solis: mirgo

Visbeidzot, apskatīsim mirgošanas rutīnu:

mirgo:

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

Vispirms ieslēdzam PD4, pēc tam izsaucam savu kavēšanās apakšprogrammu. Mēs izmantojam rcall, lai, kad dators nonāktu pie "ret" paziņojuma, tas atgrieztos rindā pēc rcall. Pēc tam aizkaves kārtība aizkavējas 30 reizes pārpildes mainīgajā, kā mēs redzējām, un tas ir gandrīz tieši 1/2 sekundes, tad mēs izslēdzam PD4, aizkavējam vēl 1/2 sekundi un pēc tam atkal atgriežamies sākumā.

Rezultāts ir mirgojoša gaismas diode!

Es domāju, ka jūs tagad piekritīsit, ka "mirgot", iespējams, nav labākā "labdien pasaule" programma montāžas valodā.

3. uzdevums: mainiet dažādus programmas parametrus tā, lai gaismas diode mirgo ar dažādu ātrumu, piemēram, sekundi vai 4 reizes sekundē utt. Piemēram, ieslēgts uz 1/4 sekundes un pēc tam izslēgts uz 2 sekundēm vai tamlīdzīgi. 5. uzdevums: mainiet TCCR0B pulksteņa atlases bitus uz 100 un pēc tam turpiniet iet pa tabulu. Kurā brīdī tas kļūst neatšķirams no mūsu programmas "hello.asm" no 1. apmācības? 6. uzdevums (pēc izvēles): ja jums ir cits kristāla oscilators, piemēram, 4 MHz vai 13,5 MHz vai kāds cits, nomainiet savu 16 MHz oscilatoru uz maizes dēļa jaunajam un redziet, kā tas ietekmē gaismas diodes mirgošanas ātrumu. Tagad jums vajadzētu būt iespējai veikt precīzu aprēķinu un precīzi paredzēt, kā tas ietekmēs likmi.

9. solis. Secinājums

Tiem no jums, kuri ir tik grūti, ka esat tik tālu, apsveicam!

Es saprotu, ka lasīšana un skatīšanās uz augšu ir diezgan grūta, nekā vadīšana un eksperimentēšana, bet es ceru, ka esat iemācījušies šādas svarīgas lietas:

  1. Kā darbojas programmas atmiņa
  2. Kā darbojas SRAM
  3. Kā meklēt reģistrus
  4. Kā meklēt instrukcijas un zināt, ko tās dara
  5. Kā ieviest pārtraukumus
  6. Kā CP izpilda kodu, kā darbojas SREG un kas notiek pārtraukumu laikā
  7. Kā veikt cilpas un lēcienus un atlekšanu kodā
  8. Cik svarīgi ir izlasīt datu lapu!
  9. Kā jūs zināt, kā to visu izdarīt mikrokontrolleram Atmega328p, tas būs relatīvs gājiens, lai uzzinātu par jauniem kontrolieriem, kas jūs interesē.
  10. Kā nomainīt CPU laiku reālā laikā un izmantot to kavēšanās režīmā.

Tagad, kad mums ir daudz teorijas, mēs varam uzrakstīt labāku kodu un kontrolēt sarežģītākas lietas. Tātad nākamajā apmācībā mēs to darīsim. Mēs izveidosim sarežģītāku, interesantāku ķēdi un kontrolēsim to jautros veidos.

7. uzdevums: “Lauziet” kodu dažādos veidos un redziet, kas notiek! Zinātniskas zinātkāres bērniņ! Vai kāds cits var pareizi mazgāt traukus? 8. uzdevums: salieciet kodu, izmantojot opciju "-l", lai izveidotu saraksta failu. T.i. "avra -l blink.lst blink.asm" un apskatiet saraksta failu. Papildu kredīts: sākumā nekomentētais kods un vēlāk apspriestais komentētais kods atšķiras! Ir viena koda rinda, kas atšķiras. Vai varat to atrast? Kāpēc šai atšķirībai nav nozīmes?

Ceru, ka jums bija jautri! Tiekamies nākamreiz…

Ieteicams: