Hantera registerpar och 16-bitarsvärden i assembler?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Glattnos
Inlägg: 3105
Blev medlem: 29 oktober 2009, 20:01:18

Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av Glattnos »

Jag tänkte göra program till min Atmega168 där jag vill jämföra ett 16-bitarsvärde(variabel) med ett direktdata(1000). Hur ska man skriva då?
Jag har bara hanterat 8-bitars värden förut och då kan man ju skriva tex:

Kod: Markera allt

	cpi		count, 100 ;Jämför 8-bitarsvärdet "count" med 100
	brne	Count_dec
Hur gör man följande i Assembler:
1. Deklarera en 16-bitars variabel och lagra i registerparet Y
2. Jämföra innehållet i registerpar Y med direktdata(t.ex. 1000)
3. Subtrahera direktdata(t.ex. 1000) från registerparet Y

Och, ja jag har läst om detta men blir förvirrad när jag inte ser konkreta exempel.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av jesse »

Du kan inte deklarera någon "variabel" som pekar på registerparet Y, men du kan använda de båda registren som kallas för Y som en 16-bitars variabel, och du kan namnge dessa två på ett lämpligt sätt.
Som registerpar kan du använda vilka register som helst, inte bara X, Y och Z.

Du kan skapa 16-bitars variabler i två register så här:

1) En variabel lagras i två register, t.ex r20 och r21
2) Du döper dessa register till t.ex. varL och varH
varL betyder de låga 8 bitarna i variabel "var" ( L = låg).
varH betyder de höga 8 bitarna i variablen (H = hög).

Kod: Markera allt

.DEF tmp          = r16  ; temporärt register
.DEF varL			= r20 ; 16-bitars varabeln "var"
.DEF varH			= r21
.DEF annanL       = r22 ; 16-bitars varaiblen "annan"
.DEF annanH       = r23
Du kan nu göra 16-bitars operationer genom att kombinera 8-bitars operationer.
t.ex addera:

add varL,annanvarL
adc varH,annanvarH

först adderar du de 8 låga bitarna.
minnessiffran får du i "carry"
sedan adderar du de höga bitarna, men med adc istället för add.
adc tar med minnessiffran från föregående addition.
Alltså måste man alltid addera de låga först och de höga sedan.

att jämföra med ett annat tal:

Kod: Markera allt

.EQU KONSTANT = 1000
ldi tmp,high(KONSTANT)
cp valL,low(KONSTANT)  ; compare
cpc valH,tmp    ;compare med carry
brcs STORRE
MINDRE:
; val är mindre än annan

STORRE:
...
eller om du vill jämföra med exakt det talet:

Kod: Markera allt

.EQU KONSTANT  = 1000
cpi varL,low(KONSTANT)
brne OLIKA
cpi varH,high(KONSTANT)
brne OLIKA
LIKA:
...

OLIKA:
...
och subtrahera:

Kod: Markera allt

subi varL,low(KONSTANT)
sbci varH,high(KONSTANT)
brcs NEGATIV ; hoppar om svaret är negativt - kan uteslutas förstås
Om du vill ha variabeln i Y byter du bara ut r20 och r21 mot r28,r29 och kanske byter namnen till YL och YH.

Som du ser i första exemplet använder jag ett temporärt 8-bitars register i instruktionen cpc. Det beror på att det inte finns någon instruktion "cpci KONSTANT", så man måste ladda värdet i tmp och sen köra cpc var,tmp.

För att förstå matematiken bakom detta ska man titta på talen i binärform eller kanske hexadecimalt format. Då förstår man vad som händer, om man förstår vad "carry"-flaggan gör. Det är vanlig binär matematik.

high(KONSTANT) och low(KONSTANT) är bara ett annat sätt att skriva 1000/256 och 1000 & 255, dvs 3 och 232. 3*256+232=1000
Nerre
Inlägg: 27205
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av Nerre »

Och just därför är det mycket enklare att skriva i C:-)

Även om den resulterande koden blir identisk så är C-kompilatorn betydligt bättre på att undvika skrivfel (t.ex. att man råkar skriva "add" istället för "adc").
Användarvisningsbild
Andax
Inlägg: 4379
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av Andax »

Chan (ELM) löste det genom macron som blev nya "16-bitars" instruktioner. Kommer inte ihåg vilket projekt på hans sida som jag såg detta, men det kan ha varit hans linjeföljande robot. link
Glattnos
Inlägg: 3105
Blev medlem: 29 oktober 2009, 20:01:18

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av Glattnos »

Jesse: Tack! Bra förklaring! Mycket "Aha!" blir det!

Andax: Wow, ja dessa macron är ju smidiga!

Hur kan man räkna om ett värde på skalan 0 - 1023 till motsvarande värde på skalan 0 - 6450?

Om man gör såhär 6450/1023=6,305
Värdet på 1023-skalan multiplicerat med 6,305 = motsvarande värde på 6450-skalan

Säg att jag har ett 16-bitarsvärde på 800 som jag vill multiplicera med 6,305. Hur kan man göra det? Decimaltecknet ställer till det lixom.

Något liknande har jag sett på forumet förut men jag hittar inte det nu. Någon kanske kan hitta det och länka?
Nerre
Inlägg: 27205
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av Nerre »

Multiplicera med 6305 och ta bort de tre sista siffrorna (eller dela med 1000).
Användarvisningsbild
Icecap
Inlägg: 26636
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av Icecap »

800 * 6,305 => (800 * 6305) / 1000
Kruxet är att mellanresultatet kan (läs: kommer) bli mer än 16 bits men det går ju lika bra att räkna med 24 eller 32 bits på en 8-bit som med 16 bit på en 8-bit.
Användarvisningsbild
ErikJ
Inlägg: 36
Blev medlem: 17 september 2004, 16:06:53
Ort: Malung

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av ErikJ »

800 * 6,305 = 800 * 1614 / 256
Multiplicera med 1614 och släng bort den lägsta byten. Då slipper du en tidskrävande division.

Kod: Markera allt

   Decimalt    Hexadecimalt
        800            3 20
*     1 614      *     6 4E
------------------------------------------
= 1 291 200      = 13 B3 C0
/       256              xx
------------------------------------------
=     5 043,75     13 B3 (decimalt 5043)
EDIT: En siffra fel: 6043 => 5043
EDIT2: Fler siffror fel: 3,605 => 6,305
Senast redigerad av ErikJ 28 december 2009, 17:16:11, redigerad totalt 2 gånger.
sodjan
EF Sponsor
Inlägg: 43249
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av sodjan »

> Hur kan man räkna om ett värde på skalan 0 - 1023 till motsvarande värde på skalan 0 - 6450?

Rent matematiskt eller kodmässigt är det ju inte en speciellt intressant fråga. Det är
ju bara att skala om värdet. Och den snabbaste metoden (som inte har nämnts) är
för övrigt en lookup-tabell med 1024 positioner (16-bitars positioner, alltså en 2048
bytes lookup-tabell).

Men, det riktigt intressanta är det bakomliggande problemet som gör att just denna
omräkning behövs. Om t.ex intervallet 0-1023 kommer från en ADC och alltså motsvarar
ett verkligt värde 0-6450, så kan de vara smidigare att skala ner den analoga
insignalen lite så att ADCn ger 0-806. Det gör hela problemet till en enkel x8 operation
vilket löses snabbt med 3 st shift operationer.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av jesse »

Nja, Sodjan.. visst, är det kanske enklast ibland, men jag tycker metoden att multiplicera med 1614 var genialt. Man måste kunna multiplicera heltal, men sååå svårt är det ju inte. Färdiga rutiner i assembler finns ju att hämta "på nätet" som multiplicerar två 16-bitars tal och ger tillbaks ett 32-bitars.

AVR assembler tutorial
Denna länk har exempel på många matematiska "problem" i assembler.
sodjan
EF Sponsor
Inlägg: 43249
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av sodjan »

> ...men jag tycker metoden att multiplicera med 1614 var genialt.

Absolut ! :-)
Det inlägget kom medan jag skrev mitt inlägg...

Min poäng var att många ofta för sällan tittar på *hela* problemet
innan man börjar labba med t.ex float-beräkningar och liknande. Det
finns ofta både smartare och snabbare lösningar/metoder om man bara
tänker igenom det hela lite...
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Hantera registerpar och 16-bitarsvärden i assembler?

Inlägg av jesse »

Nej, float har jag lyckats undvika hittills som tur är.
Det är nog det sista man vill pyssla med i en µC. Särskilt om man skriver programmet i assembler :roll:
Skriv svar