Forum: Compiler & IDEs Bit value _BV ??????? AVR-libc


von Calik (Gast)


Lesenswert?

Hallo.

Ich bin ein Neuling im Bereich AVR. wenn ich es richtig verstanden
habe, steht in der AVR-libc, das man mit diesem macro "_BV" einzelne
Bits in besonderen Registern setzen kann, z.B. für USART : UCRSB =
_BV(Bit-name);.

Wird Bit dann logisch high?

Die Frage hört sich zwar blöd an (setzt Bits = logisch high), aber dann
lese ich weiter und da steht "DDRD = _BV(PD7); //make PD7 an output".

Wird hier PD7 auch gleichzeitig gesetzt?
____________________________________________________________________

Also heisst das explizit:

1. Ich kann mit _BV Eingänge und Register-Bits setzen und
2.  "   "    "   "  Pins zum output machen.

?????????????????????????????????????????????????????????
____________________________________________________________________

Danke.

von Alex (Gast)


Lesenswert?


von Jan L. (flednanders)


Lesenswert?

habe gerade das selbe problem wie der threadsteller, aber der link ist 
nich mehr verfügbar. Kann mir jemand helfen? was macht _BV() jetzt 
genau?

von Karl H. (kbuchegg)


Lesenswert?

_BV ist nur ein Makro, welches den Ausdruck 1 << Bitnummer kapselt

#define _BV(bit)   (1 << (bit))


Was auch immer man damit dann weiter macht, hat mit _BV nichts zu tun.

Das Setzen bzw. Löschen von Bits machen die |= bzw. &= ~ Operationen


   register |= ( 1 << Bitnummer );   // bit setzen
   register &= ~( 1 << Bitnummer );  // bit löschen


ob man das jetzt so schreibt, oder ob man es so schreibt

   register |= _BV( Bitnummer );
   register &= ~ _BV( Bitnummer );

schenkt sich nichts. Denn nach der Makroersetzung von _BV kommt erst mal 
exakt das gleiche raus. Der Threadersteller interpretiert in das _BV 
Makro etwas hinein, was es nicht leistet. Er hat nicht verstanden, was 
an den ganzen Bit-Operationen der wesentliche Kernpunkt ist, der das 
gewünschte leistet und was nur Schreiberleichterung ist.

Es ist als ob man sagen würde:

Die Fläche eines Rechtecks errechnet sich zu

  Fläche = Länge * Breite

definiere ich mir statt dessen ein Makro
#define AREA(l,b)  (l*b)
und schreibe

  Fläche = AREA(Länge, Breite)

kann ich dann mit AREA auch die Fläche eines Kreises ausrechnen?

Es ist nicht die Multiplikation an sich oder dieses Makro, die die 
Fläche berechnet. Es ist die komplette Operation, die das für ein 
Rechteck macht. Und es ist völlig egal, ob ich da einen Teil dieser 
Operation in einem Makro verstecke oder nicht.

von Bernd S. (bernds1)


Lesenswert?

Beispiel:
PORTB |= _BV(PB7);

macht das gleiche wie:
PORTB |= 1<<PB7;

Nur eine andere Schreibweise. Wobei ich die zweite bevorzuge, weil man 
dort schon am Operator sieht, was gemacht wird. Nämlich eine 1 um 7 
Stellen nach links geschoben.

Gruß Bernd

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Eine Zahl erzeugen, die die als Parameter übergebene Bitnummer als
einziges Bit gesetzt hat.

Wenn der Parameter eine Konstante ist, ist das Ergebnis ebenfalls
eine Konstante.

Das ist keine weitere Magie als ganz simpel:
1
#define _BV(x) (1 << (x))

Hintergrund ist, dass beim AVR alle Bitnamen für die IO-Register
nur in Bitnummern auflösen.  Das hat man seinerzeit wohl so gewählt,
damit man einen dummen Assembler bauen kann, der die Bitnummern in
seinen SBI- und CBI-Befehlen direkt als Operand angeben kann.(*)
Da man in C jedoch nicht mit Bitnummern direkt arbeiten kann, sondern
immer Bitmasken benutzen muss, haben in der Folge alle C-Programmierer
nun die idiotische Aufgabe, für jede Bitnummer die zugehörige Maske
zu errechnen.  Man hat also zugunsten eines dummen Assemblers alle
C-Programmierer mit Strafarbeit versorgt (und das, obwohl eigentlich
von vornherein C das Primat für diese Controller haben sollte …).

(*) Es wäre kein Problem gewesen, diese Definition anders aufzuziehen
und die Bits gleich als Masken zu definieren.  Symbolisch ändert sich
gar nichts:
1
SBI  DDRB, PB5
nur numerisch wäre es dann:
1
SBI  0x04, 0x20
statt derzeit
1
SBI  0x04, 5

Für einen Assembler sollte es eine Kleinigkeit sein, das Argument
0x20 dahingehend zu überprüfen, dass genau 1 Bit im Bereich 0 bis
7 darin gesetzt ist, und dann dessen Nummer in den Opcode zu
übernehmen.

von Jan L. (flednanders)


Lesenswert?

Vielen dank für die ausführlichen erklärungen

von Εrnst B. (ernst)


Lesenswert?

Bernd S. schrieb:
> Beispiel:
> PORTB |= _BV(PB7);
>
> macht das gleiche wie:
> PORTB |= 1<<PB7;
>
> Nur eine andere Schreibweise. Wobei ich die zweite bevorzuge, weil man
> dort schon am Operator sieht, was gemacht wird. Nämlich eine 1 um 7
> Stellen nach links geschoben.

Wobei die erste Schreibeise den Vorteil hat, dass Anfänger nicht zu 
konstrukten wie
 PORTB |= 0 << PB7;
verleitet werden, wenn sie ein Bit löschen wollen...

von Shadow (Gast)


Lesenswert?

Und und möchte lieber _BV() schreiben, weil mein kleiner Finger bei << 
nicht so zielsicher ist.
vielleicht mach ich mir aber noch Textschnippsel in gedit für
(1<< )
aber was wenn ich doch im vim bin?
hab da noch keine textschnippel-funktion...
wobei mir _ und großbuchstaben auch wieder nerven, vielleicht doch 
wieder ein eigenes #define wie bv oder sbit odersowas

von Andreas B. (andreas_b77)


Lesenswert?

Shadow schrieb:
> aber was wenn ich doch im vim bin?
> hab da noch keine textschnippel-funktion...

:help abbreviations

von Shadow (Gast)


Lesenswert?

> :help abbreviations
ah, danke, spiel ich gleich mal mit rum.
Und ich hab gestern snipMate gefunden, werd ich auch noch probieren.

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.