PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verständnisproblem Bitoperator mit µC-PIN



AVRprogger91
18.12.2016, 17:58
Hallo Leute,

ich habe hier eine Schreibweise mit dem Bitoperator "<<" die mir nicht einleuchtet.

Der Bitoperator: "<<" macht ja nicht anderes als einen bestimmten Wert um einen Wert nach links zu schieben.

Bsp: (1 << 5) hier wird einfach der Wert "1" um n-Stellen in diesem Fall: "5" nach links geschoben.

Soweit ist mir alles klar.

Nur diese Schreibweise verstehe ich nicht:

DDRD |= (1<<PD5);

Erklärung:

Hier wird die "1" um "PD5" nach links geschoben.
Danach wird der Wert der sich im "DDRD-Register" befindet mit dem Wert "(1<<PD5)" ODER-Verknüpft und wieder in das DDRD-Register gespeichert.
Dies ist das "|=".

Das ganze soll den PD5-Pin vom Port: "D" auf 1 setzen also auf Ausgang schalten.

HÄ??

„PD5“ ist ja im Hintergrund nichts anderes als ein Binär-Wert wie z.B.: 01101000 (nur fürs Verständnis).
Dieser Wert wird dann mit irgendeinen Wert der im DDRD-Register steht ODER-Verknüpft und dann wieder in DDRD abgespeichert.

Da kommt doch irgendein Wert heraus, wie soll das den PIN: PD5 auf 1 setzen??

Wenn er schreiben würde: (PD5 == 1) dann ist dieser Pin als Ausgang definiert.

Ich verstehe das nicht.

MfG

021aet04
18.12.2016, 18:31
DDRD => Richtungsregister für Port D => In einer Headerdatei definiert
PD5 => Ausgangspin 5 auf Port D => In einer Headerdatei definiert
Das "<<" Zeichen bedeutet links schieben
das "|=" ist eine Oder Verknüpfung und danach wieder zurückschreiben
das "==" Zeichen ist ein Vergleichsoperator, nicht zu verwechseln mit "="

PD5 ist ist als "5" definiert

Die Zeile "DDRD |= (1<<PD5)" kann man auch so schreiben "DDRD = DDRD | (1<<PD5)"
Du darfst aber nicht "DDRD = (1<<PD5)" schreiben.

Bei "DDRD |= (1<<PD5)" wird DDRD eingelesen und nur PD5 geändert, wenn z.B. PD1 gesetzt ist, bleibt es gesetzt, da du den Oder Operator genutzt hast
Bei "DDRD = (1<<PD5)" wird nur PD5 gesetzt, egal was vorher gesetzt wurde.

"PD5 == 1" wird nur bei einer Prüfung verwendet, z.B. wenn du eine If-Schleife verwendest, also "if (PD5 == 1){ .... }"
"PD5 = 1" bewirkt aber etwas anderes, in der Headerdatei wird PD5 als 5 definiert, wenn du in deinem Programm "PD5 = 1" schreibst wird 5 mit 1 ersetzt.

Hoffe es war verständlich.

MfG Hannes

AVRprogger91
18.12.2016, 19:02
Das heißt:

Zuerst wird das DDRD-Register eingelesen.
Da dieses Register 8 Pins beinhaltet und die anderen PIN's bereits gesetzt sein können verwende ich den ODER-Operator.
Den bei ‚0 ODER 0‘ bleibt alles 0. Bei ‚1 ODER 0‘ bleibt es 1.
Somit wird bei den alten PIN’s nichts verändert.
Wenn ich den ODER-Operator anwende, dann bleibt alles bis auf den einen PIN PD5 gleich.
Bei (1<<PD5) wird der PIN PD5 von 0 auf 1 gesetzt.
Da es beim PD5-Pin eigentlich nur 0 & 1 gibt, kann mit dem "<<-Operator" eigentlich nur von 1 auf 0 oder von 0 auf 1 verschoben werden, oder?
Wenn alles Oder-Verknüpft wurde, dann wird das ganze wieder in das DDRD-Register gespeichert.

Stimmt das jetzt so, wie ich das erklärt habe?

021aet04
18.12.2016, 19:13
Grundsätzlich richtig, einen kleinen Fehler gibt es. Du kannst nur setzten (0 => 1) aber nicht rücksetzen (1 => 0).

Wenn man etwas rücksetzen will muss man den mit & Verknüpfen und was man rücksetzen will invertieren. Also z.B. "DDRD &= ~(1<<PD5)".

Zum Testen kann ich dir den Windowstaschenrechner empfehlen (umstellen auf "Programmierer").

Als Tutorial kann ich dir das AVR-GCC-Tutorial auf mikrocontroller.net empfehlen (https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial)

