Taula de continguts:

Tutorial AVR Assembler 2: 4 passos
Tutorial AVR Assembler 2: 4 passos

Vídeo: Tutorial AVR Assembler 2: 4 passos

Vídeo: Tutorial AVR Assembler 2: 4 passos
Vídeo: AVR Ассемблер. Урок 2. Порты. Мигалка. AVR Assembler. Lesson 2. Ports. Flasher. 2024, Desembre
Anonim
Tutorial de muntatge AVR 2
Tutorial de muntatge AVR 2

Aquest tutorial és una continuació del "Tutorial 1 del muntador AVR"

Si no heu passat pel tutorial 1, hauríeu d'aturar-vos ara i fer-ho primer.

En aquest tutorial continuarem el nostre estudi de la programació del llenguatge assemblador de l'atmega328p que s'utilitza a Arduino.

Necessitarà:

  1. un Arduino de taula de treball o simplement un Arduino normal com al tutorial 1
  2. un LED
  3. una resistència de 220 ohm
  4. un polsador
  5. cables de connexió per fer el circuit a la vostra taula de treball
  6. Manual d’instruccions: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. Full de dades: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…

La col·lecció completa dels meus tutorials es troba aquí:

Pas 1: Construir el circuit

Construint el circuit
Construint el circuit

Primer heu de construir el circuit que estudiarem en aquest tutorial.

Aquí està la manera com es connecta:

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

PD0 (pin digital 0): polsador - GND

Podeu comprovar que el LED està orientat correctament connectant-lo a GND en lloc de PB0. Si no passa res, invertiu l'orientació i la llum s'hauria d'encendre. A continuació, torneu-lo a connectar a PB0 i continueu. La imatge mostra com està connectat el meu arduino de taulers de suport.

Pas 2: escriure el codi de muntatge

Redacció del codi de muntatge
Redacció del codi de muntatge

Escriviu el següent codi en un fitxer de text anomenat pushbutton.asm i compileu-lo amb avra tal com heu fet al tutorial 1.

Tingueu en compte que en aquest codi tenim molts comentaris. Cada vegada que el muntador veu un punt i coma, saltarà la resta de la línia i passarà a la línia següent. És una bona pràctica de programació (sobretot en llenguatge ensamblador!) Comentar intensament el vostre codi per tal que quan hi torneu a saber en el futur sabreu què feieu. Vaig a comentar bastant les coses als primers tutorials perquè puguem saber exactament què està passant i per què. Més endavant, un cop siguem una mica millors en la codificació de muntatges, comentaré les coses amb una mica menys de detall.

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

; escrit per: 1o_o7; data: 23 d'octubre de 2014; *************************************

.nolista

.inclou "m328Pdef.inc".list.def temp = r16; designar el registre de treball r16 com a temp rjmp Init; primera línia executada

Inici:

ser temp; estableix tots els bits en temperatura a 1. fora de DDRB, temp; establir una mica com 1 a la E / S de direcció de dades; registre per a PortB, que és DDRB, defineix això; pin com a sortida, un 0 definiria aquest pin com a entrada; aquí, doncs, tots els pins PortB són sortides (ajustades a 1) ldi temp, 0b11111110; carregueu el número "immediat" al registre temporal; si fos només ld llavors el segon argument; hauria de ser una ubicació de memòria fora de DDRD, temp; mv temp a DDRD, el resultat és que PD0 és l'entrada; i la resta són sortides clr temp; tots els bits de temp estan definits a 0's fora de PortB, temp; configureu tots els bits (és a dir, pins) a PortB a 0V ldi temp, 0b00000001; carrega el número immediat per sortir de PortD, temp; mou la temperatura a PortD. PD0 té una resistència pull up; (és a dir, definit a 5V) ja que té un 1 en aquest bit; la resta són 0V des de 0.

Principal:

en temp, PinD; PinD té l'estat de PortD, copieu-lo a temp; si el botó està connectat a PD0, això serà; 0 quan es prem el botó, 1 en cas contrari des de; PD0 té una resistència pull-up que normalment és a 5V fora de PortB, temp; envia els 0 i 1 llegits més amunt a PortB; això significa que volem que el LED estigui connectat a PB0; quan PD0 és BAIX, posa PB0 a BAIX i gira; al LED (ja que l'altre costat del LED està; connectat a 5V i això establirà PB0 a 0V; correrà el corrent) rjmp Main; torna a fer el bucle fins a l'inici de Main

Fixeu-vos que aquesta vegada no només tenim molts més comentaris al nostre codi, sinó que també tenim una secció de capçalera que proporciona informació sobre qui l’ha escrit i quan s’ha escrit. La resta del codi també es separa en seccions.

Després de compilar el codi anterior, heu de carregar-lo al microcontrolador i veure que funciona. El LED s’ha d’encendre mentre premeu el botó i, després, torneu a apagar-lo quan el deixeu anar. He mostrat el seu aspecte a la imatge.

Pas 3: Anàlisi línia per línia del codi

Saltaré les línies que només són comentaris ja que el seu propòsit és evident.

.nolista

.inclou la llista de fitxers "m328Pdef.inc"

Aquestes tres línies inclouen el fitxer que conté les definicions de registre i bits de l'ATmega328P que estem programant. L'ordre.nolist indica a l'assemblador que no inclogui aquest fitxer al fitxer pushbutton.lst que produeix quan el munteu. Desactiva l'opció de llistat. Després d'incloure el fitxer, tornem a activar l'opció de llistat amb l'ordre.list. La raó per la qual ho fem és perquè el fitxer m328Pdef.inc és bastant llarg i no cal que el vegem al fitxer de llista. El nostre assemblador, avra, no genera automàticament cap fitxer de llista i, si en volem un, ens el muntaríem amb l'ordre següent:

avra -l pushbutton.lst pushbutton.asm

Si ho feu, es generarà un fitxer anomenat pushbutton.lst i, si examineu aquest fitxer, trobareu que mostra el codi del programa juntament amb informació addicional. Si mireu la informació addicional, veureu que les línies comencen amb una C: seguida de l’adreça relativa en hexadecimal de la ubicació del codi a la memòria. Bàsicament comença a 000000 amb la primera ordre i augmenta a partir d’aquí amb cada ordre posterior. La segona columna després del lloc relatiu a la memòria és el codi hexadecimal de l'ordre seguit del codi hexadecimal per a l'argument de l'ordre. En futurs tutorials, discutirem els fitxers de llista.

.def temp = r16; designar el registre de treball r16 com a temp

En aquesta línia utilitzem la directiva assembladora ".def" per definir la variable "temp" igual al "registre de treball" r16. Utilitzarem registre r16 com el que emmagatzema els números que volem copiar a diversos ports i registres (que no es poden escriure directament).

Exercici 1: intenteu copiar un número binari directament a un port o registre especial com DDRB i veure què passa quan intenteu muntar el codi.

Un registre conté un byte (8 bits) d'informació. Bàsicament sol ser una col·lecció de SR-Latches, cadascun dels quals és un "bit" i conté un 1 o un 0. Podem discutir-ho (i fins i tot crear-ne un) més endavant en aquesta sèrie. És possible que us pregunteu què és un "registre de treball" i per què hem escollit r16. Ho discutirem en un futur tutorial quan ens endinsem en el pantà de les internes del xip. De moment vull que entengueu com fer coses com escriure codi i programar maquinari físic. A continuació, tindreu un marc de referència d’aquella experiència que farà que la memòria i les propietats de registre del microcontrolador siguin més fàcils d’entendre. M’adono que la majoria de llibres de text i debats introductoris ho fan al revés, però he trobat que jugar a un videojoc durant un temps per obtenir una perspectiva global abans de llegir el manual d’instruccions és molt més fàcil que llegir-lo primer.

rjmp Init; primera línia executada

Aquesta línia és un "salt relatiu" a l'etiqueta "Init" i no és realment necessària aquí, ja que la següent ordre ja és a Init, però l'incloem per a un ús futur.

Inici:

ser temp; estableix tots els bits en temperatura a 1.

Després de l'etiqueta Init executem una ordre "set register". Això defineix tots els 8 bits del registre "temp" (que recordeu que és r16) a 1. De manera que ara la temperatura conté 0b11111111.

fora de DDRB, temp; establint una mica com a 1 al registre d'E / S de direcció de dades

; per a PortB, que és DDRB, estableix aquest pin com a sortida; un 0 definiria aquest pin com a entrada; per tant, aquí, tots els pins del PortB són sortides (definit a 1)

El registre DDRB (Data Direction Register for PortB) indica quins pins de PortB (és a dir, PB0 a PB7) es designen com a entrada i quins es designen com a sortida. Com que tenim el pin PB0 connectat al nostre LED i la resta no connectat a res, establirem tots els bits a 1, és a dir, que són totes sortides.

ldi temp, 0b11111110; carregueu el número "immediat" al registre temporal

; si fos només ld, llavors seria el segon argument; ha de ser una ubicació de memòria

Aquesta línia carrega el número binari 0b11111110 al registre temporal.

fora DDRD, temp; mv temp a DDRD, el resultat és que PD0 és l'entrada i

; la resta són sortides

Ara establim el registre de direcció de dades per a PortD des de la temperatura, ja que la temperatura encara conté 0b11111110, veiem que PD0 es designarà com a pin d'entrada (ja que hi ha un 0 a l'extrem dret) i la resta es designen com a sortides ja que hi ha Hi ha 1 en aquests llocs.

clr temp; tots els bits de temperatura estan definits a 0

fora de PortB, temp; configureu tots els bits (és a dir, pins) al PortB a 0V

Primer "esborrem" la temperatura del registre, que significa posar tots els bits a zero. A continuació, ho copiem al registre PortB que estableix 0V en tots aquests pins. Un zero en un bit PortB significa que el processador mantindrà aquest pin a 0V, un en un bit farà que aquest pin es posi a 5V.

Exercici 2: utilitzeu un multímetre per comprovar si tots els pins del PortB són realment nuls. Hi ha alguna cosa estranya amb PB1? Alguna idea de per què podria ser això? (similar a l'exercici 4 següent, seguiu el codi …) Exercici 3: traieu les dues línies anteriors del vostre codi. El programa continua funcionant correctament? Per què?

ldi temp, 0b00000001; carrega el número immediat a temp

fora de PortD, temp; mou la temperatura a PortD. PD0 és a 5V (té una resistència de tracció); ja que té un 1 en aquest bit, la resta són 0V. Exercici 4: traieu les dues línies anteriors del vostre codi. El programa continua funcionant correctament? Per què? (Això és diferent de l'exercici 3 anterior. Consulteu el diagrama de fixació. Quin és el paràmetre DDRD predeterminat per a PD0? (Consulteu la pàgina 90 del full de dades)

Primer "carreguem immediatament" el número 0b00000001 a temp. La part "immediata" hi és, ja que estem carregant un número directe a la temperatura en lloc d'un punter a una ubicació de memòria que conté el número a carregar. En aquest cas, simplement utilitzaríem "ld" en lloc de "ldi". A continuació, enviem aquest número a PortD que estableix PD0 a 5V i la resta a 0V.

Ara hem definit els pins com a entrada o sortida i hem establert els seus estats inicials com a 0V o 5V (BAIX o ALT) i, per tant, entrem al nostre programa "bucle".

Principal: en temp, PinD; PinD manté l'estat de PortD, copieu-lo a temp

; si el botó està connectat a PD0, aquest serà; un 0 quan es prem el botó, 1 en cas contrari des de; El PD0 té una resistència pull-up, normalment està a 5V

El registre PinD conté l’estat actual dels pins PortD. Per exemple, si heu connectat un cable de 5 V a PD3, al següent cicle de rellotge (que passa 16 milions de vegades per segon, ja que tenim el microcontrolador connectat a un senyal de rellotge de 16 MHz), el bit PinD3 (des de l’estat actual de PD3) esdevindria un 1 en lloc d’un 0. Per tant, en aquesta línia copiem l’estat actual dels pins a temp.

fora de PortB, temp; envia els 0 i els 1 llegits més amunt a PortB

; això significa que volem que el LED estigui connectat a PB0; quan PD0 és BAIX, establirà PB0 a BAIX i girarà; al LED (l'altre costat del LED està connectat; a 5V i això establirà PB0 a 0V perquè flueixi el corrent)

Ara enviem l’estat dels pins a PinD a la sortida PortB. Efectivament, això significa que PD0 enviarà un 1 a PortD0 tret que es prem el botó. En aquest cas, atès que el botó està connectat a terra, aquest pin estarà a 0V i enviarà un 0 a PortB0. Ara, si mireu el diagrama del circuit, 0V a PB0 significa que el LED brillarà, ja que l’altre costat és a 5V. Si no premem el botó, perquè s’enviï un 1 a PB0, això significaria que tenim 5V a PB0 i també 5V a l’altre costat del LED i, per tant, no hi ha diferència de potencial i no correrà cap corrent i, per tant, El LED no brillarà (en aquest cas és un LED que és un díode i, per tant, el corrent només flueix en una direcció independentment del que sigui).

rjmp principal; torna a tornar a iniciar

Aquest salt relatiu ens torna a la nostra etiqueta Main: i tornem a comprovar PinD, etc. Comprovar cada 16 milions de segons si s’està pressionant el botó i configurar PB0 en conseqüència.

Exercici 5: Modifiqueu el codi de manera que el LED estigui connectat a PB3 en lloc de PB0 i vegeu que funciona. Exercici 6: Connecteu el LED a GND en lloc de 5V i modifiqueu el codi en conseqüència.

Pas 4: Conclusió

En aquest tutorial hem investigat més a fons el llenguatge de muntatge de l'ATmega328p i hem après a controlar un LED amb un polsador. En particular, hem après les ordres següents:

registre ser estableix tots els bits d'un registre a 1

registre clr estableix tots els bits d'un registre a 0

al registre, el registre i / o copia el número d'un registre i / o a un registre de treball

En el següent tutorial examinarem l'estructura de l'ATmega328p i els diversos registres, operacions i recursos que conté.

Abans de continuar amb aquests tutorials, esperaré a veure el nivell d’interès. Si hi ha una sèrie de persones que realment gaudeixen aprenent a codificar programes per a aquest microprocessador en llenguatge ensamblador, continuaré construint circuits més complicats i faré servir codi més robust.

Recomanat: