PIC MikroC: Hur rotera bitar smidigast? (jfr RLF, RRF i ASM)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

PIC MikroC: Hur rotera bitar smidigast? (jfr RLF, RRF i ASM)

Inlägg av Schnegelwerfer »

Har letat runt lite, och insett att ANSI C inte har någon färdig funktion för att rotera bitar inuti en byte (RLF, RRF i assembler).

Jag antar att detta "problem" ständigt dyker upp, så jag undrar om någon på forumet har en bra, smart standardmetod som man kan använda?
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Har faktiskt aldrig behövt rotera i C, men om jag skulle göra det antar jag att jag skulle skriva något i stil med:

Kod: Markera allt

unsigned char i;

...

i = i>>1 | i<<7;
Om kompilatorn är smart nog att göra om det till RRF istället för en hel hög instruktioner vete tusan...
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

Inlägg av Schnegelwerfer »

Ok, jag kanske ta och specifiera mitt problem istället, det kanske går att lösa på ett smart sätt utan roteing av bitar.

Jag håller alltså på att skriva om mitt IR-fjärrkontrollmottagarprogram i C, och jag behöver detektera inkommande 1:or och 0:or samt lagra dessa för att sedan jämföra med en 48-bitssekvens.

Det enklaste är kanske att lagra de inkommande 1 och 0 i en sträng med 48 platser, typ:

char code[47];

Det går då åt mer minne, men det har jag råd med... några synpunkter?
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Fast behöver du då rotera eller bara skifta?
Användarvisningsbild
Schnegelwerfer
Inlägg: 1863
Blev medlem: 8 november 2004, 13:46:56

Inlägg av Schnegelwerfer »

Egentligen behöver jag ju bara skifta in bitarna, det har du ju rätt i!
Då blir ju det hela bra mycket enklare.

Ex:

Kod: Markera allt

unsigned char i ;

i = i << 1 | 1 ;
Detta borde väl skifta in en 1a?

(mina C-kunskaper är minst sagt ringrostiga! :cry: )
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Precis.

Eller

Kod: Markera allt

i = i >> 1 | 0x80;
Beroende på vilket håll man vill skifta (LSB först eller MSB först).
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag håller mig till ett "standart" sätt som fungerar bra:
Jag försöker att se till att datan kommer in med MSB först, sedan är det bara:
skifta till vänster (värde <<= 1;)
kolla om data är 1 (if(data) värde++;)

Det går såklart att köra andra hållet också men då fär man OR:a med ett lagom värde beroende på storleken på variablem man roterar.

48 bits kan sammanställas av en 16 bitars (unsigned int) och en 32 bitars (unsigned long), när man ska "överföra" bits sinsemellan kollar man om MSB:n på de lägsta bitsen är satt och skifter in den i högsta variablen, därefter skifter man den lägsta variabeln.

Kod: Markera allt

struct
  {
  int                 Bitcounter;
  union
    {
    struct
      {
      unsigned int   Highest;
      unsigned long Lowest;
      } Shift;
    unsigned char Bytes[5];
    } Value;
  } Alla_Bits;

void Start_Mottagning(void)
  {
  Alla_Bits.Bitcounter = 0;
  Alla_Bits.Shift.Lowest = 0;
  }

void Shift_In_Bit(bool Bitvalue)
  {
  Alla_Bits.Value.Shift.Highest <<= 1;
  if(Alla_Bits.Value.Shift.Lowest & 0x80000000) Alla_Bits.Value.Shift.Highest++;
  Alla_Bits.Value.Shift.Lowest <<= 1;
  if(Bitvalue) Alla_Bits.Value.Shift.Lowest++;
  Alla_Bits.Bitcounter++;
  if(Alla_Bits.Bitcounter >= 48)
    {
    // Här kan man sedan jämnföra de 5 bytes
    if((Alla_Bits.Value.Bytes[0] == 0x??) && (Alla_Bits.Value.Bytes[1] == 0x??) && (Alla_Bits.Value.Bytes[2] == 0x??) && (Alla_Bits.Value.Bytes[3] == 0x??) && (Alla_Bits.Value.Bytes[4] == 0x??))
      {
      // Jämnförd och lika, gör vad som ska göras.
      }
    }
  }
Kastat ihop lite snabbt men idéen finns där i alla fall.
macgyver
Inlägg: 321
Blev medlem: 8 juni 2005, 00:24:09
Ort: Göteborg
Kontakt:

Inlägg av macgyver »

alla har olika lösningar, så här hade nog jag gjort:
i detta fall för LSB först

unsigned char bits[6], i, j;

for(i=0; i != 6; i++) {
for(j=1; j != 8; j++) {

bits >>= 1;
bits += GET_IR_BIT() ? 0x80 : 0;

}
}
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Får jag fråga varför din for-to-next loop använder '!='?
Enligt min erfarenhet är det vida bättre att använda '<', anledningen är att om någon jävla glitch i programmet spöker till det (och det har ju händ!) kommer din version enbart att stoppa när i/j är hhv. 6 och 8, på "mitt" sätt kommer de att stoppa när endera värde är lika med eller över deras respektiva referenser.

Samtidig är det iblant snabbare att kolla för "mindre än" i den slutgiltiga koden.
macgyver
Inlägg: 321
Blev medlem: 8 juni 2005, 00:24:09
Ort: Göteborg
Kontakt:

Inlägg av macgyver »

brukar skriva != av gammal vana från programering av 8051 cpu:er
med kompilatorn jag använde sparade jag in på 1 ASM instruktion genom att använda != istället för < :)
Skriv svar