Forum: Mikrocontroller und Digitale Elektronik AVR: LO statt HI detektieren


von robur (Gast)


Lesenswert?

Hallo,

mit diesem Ausdruck

if (PINA & (1 << PA1)) {.....}

stellt man fest, ob am Pin A1 ein HI anliegt. Liegt ein HI an, wird der 
Inhalt des Funktionsblocks ausgeführt.


Mit welchem Ausdruck kann man aber feststellen, ob an PA1 ein LO 
anliegt, um den Funktionsblock auszuführen?


Folgende Überlegung:

1. Wert PINA kann 0 oder 1 sein

2. Wert (1 << PA1) ist immer 1  (?!)


Also müsste es mit einer Xor-Verknüpfung gehen:

1. = 1 ;  2. = 1 ;  Xor = 0

1. = 0 ;  2. = 1 ;  Xor = 1


Falls dem so ist, wie wird das richtig formuliert?
So: (?)

if (PINA ^ (1 << PA1)) {.....}

von Tux (Gast)


Lesenswert?

Wenn du mit PINA & (1 << PA1) prüfst ob er nicht high ist, dann nimmst 
du ganz einfach !(PINA & (1 << PA1)) um zu prüfen ob er nicht high ist 
;)

von Tux (Gast)


Lesenswert?

* das erste "nicht" natürlich streichen.

Ansonsten sei gesagt dass 1 << PA1 nicht immer 1 ist, sondern nur wenn 
PA1 den Wert 0 hat.

von batman (Gast)


Lesenswert?

Das Grundproblem ist wohl erstmal, den Unterschied zwischen bitweisen 
und logischen Operationen zu verstehen.

von Rolf M. (rmagnus)


Lesenswert?

robur schrieb:
> if (PINA & (1 << PA1)) {.....}
>
> stellt man fest, ob am Pin A1 ein HI anliegt. Liegt ein HI an, wird der
> Inhalt des Funktionsblocks ausgeführt.
>
>
> Mit welchem Ausdruck kann man aber feststellen, ob an PA1 ein LO
> anliegt, um den Funktionsblock auszuführen?

Zum Beispiel einfach durch Inverieren:
1
if (!(PINA & (1 << PA1))) {.....}

> Folgende Überlegung:
>
> 1. Wert PINA kann 0 oder 1 sein

Du meinst das gesuchte Bit in PINA. PINA selbst ist 8 Bit breit und kann 
jeden Wert von 0 bis 255 annehmen.

> 2. Wert (1 << PA1) ist immer 1  (?!)

(1 << PA1) ist 2. Das Bit für Pin A1 ist 1.

> Also müsste es mit einer Xor-Verknüpfung gehen:
>
> 1. = 1 ;  2. = 1 ;  Xor = 0
>
> 1. = 0 ;  2. = 1 ;  Xor = 1
>
>
> Falls dem so ist, wie wird das richtig formuliert?
> So: (?)
>
> if (PINA ^ (1 << PA1)) {.....}

Wenn man sich nur um das eine Bit kümmert, ja. Aber was ist mit den 
anderen 7 Bit von PINA? Der ganze Sinn der und-Verknüpfung in
1
PINA & (1 << PA1)
ist es, das eine Bit, das dich interessiert, aus den restlichen 
herauszuschälen.

von robur (Gast)


Lesenswert?

batman schrieb:
> Das Grundproblem ist wohl erstmal, den Unterschied zwischen bitweisen
> und logischen Operationen zu verstehen.

Wo findet man näheres dazu?



Rolf Magnus schrieb:
> Du meinst das gesuchte Bit in PINA. PINA selbst ist 8 Bit breit und kann
> jeden Wert von 0 bis 255 annehmen.

Ja, meine natürlich das interessierende Bit von PINA!



Tux schrieb:
> Ansonsten sei gesagt dass 1 << PA1 nicht immer 1 ist, sondern nur wenn
> PA1 den Wert 0 hat.

Wie jetzt??? Dachte, die 0 im LO-Fall kommt von PINA




Rolf Magnus schrieb:
> Zum Beispiel einfach durch Inverieren:
> if (!(PINA & (1 << PA1))) {.....}

