Talaan ng mga Nilalaman:

Tutorial sa AVR Assembler 3: 9 Mga Hakbang
Tutorial sa AVR Assembler 3: 9 Mga Hakbang

Video: Tutorial sa AVR Assembler 3: 9 Mga Hakbang

Video: Tutorial sa AVR Assembler 3: 9 Mga Hakbang
Video: Easy Crochet Mittens Pattern Tutorial 2024, Hulyo
Anonim
Tutorial sa AVR Assembler 3
Tutorial sa AVR Assembler 3

Maligayang pagdating sa tutorial bilang 3!

Bago kami magsimula nais kong gumawa ng isang pilosopiko na punto. Huwag matakot na mag-eksperimento sa mga circuit at ang code na itinatayo namin sa mga tutorial na ito. Baguhin ang mga wire sa paligid, magdagdag ng mga bagong bahagi, kumuha ng mga sangkap, palitan ang mga linya ng code, magdagdag ng mga bagong linya, tanggalin ang mga linya, at makita kung ano ang nangyayari! Napakahirap masira ang anuman at kung gagawin mo, sino ang nagmamalasakit? Wala kaming ginagamit, kabilang ang microcontroller, ay napakamahal at palaging edukasyon upang makita kung paano mabibigo ang mga bagay. Hindi mo lamang malalaman kung ano ang hindi dapat gawin sa susunod ngunit, higit sa lahat, malalaman mo kung bakit hindi ito gawin. Kung ikaw ay katulad ko, noong bata ka pa at nakakuha ka ng isang bagong laruan hindi gaanong katagal bago mo ito piraso upang makita kung ano ang tama nitong pagkiliti? Minsan ang laruan ay napunta sa hindi maibabalik na nasira ngunit walang malaking pakikitungo. Ang pagpapahintulot sa isang bata na galugarin ang kanyang pagiging mausisa kahit na sa punto ng sirang mga laruan ay kung saan siya ay naging isang siyentista o isang inhinyero sa halip na isang makinang panghugas.

Ngayon ay magiging kable kami ng isang napaka-simpleng circuit at pagkatapos ay medyo mabibigat sa teorya. Paumanhin tungkol dito, ngunit kailangan namin ang mga tool! Ipinapangako kong babawi kami para sa ito sa tutorial 4 kung saan magsasagawa kami ng mas seryosong circuit building at ang resulta ay magiging cool. Gayunpaman, ang paraang kailangan mong gawin ang lahat ng mga tutorial na ito ay sa isang napakabagal, nagmumuni-muni na paraan. Kung mag-araro ka lamang, buuin ang circuit, kopyahin at i-paste ang code, at patakbuhin ito pagkatapos, sigurado, gagana ito, ngunit hindi mo matutunan ang isang bagay. Kailangan mong isipin ang tungkol sa bawat linya. I-pause Eksperimento Imbento Kung gagawin mo ito sa ganoong paraan sa pagtatapos ng ika-5 tutorial ay hindi ka na bumubuo ng mga cool na bagay at hindi na kailangan ng pagtuturo. Kung hindi man ay nanonood ka lang sa halip na matuto at lumikha.

Sa anumang kaso, sapat na pilosopiya, magsimula tayo!

Sa tutorial na ito kakailanganin mo:

  1. iyong prototyping board
  2. isang LED
  3. pagkonekta ng mga wire
  4. isang risistor sa paligid ng 220 hanggang 330 ohms
  5. Manwal ng Itakda ng Tagubilin: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. Ang Datasheet: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. ibang kristal oscillator (opsyonal)

Narito ang isang link sa kumpletong koleksyon ng mga tutorial:

Hakbang 1: Pagbubuo ng Circuit

Pagbuo ng Circuit
Pagbuo ng Circuit

Ang circuit sa tutorial na ito ay lubos na simple. Mahalagang isusulat namin ang program na "blink" kaya ang kailangan lang namin ay ang sumusunod.

I-hook up ang isang LED sa PD4, pagkatapos ay sa isang 330 ohm risistor, pagkatapos ay sa Ground. ibig sabihin

PD4 - LED - R (330) - GND

at iyon na!

Ang teorya ay magiging matigas na pag-slog …

Hakbang 2: Bakit Kailangan Namin ang Mga Komento at ang M328Pdef.inc File?

Sa palagay ko dapat kaming magsimula sa pamamagitan ng pagpapakita kung bakit kapaki-pakinabang ang pagsasama ng file at mga komento. Wala sa kanila ang talagang kinakailangan at maaari kang magsulat, magtipon, at mag-upload ng code sa parehong paraan nang wala sila at ito ay tatakbo nang perpektong (bagaman nang walang isama ang file maaari kang makakuha ng ilang mga reklamo mula sa nagtitipon - ngunit walang mga error)

Narito ang code na isusulat namin ngayon, maliban sa naalis ko ang mga komento at isama ang file:

.device 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, 0x0 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

medyo simple diba? Haha. Kung naipunan mo at na-upload ang file na ito ay magiging sanhi ka ng LED upang magpikit sa isang rate ng 1 blink bawat segundo na may blink na tumatagal ng 1/2 segundo at ang pag-pause sa pagitan ng mga blinks na tumatagal ng 1/2 segundo.

Gayunpaman, ang pagtingin sa code na ito ay halos hindi nakapagpapaliwanag. Kung nais mong isulat ang code na tulad nito ikaw at nais itong baguhin o baguhin ito sa hinaharap na mahihirapan ka.

Kaya't ilagay natin ang mga komento at isama muli ang file upang makagawa tayo ng kahulugan dito.

Hakbang 3: Blink.asm

Narito ang code na tatalakayin natin ngayon:

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

; isinulat ni: 1o_o7; petsa:; bersyon: 1.0; nai-save ang file bilang: blink.asm; para sa AVR: atmega328p; dalas ng orasan: 16MHz (opsyonal); ***** Funcion ng programa: -----------------; binibilang ang mga segundo sa pamamagitan ng pagpikit ng isang LED;; PD4 - LED - R (330 ohm) - GND;; ------------------------------------.nolist. isama ang "./m328Pdef.inc".list; ====; Mga deklarasyon:.def temp = r16.def overflows = r17.org 0x0000; memorya (PC) lokasyon ng pag-reset ng handler rjmp Reset; nagkakahalaga ang jmp ng 2 mga siklo ng CPU at ang mga gastos sa rjmp ay 1 lamang; kaya maliban kung kailangan mong tumalon ng higit sa 8k bytes; rjmp lang ang kailangan mo. Ang ilang mga microcontroller samakatuwid lamang; may rjmp at hindi jmp.org 0x0020; lokasyon ng memorya ng Timer0 overflow handler rjmp overflow_handler; pumunta dito kung maganap ang isang pag-overflow ng overflow ng timer0 = ==== I-reset: ldi temp, 0b00000101 out TCCR0B, temp; itakda ang Clock Selector Bits CS00, CS01, CS02 sa 101; inilalagay nito ang Timer Counter0, TCNT0 sa mode na FCPU / 1024; kaya't kumikiliti ito sa CPU freq / 1024 ldi temp, 0b00000001 sts TIMSK0, temp; itakda ang Timer Overflow Interrupt Enable (TOIE0) bit; ng Timer Interrupt Mask Register (TIMSK0) sei; paganahin ang mga pandaigdigang pagkagambala - katumbas ng "sbi SREG, I" clr temp out TCNT0, temp; ipasimula ang Timer / Counter sa 0 sbi DDRD, 4; itakda ang PD4 sa output; ==================; Pangunahing katawan ng programa: blink: sbi PORTD, 4; i-on ang LED sa pagkaantala ng PD4 rcall; ang pagkaantala ay magiging 1/2 segundo cbi PORTD, 4; patayin ang LED sa pagkaantala ng PD4 rcall; ang pagkaantala ay magiging 1/2 segundo rjmp blink; loop pabalik sa simula ng pagkaantala: umapaw ang clr; itakda ang mga overflow sa 0 sec_count: cpi overflows, 30; ihambing ang bilang ng mga umapaw at 30 brne sec_count; sangay upang bumalik sa sec_count kung hindi pantay na ret; kung 30 umapaw na nangyari ang bumalik sa blink overflow_handler: inc overflows; magdagdag ng 1 sa overflows variable cpi overflows, 61; ihambing sa 61 brne PC + 2; Program Counter + 2 (laktawan ang susunod na linya) kung hindi pantay na umaapaw na clr; kung 61 umapaw na nangyari ang pag-reset sa counter sa zero reti; bumalik mula sa abala

Tulad ng nakikita mo, ang aking mga komento ay medyo mas maikli ngayon. Kapag alam na natin kung ano ang mga utos sa hanay ng pagtuturo hindi na natin kailangang ipaliwanag iyon sa mga komento. Kailangan lamang naming ipaliwanag kung ano ang nangyayari mula sa pananaw ng programa.

Tatalakayin namin kung ano ang ginagawa ng lahat ng ito nang paunti-unti, ngunit subukang muna nating makakuha ng isang pandaigdigang pananaw. Ang pangunahing katawan ng programa ay gumagana tulad ng sumusunod.

Una naming itinakda ang bit 4 ng PORTD na may "sbi PORTD, 4" nagpapadala ito ng 1 sa PD4 na naglalagay ng boltahe sa 5V sa pin na iyon. Bubuksan nito ang LED. Pagkatapos ay tumalon kami sa "pagkaantala" na subroutine na binibilang ang 1/2 sa isang segundo (ipapaliwanag namin kung paano ito gagawin sa paglaon). Pagkatapos ay bumalik kami sa blink at i-clear ang bit 4 sa PORTD na nagtatakda ng PD4 sa 0V at kaya pinapatay ang LED. Pagkatapos ay naantala namin para sa isa pang 1/2 segundo, at pagkatapos ay tumalon pabalik sa simula ng blink muli sa "rjmp blink".

Dapat mong patakbuhin ang code na ito at makita na ginagawa nito kung ano ang nararapat.

At ayan mayroon ka nito! Iyon lang ang pisikal na ginagawa ng code na ito. Ang panloob na mekanika ng ginagawa ng microcontroller ay medyo kasangkot at iyon ang dahilan kung bakit ginagawa namin ang tutorial na ito. Kaya't talakayin natin ang bawat seksyon nang magkakasunod.

Hakbang 4:.org Mga Direktoryo ng Assembler

Alam na natin kung ano ang ginagawa ng.nolist,.list,.kasama, at.def assembler direktiba mula sa aming nakaraang mga tutorial, kaya't tingnan muna natin ang 4 na linya ng code na dumating pagkatapos nito:

