Forum: Mikrocontroller und Digitale Elektronik Frage zu Bitoperatoren in C (AVR)


von O. A. (sokrates1989)


Lesenswert?

Hallo,

was bedeutet das (1<<PB2) ?

PB steht wohl für PortB.. Muss man das dem MC noch mitteilen oder weiß 
der das.



if (PINB & (1<<2)||(PINB & (1<<3)))

wenn ich soetwas habe, soll das bedeuten wenn "PinB2 = 1" oder "PinB3 = 
1"
dann wäre die Bedingung erfüllt?

Und wäre dann (0<<PB2) = PortB2 = 0?

Danke.

von Olly T. (twinpeaks)


Lesenswert?

O. A. schrieb:

> was bedeutet das (1<<PB2) ?

PB2 ist irgendwo in einem AVR-spezifischen Headerfile als 2 definiert.
Damit bedeutet das '1 um 2 Bits nach links geschoben' und soll als 
Bitmaske für PortB Bit 2 stehen. Kann man auch als 0x04 schreiben oder 
00000100 binär (wobei das kein Standard-C ist).


> PB steht wohl für PortB.. Muss man das dem MC noch mitteilen oder weiß
> der das.

Das muss man dem C-Compiler mitteilen, i.d.R. durch inkludieren einer 
passenden Headerdatei. Das hat alles schon einmal jemand definiert.



> if (PINB & (1<<2)||(PINB & (1<<3)))
>
> wenn ich soetwas habe, soll das bedeuten wenn "PinB2 = 1" oder "PinB3 =
> 1"
> dann wäre die Bedingung erfüllt?

Ja.



> Und wäre dann (0<<PB2) = PortB2 = 0?

Nein.

if (PINB & (1<<2)) ist die Kurzform für
if ((PINB & (1<<2)) != 0)


Das Inverse wäre dann
if ((PINB & (1<<2)) == 0)
oder
if (!(PINB & (1<<2)))

von foobar (Gast)


Lesenswert?

> Das Inverse wäre dann
> if (PINB & (1<<2)) == 0)
> oder
> if (!(PINB & (1<<2)))
  oder
  if (~PINB & (1<<2))

von Wolfgang (Gast)


Lesenswert?

O. A. schrieb:
> PB steht wohl für PortB.. Muss man das dem MC noch mitteilen oder weiß
> der das.

Nein, das "PB" ist dabei völlig bedeutungslos. Entscheiden ist die 2 und 
die steht für das zweite Bit (irgendeines Bytes, das kann genauso Port C 
sein).

von Einer K. (Gast)


Lesenswert?

Wolfgang schrieb:
> Nein, das "PB" ist dabei völlig bedeutungslos. Entscheiden ist die 2 und
> die steht für das zweite Bit (irgendeines Bytes, das kann genauso Port C
> sein).
Das ist nicht ganz richtig!
Ein bisschen Sorgfalt kann auch dort nicht schaden!

Beispiel:
Beim ATMega328P ist PC7 nicht definiert.
PB7 dagegen existiert.

Es ist also nicht immer bedeutungslos, ob B oder C.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Arduino F. schrieb:
> Es ist also nicht immer bedeutungslos, ob B oder C.

Da PB2 = PC2 = 2, ist es im Prinzip egal, was man verwendet.
Nur der geneigte Leser könnte darüber stolpern. Dem Compiler und dem 
Prozessor ist es egal.

von Einer K. (Gast)


Lesenswert?

Christian H. schrieb:
> Da PB2 = PC2 = 2, ist es im Prinzip egal, was man verwendet.
Auch du sprichst über die Implementierung!

Bitte nutze und verbreite die Schnittstelle.
(du selber musst dich ja nicht daran halten, auf deinem Basteltisch)

von Wolfgang (Gast)


Lesenswert?

Arduino F. schrieb:
> Das ist nicht ganz richtig!

Was ist  daran nicht richtig?

Welche Bedeutung hat denn das "PB" deiner Meinung, außer dass es ein 
Namensteil ist, der genauso gut auch MEINPORTBIT heißen könnte

> Beim ATMega328P ist PC7 nicht definiert.
> PB7 dagegen existiert.

Da kommt man hinter, spätestens wenn der Compiler meckert. Nicht 
definierte Zeichenketten zu verwenden, bringt natürlich nichts.

Trotztdem verbirgt sich sowohl hinter PB6 als auch hinter PC6 die Zahl 
6, vorausgesetzt es gibt beide in der betreffenden Prozessordefinition.

von Einer K. (Gast)


Lesenswert?

Wolfgang schrieb:
> Welche Bedeutung hat denn das "PB" deiner Meinung,
>....
> Da kommt man hinter, spätestens wenn der Compiler meckert.

Genau!
Das hast du gut erkannt.
Und darum sollte man auch die richtigen Bezeichner verwenden, damit der 
Compiler eine Chance hat.

Hier mal ein schlechtes Beispiel:
PORTC |= (1<<PB7)
Der Kompiler ist still!

So musses:
PORTC |= (1<<PC7)
Der Kompiler schreit

Wolfgang schrieb:
> außer dass es ein
> Namensteil ist, der genauso gut auch MEINPORTBIT heißen könnte
Zuhause kannst du alles so nennen, wie du willst.
Aber die Verwendung von PB7 oder auch PB2 sind feste Konventionen.

von Axel S. (a-za-z0-9)


Lesenswert?

Christian H. schrieb:
> Arduino F. schrieb:
>> Es ist also nicht immer bedeutungslos, ob B oder C.
>
> Da PB2 = PC2 = 2, ist es im Prinzip egal, was man verwendet.

Es ist nur in diesem speziellen Fall egal. Weil bei Atmel netterweise 
die Numerierung von Pins und Bits in den Steuerregistern gleich ist.

Wolfgang schrieb:
> Welche Bedeutung hat denn das "PB" deiner Meinung, außer dass es ein
> Namensteil ist, der genauso gut auch MEINPORTBIT heißen könnte

Genau das ist der wichtige Teil. Genau deswegen verwendet man sprechende 
Bezeichner für Makros (wie hier) oder Variablen (anderswo). PB2 ist die 
Nummer des Steuerbits für den Pin mit dem Namen PB2. Und weil man 
entsprechende Makros für die Steuerbits aller Pins hat, muß und will 
man sich gar nicht mehr damit auseinandersetzen, ob PB2 und PC2 am Ende 
zur gleichen Nummer werden.

Wenn man den Pin PB2 in DDRB/PINB/PORTB anspricht, verwendet man einfach 
das PB2 Makro und fertig. Das ist einfach (lesbar) und selbsterklärend. 
Zugegeben, bei der sehr regulären Anordung der IO-Pins scheint das etwas 
überzogen, aber bei anderen Steuerbits (z.B. beim UART) wird es sofort 
klar, warum man die (und genau nur die) Makros aus den Headerfiles 
nehmen will.

von Heiko L. (zer0)


Lesenswert?

Axel S. schrieb:
> Und weil man
> entsprechende Makros für die Steuerbits aller Pins hat, muß und will
> man sich gar nicht mehr damit auseinandersetzen, ob PB2 und PC2 am Ende
> zur gleichen Nummer werden.

Andererseits glaube ich kaum, dass jemand ein
1
PORTD = 0x11;
gegen
1
PORTD = (1<<PORTD5) | (1<<PORTD1)
austauschen würde. Oder hat wer für sowas einen entsprechenden "switch" 
Verteiler? :D

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Heiko L. schrieb:
> gegenPORTD = (1<<PORTD5) | (1<<PORTD1)
Das haut dir der Kompiler um die Ohren

von Heiko L. (zer0)


Lesenswert?

Arduino F. schrieb:
> Heiko L. schrieb:
>> gegenPORTD = (1<<PORTD5) | (1<<PORTD1)
> Das haut dir der Kompiler um die Ohren

Aber den Gedanken hast du verstanden?

von Einer K. (Gast)


Lesenswert?

Nein!

Korrektur!

>PORTD = (1<<PORTD5) | (1<<PORTD1)
kompiliert bei mir sehr wohl
Also nix "um die Ohren"

von Felix P. (fixxl)


Lesenswert?

Heiko L. schrieb:
> Andererseits glaube ich kaum, dass jemand ein PORTD = 0x11;
>
> gegen PORTD = (1<<PORTD5) | (1<<PORTD1)
>
> austauschen würde