Also mit drei Klammerpaaren?!




>> if (PINA ^ (1 << PA1)) {.....}
>
> Wenn man sich nur um das eine Bit kümmert, ja. Aber was ist mit den
> anderen 7 Bit von PINA? Der ganze Sinn der und-Verknüpfung inPINA & (1 << PA1)
> ist es, das eine Bit, das dich interessiert, aus den restlichen
> herauszuschälen.

Verstehe ich nicht ganz.
if (PINA ^ (1 << PA1)) {.....} funktioniert bei mir im Programm übrigens 
so nicht.

von robur (Gast)


Lesenswert?

Ansonsten DANKE für den Hinweis mit der INVERTIERUNG !!!

:-)

von Stefan E. (sternst)


Lesenswert?

robur schrieb:
> Verstehe ich nicht ganz.

"PINA" sind alle 8 Bits. Was, wenn die 8 Bits 10000010 sind? Was ist 
dann das Ergebnis von dem XOR?

von robur (Gast)


Lesenswert?

Danke!

Was ist denn der Wert von PA1 in (1 << PA1)?

von M. K. (sylaina)


Lesenswert?

robur schrieb:
> Danke!
>
> Was ist denn der Wert von PA1 in (1 << PA1)?

1…einfach mal in die Header-Datei schaun ;)

von Patrick (Gast)


Lesenswert?

robur schrieb:
> Was ist denn der Wert von PA1 in (1 << PA1)?

Woher sollen wir das wissen - wir kennen weder Deinen Prozessor noch 
Deine Toolchain...

Wild geraten: Bei der AVR-libc ist für alle mir geläufigen 
AVR-Prozessoren PA1 als Konstante mit dem Wert 1 definiert.

Bitte Bitmanipulation lesen und verstehen - es hat wenig Sinn, hier 
einmal wieder alle Grundlagen zu beschreiben.

von Karl H. (kbuchegg)


Lesenswert?

robur schrieb:
> Danke!
>
> Was ist denn der Wert von PA1 in (1 << PA1)?

(beim avr-gcc auf einem AVR)
1

PA0    0
PA1    1
PA2    2
PA3    3
PA4    4
PA5    5
PA6    6
PA7    7


Welches die Werte von PB0, PB1, PB2, etc. sind, schlüssle ich dir jeztt 
nicht auf.
Selbiges für PINB0, PINB1, PINB2, etc. etc.

Das sind alles nur glorifizierte 'Namen' für 0, 1, 2, 3, 4, 5, 6, 7

Meiner Meinung nach hätte man diese ganzen verschiedenen Bezeichnungen 
nie einführen sollen, sondern einfach nur BIT0, BIT1, BIT2, ... BIT7
Dann wäre alles klar gewesen, dass zb PA2 dasselbe ist wie PB2 oder PC2 
oder PINB2 oder PD2 oder ...

von M. K. (sylaina)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Meiner Meinung nach hätte man diese ganzen verschiedenen Bezeichnungen
> nie einführen sollen, sondern einfach nur BIT0, BIT1, BIT2, ... BIT7
> Dann wäre alles klar gewesen, dass zb PA2 dasselbe ist wie PB2 oder PC2
> oder PINB2 oder PD2 oder ...

Naja, so, finde ich, ist später der Code lesbarer bzw. man sieht dann 
schneller, welcher Pin hier grad angesteuert wird.
Mit PA1 weiß man sofort, dass Pin 1 am Port A angesteuert wird bzw. 
werden soll, wenn da nur ne 1 steht ist noch lange nicht klar, welcher 
Pin hier gesteuert werden soll. ;)

von Karl H. (kbuchegg)


Lesenswert?

Michael Köhler schrieb:
> Karl Heinz Buchegger schrieb:
>> Meiner Meinung nach hätte man diese ganzen verschiedenen Bezeichnungen
>> nie einführen sollen, sondern einfach nur BIT0, BIT1, BIT2, ... BIT7
>> Dann wäre alles klar gewesen, dass zb PA2 dasselbe ist wie PB2 oder PC2
>> oder PINB2 oder PD2 oder ...
>
> Naja, so, finde ich, ist später der Code lesbarer bzw. man sieht dann
> schneller, welcher Pin hier grad angesteuert wird.
> Mit PA1 weiß man sofort, dass Pin 1 am Port A angesteuert wird

Nö.
Genau das weißt du eben nicht.

  PORTB |= ( 1 << PA1 );

was gilt denn nun? Port A oder Port B? Ist das A in PA1 in irgendeiner 
Art und Weise relevant? Nein, ist es nicht.


> bzw.
> werden soll, wenn da nur ne 1 steht ist noch lange nicht klar, welcher
> Pin hier gesteuert werden soll. ;)

was fehlt dir bei

  PORTB |= ( 1 << BIT1 );

an Information?

von kopfkratzer (Gast)


Lesenswert?

robur schrieb:
> Danke!
>
> Was ist denn der Wert von PA1 in (1 << PA1)?

Da schaust Du im Headerfile nach dem entsprechden #define ;-)

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ist das A in PA1 in irgendeiner
> Art und Weise relevant? Nein, ist es nicht

Doch! :-P Zumindest ist es Flexibler. PA1 steht für die Pinbezeichnung 
des Prozessors (also ein Konkreter Hardwarepin), im Register könnte 
aber der PA1 auch dadurch manipuliert werden, dass Bit5 gesetzt wird.
Ich weiß nicht ob es getan wurde, aber im Prinzip wären auch nochmal 
alle "Spezialnamen" interessant, so dass man sagen kann
1
ADCPORT |= (1 << ADC1);
Was automatisch auf jedem Prozessor der einen ADC hat 'richtig' 
kompilieren würde.

Überspitzt gesagt:
>> was fehlt dir bei
1
 PORTB |= ( 1 << 0 );
>> an Information?

;-)

von M. K. (sylaina)


Lesenswert?

Karl Heinz Buchegger schrieb:
> was fehlt dir bei
>
>   PORTB |= ( 1 << BIT1 );
>
> an Information?

Nun, vielleicht hab ich mich vertippt und wollte nicht PORTB sondern 
PORTA manipulieren. Das sehe ich damit nicht aber mit

PORTB |= (1 << PA1);

sehe ich sofort, dass etwas nicht stimmen kann. Der Code ist IMO (das 
heißt: meiner Meinung nach ;)) lesbarer. Im Prinzip wirft das direkt 
deine Fragen von weiter oben auf:

Karl Heinz Buchegger schrieb:
> was gilt denn nun? Port A oder Port B?

Wollte man mit

Karl Heinz Buchegger schrieb:
> PORTB |= ( 1 << BIT1 );

wirklich das BIT1 von PORTB manipulieren?
Bedenke hierbei auch, dass Datenblatt. BIT1 von PORTB heißt dort ebenso 
PB1 und nicht BIT1 ;)

Die Bezeichnungen sind IMO durchweg schlüssig und konsequent 
eingehalten. Wenn ich die Ports alle mit BIT0, BIT1, BIT2... 
durchnummeriere wird spätestens bei zwei Ports unübersichtlich und wer 
dann noch meint bei vier Ports den Überblick zu haben hat ein verdammt 
gutes Gedächtnis, ich zähle mich nicht dazu.

Und so ganz nebenbei. Niemand hindert dich daran

#define BIT0 0
#define BIT1 1
#define BIT2 2
…

in deinen Quellcode zu schreiben ;)

von Karl H. (kbuchegg)


Lesenswert?

Michael Köhler schrieb:

> durchnummeriere wird spätestens bei zwei Ports unübersichtlich und wer
> dann noch meint bei vier Ports den Überblick zu haben hat ein verdammt
> gutes Gedächtnis, ich zähle mich nicht dazu.

Na ja.
Das ganze geht ja weiter.
Denn

   PORTB |= ( 1 << PA1 );

sollte ja so sowieso nicht im Code stehen.
Da sollte stehen

   LED_PORT |= ( 1 << ERROR_LED );

oder überhaupt gleich

   LED_ON( ERROR_LED );

so gesehen zieht für mich das Argument mit dem Überblick so nicht ganz. 
Denn die Pinnummern kommen dann nur mehr an einer einzigen Stelle 
gesammelt vor. und ob da dann steht
1
#define LED_PORT  PORTB
2
#define ERROR_LED PB1
3
#define READY_LED PB2

oder
1
#define LED_PORT  PORTB
2
#define ERROR_LED BIT1
3
#define READY_LED BIT2

oder meintwegen, wenn man sich an 'BIT' stört
1
#define LED_PORT  PORTB
2
#define ERROR_LED P1
3
#define READY_LED P2

schenkt sich nun wirklich nichts.

> Und so ganz nebenbei. Niemand hindert dich daran

Ist schon klar.
Das Problem ist aber, dass regelmässig Anfänger in PA1 etwas 
hineininterpretieren, was nicht vorhanden ist. Mit PA1 ist für den 
Compiler per se erst mal keine wie immer geartete Verbindung mit Port A 
verbunden. Die Bezeichnung suggeriert etwas, was nicht da ist.

Läubis Argumentation kann ich noch was abgewinnen, auch wenn er wohl 
auch selbst zugeben muss, dass der Fall etwas an dern Haaren 
herbeigezogen ist. Aber möglich wäre er.

von M. K. (sylaina)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die Bezeichnung suggeriert etwas, was nicht da ist.

Na dein BIT1 tut das aber auch nicht!

Karl Heinz Buchegger schrieb:
> Mit PA1 ist für den
> Compiler per se erst mal keine wie immer geartete Verbindung mit Port A
> verbunden.

Das ist zwar richtig, bei der µC-Programmierung muss man aber IMO immer 
eine Verbindung zur Hardware schaffen da der Code so (PA1) oder so 
(BIT1) ohne Hardware keinen Sinn macht.

von M. K. (sylaina)


Lesenswert?

Ach, und übrigens, dein Vorschlag die Ports und Pins entsprechende zu 
definieren: Ich weiß nicht wie andere das machen aber ich mach das so 
wie du vorgeschlagen hast. d.h. ein LCD-Port heißt bei mir im Code auch 
immer so, oder ein OK-Knopf (z.B. PB3) heist bei mir auch

#define OK_Button PB1

Eben wegen der Lesbarkeit ;)

von Karl H. (kbuchegg)


Lesenswert?

OK, Ich halte fest:
Wir sind unterschiedlicher Meinung.
damit hab ich erst mal kein Problem :-)

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Läubis Argumentation kann ich noch was abgewinnen, auch wenn er wohl
> auch selbst zugeben muss, dass der Fall etwas an dern Haaren
> herbeigezogen ist. Aber möglich wäre er.

Naja spätestens be den Timern etc. wird doch fröhliches Bit-Würfeln 
zwischen denProzessor Familien gespielt... Da würdest du ja auch nicht 
plädieren einfach immer Bit0...Bit7 zu verwenden um SFRS zu 
konfigurieren oder ;-) Und ein Port ist auch nur ein SFR was zufällig 
eine 1:1 Beziehung zur Wirklichkeit hat.
Klar ist es sinnvoll da nicht unötig zu würfeln (gerade wenn man mal 
ASM schreiben muss), technisch notwendig ist es nicht das das so 'schön 
sortiert' ist, und dass C da keine Typsicherheit bietet ließe sich wohl 
nur durch einen z.B. objektorientierten Ansatz gewährleisten.

Ich finde es auch nicht zwangsweise übersichtlicher, es ist aber 
konsequent.

von Karl H. (kbuchegg)


Lesenswert?

Läubi .. schrieb:
> Karl Heinz Buchegger schrieb:
>> Läubis Argumentation kann ich noch was abgewinnen, auch wenn er wohl
>> auch selbst zugeben muss, dass der Fall etwas an dern Haaren
>> herbeigezogen ist. Aber möglich wäre er.
>
> Naja spätestens be den Timern etc. wird doch fröhliches Bit-Würfeln
> zwischen denProzessor Familien gespielt... Da würdest du ja auch nicht
> plädieren einfach immer Bit0...Bit7 zu verwenden um SFRS zu
> konfigurieren oder ;-)

Langsam, langsam. Ich habs nichts gegen die diversen Bitnamen der andern 
Register.
Mir gehts ausschliesslich um die Bezeichnungen für die Portpins. Es gibt 
ja nicht nur PA1. Da ist ja auch noch eine eigene Bezeichnung für das 
Bit im DDR Register, es gibt ein PIN_A0 und ich glaube auch ein PORT_A0 
(auch wenn ich jetzt die genauen Schreibweisen auch nicht mehr weiß. 
Aber es gibt sie)

von M. K. (sylaina)


Lesenswert?

Yo, jeder so wie er es mag. Ich denke auch, dass das schlichtweg 
Geschmackssache ist. Klar, wenn ich jetzt ein Code schreibe weiß ich 
auch was ich da mache. Wenn ich mir den Code aber in einem Jahr anschaue 
weiß ich im Leben nicht mehr, was z.B. mit

PORTB |= (1 << PB1);

eingeschaltet wurde. Mit

PORTB |= (1 << ERROR-LED);

weiß ich recht schnell, dass hier eine Fehleranzeige eingeschaltet wurde 
ohne mir groß noch mal Schaltung und Code anzusehen. Aber das hält 
jeder, wie er denkt ;)

von batman (Gast)


Lesenswert?

Michael Köhler schrieb:
> Ach, und übrigens, dein Vorschlag die Ports und Pins entsprechende zu
> definieren: Ich weiß nicht wie andere das machen aber ich mach das so
> wie du vorgeschlagen hast. d.h. ein LCD-Port heißt bei mir im Code auch
> immer so, oder ein OK-Knopf (z.B. PB3) heist bei mir auch
>
> #define OK_Button PB1
>
> Eben wegen der Lesbarkeit ;)

Dazu kommt dann aber i.d.R. ein

#define OK_Port PORTB

Da ist die Info dann eben schon redundant, was es für mich nicht besser 
macht.

Gut wäre vielleicht ein Makro, das aus der Definition PB1 dann auch den 
richtigen PORTB assoziiert. Hmm gibbs das schon?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Michael Köhler schrieb:
> weiß ich recht schnell, dass hier eine Fehleranzeige eingeschaltet
> wurde ohne mir groß noch mal Schaltung und Code anzusehen
Also ich schalt meine LEDs immer nach GND ;-P

batman schrieb:
> Gut wäre vielleicht ein Makro, das aus der Definition PB1 dann auch den
> richtigen PORTB assoziiert. Hmm gibbs das schon?

Gab es hier im Forum irgendwo schon mal ja. Schön ist aber was anderes.

von M. K. (sylaina)


Lesenswert?

batman schrieb:
> Dazu kommt dann aber i.d.R. ein
>
> #define OK_Port PORTB

In meinem letzten Projekt war es ein Port der verschiedene Status 
angezeigt hat. Da gab es dann eine LED für TANK_FULL, eine LED für 
PUMP_RUN, eine LED für DOOR_CLOSE usw. Der Port hieß STATUS_PORT, was 
für ne Überraschung ;)


Läubi .. schrieb:
> Also ich schalt meine LEDs immer nach GND ;-P

Echt? Bei mir ists oft Vcc ;-P

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Michael Köhler schrieb:
> Echt? Bei mir ists oft Vcc ;-P

Deswegen halte ich es für gewagt, zu sehen was passiert nur am Code ohne 
die Schaltung zu kennen :-)

von Thomas E. (thomase)


Lesenswert?

Ich schreibe immer z.B.
1
PORTA |= (1 << 3);
2
DDRA |= (1 << 2);
Was ist daran missverständlich? Alles andere ist mir viel zuviel 
Schreibarbeit.

Da der Präprozessor nichts ersetzen muß, geht ein Build dann auch noch 
ein paar ns schneller. Carpe diem!

mfg.

von M. K. (sylaina)


Lesenswert?

Läubi .. schrieb:
> Deswegen halte ich es für gewagt, zu sehen was passiert nur am Code ohne
> die Schaltung zu kennen :-)

DAS hab ich oben schon geschrieben ;)

Michael Köhler schrieb:
> bei der µC-Programmierung muss man aber IMO immer
> eine Verbindung zur Hardware schaffen da der Code so (PA1) oder so
> (BIT1) ohne Hardware keinen Sinn macht.

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.