Forum: Compiler & IDEs Wie uint16_t bitweise verarbeiten


von Guenter B. (gbl)


Lesenswert?

Hallo,

ich versuche eine uint16_t Variable bitweise abzutasten und über einen 
Port zu einem andern AVR zu senden. Irgendwie passt das ausgegebene 
Bitmuster nicht zu dem was ich erwarte.

Habe ich einen Denkfehler?

Ich vermute den Fehler beim if-Vergleich.
Ich möchte durch den if-Vergleich herausfinden, ob das geweilige Bit in 
der sbyte-Variable gesetzt ist.


1
void sendebyte(uint16_t sbyte)
2
  {
3
  DDRB=0x01; //schaltet den PIN auf Ausgang
4
  uint16_t Vergleich=32768; //Schiebevariable auf Bit15 setzen
5
  uint8_t BitCount = 0;
6
  for (BitCount=0;BitCount<16;BitCount++)
7
    {
8
      if(Vergleich&sbyte)
9
        puls(); //sendet langen Impuls
10
      else
11
        pause(); //sendet kurzen Impuls
12
    Vergleich=Vergleich/2; //schiebt das Bit das nächste Bit
13
    }
14
  DDRB=0x00; //schaltet den PIN wieder auf Eingang
15
  }

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nö, das ist soweit korrekt.

Allerdings kann man das auch ein bisschen anders schreiben:
1
uint16_t Vergleich = 1 << 15;
2
uint8_t BitCount = 0;
3
4
for (BitCount = 0; BitCount < 16; BitCount++)
5
{
6
  if (Vergleich & sbyte)
7
    puls(); //sendet langen Impuls
8
  else
9
    pause(); //sendet kurzen Impuls
10
  Vergleich >>= 1;
11
}

Inhaltlich ist das aber exakt das gleiche, es wird nacheinander Bit 15 
bis Bit 0 von "sbyte" untersucht und entsprechend "puls" oder "pause" 
aufgerufen.

Nur am Rande:
Der Variablenname "sbyte" ist ungeschickt gewählt.

von Guenter B. (gbl)


Lesenswert?

Denkfehler meinerseits:

Der Wert wird korrekt ausgegeben.
Nur ich Depp habe ihn falsch ins Binärformat umgerechnet und somit etwas 
anderes erwartet.

Danke für die schnelle Antwort und die Tipps zur Schreibweise.

Gruß

Günter

von W.S. (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Allerdings kann man das auch ein bisschen anders schreiben:

Seh ich auch so:

Vergleich = 1<<15;
while (Vergleich)
{ if (Vergleich & sbyte)
    puls(); //sendet langen Impuls
  else
    pause(); //sendet kurzen Impuls
  Vergleich >>= 1;
}


Oder?

Nebenbei kann ich sowas leiden wie die Pest:
Rufus Τ. Firefly schrieb:
> uint16_t Vergleich = 1 << 15;

Schreib lieber
uint16_t Vergleich;

...
 Vergleich = 1<<15;
 while (....

Glaub's mir, der Compiler macht schon das Richtige draus, ohne daß es im 
Code aufträgt. Es ist ne Sache der Vermeidung von Schusselfehlern, 
direkt vor der Verwendung seine Schleifenvariable zu setzen, weil man 
sonst gar zu häufig bei etwas längeren Funktionen selbiges vergißt (Ich 
hab's ja ganz oben schon gemacht..)


W.S.

von Roland (Gast)


Lesenswert?

Mit Atmel habe ich nix am Hut, aber im Prinzip würde ich so vorgehen:

for (i=0;i<16; i++)
{
  Portpin = 0;
  pause (Zeit nach Wunsch)
  Portpin = Variable & 0x0001;
  Variable>>1;
  pause (Zeit nach Wunsch - 2 OPs)
}

Das ganze geht natürlich auch MSB first:

...
  Portpin = Variable & 0x800;
  Variable <<1;
...

Sauberer ist es das Ganze in einen Timer zu schicken, welcher exakt die 
Flanken generiert.

von Roland (Gast)


Lesenswert?

Ups. Fehlt ne '0'

Portpin = Variable & 0x8000;

von Simon S. (-schumi-)


Lesenswert?

Ich würds so machen:
1
for(int8_t i=15; i>=0; i-=1)
2
  (sbyte & (1<<i)) ? puls() : pause();
Ich weis, dass viele Leute das ? nicht so toll finden, aber ich finde es 
bei sehr kurzen Codesequenzen übersichtlicher als auf vier Zeilen 
gestreckt.

Und wer kein >=c99 verwendet, muss das int8_t vor die for-schleife 
setzen.


W.S. schrieb:
> sowas leiden wie die Pest:
> Rufus Τ. Firefly schrieb:
>> uint16_t Vergleich = 1 << 15;
>
> Schreib lieber
> uint16_t Vergleich;
>
> ...
>  Vergleich = 1<<15;
>  while (....
Genau das versuche ich zu vermeiden, da man sonst möglicherweise 
ausversehen die Variable benutzt bevor man sie initialisiert hat. Und je 
nach dem was vorher im RAM stand, bekommt man schwer reproduzierbare 
Ergebnisse.

> Es ist ne Sache der Vermeidung von Schusselfehlern,
> direkt vor der Verwendung seine Schleifenvariable zu setzen, weil man
> sonst gar zu häufig bei etwas längeren Funktionen selbiges vergißt (Ich
> hab's ja ganz oben schon gemacht..)
Ich deklariere meine Variablen erst dort, wo ich sie benötige, 
idealerweise im Schleifenkopf selbst. Nervt, wenn man wieder zum 
Funktionsanfang scrollen muss, nur um nachzusehen, ob die Variable jetzt 
ein int8_t oder ein uint8_t war. Und schön aussehen tut so ein 
Variablenblob am Anfang auch nicht.

von Helmut L. (helmi1)


Lesenswert?

Simon S. schrieb:
> Genau das versuche ich zu vermeiden, da man sonst möglicherweise
> ausversehen die Variable benutzt bevor man sie initialisiert hat. Und je
> nach dem was vorher im RAM stand, bekommt man schwer reproduzierbare
> Ergebnisse.

Das sollte ein vernueftiger Compiler schon anmeckern.

von Marius W. (mw1987)


Lesenswert?

Simon S. schrieb:
> Ich würds so machen:for(int8_t i=15; i>=0; i-=1)
>   (sbyte & (1<<i)) ? puls() : pause();
> Ich weis, dass viele Leute das ? nicht so toll finden, aber ich finde es
> bei sehr kurzen Codesequenzen übersichtlicher als auf vier Zeilen
> gestreckt.

Ist ganz nett, aber man muss sich bewusst sein, dass der erzeugte Code 
je nach Architektur nicht unbedingt ideal wird. Auf einem AVR wird das 
(1 << i) mangels Barrel-Shifters nicht unbedingt performant.

Gruß
Marius

von Peter D. (peda)


Lesenswert?

Ich würds so schreiben:
1
void sendebyte( uint16_t val )
2
{
3
  DDRB=0x01; //schaltet den PIN auf Ausgang
4
  for( uint8_t i = 16; i--; val <= 1 )
5
    val & 1<<15 ? puls() : pause();
6
  DDRB=0x00; //schaltet den PIN wieder auf Eingang
7
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
>   for( uint8_t i = 16; i--; val <= 1 )
______________________________^^^^^^^^
val <<= 1

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.