Das wäre nicht gut, denn PORTD = 0x11 setzt PD4 und PD0, nicht PD5 und 
PD1.

: Bearbeitet durch User
von Heiko L. (zer0)


Lesenswert?

Felix P. schrieb:
> Heiko L. schrieb:
>> Andererseits glaube ich kaum, dass jemand ein PORTD = 0x11;
>>
>> gegen PORTD = (1<<PORTD5) | (1<<PORTD1)
>>
>> austauschen würde
>
> Das wäre nicht gut, denn PORTD = 0x11 setzt PD4 und PD0, nicht PD5 und
> PD1.

Aber sonst würdest du den einbauen?

von Wilhelm M. (wimalopaan)


Lesenswert?

Axel S. schrieb:
> Wolfgang schrieb:
>> Welche Bedeutung hat denn das "PB" deiner Meinung, außer dass es ein
>> Namensteil ist, der genauso gut auch MEINPORTBIT heißen könnte
>
> Genau das ist der wichtige Teil. Genau deswegen verwendet man sprechende
> Bezeichner für Makros (wie hier) oder Variablen (anderswo). PB2 ist die
> Nummer des Steuerbits für den Pin mit dem Namen PB2. Und weil man
> entsprechende Makros für die Steuerbits aller Pins hat, muß und /will/
> man sich gar nicht mehr damit auseinandersetzen, ob PB2 und PC2 am Ende
> zur gleichen Nummer werden.

Das Problem ist jedoch, dass man auch
1
TCCR0A |= (1 << WGM02);
schreiben kann, und der Compiler es übersetzt. Denn TCCR0A ist vom Typ 
volatile uint8_t und (1 << WGM02) hat den Typ int, und das ist implizit 
konvertierbar.

Besser wäre es, wenn TCCR0A einen speziellen Typ hätte und es für die 
Bits des TCCR0A und TCCR0B jeweils auch andere Typen geben würde, die 
dann inkompatibel sind, so dass der obige Code zu einem Compilzeitfehler 
führt.

Das lässt sich mit C aber leider nicht machen (mit anderen Sprachen 
schon).

von O. A. (sokrates1989)


Lesenswert?

ich habe noch eine Frage.

was bedeutet "==", entspricht das in Assembler etwa "cpi" ?

Das heißt wenn zwei Ausdrücke gleich sind, wird das Z-Flag gesetzt?

Und was ist bedeutet "&=~"

Portb &=~ (1<<PB7)

wobei "~" eine bitweise negation ist. aber in Zusammenhang mit dem dem 
Gleich und "&"?

von Einer K. (Gast)


Lesenswert?

O. A. schrieb:
> wobei "~" eine bitweise negation ist. aber in Zusammenhang mit dem dem
> Gleich und "&"?
Auch dort!

> Portb &=~ (1<<PB7)


 (1<<PB7) == 0b10000000
~ 0b10000000 == 0b01111111

PORTB = PORTB & 0b01111111;

von dummschwaetzer (Gast)


Lesenswert?

lösche Bit7

von Rolf M. (rmagnus)


Lesenswert?

Axel S. schrieb:
> Wenn man den Pin PB2 in DDRB/PINB/PORTB anspricht, verwendet man einfach
> das PB2 Makro und fertig.

Eigentlich gibt es für die Nutzung mit dem PIN-Register den Namen PINB2 
und für das DDRB-Register den Namen DDB2. Denn so heißen diese Bits auch 
im Datenblatt des Prozessors.

von foobar (Gast)


Lesenswert?

> Und was ist bedeutet "&=~"
>
> Portb &=~ (1<<PB7)

Das sind zwei Operatoren, &= und ~, nur ohne Leerstellen direkt 
hintereinander geschrieben. Etwas anders formatiert:

Portb &= ~(1<<PB7)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

foobar schrieb:
> Etwas anders formatiert:
> Portb &= ~(1<<PB7)
Und etwas ganz ausgeschrieben dann:
Portb = Portb & ~(1<<PB7);
In Worten: lese Portb, lösche im gelesenen Wert das Bit 7 durch verUNDen 
mit dem invertierten Wert von 1000000 und schreibe das Ergebnis wieder 
zurück an Portb

: Bearbeitet durch Moderator
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.