.org 0x0000

jmp I-reset.org 0x0020 jmp overflow_handler

Ang pahayag na.org ay nagsasabi sa nagtitipon kung saan sa "Program Memory" upang ilagay ang susunod na pahayag. Habang nagpapatupad ang iyong programa, naglalaman ang "Program Counter" (na binago bilang PC) ang address ng kasalukuyang linya na naisakatuparan. Kaya sa kasong ito kapag ang PC ay nasa 0x0000 makikita nito ang utos na "jmp Reset" na nakatira sa lokasyon ng memorya na iyon. Ang dahilan kung bakit nais naming ilagay ang jmp Reset sa lokasyon na iyon ay dahil kapag nagsimula ang programa, o ang chip ay na-reset, nagsisimula ang PC sa pagpapatupad ng code sa lugar na ito. Kaya, tulad ng nakikita natin, sinabi lamang sa atin na agad na "tumalon" sa seksyon na may label na "I-reset". Bakit natin nagawa iyon? Nangangahulugan iyon na ang huling dalawang linya sa itaas ay nilalaktawan lamang! Bakit?

Sa gayon ay doon nakakainteres ang mga bagay. Kailangan mong buksan ngayon ang isang manonood ng pdf na may buong ATmega328p datasheet na itinuro ko sa unang pahina ng tutorial na ito (iyon ang dahilan kung bakit ito ang item 4 sa seksyong "kakailanganin mo"). Kung ang iyong screen ay masyadong maliit, o mayroon kang masyadong maraming mga bintana na bukas (tulad ng kaso sa akin) maaari mong gawin ang ginagawa ko at ilagay ito sa isang Ereader, o sa iyong Android phone. Gagamitin mo ito palagi kung balak mong magsulat ng code ng pagpupulong. Ang cool na bagay ay ang lahat ng mga microcontoller ay nakaayos sa halos magkatulad na mga paraan at sa gayon sa sandaling masanay ka sa pagbabasa ng mga datasheet at pag-coding mula sa kanila ay mahahanap mo itong halos walang halaga na gawin ang pareho para sa isang iba't ibang microcontroller. Sa gayon ay natututo talaga kami kung paano gamitin ang lahat ng mga microcontroller sa isang kahulugan at hindi lamang ang atmega328p.

Okay, buksan ang pahina 18 sa datasheet at tingnan ang Larawan 8-2.

Ganito naka-set up ang Memory ng Program sa microcontroller. Maaari mong makita na nagsisimula ito sa address na 0x0000 at pinaghiwalay sa dalawang seksyon; isang seksyon ng flash ng application at isang seksyon ng flash ng boot. Kung sumangguni ka nang maikli sa pahina 277 talahanayan 27-14 makikita mo na ang seksyon ng flash ng application ay tumatagal ng mga lokasyon mula 0x0000 hanggang 0x37FF at ang seksyon ng boot flash ay tumatagal ng natitirang mga lokasyon mula 0x3800 hanggang 0x3FFF.

Pagsasanay 1: Ilan ang mga lokasyon doon sa memorya ng Program? I.e. i-convert ang 3FFF sa decimal at magdagdag ng 1 dahil nagsimula kaming magbilang sa 0. Dahil ang bawat lokasyon ng memorya ay 16 bits (o 2 bytes) ang lapad ano ang kabuuang bilang ng mga byte ng memorya? Ngayon i-convert ito sa kilobytes, naaalala na mayroong 2 ^ 10 = 1024 bytes sa isang kilobyte. Ang seksyon ng boot flash ay napupunta sa 0x3800 hanggang 0x37FF, gaano karaming kilobytes ito? Ilan sa mga kilobytes ng memorya ang natitira para magamit namin upang maiimbak ang aming programa? Sa madaling salita, gaano kalaki ang ating programa? Panghuli, kung gaano karaming mga linya ng code ang maaari nating makuha?

O sige, ngayong alam na natin ang lahat tungkol sa pag-aayos ng memorya ng flash program, ipagpatuloy natin ang ating talakayan sa mga pahayag ng.org. Nakita namin na ang unang lokasyon ng memorya na 0x0000 ay naglalaman ng aming tagubilin na tumalon sa aming seksyon na may label kaming Reset. Ngayon nakikita natin kung ano ang ginagawa ng pahayag na ".org 0x0020". Sinasabi nito na nais namin ang tagubilin sa susunod na linya na mailagay sa lokasyon ng memorya na 0x0020. Ang tagubilin na inilagay namin doon ay isang pagtalon sa isang seksyon sa aming code na may label kaming "overflow_handler" … ngayon bakit namin hiniling na ang paglukso na ito ay mailagay sa lokasyon ng memorya na 0x0020? Upang malaman, babaling kami sa pahina 65 sa datasheet at tingnan ang Talahanayan 12-6.

Ang Talaan 12-6 ay isang talahanayan ng "I-reset at Makagambala Mga Vector" at ipinapakita nito nang eksakto kung saan pupunta ang PC kapag nakatanggap ito ng isang "makagambala". Halimbawa, kung titingnan mo ang numero ng Vector 1. Ang "mapagkukunan" ng makagambala ay "RESET" na tinukoy bilang "External Pin, Power-on Reset, Brown-out Reset, at Watchdog system reset" ibig sabihin, kung alinman sa ang mga bagay na nangyari sa aming microcontroller, magsisimula ang PC sa pagpapatupad ng aming programa sa lokasyon ng memorya ng programa na 0x0000. Kumusta naman ang direktiba ng.org natin noon? Sa gayon, naglagay kami ng isang utos sa lokasyon ng memorya na 0x0020 at kung titingnan mo ang talahanayan makikita mo na kung ang isang Timer / Counter0 overflow ay nangyayari (nagmumula sa TIMER0 OVF) ay isasagawa nito ang anumang nasa lokasyon 0x0020. Kaya't tuwing nangyari iyon, ang PC ay tatalon sa lugar na may label naming "overflow_handler". Cool diba Makikita mo sa isang minuto kung bakit natin ito nagawa, ngunit tapusin muna natin ang hakbang na ito ng tutorial nang isang tabi.

Kung nais naming gawing mas maayos at malinis ang aming code dapat talaga nating palitan ang 4 na linya na kasalukuyang tinatalakay namin sa mga sumusunod (tingnan ang pahina 66):

.org 0x0000

rjmp I-reset; PC = 0x0000 reti; PC = 0x0002 reti; PC = 0x0004 reti; PC = 0x0006 reti; PC = 0x0008 reti; PC = 0x000A… reti; PC = 0x001E jmp overflow_handler: PC = 0x0020 reti: PC = 0x0022… reti; PC = 0x0030 reti; PC = 0x0032

Kaya't kung nangyari ang isang pagkakagambala ay "reti" lamang na nangangahulugang "bumalik mula sa abala" at wala nang iba pang mangyayari. Ngunit kung hindi namin "Pinapagana" ang iba't ibang mga pagkagambala, kung gayon hindi ito gagamitin at maaari naming mailagay ang code ng programa sa mga spot na ito. Sa aming kasalukuyang "blink.asm" na programa ay paganahin lamang namin ang timer0 overflow na makagambala (at syempre ang pag-reset ay nakakagambala na palaging pinagana) at sa gayon hindi kami makagambala sa iba pa.

Paano namin "pagaganahin" ang pag-overflow ng timer0 pagkatapos nito? … iyon ang paksa ng aming susunod na hakbang sa tutorial na ito.

Hakbang 5: Timer / Counter 0

Timer / Counter 0
Timer / Counter 0

Tingnan ang larawan sa itaas. Ito ang proseso ng paggawa ng desisyon ng "PC" kapag ang ilang impluwensya sa labas ay "nakakagambala" sa daloy ng aming programa. Ang unang bagay na ginagawa nito kapag nakakakuha ito ng isang senyas mula sa labas na naganap ang isang nakakagambala ay suriin upang malaman kung naitakda namin ang "makagambala paganahin" ang bit para sa uri ng paggambala. Kung wala pa kami, nagpapatuloy lamang ito sa pagpapatupad ng aming susunod na linya ng code. Kung naitakda namin ang partikular na makagambala na paganahin ang bit (upang mayroong isang 1 sa lokasyon ng bit na iyon sa halip na isang 0) susuriin nito kung pinagana natin o hindi ang "mga pandaigdigang pagkagambala", kung hindi ay muli itong pupunta sa susunod na linya ng code at magpatuloy. Kung pinagana din namin ang mga pandaigdigang pagkagambala, pagkatapos ay pupunta ito sa lokasyon ng memorya ng Program ng ganitong uri ng nakakagambala (tulad ng ipinakita sa Talahanayan 12-6) at isagawa ang anumang utos na inilagay namin doon. Kaya't tingnan natin kung paano natin ipinatupad ang lahat ng ito sa aming code.

Ang seksyon ng I-reset ang may label na aming code ay nagsisimula sa mga sumusunod na dalawang linya:

I-reset:

ldi temp, 0b00000101 out TCCR0B, temp

Tulad ng alam na natin, naglo-load ito sa temp (ibig sabihin, R16) ang bilang na sumusunod kaagad, na kung saan ay 0b00000101. Pagkatapos ay isinusulat nito ang bilang na ito sa rehistro na tinatawag na TCCR0B gamit ang "out" na utos. Ano ang rehistro na ito? Kaya, magtungo tayo sa pahina 614 ng datasheet. Nasa gitna ito ng isang mesa na nagbubuod sa lahat ng mga rehistro. Sa address na 0x25 makikita mo ang TCCR0B. (Ngayon alam mo kung saan nagmula ang linya na "out 0x25, r16" sa aking hindi nai-komentong bersyon ng code). Nakita namin sa pamamagitan ng segment ng code sa itaas na naitakda namin ang ika-0 na bit at ang ika-2 bit at na-clear ang lahat ng natitira. Sa pamamagitan ng pagtingin sa talahanayan maaari mong makita na nangangahulugan ito na naitakda namin ang CS00 at CS02. Hinahayaan ngayon ang magtungo sa kabanata sa datasheet na tinatawag na "8-bit Timer / Counter0 na may PWM". Sa partikular, pumunta sa pahina 107 ng kabanatang iyon. Makikita mo ang parehong paglalarawan ng rehistro ng "Timer / Counter Control Rehistro B" (TCCR0B) na nakita lamang namin sa talahanayan ng buod ng rehistro (kaya maaari kaming dumiretso dito, ngunit nais kong makita mo kung paano gamitin ang mga talahanayan ng buod para sa sanggunian sa hinaharap). Ang datasheet ay patuloy na nagbibigay ng isang paglalarawan ng bawat isa sa mga piraso sa rehistro na iyon at kung ano ang ginagawa nila. Palalampasin namin ang lahat ng iyon sa ngayon at iikot ang pahina sa Talahanayan 15-9. Ipinapakita ng talahanayan na ito ang "Clock Select Bit Description". Tingnan ngayon ang talahanayan na iyon hanggang sa makita mo ang linya na tumutugma sa mga piraso na itinakda lamang namin sa rehistro na iyon. Sinasabi ng linya na "clk / 1024 (mula sa prescaler)". Ang ibig sabihin nito ay nais naming mag-tick ang Timer / Counter0 (TCNT0) sa isang rate na ang dalas ng CPU ay hinati ng 1024. Dahil mayroon kaming aming microcontroller na pinakain ng isang 16MHz crystal oscillator nangangahulugan ito na ang rate na isinasagawa ng aming CPU ang mga tagubilin ay 16 milyong tagubilin bawat segundo. Kaya't ang rate na kikilitiin ng aming counter ng TCNT0 ay pagkatapos ay 16 milyon / 1024 = 15625 beses bawat segundo (subukan ito sa iba't ibang mga piniling orasan at tingnan kung ano ang nangyayari - tandaan ang aming pilosopiya?). Panatilihin natin ang numero 15625 sa likod ng ating isipan para sa paglaon at magpatuloy sa susunod na dalawang linya ng code:

ldi temp, 0b00000001

sts TIMSK0, temp

Itinatakda nito ang ika-0 piraso ng isang rehistro na tinatawag na TIMSK0 at nililimas ang lahat ng natitira. Kung titingnan mo ang pahina 109 sa datasheet makikita mo na ang TIMSK0 ay nangangahulugang "Timer / Counter Interrupt Mask register 0" at itinakda ng aming code ang 0th bit na pinangalanang TOIE0 na nangangahulugang "Timer / Counter0 Overflow Interrupt Enable" … Ayan! Ngayon nakikita mo kung ano ang tungkol dito. Mayroon kaming "makagambala paganahin ang bit set" na nais namin mula sa unang desisyon sa aming larawan sa itaas. Kaya ngayon ang kailangan lang nating gawin ay paganahin ang "mga pandaigdigang pagkagambala" at ang aming programa ay magagawang tumugon sa ganitong uri ng mga pagkagambala. Papaganahin namin ang mga pandaigdigang pagkagambala sa ilang sandali, ngunit bago namin ito gawin ay maaaring nalito ka sa isang bagay.. bakit ano ba ginamit ko ang utos na "sts" upang kopyahin sa pagrehistro ng TIMSK0 sa halip na ang karaniwang "labas"?

Tuwing nakikita mo akong gumagamit ng isang tagubilin na hindi mo pa nakikita bago ang unang bagay na dapat mong gawin ay lumipat sa pahina 616 sa datasheet. Ito ang "Buod ng Pagtakda ng Pagtuturo". Ngayon hanapin ang tagubilin na "STS" na siyang ginamit ko. Sinasabi na tumatagal ito ng isang numero mula sa isang R register (ginamit namin ang R16) at "Store derekta sa SRAM" na lokasyon k (sa aming kaso na ibinigay ng TIMSK0). Kaya bakit kailangan naming gumamit ng "sts" na tumatagal ng 2 cycle ng orasan (tingnan ang huling haligi sa talahanayan) upang maiimbak sa TIMSK0 at kailangan lang namin ng "out", na tumatagal lamang ng isang cycle ng orasan, upang maiimbak sa TCCR0B dati? Upang sagutin ang katanungang ito kailangan naming bumalik sa aming talahanayan ng buod ng rehistro sa pahina 614. Nakita mo na ang rehistro ng TCCR0B ay nasa address na 0x25 ngunit sa (0x45) din di ba? Nangangahulugan ito na ito ay isang rehistro sa SRAM, ngunit ito rin ay isang tiyak na uri ng rehistro na tinatawag na "port" (o i / o rehistro). Kung titingnan mo ang talahanayan ng buod ng tagubilin sa tabi ng utos na "out" makikita mo na tumatagal ng mga halaga mula sa "mga gumaganang rehistro" tulad ng R16 at ipinapadala ang mga ito sa isang PORT. Kaya maaari naming gamitin ang "out" kapag sumusulat sa TCCR0B at i-save ang ating sarili ng isang cycle ng orasan. Ngunit ngayon tingnan ang TIMSK0 sa rehistro ng talahanayan. Makikita mo na mayroon itong address na 0x6e. Nasa labas ito ng saklaw ng mga port (na kung saan ay ang unang mga lokasyon lamang ng 0x3F ng SRAM) at sa gayon kailangan mong bumalik sa paggamit ng utos ng sts at pagkuha ng dalawang siklo ng orasan ng CPU upang magawa ito. Mangyaring basahin ang Tandaan 4 sa pagtatapos ng talahanayan ng buod ng tagubilin sa pahina 615 ngayon din. Pansinin din na ang lahat ng aming mga input at output port, tulad ng PORTD ay matatagpuan sa ilalim ng talahanayan. Halimbawa, ang PD4 ay medyo 4 sa address na 0x0b (ngayon nakikita mo kung saan nagmula ang lahat ng mga bagay na 0x0b sa aking hindi nai-komentong code!).. okay, mabilis na tanong: binago mo ba ang "sts" upang "lumabas" at tingnan kung ano nangyayari Tandaan ang aming pilosopiya! basagin mo! huwag lamang gawin ang aking salita para sa mga bagay.

Okay, bago tayo magpatuloy, buksan ang pahina 19 sa datasheet nang isang minuto. Nakikita mo ang isang larawan ng memorya ng data (SRAM). Ang unang 32 rehistro sa SRAM (mula 0x0000 hanggang 0x001F) ay ang "pangkalahatang layunin na mga rehistro sa pagtatrabaho" R0 hanggang sa R31 na ginagamit namin sa lahat ng oras bilang mga variable sa aming code. Ang susunod na 64 na rehistro ay ang mga port ng I / O hanggang sa 0x005f (ibig sabihin, ang mga pinag-uusapan natin na mayroong mga hindi naka-braket na address sa tabi nila sa talahanayan ng rehistro na maaari naming gamitin ang "out" na utos sa halip na "sts") Sa wakas ang susunod na seksyon ng SRAM ay naglalaman ng lahat ng iba pang mga pagrehistro sa talahanayan ng buod hanggang sa matugunan ang 0x00FF, at sa wakas ang natitira ay panloob na SRAM. Ngayon mabilis, lumipat tayo sa pahina 12 para sa isang segundo. Makikita mo doon ang isang talahanayan ng "mga pangkalahatang layunin na gumaganang rehistro" na palagi naming ginagamit bilang aming mga variable. Nakita mo ang makapal na linya sa pagitan ng mga numero na R0 hanggang R15 at pagkatapos ay R16 hanggang R31? Ang linyang iyon ang dahilan kung bakit palagi naming ginagamit ang R16 bilang pinakamaliit at makakasama ko ito nang kaunti pa sa susunod na tutorial kung saan kakailanganin din namin ang tatlong 16-bit na hindi direktang mga rehistro ng address, X, Y, at Z. Hindi ko makapunta sa na lamang kahit na dahil hindi namin ito kailangan ngayon at nakakakuha kami ng sapat na bogged dito.

I-flip pabalik ang isang pahina sa pahina 11 ng datasheet. Makakakita ka ng isang diagram ng magparehistro ng SREG sa kanang itaas? Nakikita mo na ang bit 7 ng rehistro na iyon ay tinatawag na "I". Bumaba ngayon sa pahina at basahin ang paglalarawan ng Bit 7 …. ah! Ito ang Global Interrupt Enable bit. Iyon ang kailangan nating itakda upang makapasa sa pangalawang desisyon sa aming diagram sa itaas at payagan ang mga pag-overflow ng timer / counter sa aming programa. Kaya't ang susunod na linya ng aming programa ay dapat basahin:

sbi SREG, ako

na nagtatakda ng bahaging tinatawag na "I" sa SREG register. Gayunpaman, sa halip na ito ay ginamit namin ang tagubilin

sei

sa halip Ang bit na ito ay itinakda nang madalas sa mga programa na gumawa lamang sila ng isang mas simpleng paraan upang magawa ito.

Sige! Nakatanggap na namin ang mga overflow interrupts na handa nang puntahan upang ang aming "jmp overflow_handler" ay papatayin sa tuwing may mangyari.

Bago tayo magpatuloy, tingnan ang mabilis sa rehistro ng SREG (Pagrehistro sa Katayuan) sapagkat ito ay napakahalaga. Basahin kung ano ang kinakatawan ng bawat isa sa mga watawat. Sa partikular, marami sa mga tagubiling ginagamit namin ay magtatakda at suriin ang mga watawat na ito sa lahat ng oras. Halimbawa, sa paglaon ay gumagamit kami ng utos na "CPI" na nangangahulugang "ihambing kaagad". Tingnan ang talahanayan ng buod ng tagubilin para sa tagubiling ito at pansinin kung gaano karaming mga flag ang itinatakda nito sa haligi ng "mga flag". Ang lahat ng ito ay mga watawat sa SREG at itatakda ng aming code ang mga ito at patuloy na suriin ang mga ito. Makikita mo ang ilang mga halimbawa sa ilang sandali. Sa wakas ang huling piraso ng seksyon na ito ng code ay:

clr temp

palabas sa TCNT0, temp sbi DDRD, 4

Ang huling linya dito ay medyo halata. Itinatakda lamang nito ang ika-4 na bit ng Data Direction Register para sa PortD na nagdudulot sa PD4 na maging OUTPUT.

Itinakda ng una ang variable temp sa zero at pagkatapos ay kopyahin iyon sa rehistro ng TCNT0. Ang TCNT0 ang aming Timer / Counter0. Itinakda ito sa zero. Sa sandaling ipatupad ng PC ang linyang ito ang timer0 ay magsisimula sa zero at bibilangin sa rate na 15625 beses bawat segundo. Ang problema ay ito: Ang TCNT0 ay isang "8-bit" na rehistro di ba? Kaya't ano ang pinakamalaking bilang na maaaring hawakan ng isang 8-bit na rehistro? Well 0b11111111 ito ba. Ito ang bilang na 0xFF. Alin ang 255. Kaya't nakikita mo kung anong nangyayari? Ang timer ay zipping kasama ang pagtaas ng 15625 beses sa isang segundo at sa tuwing umabot sa 255 ito ay "umaapaw" at babalik sa 0 ulit. Sa parehong oras na bumalik ito sa zero nagpapadala ito ng isang Timer Overflow Interrupt signal. Nakukuha ito ng PC at alam mo kung ano ang ginagawa nito ngayon di ba? Yep Pumunta ito sa lokasyon ng Memory ng Program na 0x0020 at isinasagawa ang tagubiling matatagpuan dito.

Malaki! Kung kasama mo pa rin ako pagkatapos ay isa kang walang pagod na superhero! Magpatuloy tayo…

Hakbang 6: Overler Handler

Kaya't ipagpalagay natin na ang pagrehistro ng timer / counter0 ay umapaw lamang. Alam namin ngayon na ang programa ay tumatanggap ng isang nakakagambala signal at nagpapatupad ng 0x0020 na nagsasabi sa Program Counter, PC na tumalon sa label na "overflow_handler" ang sumusunod ay ang code na isinulat namin pagkatapos ng label na iyon:

overflow_handler:

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

Ang unang bagay na ginagawa nito ay ang pagtaas ng variable na "overflows" (na kung saan ay ang aming pangalan para sa pangkalahatang layunin na nagtatrabaho rehistro R17) pagkatapos ay "pinaghahambing" ang mga nilalaman ng mga umaapaw sa numero 61. Ang paraan na gumagana ang tagubilin cpi ay simpleng bumabawas ang dalawang numero at kung ang resulta ay zero itinatakda nito ang Z flag sa rehistro ng SREG (Sinabi ko sa iyo na makikita namin ang rehistro na ito sa lahat ng oras). Kung ang dalawang numero ay pantay-pantay pagkatapos ay ang Z flag ay magiging isang 1, kung ang dalawang numero ay hindi pantay pagkatapos ito ay magiging isang 0.

Ang susunod na linya ay nagsasabing "brne PC + 2" na nangangahulugang "sangay kung hindi pantay". Mahalaga, sinusuri nito ang flag ng Z sa SREG at kung HINDI ito isang (ibig sabihin, ang dalawang numero ay hindi pantay, kung pantay sila, maitatakda ang zero flag) ang mga sangay ng PC sa PC + 2, ibig sabihin ay lalaktaw ito sa susunod linya at dumidiretso sa "reti" na bumalik mula sa makagambala sa anumang lugar na ito ay nasa code nang dumating ang abala. Kung ang tagubilin ng brne ay natagpuan ang isang 1 sa zero flag bit hindi ito magsasanga at sa halip ay magpapatuloy lamang ito sa susunod na linya na kung saan ay clr overflows i-reset ito sa 0.

Ano ang net resulta ng lahat ng ito?

Kaya nakikita natin na sa tuwing mayroong timer overflow ang handler na ito ay nagdaragdag ng halaga ng "overflows" ng isa. Kaya't ang variable na "overflows" ay binibilang ang bilang ng mga overflows sa nangyari. Kailan man umabot ang numero sa 61 i-reset namin ito sa zero.

Ngayon bakit sa mundo natin ito gagawin?

Tingnan natin. Alalahanin na ang aming bilis ng orasan para sa aming CPU ay 16MHz at "prescaled" namin ito gamit ang TCCR0B upang ang timer ay bibilangin lamang sa rate na 15625 na bilang bawat segundo di ba? At sa tuwing umabot ang timer sa bilang ng 255 umaapaw ito. Kaya't nangangahulugan ito na umaapaw ito ng 15625/256 = 61.04 beses bawat segundo. Sinusubaybayan namin ang bilang ng mga overflow sa aming variable na "overflows" at inihahambing namin ang numerong iyon sa 61. Kaya nakikita namin na ang "overflows" ay katumbas ng 61 minsan bawat segundo! Kaya ire-reset ng aming handler ang "overflows" sa zero minsan bawat segundo. Kaya't kung susubaybayan lamang namin ang variable na "overflows" at tandaan ang bawat oras na ito ay nagre-reset sa zero ay bibibilang namin ang segundo bawat segundo sa real time (Tandaan na sa susunod na tutorial ipapakita namin kung paano makakuha ng isang mas eksaktong antala sa milliseconds sa parehong paraan na gumagana ang routine na "pagkaantala" ng Arduino).

Ngayon ay "napangasiwaan" namin ang timer overflow na nakakagambala. Tiyaking naiintindihan mo kung paano ito gumagana at pagkatapos ay magpatuloy sa susunod na hakbang kung saan ginagamit namin ang katotohanang ito.

Hakbang 7: Pagkaantala

Ngayon na nakita namin na ang aming timer overflow makagambala handler na "overflow_handler" na gawain ay itatakda ang variable na "overflows" sa zero isang beses bawat segundo maaari naming gamitin ang katotohanang ito upang mag-disenyo ng isang "pagkaantala" subroutine.

Tingnan ang sumusunod na code mula sa ilalim ng aming pagkaantala: label

antala:

umaapaw ang clr sa sec_count: umaapaw ang cpi, 30 brne sec_count ret

Tatawagan namin ang subroutine na ito sa tuwing kailangan namin ng pagkaantala sa aming programa. Ang paraan ng paggana nito ay itinakda muna nito ang variable na "umaapaw" sa zero. Pagkatapos ay pumapasok ito sa isang lugar na may label na "sec_count" at ihinahambing ang mga umaapaw sa 30, kung hindi sila katumbas ay bumalik ito sa label na sec_count at ihinahambing muli, at muli, atbp hanggang sa wakas na pantay sila (tandaan na sa buong oras na ito ay pupunta sa aming timer na nakakagambala ng timer ay patuloy na nadagdagan ang variable na umaapaw at sa gayon ay nagbabago sa bawat oras na lumilibot tayo dito. Kapag ang umaapaw sa wakas ay katumbas ng 30 ay lumalabas ito mula sa loop at babalik sa kung saan man tayo tumawag na pagkaantala: mula. Ang net na resulta ay isang pagkaantala ng 1/2 segundo

Pagsasanay 2: Palitan ang gawain ng overflow_handler sa mga sumusunod:

overflow_handler:

inc overflows reti

at patakbuhin ang programa. May naiiba ba? Bakit o bakit hindi?

Hakbang 8: Blink

Sa wakas tingnan natin ang nakagawian na gawain:

kumurap:

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

Una naming binuksan ang PD4, pagkatapos ay i-rcall namin ang aming pagkaantala subroutine. Gumagamit kami ng rcall upang kapag nakuha ng PC ang isang "ret" na pahayag ay babalik ito sa linya na sumusunod sa rcall. Pagkatapos ang pagkaantala ng regular na pagkaantala para sa 30 na bilang sa variable ng overflow tulad ng nakita natin at ito ay halos eksaktong 1/2 segundo, pagkatapos ay patayin namin ang PD4, antalahin ang isa pang 1/2 na segundo, at pagkatapos ay bumalik muli sa simula.

Ang netong resulta ay isang kumukurap na LED!

Sa palagay ko ay sasang-ayon ka na ngayon na ang "blink" ay marahil ay hindi ang pinakamahusay na "hello world" na programa sa wika ng pagpupulong.

Exercise 3: Palitan ang iba't ibang mga parameter sa programa upang ang LED ay kumurap sa iba't ibang mga rate tulad ng isang segundo o 4 na beses sa isang segundo, atbp. Pagsasanay 4: Palitan ito upang ang LED ay naka-on at naka-off para sa iba't ibang dami ng oras. Halimbawa sa para sa 1/4 segundo at pagkatapos ay off para sa 2 segundo o isang bagay tulad nito. Pagsasanay 5: Palitan ang TCCR0B na orasan pumili ng mga piraso sa 100 at pagkatapos ay ipagpatuloy ang pagtaas ng talahanayan. Sa anong punto ito nagiging hindi makilala mula sa aming "hello.asm" na programa mula sa tutorial 1? Exercise 6 (opsyonal): Kung mayroon kang ibang kristal oscillator, tulad ng isang 4 MHz o isang 13.5 MHz o anupaman, baguhin ang iyong 16 MHz oscillator sa iyong breadboard para sa bago at tingnan kung paano ito nakakaapekto sa blinking rate ng LED. Dapat mo na ngayong dumaan sa tumpak na pagkalkula at hulaan nang eksakto kung paano ito makakaapekto sa rate.

Hakbang 9: Konklusyon

Para sa iyo na mga hard-hard na nakarating dito, Binabati kita!

Napagtanto kong napakahirap ng pag-slog kapag gumagawa ka ng higit na pagbabasa at pagtingala kaysa sa iyong mga kable at eksperimento ngunit inaasahan kong natutunan mo ang mga sumusunod na mahahalagang bagay:

  1. Paano gumagana ang Memory ng Program
  2. Paano gumagana ang SRAM
  3. Paano maghanap ng mga rehistro
  4. Paano maghanap ng mga tagubilin at malaman kung ano ang ginagawa nila
  5. Paano ipatupad ang mga nakakagambala
  6. Paano ipinatutupad ng CP ang code, kung paano gumagana ang SREG, at kung ano ang nangyayari habang nagagambala
  7. Paano gumawa ng mga loop at jumps at bounce sa paligid ng code
  8. Gaano kahalaga na basahin ang datasheet!
  9. Paano nalaman mo kung paano gawin ang lahat ng ito para sa Atmega328p microcontroller ay magiging isang kamag-anak na paglalakad ng cake upang malaman ang anumang mga bagong tagakontrol na interesado ka.
  10. Paano baguhin ang oras ng CPU sa real time at gamitin ito sa mga pagkaantala sa gawain.

Ngayon na mayroon kaming maraming teorya sa labas ng paraan na nakakasulat kami ng mas mahusay na code at makontrol ang mas kumplikadong mga bagay. Kaya't ang susunod na tutorial na gagawin lamang namin. Buuin namin ang isang mas kumplikado, mas kawili-wiling, circuit at kontrolin ito sa mga nakakatuwang paraan.

Exercise 7: "Masira" ang code sa iba't ibang paraan at makita kung ano ang mangyayari! Scientific curiousity baby! Ang ibang tao ay maaaring maghugas ng pinggan di ba? Exercise 8: Ipunin ang code gamit ang pagpipiliang "-l" upang makabuo ng isang file ng listahan. I.e. "avra -l blink.lst blink.asm" at tingnan ang file ng listahan. Dagdag na Kredito: Ang code na hindi nagkomento na ibinigay ko sa simula at ang nagkomento na code na tinatalakay namin sa paglaon ay magkakaiba! Mayroong isang linya ng code na naiiba. Mahahanap mo ba ito Bakit hindi mahalaga ang pagkakaiba na iyon?

Sana masaya ka! Kita mo sa susunod …

Inirerekumendang: