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 = 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 = 65 535 muligheter, det er litt bedre. Med 24-bit blir det = 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.