Përmbajtje:

Tutoriali i AVR Assembler 2: 4 Hapa
Tutoriali i AVR Assembler 2: 4 Hapa

Video: Tutoriali i AVR Assembler 2: 4 Hapa

Video: Tutoriali i AVR Assembler 2: 4 Hapa
Video: Лекция 4. Архитектура AVR. Ассемблер 2024, Korrik
Anonim
Tutoriali i AVR Assembler 2
Tutoriali i AVR Assembler 2

Ky tutorial është një vazhdim i "AVR Assembler Tutorial 1"

Nëse nuk e keni kaluar Tutorial 1, duhet të ndaloni tani dhe ta bëni atë së pari.

Në këtë tutorial ne do të vazhdojmë studimin tonë të programimit të gjuhës së asamblesë të atmega328p të përdorur në Arduino's.

Do t'ju duhet:

  1. një Arduino me dërrasa buke ose thjesht një Arduino normale si në Tutorial 1
  2. një LED
  3. një rezistencë 220 ohm
  4. një buton shtypës
  5. telat lidhës për të bërë qarkun në tabelën tuaj të bukës
  6. Manuali i Setit të Instuksioneve: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. Fleta e të dhënave: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…

Koleksioni i plotë i mësimeve të mia mund të gjendet këtu:

Hapi 1: Ndërtimi i qarkut

Ndërtimi i qarkut
Ndërtimi i qarkut

Së pari ju duhet të ndërtoni qarkun që ne do të studiojmë në këtë tutorial.

Këtu është mënyra se si lidhet:

PB0 (pin dixhital 8) - LED - R (220 ohm) - 5V

PD0 (kunja dixhitale 0) - butoni - GND

Ju mund të kontrolloni që LED juaj është i orientuar siç duhet duke e lidhur atë me GND në vend të PB0. Nëse asgjë nuk ndodh atëherë kthejeni orientimin dhe drita duhet të ndizet. Pastaj lidheni përsëri me PB0 dhe vazhdoni. Fotografia tregon se si është lidhur arduino ime e bukës.

Hapi 2: Shkrimi i Kodit të Kuvendit

Shkrimi i Kodit të Kuvendit
Shkrimi i Kodit të Kuvendit

Shkruani kodin e mëposhtëm në një skedar teksti të quajtur pushbutton.asm dhe përpilojeni atë me avra siç bëtë në Tutorial 1.

Vini re se në këtë kod kemi shumë komente. Sa herë që montuesi sheh një pikëpresje, ai do të kalojë pjesën tjetër të rreshtit dhe do të kalojë në rreshtin tjetër. Practiceshtë praktikë e mirë programimi (veçanërisht në gjuhën e asamblesë!) Të komentosh shumë kodin tënd, në mënyrë që kur të kthehesh tek ai në të ardhmen të dish se çfarë po bëje. Unë do të komentoj shumë gjëra në mësimet e para, në mënyrë që të dimë saktësisht se çfarë po ndodh dhe pse. Më vonë, sapo të bëhemi pak më të mirë në kodimin e asamblesë, unë do t'i komentoj gjërat në më pak detaje.

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

; shkruar nga: 1o_o7; data: 23 tetor 2014; *********************************

.nolist

.përfshi "m328Pdef.inc".list.def temp = r16; caktoni regjistrin e punës r16 si temp rjmp Init; rreshti i parë i ekzekutuar

Fillo:

ser temp; vendosni të gjitha bitët në temp në 1. jashtë DDRB, temp; duke vendosur pak si 1 në Drejtimin e të Dhënave I/O; regjistrohuni për PortB, e cila është DDRB, e vendos atë; pin si dalje, një 0 do ta caktonte atë pin si hyrje; kështu që këtu, të gjitha kunjat e PortB janë dalje (të vendosura në 1) ldi temp, 0b11111110; ngarkoni numrin "e menjëhershëm" në regjistrin temp; nëse do të ishte vetëm ld atëherë argumenti i dytë; do të duhej të ishte një vendndodhje e kujtesës në vend të DDRD, temp; mv temp në DDRD, rezultati është që PD0 është input; dhe pjesa tjetër janë dalje clr temp; të gjitha bitët në temp janë vendosur në 0 nga PortB, temp; vendosni të gjitha bitët (domethënë kunjat) në PortB në 0V ldi temp, 0b00000001; ngarkoni numrin e menjëhershëm në temp out PortD, temp; kaloni temp në PortD. PD0 ka një rezistencë tërheqëse; (dmth. i vendosur në 5V) pasi ka një 1 në atë bit; pjesa tjetër janë 0V që nga 0.

Kryesore:

në temp, PinD; PinD mban gjendjen e PortD, kopjoni këtë në temp; nëse butoni është i lidhur me PD0 kjo do të jetë; 0 kur shtypet butoni, 1 ndryshe që kur; PD0 ka një rezistencë tërheqëse është normalisht në 5V jashtë PortB, temp; dërgon 0 dhe 1 të lexuara më lart në PortB; kjo do të thotë që ne duam LED të lidhur me PB0,; kur PD0 është LOW, e vendos PB0 në LOW dhe kthehet; në LED (pasi ana tjetër e LED është; e lidhur me 5V dhe kjo do të vendosë PB0 në 0V kështu; rryma do të rrjedhë) rjmp Main; kthehet në fillimin e Main

Vini re se këtë herë ne jo vetëm që kemi shumë komente të tjera në kodin tonë, por gjithashtu kemi një seksion me titull i cili jep disa informacione se kush e ka shkruar dhe kur është shkruar. Pjesa tjetër e kodit është gjithashtu e ndarë në seksione.

Pasi të keni përpiluar kodin e mësipërm, duhet ta ngarkoni atë në mikrokontrollues dhe të shihni se funksionon. LED duhet të ndizet ndërsa shtypni butonin dhe pastaj fiket përsëri kur e lini të shkojë. Unë kam treguar se si duket në foto.

Hapi 3: Analiza rresht pas rreshti e Kodit

Unë do të anashkaloj linjat që janë thjesht komente pasi qëllimi i tyre është i qartë.

.nolist

.përfshi "m328Pdef.inc".listë

Këto tre rreshta përfshijnë skedarin që përmban përkufizimet e Regjistrit dhe Bit për ATmega328P që ne po programojmë. Komanda.nolist i thotë montuesit të mos e përfshijë këtë skedar në skedarin pushbutton.lst që prodhon kur e montoni. Fik opsionin e listimit. Pas përfshirjes së skedarit ne e kthejmë përsëri opsionin e listimit me komandën.list. Arsyeja pse e bëjmë këtë është sepse skedari m328Pdef.inc është mjaft i gjatë dhe nuk kemi nevojë ta shohim në skedarin e listës. Montuesi ynë, avra, nuk gjeneron automatikisht një skedar liste dhe nëse do të donim një të tillë, do të mblidheshim duke përdorur komandën e mëposhtme:

avra -l shtytës.lst buton.asm

Nëse e bëni këtë do të krijojë një skedar të quajtur pushbutton.lst dhe nëse e ekzaminoni këtë skedar do të gjeni se ai tregon kodin tuaj të programit së bashku me informacion shtesë. Nëse shikoni informacionin shtesë do të shihni se linjat fillojnë me një C: e ndjekur nga adresa relative në gjashtëkëndëshin e vendit ku kodi është vendosur në kujtesë. Në thelb fillon në 000000 me komandën e parë dhe rritet prej andej me secilën komandë pasuese. Kolona e dytë pas vendit relativ në memorje është kodi gjashtëkëndësh për komandën i ndjekur nga kodi gjashtëkëndësh për argumentin e komandës. Ne do të diskutojmë skedarët e listave më tej në mësimet e ardhshme.

.def temp = r16; caktoni regjistrin e punës r16 si temp

Në këtë linjë ne përdorim direktivën assembler ".def" për të përcaktuar ndryshoren "temp" si të barabartë me r16 "regjistrin e punës". Ne do të përdorim regjistrin r16 si ai që ruan numrat që duam të kopjojmë në porte dhe regjistra të ndryshëm (të cilët nuk mund të shkruhen direkt).

Ushtrimi 1: Mundohuni të kopjoni një numër binar direkt në një port ose regjistër special si DDRB dhe shihni se çfarë ndodh kur përpiqeni të mblidhni kodin.

Një regjistër përmban një bajt (8 bit) informacion. Në thelb është zakonisht një koleksion i SR-Latches secila prej tyre është një "bit" dhe përmban një 1 ose 0. Ne mund ta diskutojmë këtë (dhe madje të ndërtojmë një!) Më vonë në këtë seri. Ju mund të pyesni se çfarë është një "regjistër pune" dhe pse ne zgjodhëm r16. Ne do ta diskutojmë atë në një tutorial të ardhshëm kur të zhyteni në moçalin e brendshëm të çipit. Tani për tani unë dua që ju të kuptoni se si të bëni gjëra të tilla si të shkruani kod dhe programoni pajisje fizike. Atëherë do të keni një kornizë referimi nga ajo përvojë e cila do ta bëjë kujtesën dhe regjistrimin e vetive të mikrokontrolluesit më të lehtë për t’u kuptuar. E kuptoj që shumica e teksteve dhe diskutimeve hyrëse e bëjnë këtë anasjelltas, por kam gjetur se të luash një lojë video për një kohë së pari për të marrë një perspektivë globale para se të lexosh manualin e udhëzimeve është shumë më e lehtë sesa të lexosh manualin e parë.

rjmp Init; rreshti i parë i ekzekutuar

Kjo linjë është një "kërcim relativ" në etiketën "Init" dhe nuk është vërtet e nevojshme këtu pasi komanda tjetër është tashmë në Init, por ne e përfshijmë atë për përdorim në të ardhmen.

Fillo:

ser temp; vendosni të gjitha bitët në temp në 1.

Pas etiketës Init ne ekzekutojmë një komandë "vendos regjistër". Kjo i vendos të gjitha 8 bitët në regjistrin "temp" (që ju kujtoni është r16) në 1. Pra temp tani përmban 0b11111111.

jashtë DDRB, temp; duke vendosur pak si 1 në regjistrin I/O të Drejtimit të të Dhënave

; për PortB, e cila është DDRB, e vendos atë pin si dalje; a 0 do ta caktonte atë pin si hyrje; kështu që këtu, të gjitha kunjat e PortB janë dalje (të vendosura në 1)

Regjistri DDRB (Regjistri i Drejtimit të të Dhënave për PortB) tregon se cilat kunja në PortB (d.m.th. PB0 deri PB7) janë caktuar si hyrje dhe cilat janë caktuar si dalje. Meqenëse kemi pinin PB0 të lidhur me LED -in tonë dhe pjesën tjetër nuk është e lidhur me asgjë, ne do t'i vendosim të gjitha bitët në 1 që do të thotë se ato janë të gjitha dalje.

ldi temp, 0b11111110; ngarkoni numrin "e menjëhershëm" në regjistrin temp

; nëse do të ishte vetëm ld atëherë argumenti i dytë do të; duhet të jetë vendndodhje e kujtesës

Kjo linjë ngarkon numrin binar 0b11111110 në regjistrin temp.

jashtë DDRD, temp; mv temp në DDRD, rezultati është që PD0 është hyrje dhe

; pjesa tjetër janë dalje

Tani e vendosim Regjistrin e Drejtimit të të Dhënave për PortD nga temp, meqenëse temp përmban akoma 0b11111110 ne shohim që PD0 do të përcaktohet si një pin hyrës (meqë ka një 0 në pikën e djathtë) dhe pjesa tjetër përcaktohen si dalje pasi që ka 1 në ato vende.

clr temp; të gjitha bitët në temp janë vendosur në 0

jashtë PortB, temp; vendosni të gjitha bitët (domethënë kunjat) në PortB në 0V

Së pari ne "pastrojmë" temperaturën e regjistrit që do të thotë vendosjen e të gjitha bitave në zero. Pastaj e kopjojmë atë në regjistrin PortB i cili vendos 0V në të gjitha ato kunjat. Një zero në një bit PortB do të thotë që procesori do ta mbajë atë pin në 0V, një në një bit do të bëjë që ai pin të vendoset në 5V.

Ushtrimi 2: Përdorni një multimetër për të kontrolluar nëse të gjitha kunjat në PortB janë në të vërtetë zero. A po ndodh diçka e çuditshme me PB1? A keni ndonjë ide pse mund të jetë? (i ngjashëm me ushtrimin 4 më poshtë pastaj ndiqni kodin …) Ushtrimi 3: Hiqni dy rreshtat e mësipërm nga kodi juaj. A funksionon programi akoma si duhet? Pse?

ldi temp, 0b00000001; ngarkoni numrin e menjëhershëm në temp

jashtë PortD, temp; kaloni temp në PortD. PD0 është në 5V (ka një rezistencë tërheqëse); meqenëse ka një 1 në atë bit pjesa tjetër janë 0V. Ushtrimi 4: Hiqni dy rreshtat e mësipërm nga kodi juaj. A funksionon programi akoma si duhet? Pse? (Kjo është e ndryshme nga Ushtrimi 3 më sipër. Shihni diagramin pin out. Cili është cilësimi i paracaktuar i DDRD për PD0? (Shih faqen 90 të fletës së të dhënave

Së pari ne "ngarkojmë menjëherë" numrin 0b00000001 në temp. Pjesa "e menjëhershme" është atje pasi ne po ngarkojmë një numër direkt në temp sesa një tregues në një vendndodhje të kujtesës që përmban numrin për t'u ngarkuar. Në atë rast ne thjesht do të përdorim "ld" në vend se "ldi". Pastaj ne e dërgojmë këtë numër në PortD i cili vendos PD0 në 5V dhe pjesën tjetër në 0V.

Tani ne kemi vendosur kunjat si hyrje ose dalje dhe kemi vendosur gjendjet e tyre fillestare si 0V ose 5V (LOW ose HIGH) dhe kështu ne tani hyjmë në programin tonë "lak".

Kryesore: në temp, PinD; PinD mban gjendjen e PortD, kopjoni këtë në temp

; nëse butoni është i lidhur me PD0 atëherë kjo do të jetë; a 0 kur shtypet butoni, 1 ndryshe që kur; PD0 ka një rezistencë tërheqëse, normalisht është në 5V

Regjistri PinD përmban gjendjen aktuale të kunjave të PortD. Për shembull, nëse i lidhni një tel 5V PD3, atëherë në ciklin tjetër të orës (që ndodh 16 milion herë në sekondë pasi kemi mikrokontrolluesin të kyçur në një sinjal të orës 16MHz) bitin PinD3 (nga gjendja aktuale e PD3) do të bëhej 1 në vend të 0. Pra në këtë rresht ne kopjojmë gjendjen aktuale të kunjave në temp.

jashtë PortB, temp; dërgon 0 dhe 1 të lexuara më lart në PortB

; kjo do të thotë që ne duam që LED të lidhet me PB0, pra; kur PD0 është LOW, do të vendosë PB0 në LOW dhe kthehet; në LED (ana tjetër e LED është e lidhur; në 5V dhe kjo do të vendosë PB0 në 0V në mënyrë që rryma të rrjedhë)

Tani ne dërgojmë gjendjen e kunjave në PinD në daljen PortB. Në mënyrë efektive, kjo do të thotë që PD0 do të dërgojë një 1 në PortD0 nëse nuk shtypet butoni. Në atë rast meqenëse butoni është i lidhur me tokën ai pin do të jetë në 0V dhe do të dërgojë një 0 në PortB0. Tani, nëse shikoni diagramin e qarkut, 0V në PB0 do të thotë që LED do të shkëlqejë pasi ana tjetër e tij është në 5V. Nëse ne nuk po shtypim butonin, në mënyrë që një 1 të dërgohet në PB0, kjo do të thotë që kemi 5V në PB0 dhe gjithashtu 5V në anën tjetër të LED dhe kështu nuk ka ndonjë ndryshim të mundshëm dhe nuk do të rrjedhë rrymë dhe kështu LED nuk do të shkëlqejë (në këtë rast është një LED e cila është një diodë dhe kështu rryma rrjedh vetëm në një drejtim pavarësisht, sido që të jetë).

rjmp Kryesore; kthehet përsëri në Start

Ky kërcim relativ na kthen në etiketën kryesore: kontrolloni PinD përsëri dhe kështu me radhë. Kontrolloni çdo 16 milionë të sekondës nëse butoni po shtyhet dhe vendosni PB0 në përputhje me rrethanat.

Ushtrimi 5: Ndryshoni kodin tuaj në mënyrë që LED -i juaj të jetë i lidhur me PB3 në vend të PB0 dhe shikoni se funksionon. Ushtrimi 6: Lidheni LED -in tuaj në GND në vend të 5V dhe modifikoni kodin tuaj në përputhje me rrethanat.

Hapi 4: Përfundimi

Në këtë tutorial ne kemi hetuar më tej gjuhën e asamblesë për ATmega328p dhe kemi mësuar se si të kontrollojmë një LED me një buton. Në veçanti kemi mësuar komandat e mëposhtme:

ser regjistri ser i vendos të gjitha bitët e një regjistri në 1

regjistri clr i vendos të gjitha bitët e një regjistri në 0

në regjistër, regjistri i/o kopjon numrin nga një regjistër i/o në një regjistër pune

Në tutorialin tjetër ne do të shqyrtojmë strukturën e ATmega328p dhe regjistrat, operacionet dhe burimet e ndryshme që përmbahen aty.

Para se të vazhdoj me këto mësime do të pres dhe do të shoh nivelin e interesit. Nëse ka një numër njerëzish që në të vërtetë po kënaqen duke mësuar se si të kodojnë programe për këtë mikroprocesor në gjuhën e asamblesë, atëherë unë do të vazhdoj dhe do të ndërtoj qarqe më të komplikuara dhe do të përdor kod më të fuqishëm.

Recommended: