AVR Assembler handledning 5 (4 / 8 steg)
Steg 4: En annan titta på pekare och uppslagstabeller
Låt oss nu se om vi kan använda våra analyzer för att få en bättre uppfattning om hur dessa X, Y och Z pekare och uppslagstabeller fungerar. Jag inser att vår diskussion i sista handledningen kan ha varit lite förvirrande för nykomlingen. Jag tror att detta kommer att göra det allt mer klart.
Låt oss börja med att ändra vår kod enligt följande:
;************************************
; Skrivet av: 1o_o7
; datum: < 2014|11|03 >
; version: 1.0
; filen sparas som: analyzer2.asm
; för AVR: atmega328p
; klockfrekvens: 16MHz
;************************************
; Programmera funcion:---
; analyserar de bitarna lagras i ett register
;---------------------------------------
.nolist
.include ". / m328Pdef.inc"
.lista
.def temp = r16
.org 0x0000
rjmp Init
nummer:
DB 0b01111111, 0b11011110, 0b01011110, 0b11010010
DB 0b01010010, 0b11000000
Init:
ser temp
ut DDRB, temp
ut DDRC, temp
Färgtemp
ut PortB, temp
ut PortC, temp
viktigaste:
LDI ZH, high(2*numbers); ZH är den höga byten i adressen till nummer
LDI ZL, low(2*numbers); ZL är den låga byten i adressen till nummer
MOV r20, r30
rcall analysera
rjmp huvudsakliga
analysera:
Färgtemp
ut portb, temp
ut portc, temp
sbrc r20, 7
SBI portb, 1
sbrc r20, 6
SBI portb, 2
sbrc r20, 5
SBI portb, 3
sbrc r20, 4
SBI portb, 4
sbrc r20, 3
SBI portc, 1
sbrc r20, 2
SBI portc, 2
sbrc r20, 1
SBI portc, 3
sbrc r20, 0
SBI portc, 4
ret
Vi har helt enkelt lagt till en uppslagstabell i toppen (som är exakt samma som vi använde i vår dice program för handledning 4) och sedan vi lagt raderna ZL och ZH i vår Main rutin att initiera Z pekaren.
Vi sedan ladda r30 i våra analyzer register r20 och analysera den på vår styrelse. Du bör göra detta. Du ska hitta det r30 innehåller 0b00000010. Nu gör samma för r31 och du kommer att få 0b00000000.
Adressen till "nummer" är 0x0001 som i binär är 0b0000000000000001 så
LDI ZH, high(2*numbers)
innebär exakt samma som
LDI r31, high(0b0000000000000010)
som är
LDI r31, 0b00000000
På samma sätt
LDI ZL, low(2*numbers)
innebär exakt samma som
LDI r30, low(0b0000000000000010)
som är
LDI r30, 0b00000010
Minns att r30 och r31 kombinera tillsammans göra Z.
Prova detta:
viktigaste:
LDI ZH, high(2*numbers)
LDI ZL, low(2*numbers)
MOV r20, ZL
rcall analysera
rjmp huvudsakliga
Vad händer nu om vi tittar på Z? Tja kan prova det:
viktigaste:
LDI ZH, high(2*numbers)
LDI ZL, low(2*numbers)
LPM r20, Z
rcall analysera
rjmp huvudsakliga
Observera att använda Z, måste vi kommandot LPM. Detta kommer att ladda oavsett data i sitter i adressen som pekas ut av Z. Adressen pekar Z hittas genom att börja med vad som finns i r31 r30, som är 0b0000000000000010 och sedan flytta det tillbaka igen till höger för att få 0b0000000000000001. Så prova det och se vad du får... tjusig rätt? Du får 0b01111111 vilket är precis vad vi lagrade på den adressen. Låt oss fortsätta att försöka göra detta mer uppenbart. Låt oss göra följande:
viktigaste:
LDI ZH, high(2*numbers)
LDI ZL, low(2*numbers)
adiw ZH:ZL, 1
MOV r20, ZL
rcall analysera
rjmp huvudsakliga
Du ser vi lagt 1 till ZH:ZL vilket gör ZL = 0b00000011. Om du bytt ZL i ovanstående med r30 skulle du få exakt samma sak. De är olika namn för samma nummer. Om istället för att använda "adiw ZH:ZL" i ovanstående du använt "inc ZL" eller ens "inc r30" skulle du få samma sak igen. Instruktion adiw betyder "Lägg omedelbart till word" och ett "ord" är 2 byte eller 16 bitar. Så du måste ge det två 8-bitars register, lägger ZH:ZL, eller ekvivalent r31:r30 och det k till denna. I vårt exempel över k är 1.
Låt oss lägga till 1 r30 och sedan se var Z pekar:
viktigaste:
LDI ZH, high(2*numbers)
LDI ZL, low(2*numbers)
Inc r30
LPM r20, Z
rcall analysera
rjmp huvudsakliga
Så Z innehåller ZH:ZL som är samma som r31:r30 som är 0x0003 eftersom "siffror:" börjar vid 0x0001 och vi gånger med 2 för att initiera ZL och ZH vilket innebar att Z innehöll 0x0002, då vi ökas r30 (som är den nedre halvan av Z) så att nu Z = r31:r30 = 0x00:0x03 = 0x0003. När instruktionen LPM ombeds att ladda programminne från Z r20 tar det numret i Z, som är 0x0003 = 0b0000000000000011, och säger: "Okej, 0. lite är en 1, som innebär att jag vill ta den andra byten på adress 0b0000000000000001 vilket är den adress som jag får genom att flytta Z till höger en position (eller dividera med 2)"
Jag vill göra en sista sak här för att försöka göra den mindre förvirrande. Låt oss gå tillbaka till toppen av vårt program och sticka en .org uttalande där. Så har du
.org 0x0000
rjmp Init
.org 0x0008
nummer:
DB 0b01111111, 0b11011110, 0b01011110, 0b11010010
DB 0b01010010, 0b11000000
Kan du se vad jag har gjort? Jag har uttryckligen sagt PC att sticka mitt bord nummer på programminne adress 0x0008, som i binär 0b0000000000001000
(Minns att eftersom jag inte så att någon avbryter jag kan kan använda dessa minne utrymmen för vad jag vill.)
Sedan siffrorna: tabell startar på ovanstående adress, vad kommer att få laddas in r30 och r31 denna gång?
Multiplicera väl som tar itu med 2 och du får 0b0000000000010000 som avskiljer som 00000000:00010000 så som berättar att r31, ZH om du vill, är 0b00000000 och r30 eller ZL om du vill, är 0b00010000.
Övning 2: kontrollera detta med din analyzer genom mata r30.
Nu prova det här:
viktigaste:
LDI ZH, high(2*numbers)
LDI ZL, low(2*numbers)
adiw ZH:ZL, 3
LPM r20, Z
rcall analysera
rjmp huvudsakliga
Du bör peka på den 4: e nummer i vår lista sedan vi började på den första en och lagt 3 till adressen. Vad är den faktiska programminne adressen av detta nummer? Jo, programmet minnesadressen för den första i listan är 0x0008, som är 0b0000000000001000, och programmet minnet av den andra siffran i listan är också 0x0008. Fjärde numret program adress är också 0x0009 programminnet av det tredje numret i listan är 0x0009. Hur vi får det fjärde numret är börjar vi med sin adress 0b0000000000001001 och vi flytta vänster, 1 bit (dvs gånger med 2) för att få 0b0000000000010010 och detta ger ZH:ZL värdena för den första siffran på denna adress, dvs det tredje numret i vår lista, för att få den andra siffran lagras på samma adress (med andra ord den övre halvan av 16-bitars registret på adress 0x0009) vi bara lägga till en till den skiftade nummer. Vilket är 0b0000000000010011. Detta är antalet 0x13 i hex, eller 19 i decimal. Så vi vill ha ett tal som lagras på programminne adress nummer 9 och så vi ZH:ZL till 0:19 låt oss bevisa alla detta. Kan bara hålla detta nummer i r30 och r31 och se vad som kommer ur Z.
viktigaste:
LDI ZH, high(2*numbers)
LDI ZL, low(2*numbers)
LDI r31, 0
LDI r30, 19
LPM r20, Z
rcall analysera
rjmp huvudsakliga
Hör och häpna. Din LED visar 4. numret på vår lista.
Jag hoppas att detta har hjälpt människor att förstå vad händer med Z pekaren, hur programminne läggas ut, hur ADIW och LPM fungerar och varför de har att göra detta multipliceras med två grejer att få rätt byte data ur en viss minnesadress. Märka det finns två olika 16 bitars saker här. Själva programminne adressen är ett 16-bitars nummer, och registret på var och en av dessa adress är 16 bitar bred. Den första omständigheten därför Z har gjorts av 2 av våra 8-bitars arbetande register så att det kan hålla en komplett minnesadress, andra är därför måste vi multiplicera med 2 så vi kan få låga eller höga byte av data som lagras på varje adress.
Övning 3: lek med att placera data i olika minnesplatser, öka och minska r30 och r31 registren, vad händer när du startar på r31 = 0xFF och öka det? Också försöka använda X och Y pekare också.
Usch! Låt oss ta en paus och göra något roligt...