Warum verwenden die Leute (1 << PA0) beim Festlegen des Ports?

In AVR-Tutorials sehe ich oft:

DDRA |= (1 << PA0);
PORTA |= (1 << PA0);

verwendet statt:

DDRA |= PA0;
PORTA |= PA0;

Was ist der Zweck davon?

Ich weiß nicht viel über AVR, aber (1 << 2) ist nicht dasselbe wie 2.
Weil sie in C programmieren. In Assembler würden Sie direkt eine Bit-Setting-Anweisung verwenden, in Ada haben Sie mehrere Möglichkeiten, zum einen können Sie einfach True oder False einem Mitglied eines gepackten Arrays von booleschen Werten zuweisen:PortA(PAO) := True;
Wenn PA0 eine Bitnummer angibt (z. B. 0 bis 31), dann stellt (1 << PA0) eine Bitmaske oder ein Bitfeld dar, in dem dieses Bit gesetzt ist.
Es scheint, dass Sie bitweise Operatoren nicht verstehen. Hier ist eines, das ich verwendet habe: Bit-Manipulation Es beginnt mit den Grundlagen und geht so weit wie erforderlich.
Abgesehen davon kann man in AVR C normalerweise auch das _BV()Makro verwenden, um den "Bitwert" zu erhalten (z . B. PORTA |= _BV(PA0);. Ich persönlich denke, es macht den Code lesbarer, aber die Meinungen in der Community gehen ziemlich weit auseinander.
Zu Ada: Du hast auch Bitfelder in C.

Antworten (4)

PA0wird als 0 definiert, also die folgende Zeile:

DDRA |= (1 << PA0);

Entspricht dem Verschieben von 1 um null Bits nach links, wobei ein ODER mit dem Wert 1 übrig bleibt, um das erste Bit zu setzen. Während die folgende Zeile:

 DDRA |= PA0;

Führt ein OR mit Null durch, ändert also die Register überhaupt nicht.

Da frage ich mich, warum sie nicht einfach DDRA |= 1. Erwarten sie , dass PA0sie sich in verschiedenen Umgebungen ändern werden?
@corsiKa: was ist einfacher zu lesen und zu verstehen: DDRA |= 72;oder DDRA |= (1<<PA6) | (1<<PA3);?
Ah, es gibt noch andere Bits im Muster. Gotchy. Nein, ich mag es.
@corsiKa, auch wenn Sie nur 1 Bit setzen, ist |= 128sinnvoller als |= (1 << 7). Woher wissen Sie, dass das 7. Bit gesetzt wird, wenn Sie sich Werte wie 128 ansehen?
@LưuVĩnhPhúc Natürlich nicht. Aber für jemanden, der dieses Framework nicht verwendet, ist es auf den ersten Blick nicht klar, dass es ihm wichtig ist, "ein bisschen einzustellen", daher habe ich gefragt. Es genügt zu sagen, dass PA0es nicht sehr beschreibend ist, was es tatsächlich tut.

Warum tun sie das? Wahrscheinlich, weil alle anderen, die sie um Hilfe bitten oder von denen sie gelernt haben, es so gemacht haben. Und weil die Standarddefinitionen seltsam gemacht sind.

Das Verschieben um eine Zahl, typischerweise eine Dezimalzahl, verschiebt diesen Wert um so viele Binärstellen. 1 << PA0verschiebt sich um 1 PA0nach links. Da PA00 ist, gibt es keine Verschiebung. Aber gegebene 1 << 61 wird zu 0b1000000. Gegeben 13 << 6wird 13, binär 0b1101, um 6 verschoben, um 0b1101000000 oder 832 zu werden.

Jetzt müssen wir sehen, wie PA0 - PA7 definiert sind. Diese werden normalerweise in dem spezifischen Header für Ihren spezifischen Mikrocontroller definiert, der über io.h oder portpins.h enthalten ist

#define     PA7   7
#define     PA6   6
~
#define     PA1   1
#define     PA0   0

Sie sind als ihre numerische Position dezimal definiert!

Sie können nicht direkt als Bits zugeordnet werden, da es sich nicht um einzelne Bits handelt.

Wenn Sie davon ausgehen, PORTA |= PA7;dass PORTA 0b00000000 ist (alles aus), erhalten Sie:

PORTA = PORTA | PA7;oder PORTA = 0 | 7;oderPORTA = 0 | 0b111

Sehen Sie das Problem? Sie haben gerade PA0, PA1, PA2 anstelle von PA7 eingeschaltet.

Funktioniert aber PORTA |= (1 << PA7);wie erwartet.

PORTA = PORTA | (1 << PA7);oder PORTA = 0 | (1 << 7);oderPORTA = 0 | 0b10000000;


Der intelligentere Weg

Der andere, bessere Mikrocontroller, der MSP430, hat eine Standarddefinition von Bits als:

#define BIT0                (0x0001)
#define BIT1                (0x0002)
~
#define BIT6                (0x0040)
#define BIT7                (0x0080)

Diese sind als ihre binäre Position in Hex definiert. BIT0 ist 0b0001, nicht wie PA0, das 0 ist. BIT7 ist 0b10000000, nicht wie PA7, das 0b111 ist.

Direkte Zuweisungen wie P1OUT |= BIT7;funktionieren also genauso wie P1OUT |= (1 << 7);würden.

Ihre Frage wurde bereits beantwortet, aber ich möchte eine Alternative vorstellen, die für einen Kommentar etwas zu viel war. Eines der ersten Dinge, die ich tue, wenn ich ein eingebettetes Projekt starte, ist, meinen Bitsatz zu definieren und Makros zu löschen.

#define bitset(var,bitno) ((var) |= 1 << (bitno))
#define bitclr(var,bitno) ((var) &= ~(1 << (bitno)))

Mit den Makros wird Ihr Code zu:

bitset(DDRA,0);
bitset(PORTA,0);

Das Endergebnis ist eine Bit-Set-Anweisung in Assembler.

Sie haben sich vertippt, die zweite Zeile sollte zB "bitclear" lauten.
Dein 2. #define, nicht dein 2. Beispiel.

Schau mal hier: http://nongnu.org/avr-libc/user-manual/FAQ.html#faq_use_bv

Diese Makros werden verwendet, wenn bestimmte Bits in einem Register gesetzt werden. Beispiel: Wenn PORTA 8 Bit breit ist, dann ist PA0 das niedrigste Bit, PA7 das höchste. Um PA0 auf 1 zu setzen, müssen Sie 0x01 in das Register schreiben ("or-write"). Wenn Sie PA2 setzen möchten, benötigen Sie einen Wert, der im Binärformat an der richtigen Stelle eine Eins enthält, für PA2 ist dies 0x04.

Die Leute wollen sich nicht merken, welches Bit eine bestimmte Position hat (da andere Register andere Bitnamen haben können, z. B. CS12, CS10, ADSC usw.), also verwenden sie abstraktere Namen. Anstatt PORTA = 0x04 einzugeben, geben Sie PORTA = _BV(PA2) ein und Sie wissen sofort, dass Pin PA2 hoch wird.