Kombinere registre på AVR

Hva gjør man hvis man skal oppbevare store verdier i et register og de tilgjengelige (ubrukte) arbeidsregistrene til mikrokontrolleren kun er 8-bit? Da er jo maks antall muligheter bare 2^{8} = 256. Det betyr at verdien bare kan være fra og med 0 til og med 255 … Og dette er altfor lite. Går man over oppstår overflyt («overflow»), da nullstilles registeret; 255 + 1 = 0 og 0 – 1 = 255.

Dette er når nummeret er usignert, altså er negative tall ikke støttet. Ved støtte av negative tall, kan lagret verdi være fra og med -128 til og med 127. (Forklaring: 128, 127, pluss tallet 0, gir 256 muligheter.) Overflyt gir her samme resultat, registeret nullstilles igjen; 127 + 1 = -128 og -128 – 1 = 127.

Om man derimot kombinerer 2 stk. 8-bit registre får man 16-bit og 2^{16} = 65 535 muligheter, det er litt bedre. Med 24-bit blir det 2^{24} = 16 777 216 muligheter, da bør man være rimelig sikret. (Dessuten har jeg ikke funnet flere registre jeg tør å bruke ..)

Her må man i grunn ned på bitnivå for å forstå hvordan det fungerer: Med 12 345 678 som tilfeldig valgt desimaltall, får man heksadesimaltallet BC 61 4E og binærtallet 1011 1100 0110 0001 0100 1110. Delt i tre blir dette BC = 1011 1100, 61 = 0110 0001 og 4E = 0100 1110. Hver del kan nå lagres i et 8-bit register. Ved uthenting må registrene avleses og hver del limes sammen igjen, i riktig rekkefølge. Sjekk selv med kalkulator som gjør om til forskjellige tallsystemer.

Ved å kombinere 3 stk. 8-bit registre (GPIOR0, GPIOR1 og GPIOR2) i ATmega328P, fikk jeg følgende kode som gjør jobben helt greit:

void SetRegisterValue(int isSigned, long int number)
{
   if (isSigned) number += 8388608;

   GPIOR2 = (number & 0xFF0000)>>16;
   GPIOR1 = (number & 0xFF00)>>8;
   GPIOR0 = number & 0x0000FF;
}

long int GetRegisterValue(int isSigned)
{
   long int msb = GPIOR2;
   msb = msb<<16;

   long int cb = GPIOR1;
   cb = cb<<8;

   long int lsb = GPIOR0;

   long int number = msb | cb | lsb;

   if (isSigned) number -= 8388608;

   return number;
}

Navnet GPIOR er forkortelse for «general purpose input output register». Dette er en type register man kan bruke til hva som helst. Og ved testing ser det ut til å fungere helt fint. Ved prøvekjøring klarer programmet å telle gjennom hele intervallet, både når man velger usignert og signert.

Dataene forblir i registeret (så lenge strømmen er tilkoblet), uten at mikrokontrolleren forandrer noe på egenhånd. Og ved overflyt begynner den automatisk på nytt, uten å klage på noe.

Egentlig er ikke dette så komplisert: Ved hjelp av masker (0xFF0000 og 0xFF00) klippes tallet i tre deler. Og for å gjøre 24-bit og 16-bit til 8-bit, benyttes «bit shifting» (fra koden over: >>16, >>8, <<16 og <<8). Dermed kan en tallverdi trygt oppbevares fordelt på flere registre, også forvandles den tilbake etter avlesing.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *