Forum: Compiler & IDEs AVR ATMEGA8-16 -- Problem mit Bedingungen in Abfragen (while, if)


von André D. (dufman)


Lesenswert?

Bitabfragen:

Ich habe ein kleines C-Programm für einen ATMEL ATMEGA 8-16 geschrieben.
Weil ich noch keine tiefgreifenden Kenntnisse habe, probiere ich halt 
gerne mal etwas aus, indem ich ein Programm etwas umgestalte. Das soll 
heißen, dass ich Abfragen, die mir unübersichtlich erscheinen, auch mal 
in eine andere Form zu bringen versuche. Habe mir einige 
Programmiervorschläge angesehen und versuche diese dann anzuwenden.
Dabei bin ich auf ein kleines Problem gestoßen, da ich der Meinung bin, 
dass folgende Statements eigentlich äquivalent sein müssten, aber leider 
der Programmablauf später das Gegenteil zeigt.


*Die folgende Abfrage funktioniert einwandfrei:*

while (PIND & ((1 << PIND0) | (1 << PIND1)))
/* Wenn Bit 1 (PIND0) ODER Bit 2 (PIND1) gesetzt ist wird die Schleife 
ausgeführt */



*Die nächste Abfrage funktioniert merkwürdigerweise nicht:*

if (PIND & ((1 << PIND0) & (1 << PIND1)))
/* Wenn Bit 1 (PIND0) UND Bit 2 (PIND1) gesetzt sind wird die Anweisung 
ausgeführt */

Bzw.

while (PIND & ((1 << PIND0) & (1 << PIND1)))
/* Wenn Bit 1 (PIND0) UND Bit 2 (PIND1) gesetzt sind wird die Schleife 
ausgeführt */


Warum ist das so ?
Die Abfrage mit „ODER“ funktioniert, die mit „UND“ aber nicht.


*Ändere ich die Abfrage aber um in:*

if ((PIND & 0x03) == 0x03)

bzw.

while ((PIND & 0x03) == 0x03)

dann funktioniert die „UND“-Abfrage einwandfrei !!!
Was mache ich denn hier verkehrt ?...
Hab schon alles Mögliche ausprobiert….   Bin aber leider kein Profi, 
habe gerade erst mit der Programmierung in C nach 15 Jahren wieder 
angefangen, hatte vorher ein bissl mit Assembler programmiert, aber auch 
nur Amateurmäßig….

Ich wäre für einen kleinen Tipp sehr dankbar…..

von Django Noodo (Gast)


Lesenswert?

Du solltest dir vor dem Programmieren über die logischen Operatoren im 
Klaren werden :-).

von André D. (dufman)


Lesenswert?

Ja, genau das versuche ich ja, indem ich mal was ausprobiere...
Ist nicht so easy wenn man jahrelang nix gemacht hat..   jedenfalls 
sehen für mich die Bedingungen der UND-Verknüpfung gleich aus....  soll 
heißen...

if ((PIND & 0x03) == 0x03) ist für mich dasselbe wie

if (PIND & ((1 << PIND0) & (1 << PIND1))), also ne 1 auf Pin D0 UND ne 1 
auf Pin D1....

da ich ja bereits zugegeben habe, dass ich gerade mal wieder am anfang 
stehe, hoffte ich auf einen hinweis....

ist schon schwer, wenn man alleine alles rausfinden muss...   noch 
schwieriger ist es, wenn man antworten bekommt, die wenig hilfreich 
sind, obwohl die guten leute offenkundig des rätsels lösung wissen, aber 
nicht bereit sind, sie preiszugeben....

LG
Duffy

von Wolfgang H. (Firma: AknF) (wolfgang_horn)


Lesenswert?

Hi, André,

> *Die folgende Abfrage funktioniert einwandfrei:*
>
> while (PIND & ((1 << PIND0) | (1 << PIND1)))
> /* Wenn Bit 1 (PIND0) ODER Bit 2 (PIND1) gesetzt ist wird die Schleife
> ausgeführt */
>
PIND, PIND0 und PIND1 sind Makros.
Was bedeuten die denn?
Schrecklich wäre, wenn PIND eine Portadresse bezeichnet, PIND0 und PIND1 
aber nur die Nummer eines Pins im Port.

Wenn ich den Pegel an einem bestimmten Pin eines Ports abfragen will, 
dann lese ich den, beispielsweise mit while(bit_is_clear(PIND, 0)) ...;

Logik üben ist ja fein, aber besser erst mal mit Zahlen statt mit 
unklaren Ausdrücken.

Ciao
Wolfgang Horn

von Klaus W. (mfgkw)


Lesenswert?

(PIND & 0x03) == 0x03 ist genau dann erfüllt, wenn beide Bits 0 
(...0001) und 1 (...0010) gesetzt sind, andere Bits sind egal.

Für PIND & ((1 << PIND0) & (1 << PIND1)) ist erstmal (1 << PIND0) & (1 
<< PIND1) nötig.
(1 << PIND0) & (1 << PIND1) heißt: ...0001 binär verUNDet mit ...0010.
Und das ist immer.
Diese 0 wird mit PIND verUNDet, was ebenfalls immer 0 gibt, egal was in 
PIND steht.


Meintest du (1 << PIND0) | (1 << PIND1) statt (1 << PIND0) & (1 << 
PIND1)?
Dann wären die beiden Ausdrücke schon ähnlicher, auch wenn immer noch 
nicht gleichwertig (weil im zweiten Fall bereits eines der Bits für 
insgesamt "wahr" reicht).

von Markus P. (sebastianwurst)


Lesenswert?

Zwei && in der iffe , dann sollts gehen !

von Klaus W. (mfgkw)


Lesenswert?

du meinst:
  PIND && ((1 << PIND0) && (1 << PIND1))
?
Das ist "wahr", wenn irgendein Bit in PIND gesetzt ist.
Nicht zielführend.

von Christian H. (christian_h)


Lesenswert?

Also, nochmal, was sagt uns UND?

A    B    E

0    0    0
0    1    0
1    0    0
1    1    1

in Worten: Nur wahr, wenn alle Bedingungen wahr sind.

und dann sollte dir noch die ODER-Verknüpf. bekannt sein:

A    B    E

0    0    0
0    1    1
1    0    1
1    1    1

in Worten: Bereits wahr, wenn mindestens eine Bedingung wahr ist.

Logische Bit-Verknüpfungen: & (UND)    | (ODER)
Logische Verknüpfungen: && (UND)       || (ODER)

von Rolf Magnus (Gast)


Lesenswert?

André Derfert schrieb:
> if ((PIND & 0x03) == 0x03) ist für mich dasselbe wie
>
> if (PIND & ((1 << PIND0) & (1 << PIND1))), also ne 1 auf Pin D0 UND ne 1
> auf Pin D1....

Für dich vielleicht, aber für einen Compiler ist das was ganz 
unterschiedliches. Das Problem ist, daß du nicht logisch (im Sinne 
boole'scher Logik), sondern umgangssprachlich denkst. Du willst 
abfragen, ob PIND0 UND PIND1 gesetzt sind, also schreibst du eine 
UND-Verknüpfung hin. Aber das ist falsch.

Bei
1
(1 << PIND0) & (1 << PIND1)
wrd jedes einzelne Bit aus 1 << PIND0 mit dem entsprechenden Bit aus 1 
<< PIND1 UND-Verknüpft. Als Ergebnis kommt dann ein Wert mit den 
dazugehörigen Ergebnis-Bits raus. Da sind dann nur die Bits 1, die auch 
in beiden Eingangswerten 1 sind. Die Rechnung sieht dann etwa so aus:
1
1 << PIND0     =  1 << 0         = 00000001
2
1 << PIND1     =  1 << 1         = 00000010
3
**********************************************
4
(1 << PIND0)  & (1 << PIND1) = 00000000

Aus deiner Abfrage wird also ein:
1
 if (PIND & 0)

Und bei dieser Verknüpfung kann im Ergebnis kein Bit jemals 1 sein, da 
auf der rechten Seite alle Bits 0 sind.

> ist schon schwer, wenn man alleine alles rausfinden muss...

Deshalb wurden Bücher und Tutorials erfunden, die sowas erklären.

> noch schwieriger ist es, wenn man antworten bekommt, die wenig hilfreich
> sind, obwohl die guten leute offenkundig des rätsels lösung wissen, aber
> nicht bereit sind, sie preiszugeben....

Die meisten Leute hier haben eben wenig Lust, vorgekaute Lösungen zu 
präsentieren, sondern versuchen lieber, den Fragesteller zu animieren, 
selbst auf die Lösung zu kommen.

von André D. (dufman)


Lesenswert?

Hmm..
Danke erst mal für die Resonanz..

@Wolfgang:
Also, für mich ist 0x03 keine Zahl, wenn ich Hex-Ausdrücke in Programmen 
sehe, gehen mir immmer die Nackenhaare hoch. Nicht, weil ich damit nicht 
umgehen kann, sondern weil es für mich einfach zu viel Kopfarbeit 
bedeutet, wenn man mal schnell was im Programm nachvollziehen möchte. 
Ich finde dann die Ausdrücke mit  (1 << PINx) oder so leichter zu 
verstehen als irgendein 0x3f oder so was, da rechnet man sich ja nen 
heißen bei.

@Klaus:
Vielen Dank, ich glaube das hat mich einen Schritt weiter gebracht, wenn 
es so ist dass (1<<PIND1) = 00000010 und (1 << PIND0) = 00000001 ist, 
dann kann es natürlich nicht funktionieren.

@Christian:
Danke für die kleine Einführung in die logischen Verknüpfungen, aber ich 
denke, wer die Wahrheitstabellen von UND und ODER nicht kennt, sollte eh 
die Finger davon lassen, soll heißen, dass ich damit bestens vertraut 
bin. Trotzdem danke.

Also, nochmal kurz zum Verständnis:
Ich suchte eine andere Form der Abfrage     if ((PIND & 0x03) == 0x03) 
---> (Bit 1 und Bit 2 bzw. PIND0 und PIND1 beide gleichzeitig gesetzt).
Das ist ein Zustand, der nicht vorkommen darf, weil PIND0 in meinem 
Projekt bedeutet, dass ein Motor rechts herum läuft und PIND1 sorgt für 
den Linkslauf. Klar, dass beides zusammen nicht passieren darf.
Also letztendlich will ich detektieren, ob Bit 1 und Bit 2 gleichzeitig 
gesetzt sind, unabhängig von den restlichen Bits. Und das möglichst 
nicht mit Hex- und Dezimalausdrücken, sondern auf Basis der 
Bitdarstellung (1<<PINDx).

von Christian H. (christian_h)


Lesenswert?

if(PIN & (BLABLA1 | BLABLA2))

Die Bezeichnungen eben durch (1 << BLABLA) ersetzen.

von André D. (dufman)


Lesenswert?

Danke, Christian,
das bedeutet aber doch, dass die Bedingung erfüllt ist, wenn nur einer 
der beiden PINs High ist, oder nicht ?

Jedenfalls habe ich eine derartige Abfrage schon in meinem Programm, 
weil der Controller ja auch was tun soll, wenn einer der beiden Pins 
high ist (entweder Rechtslauf oder Linkslauf), und das funktioniert ja 
auch soweit.

Nur wenn beide Pins high sind, dann erfolgt eine akustische 
Fehlerausgabe.
Und das habe ich bislang nur hinbekommen, indem ich eine UND-Verknüpfung 
mit dem Hexwert der entsprechend gesetzten Bits durchgeführt hab, wie 
ich in den Beispielen schon vorher beschrieben hatte.

von Rolf Magnus (Gast)


Lesenswert?

André Derfert schrieb:
> Also, nochmal kurz zum Verständnis:
> Ich suchte eine andere Form der Abfrage     if ((PIND & 0x03) == 0x03)
> ---> (Bit 1 und Bit 2 bzw. PIND0 und PIND1 beide gleichzeitig gesetzt).

Nun, wenn du die Wahrheitstabellen für UND und ODER kennst, dann sollte 
ja klar geworden sein, daß 0x03 dem Ausdruck (1 << PIND0) | (1 << PIND1) 
entspricht.

> Das ist ein Zustand, der nicht vorkommen darf, weil PIND0 in meinem
> Projekt bedeutet, dass ein Motor rechts herum läuft und PIND1 sorgt für
> den Linkslauf. Klar, dass beides zusammen nicht passieren darf.
> Also letztendlich will ich detektieren, ob Bit 1 und Bit 2 gleichzeitig
> gesetzt sind, unabhängig von den restlichen Bits. Und das möglichst
> nicht mit Hex- und Dezimalausdrücken, sondern auf Basis der
> Bitdarstellung (1<<PINDx).
1
if ((PIND & ((1 << PIND0) | (1 << PIND1))) == ((1 << PIND0) | (1 << PIND1)))

Ich würde aber wahrscheinlich eher schreiben:
1
#define RECHTSLAUF (1 << PIND0)
2
#define LINKSLAUF     (1 << PIND1)
3
#define RICHTUNGSMASKE (RECHTSLAUF | LINKSLAUF)
4
//...
5
if (PIND & RICHTUNGSMASKE == RECHTSLAUF | LINKSLAUF)

von Christian H. (christian_h)


Lesenswert?

André Derfert schrieb:
> Danke, Christian,
> das bedeutet aber doch, dass die Bedingung erfüllt ist, wenn nur einer
> der beiden PINs High ist, oder nicht ?

Nein, denn sowas, wie PIND0 oder PIND1 sind einfach nur definierte 
Zahlen, nämlich 0(PIND0) und 1 (PIND1), so, also:
1
if(PIN & ((1 << PIND0) | (1 << PIND1)))
 entspricht ebenfalls
1
if(PIN & ((1 << 0) | (1 << 1)))
, welches wiederrum
1
if(PIN & (1 | 2))
 entspricht,
1
if(PIN & 0x3)

Also, der rechte Ausdruck ist immer definiert, auf High, da du ja die 1 
um die Pinnummer verschiebst, der rechte Ausdruck ist daher immer wahr. 
Du willst ja den linken Ausdruck überprüfen, sei PIN:
0000 00 01 , da
1
(1 << PIND0) | (1 << PIND1)
 ja 0x3 und somit 0000 00 11 ist, und UND dadurch falsch ist, ist if 
falsch, wenn aber PIN nun
0000 00 11 ist, und der rechte Ausdruck ja immer gleich ist, kommt wahr 
raus.

Mit dem ODER von
1
(1 << PIND0) | (1 << PIND1)
 verknüpft man ja nur einfach die Werte, die vorgegeben sind. Die 
dadurch entstandene Maske wird mit dem PIN geUNDt und dann geschaut, ob 
PIND0 und PIND1 in !! PIN !! gesetzt sind, nicht andersrum.



Vielleicht siehst du auch, dass dein if(PIN & ( (1 << PIND0) & (1 << 
PIND1))) dadurch Blödsinn ist, dann 0 und 1 UND garantiert 0 ist, du 
löscht sie gegenseitig aus, da PIND0 und PIND1 ja absichtlich wohl nicht 
das gleiche beinhalten.

von André D. (dufman)


Lesenswert?

> Nun, wenn du die Wahrheitstabellen für UND und ODER kennst, dann sollte
> ja klar geworden sein, daß 0x03 dem Ausdruck (1 << PIND0) | (1 << PIND1)
> entspricht.

Klar Rolf, das weiß ich schon.

Mein Problem ist, dass ich dachte dass:

if (PIND & ((1 << PIND0) & (1 << PIND1))) --- man beachte das "&" 
zwischen

                                              den PINs !!
dasselbe wäre wie

if ((PIND & 0x03) == 0x03)

Das scheint wohl aber nicht so, die Frage ist also, was genau ist dann

if (PIND & ((1 << PIND0) & (1 << PIND1)))   ????

Ich tendiere dazu, anzunehmen, dass Klaus recht hatte und das ganze 
folglich so zu deuten sein müsste :

if (PIND & ((00000001) & (00000010)))

Und das ergibt natürlich immer 0 !!

von Christian H. (christian_h)


Lesenswert?

siehe mein Post über dir.

von Klaus W. (mfgkw)


Lesenswert?

Also wenn du nur testen willst, ob beide an sind, würde ich das so 
formulieren:
1
   if( ( PIND & 1<<PIND0 )  // Linkslauf
2
       &&
3
       ( PIND & 1<<PIND1 )  // Rechtslauf
4
     )
5
   {
6
      /// oioioi!
7
   }

bzw. statt der hartverdrahteten Makros welche mit sprechenderen Namen, 
aber das ist ein anderes Thema.

von André D. (dufman)


Lesenswert?

Danke Christian...

Aber dann dürfte mein Programm ja nicht funktionieren...
Die Abfrage um die es ging hatte ja nur den Zweck einen Fehler in meiner 
Auswerteelektronik festzustellen und einen Meldung auszugeben.
Aber das gesamte Programm befindet sich in einer Schleife, die der Form 
entspricht, die Du hier dargelegt hast
--  while (PIND & ((1 << PIND0) | (1 << PIND1)))


hier mal ein Ausschnitt aus dem Programm:

while(1)
  {

      while (PIND & ((1 << PIND0) | (1 << PIND1)))

      {

          if ((PIND & 0x03) == 0x03)

             {
               Hilfe1 = Frequenz;
               Frequenz = 30;
               ALARM = 1;
             }

           else
             {
               Frequenz = Hilfe1;
               ALARM = 0;
             }



           while ((PIND & 0x03) == 0x03)
             {

               PORTC &= 0xFC;

               ALARMTON(TONDAUER_ALARM, Frequenz);  /* OUTPUT ERROR */


             }

                                        .
                                        .
                                        .
                                        .

      }

  }


Wenn es so ist, wie Du sagst, dann dürfte mein Programm gar nichts 
bewirken, da ja angeblich
die Bedingung nur dann erfüllt ist, wenn beide Pins auf High sind. Aber 
das Programm macht sowohl
den Rechtslauf (PIN0 = High), als auch den Linkslauf (PIN1 = High).
Und erzwinge ich den verbotenen Zustand (Beide Pins auf High), dann geht 
auch die Fehlerausgabe.
Ich bin etwas verwirrt jetzt.

von Rolf Magnus (Gast)


Lesenswert?

André Derfert schrieb:
> Das scheint wohl aber nicht so, die Frage ist also, was genau ist dann
>
> if (PIND & ((1 << PIND0) & (1 << PIND1)))   ????

Das habe ich doch ausführlich erklärt!

André Derfert schrieb:
> Aber das gesamte Programm befindet sich in einer Schleife, die der Form
> entspricht, die Du hier dargelegt hast
> --  while (PIND & ((1 << PIND0) | (1 << PIND1)))

Das stimmt auch nicht ganz. Wie es aussehen müßte, hab ich auch erklärt. 
Wenn du keinen Bock hast, meine Antworten zu lesen, dann kann ich's auch 
gleich bleiben lassen.

von André D. (dufman)


Lesenswert?

@Klaus
Danke sehr..   damit funktioniert es..   Hurra !

@Rolf
Sorry, aber Du bist ja nicht der Einzige, der hier was schreibt, ich 
lese mir das sehr wohl durch, aber wie so oft ist es mit der 
Kommunikation nicht so einfach...
Wird das Problem, dass ich schildere denn auch so verstanden, wie ich es 
haben möchte ?? Manchmal scheint man auch nur aneinander vorbeizureden.
Tut mir Leid, wenn Du Dich auf den Schlips getreten fühlst, das war 
nicht meine Absicht

von Rolf Magnus (Gast)


Lesenswert?

André Derfert schrieb:
> @Rolf
> Sorry, aber Du bist ja nicht der Einzige, der hier was schreibt, ich
> lese mir das sehr wohl durch, aber wie so oft ist es mit der
> Kommunikation nicht so einfach...
> Wird das Problem, dass ich schildere denn auch so verstanden, wie ich es
> haben möchte ?? Manchmal scheint man auch nur aneinander vorbeizureden.
> Tut mir Leid, wenn Du Dich auf den Schlips getreten fühlst, das war
> nicht meine Absicht

Es hat für mich zweimal so ausgesehen, als hättest du meine Antwort gar 
nicht erst gelesen, weil du Fragen gestellt hast, die ich eigentlich 
schon beantwortet hatte.
Wenn dir an meiner Antwort was nicht klar ist, kannst du ja nochmal 
konkret nachfragen.

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.