Hallo,
was bedeutet eigentlich das "PINA0" beim Bit-Shiften in Ausdrücken wie
Code
1
if((PINA&(1<<PINA0)==0){
2
// wird ausgeführt, wenn PinA0 auf LO gezogen wird
3
}
4
Code
?
Sind das einfach nur die jeweiligen Potenzen von 2, also
PINA0 = 2^0 = 1
PINA1 = 2^1 = 2
PINA2 = 2^2 = 4
etc.
Könnte man es dann auch einfach so schreiben?
Code
1
if((PINA&(1<<1)==0){// "PINA0" durch "1" ersetzt
2
// wird ausgeführt, wenn PinA0 auf LO gezogen wird
3
}
4
Code
(Die Frage gilt natürlich analog auch für Ausdrücke wie PINB0, PIND7
usw.)
Es ist die Anzahl die eine ›1‹ geschoben werden muss damit sie an der
richtigen Position ist. Also im einfachsten Fall entspricht PINA0…PINA7
== 0…7
Sehr vereinfacht, bestimmt werden gleich eine Menge zorniger Kommentare
auf Sonderfälle hinweisen… ;-)
kai schrieb:> Könnte man es dann auch einfach so schreiben?> Code
1
>if((PINA&(1<<1)==0){// "PINA0" durch "1" ersetzt
2
>// wird ausgeführt, wenn PinA0 auf LO gezogen wird
3
>}
4
>Code
Nein, denn PINA0 ist mit großer Wahrscheinlichkeit 0 nicht 1. Kann aber
auch was völlig anderes sein (sehr unwahrscheinlich).
So etwas wie
1
if (( PINA & (1 << PINA0) == 0) {
nennt man ein Idiom. https://en.wikipedia.org/wiki/Programming_idiom
Etwas was man immer so hin schreibt - damit man eben nicht Fehler macht
wie mal 0 und 1 verwechseln. Dinge die man so schreibt weil man sie so
schreibt, weil "jeder" sie so schreibt und Jahrzehnte Erfahrung gezeigt
haben dass es so am vernünftigsten ist. Ausnahmen gibt es bei
Bullshit-Hipster-Programmiersprachen wo Leute sich unbedingt im
persönlichen Ausdruckstanz üben möchten.
Ich würde es noch etwas anders schreiben
1
if(!(PINA & (1 << PINA0)) {
Das ist dann für Leute die wissen wie C funktioniert.
PINA0 ist ein Literal und beschreibt die Wertigkeit des Bits im
Portbyte. Es dient dazu, eine bequeme Maskierung des Bits zu erzielen,
ohne wissen zu müssen, an welcher Stelle im Byte das Bit sitzt.
Also es stellt oft den jeweiligen Exponenten von 2 dar:
PINA0 = 0 -> 2^0
PINA1 = 1 -> 2^1
PINA2 = 2 -> 2^2
etc.
Georg M. schrieb:> Verständlich.
Ja, danke!
kai schrieb:> Also es stellt oft den jeweiligen Exponenten von 2 dar:
Da es sich hier (sehr vermutlich) um eine Frage zur avrlibc handelt,
stellt das weder oft noch überhaupt irgendwelche Exponenten da.
IN dem zum Prozessor zugehörigen include-File, welches über #include
<avr/io.h> letzedlich inkludiert wird, stehen die Definitionen, und die
sehen so aus:
Helmut -. schrieb:> PINA0 ist ein Literal und beschreibt die Wertigkeit des Bits im> Portbyte.
PINA0 ist ein Makro, dessen Nutzung der Präprozessor durch ein Literal
ersetzt.
> Es dient dazu, eine bequeme Maskierung des Bits zu erzielen,> ohne wissen zu müssen, an welcher Stelle im Byte das Bit sitzt.
Wobei das für die PIN-Bits jetzt nicht so viel bringt wie für die Bits
in anderen I/O-Registern.
Oliver S. schrieb:> kai schrieb:>> Also es stellt oft den jeweiligen Exponenten von 2 dar:>> Da es sich hier (sehr vermutlich) um eine Frage zur avrlibc handelt,> stellt das weder oft noch überhaupt irgendwelche Exponenten da.
Es stellt den Exponenten der Wertigkeit des Bits da_r_, gerade beim AVR.
Der Wert des Bits für Pin A4 ist z.B. 2 hoch 4, und die 4, also der
Exponent ist das, was in dem Makro steht.
> #define PINA4 4
Hallo
Als ein immer noch Anfänger darf ich sagen:
Fluch und Segen gleichzeitig.
- Fluch weil man eben als Anfänger verwirrt wird wenn die "Anleitung"
(Tutorial, Schulung, Unterlagen,...) schlecht ist und nicht bei "Null"
angefangen wird.
Das kommt leider oft vor wenn die "Anleitung" von einen langjährigen
Programmierer mit viel Praxiserfahrung stammt, der aber seine eigenen
Anfänge vergessen hat und didaktisch nicht allzuviel drauf hat.
- Segen weil es dann in der Praxis einfacher ist und man nicht wegen
"billigen" Kleinigkeiten Fehler macht -wenn man es denn dann beherrscht
und die eigentlich einfache Idee dahinter verstanden hat was "dank" in
der Programmierwelt grundsätzlich maximal abgehobenen Sprache (Idiom...
geht es noch und das ist ein Begriff den man eventuell noch kennt)und
denn irgendwie "komischen" denken insgesamt über lange Zeit sehr
schwierig ist - bis es mehr oder weniger auf einmal "Klick" macht.
Schade das die teilweise sehr guten Erklärungen die man hier in Forum
lesen kann (dafür braucht es aber auch die entsprechenden Fragen) man so
gut wie nie in Lehrbüchern, Onlinekursen usw. lesen kann...
Anfänger
// wird ausgeführt, wenn PinA0 auf LO gezogen wird
4
5
}
passiert:
(1 << PINA0) erzeugt eine sogenannte Maske. Man könnte auch direkt
0b00000001 hinschreiben. Diese Maske ist keine Zahl im herkömmlichen
Sinn sonder ein bitweiser Operator und nicht aus einer Potenzierung
erzeugt. Das hier eine Verschiebung stattfindet, die manchmal auch zum
Potenzieren benutzt wird, ist eine rein optische Übereinstimmung und in
diesem Zusammenhang völlig unnötig erwähnt und bringt den Anfänger auf
eine vollkommen falsche Spur.
Würden die Pin[0-7] auf zwei Byte verteilt, dann würden die Makros z.B.
wie folgt lauten
1
#define PINA7 15
2
#define PINA6 13
3
#define PINA5 11
4
#define PINA4 9
5
#define PINA3 7
6
#define PINA2 5
7
#define PINA1 3
8
#define PINA0 1
und dazwischen die DDRA-bits und schon ist es mit den Potenzen vorbei.
(1 << PINA0) statt 0b00000001 zu schreiben, hat nur den Vorteil, dass
man sofort erkennt, um was es geht: PINA0 in Register PINA wird
abgefragt, ob es HIGH ist. Das Ergebnis wird dann mit 0 verglichen.
Ich vermute stark, dass es einem Atmel-Ingenieur irgendwann zu doof
wurde, die ganzen bits hinzuschreiben und aus Faulheit diese Makros
schrieb. Die anderen fanden das zwar ganz nett, aber wirklich nötig ...?
Und heute sind es wahrscheinlich die meistgebrauchten Makros in der
Atmel-Welt.
Rolf M. schrieb:> Es stellt den Exponenten der Wertigkeit des Bits da_r_, gerade beim AVR.
Es gibt keine verschiedenen Wertigkeiten zwischen den Pins, alle sind
gleichviel Wert und haben nur vom Programm abhängig verschiedene
Aufgaben.
Grüße
gfl schrieb:> (1 << PINA0) erzeugt eine sogenannte Maske. Man könnte auch direkt> 0b00000001 hinschreiben. Diese Maske ist keine Zahl im herkömmlichen> Sinn sonder ein bitweiser Operator und nicht aus einer Potenzierung> erzeugt.
Der erzeugte Wert ist gleich dem einer Potenzierung. 1 << 4 ist das
gleiche wie 2⁴. Dementsprechend könnte man stattdessen auch 16
schreiben, mit der gleichen Auswirkung.
> Würden die Pin[0-7] auf zwei Byte verteilt, dann würden die Makros z.B.> wie folgt lauten> #define PINA7 15> #define PINA6 13> #define PINA5 11> #define PINA4 9> #define PINA3 7> #define PINA2 5> #define PINA1 3> #define PINA0 1> und dazwischen die DDRA-bits und schon ist es mit den Potenzen vorbei.
Und du sprichst davon, den Fragesteller nicht zu verwirren?
Abgesehen davon hat das mit den Potenzen nichts zu tun. 1 << 9 ist auch
das selbe wie 2⁹.
> Rolf M. schrieb:>> Es stellt den Exponenten der Wertigkeit des Bits da_r_, gerade beim AVR.>> Es gibt keine verschiedenen Wertigkeiten zwischen den Pins, alle sind> gleichviel Wert und haben nur vom Programm abhängig verschiedene> Aufgaben.
Bitte genauer lesen. Ich schrieb Bits, nicht Pins. Jedes Bit in dem
Register hat natürlich eine Wertigkeit.
kai schrieb:> was bedeutet eigentlich das "PINA0" beim Bit-Shiften in Ausdrücken wie> Codeif (( PINA & (1 << PINA0) == 0) {> // wird ausgeführt, wenn PinA0 auf LO gezogen wird> }> Code> ?>> Sind das einfach nur die jeweiligen Potenzen von 2, also> PINA0 = 2^0 = 1> PINA1 = 2^1 = 2> PINA2 = 2^2 = 4> etc.
Bestimmt nicht. Die Konstanten müssen wie folgt festgelegt sein:
PINA0 = 0
PINA1 = 1
PINA2 = 2
...
Sonst funktioniert die Abfrage nicht.
Wolfgang schrieb:> Sonst funktioniert die Abfrage nicht.
Vielleicht ist es hier erstmal hilfreicher, sich darüber klar zu werden,
daß solche Bezeichner wie PINA0 einfach nur Namen sind. Man könnte das
auch Ottokar nennen. Dem Compiler ist das egal, solange die zugehörige
Definition stimmt.
Generell ist es für einen Menschen hilfreicher, mit Namen zu hantieren
anstelle mit Anzahl von Verschiebungen, um eine Maske zu erzeugen, mit
der man ein Bit aus einem Byte, Word oder sonstws isolieren kann. Aber
die Kehrseite ist oftmals, daß die entsprechenden Definitionen bzw.
Umsetzungen wie z.B.
#define Ottokar 3
oft in einer anderen Datei stehen. Um eine funktionierende Firmware zu
erzeugen, muß man sich dann drauf verlassen, daß so eine Definition dann
genau so wie gedacht dort steht. Das schafft eine Abhängigkeit, die auch
ein Fehlergrund sein kann: Wenn die betreffende Datei eben NICHT zum
aktuellen Projekt gehört, sondern zu dem Zeug, was man bei irgendeiner
Toolchain eben so dabei hat, dann kann dort auch mal sowas stehen, wenn
sich die Toolchains verschiedener Leute voneinander unterscheiden:
#define Ottokar (1<<3)
Was lehrt uns das? Nun, man sollte die Abhängigkeiten seines Projektes
von anderen Dateien, die nicht zum aktuellen Projekt gehören, nicht
unnötig groß machen. Also nicht ohne triftigen Grund Referenzen zwischen
den Dateien des Projektes und anderen Dateien erzeugen. Ich halte da ST
für ein ausnehmend negatives Beispiel. Dort werden in den
Chip-Definitionen ganze Urwälder von Namen erzeugt und die
entsprechenden .h Dateien sind dann riesengroß und recht unübersichtlich
und gespickt mit Bezeichnern, die weitere Abhängigkeiten zu noch anderen
Dateien erzeugen. Eben ein Urwald.
W.S.