www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Bits schieben


Autor: Heiopei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wollte die (invertierten) Portleitungen D7~4 abfragen.
Ergebnis sollte eine Zahl von 0 bis 15 sein.
unsigned char n;
n = (~PIND) >> 4;
Zuerst wird doch PIND invertiert.
Dann wird das Ergebniss viermal rechtsgeschoben.
Da n unsigned char ist, sollten doch links nullen nachgeschoben werden?!
Leider klappt das so nicht.
unsigned char n;
n = ((~PIND) >> 4) & 0b00001111;
Aber so klappt es. Warum ist die maskierung mit 0b00001111 nötig?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Überrascht mich jetzt spontan auch.
Offenbar ist ~PIND erstmal wieder signed.
Die Lösung ist:
n = ( (unsigned char /* bzw. uint8_t */)(~PIND) >> 4) & 0b00001111;

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiopei schrieb:

> Da n unsigned char ist, sollten doch links nullen nachgeschoben werden?!

Diese Begründung ist nicht richtig. Mit n hat das nix zu tun, da n gar 
nicht geschoben wird.

Jetzt fragt sich, ob der Kompiler aus den 8Bit bei der Komplementierung 
von PIND einen Integer macht. Der wäre auf dem AVR 16 bit breit. Dann 
wird bei

   PIND = 0b01010101

das Ergebnis von ~PIND auf 16 Bit aufgebohrt, also:

   ~PIND : 0b1111111110101010

Wenn man das nach rechts schiebt um 4 Stellen, dann wird daraus:

   (~PIND) >> 4: 0b1111111111111010

Oben schieben sich bei negativen Zahlen (2er Komplement) 1en rein[1], 
spielt hier aber keine Rolle, denn es werden nur die untersten 8 Bit im 
n gespeichert. Dann sieht n so aus:

   n: 0b11111010

Wohlgemerkt, alles nur, wenn der Compiler das Ergebnis von ~PIND auf 16 
Bit (= Integer auf z.B. ATmega8) aufbohrt. Um welchen Compiler/Prozessor 
handelt es sich denn?

Gruß,

Frank

[1] Vielleicht wird aus ~PIND auch ein unsigned int, dann kommen halt 4 
0en von oben rein. Nützt Dir aber auch nix. Du hast immer noch 4 Einsen 
vor Deinem Wert.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Überrascht mich jetzt spontan auch.
> Offenbar ist ~PIND erstmal wieder signed.

Ob signed oder nicht, ist egal, ~PIND es ist halt ein Integer mit 16 
Bit. Kann auch unsigned int sein, Du hast trotzdem 8 Einsen im 
höherwertigen Byte. Die kriegst Du durch Shiften um 4 Stellen auch nicht 
weg ;-)

> Die Lösung ist:
>
> n = ( (unsigned char /* bzw. uint8_t */)(~PIND) >> 4) & 0b00001111;
> 

Jepp. Hier verkleinerst Du (~PIND) wieder auf 8 Bit. Damit ist wieder 
alles im Lot und das "& 0b00001111" kann man sich wieder sparen.

Gruß,

Frank

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Jetzt fragt sich, ob der Kompiler aus den 8Bit bei der Komplementierung
>von PIND einen Integer macht.

Das kann ich bestätigen. Ich hatte ein vergleichbares Problem vor 
längerer Zeit.

Autor: Heiopei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen Dank für die rege Anteilnahme

Frank M. schrieb:
> Um welchen Compiler/Prozessor handelt es sich denn?

Der Compiler ist der GCC vom AVR Studio 4.
Der Proz ist der ATmega8.

In der Datei IOM8.h steht:
#define PIND  _SFR_IO8(0x10)

Nun ist mir immer noch nicht klar, wie der Compiler darauf kommt,
das Ergebnis von ~PIND auf 16 Bit aufgebohren.
Klar, das maskieren mit 0b00001111 oder casting auf unsigned char hilft, 
ist aber irgendwie nur ein kurieren der Sympthome...   ;-)

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stichwort: Integer promotion.  Die gilt auch für den ~-Operator.  Sie 
besagt (vereinfacht), dass alle Berechnungen mindestens in int 
durchzuführen sind und für kleinere Typen vor der Anwendung des 
Operators zunächst die Variablen nach int aufgeblasen werden müssen.

Der Compiler berechnet also zu Recht das Komplement von 0x00n0 anstelle 
von 0xn0.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.