MfG Hannes

AVRprogger91
18.12.2016, 21:16
In Binär sieht das dann so aus:

PD5 ist ja "5".

DDRD |= (1<<PD5)

DDRD ist z.B. 10000011.

(1<<PD5) ist 00000001 um 5 stellen nach links verschoben ergibt das: 00100000

Hier wird diese Operation durchgeführt: "|="

ODER-Verknüpfen:

10000011
00100000
---------
10100011 -> Dieser Wert wird nun in das DDRD-Register gespeichert.


Alter Wert von DDRD-Register = 10000011 (Hier ist der PIN: 0,1,7 als Ausgang definiert).
Neuer Wert von DDRD-Register = 10100011 (Hier ist der PIN: 0,1,5,7 als Ausgang definiert).

Hab ich das so richtig aufgeschrieben?


MfG

021aet04
18.12.2016, 21:22
Ja das stimmt so.

MfG Hannes

Peter(TOO)
19.12.2016, 01:13
Hab ich das so richtig aufgeschrieben?
Soweit ist alles richtig.

Es gibt noch einen kleinen Haken an der Geschichte:
Bei manchen µCs ist das DDR-Register nicht lesbar, bzw. liefert immer den Wert 0xFF beim Lesen. Dies ist vor allem bei µCs welche auf der Motorola-Architektur aufbauen verbreitet.

Das steht aber im Datenblatt des µCs.

z.B. https://www.renesas.com/en-eu/doc/products/mpumcu/001/e602095_h83217.pdf?key=7f3f3b11b052be7e7c40fb0fdda 5d9dc
Seite 117: P1DDR kann nur geschrieben werden.


MfG Peter(TOO)

Ceos
19.12.2016, 12:09
und um die Verwirrung zu komplettieren:

XMega Prozessoren haben zu den DIR registern auch noch ein DIRSET und DIRCLR
die ersparen dir das verodern, du schreibst einfach in das SET oder CLR register das bit hinein dass du setzen oder löschen möchtest :)

AVRprogger91
20.12.2016, 06:24
Das heißt, das was ich im Beitrag: "#5" geschrieben habe kann ich nicht bei einem ATxMega anwenden sondern nur bei einem ATmega?

Peter(TOO)
20.12.2016, 08:19
Das heißt, das was ich im Beitrag: "#5" geschrieben habe kann ich nicht bei einem ATxMega anwenden sondern nur bei einem ATmega?
Doch, direkt auf dem DIR-Register funktioniert es so wie in #5 beschrieben.

Zusätzlich ist aber die ODER-Verknüpfung auch als Hardware vorhanden.

DIR |= (1<<P5);
funktionier auch auf dem xMEGA.

Zusätzlich geht aber auch:
DIRSET = (1<<P5);

Zudem kann man über DIRSET auch mehrere Bits gleichzeitig setzen:
DIR |= ((1<<P5)|(1<<P4)|(1<<P3));
oder
DIRSET = ((1<<P5)|(1<<P4)|(1<<P3));

besonders das Zurücksetzen wird noch etwas vereinfacht
DIR &= ¨(1<<P5);
oder
DIRCLR = (1<<P5);

MfG Peter(TOO)

Ceos
20.12.2016, 08:24
das spart wertvolle Rechentakte, vor allem beim Bitbanging! (Also wenn man irgend einen Bus in Software simuliert)

AVRprogger91
20.12.2016, 09:17
O.K.,

das heißt beim xMega muss ich halt das Register: "DIR" statt "DDRx" verwenden, wenn ich es so machen will wie in meinem Beitrag #5.
Dann funktioniert das genauso.

Danke für die Hilfe!

MfG

Ceos
20.12.2016, 10:03
korrekt!

die REgister sind beim XMega allerdings etwas anders strukturiert als beim normalen Mega

PORTx.DIR zum beispiel statt DDRx wie du es beschrieben hast. Es werden zwar auch die entsprechenden direkten PORTx_DIR Makros angeboten, aber nicht für alle Funktionen des Controller, daher ist es besser sich gleich die Struktur Variante anzugewöhnen.

Und behalte die Verwendung der DIRSET und DIRCLR REgister im Hinterkopf, die Dokumentation greift sehr oft darauf zurück und es spart wie erwähnt Rechentakte (falls es der Compiler am ende nicht sowieso optimiert, wäre interessant mal den Assembler Code dazu zu debuggen)

PS: es gibt sogar ein DIRTGL bei dem man mit einer einfachen 1 den pin hin und herschalten kann mit nur einem Rechencycle :)

AVRprogger91
21.12.2016, 12:04
Super, danke für die Hilfe!