Forum: Compiler & IDEs Argumente in der while-Schleife ?


von Pawel Ziolkowski (Gast)


Lesenswert?

Schönen Abend,

ich beschäftige mich eher seit kurzer Zeit mit der Kunst des
uC-Programmierens und habe eine für viele von euch wahrscheinlich eher
dumm gestrickte Frage.

Hier mein Problem:

Ich würde gerne innerhalb des Hauptprogramms durch eine while-Schleife
das Programm zum Warten veranlassen. Dieses Warten soll unterbrochen
werden, wenn eine der beiden Bedingungen erfüllt ist:
1.) die Variable "start" ihren Wert auf 1 verändert
    (dies kann nur innerhalb der Interrupt-Routine geschehen)
2.) der Zustand eines als Eingang definierten Pins auf logisch "high"
wechselt.

Der Code gestaltet sich folgendermaßen (so wie ich's mir ersponnen
habe):
SIGNAL(SIG_INTERRUPT0)
{
  if (start == 0)
  {
    start = 1;
                ...
  }
  else
  {
    start = 0;
                ...
  }
}
// im Main:
volatile uint8_t start;
while( !(PINC & (1<<PC1)) || (start) ); <- hier das Problem

Die Einzelanweisung funktionieren einwandfrei, sprich die Abfrage des
Pins PC1 oder die Abfrage nach dem Variablenwert start. Lediglich die
mit Oder (||) verknüpfte Symbiose möchte irgendwie nicht funken??
Nun habe ich das Tutorial durchforstet (wirklich gut gemacht!) aber in
meinem Fall glaube ich liegt das Problem eher bei meinem C-Code. ich
habe auch schon diverse andere Codes versucht wie z.B.:

while( !(PINC & (1<<PC1)) || (start==1) );

Langsam weiß ich nicht recht weiter. Ich hoffe irgend jemand kann mir
hierbei helfen.

Gruß,
Pawel

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Die Variable "start" muss als "volatile" deklariert werden.

von Pawel Ziolkowski (Gast)


Lesenswert?

Hallo Rufus,

danke für die schnelle Antwort. Ist die Deklaration denn falsch ?

volatile uint8_t start;

Oder ist es die Position der Deklaration im allgemeinen Teil des
Programms (also unmittelbar vor dem Main-Hauptprogramm, aber in der
gleichen C-Datei)

von asso (Gast)


Lesenswert?

Ja, wenn "volatile uint8_t start;" in dem main-rumpf steht, ist diese
Variable auch nur dort sichtbar.

von Peter (Gast)


Lesenswert?

Hi Pawel

Nee, die Deklaration mit volatile ist prima!

Das Problem liegt woanders, Du hast einen Logik-Fehler: In Deinem Fall
brauchst Du eine AND-Verknüpfung nicht OR.

while( !(PINC & (1<<PC1)) && (start==1));

Du wirst bestimmt selbst draufkommen, wieso...   ;o))


Gruss Peter

von Pawel Ziolkowski (Gast)


Lesenswert?

Hallo Peter,

du hattest vollkommen recht. Die Logik war's. Ich danke dir für die
gute Antwort zu so später Stund.

Gruß,
Pawel

von Marco S (Gast)


Lesenswert?

Zu der Logik:

Als Eingang stehen der Pin und der Inhalt von start zur verfügung.
Der Pin sei durch P repräsentiert und start durch C (start=0 sei
logisch 0, alles andere logisch 1). Soll der Abbruch erfolgen, wenn
mindestens eine der beiden Bedingungen erfüllt ist, so muss gelten:
Abbruch A = P + C. Die Schleifenbedingung S der while-Schleife ist der
Abbruchbedingung entgegengesetzt, also S = /A.
Somit wird S = /(P + C). Nun kann man noch mit DeMorgan rumröteln und S
= /P * /C abfragen. Belassen wir es mal beim ersteren.

while(S)
while(/A)
while(/(P + C))

while(!(P + C))
while(!((P) + start))
while(!((PINC & (1 << PC1)) + start))

Eingesetzt in dem Sourcecode

int main (void) {
  while(!((PINC & (1 << PC1)) || start)) ;
  while(!(PINC & (1 << PC1)) && (start == 1));
}

führt es zu folgendem Assembler-Code:

  ...
  while(!((PINC & (1 << PC1)) || start)) ;
  7c:   99 99           sbic    0x13, 1 ; 19
  7e:   04 c0           rjmp    .+8             ; 0x88
  80:   80 91 60 00     lds     r24, 0x0060
  84:   88 23           and     r24, r24
  86:   d1 f3           breq    .-12            ; 0x7c

  while(!(PINC & (1 << PC1)) && (start == 1));
  88:   99 99           sbic    0x13, 1 ; 19
  8a:   04 c0           rjmp    .+8             ; 0x94
  8c:   80 91 60 00     lds     r24, 0x0060
  90:   81 30           cpi     r24, 0x01       ; 1
  92:   d1 f3           breq    .-12            ; 0x88

  ...

start steht im RAM bei 0x0060. Der Vergleich mit der zuvor genannten
Lösung zeigt einen Unterschied auf. Im ersten Fall wird in der Schleife
verblieben, wenn start==0 ist. Dagegen im zweiten Fall, wenn start==1
ist.

Gruß
Marco
-

von Peter (Gast)


Lesenswert?

@Pawel:
Bitte, gern geschen. Aber Pawel hat eigentlich mit seinem Hinweis
ebenfalls recht: "volatile uint8_t start;" müsste ausserhalb vom main
als globale Variable definiert sein. Reklamiert denn der Compiler nicht,
weil "start" in der ISR undefiniert ist?

@Marco:
Nette Abhandlung, Du magste es offenbar sehr ausführlich!  ;o))
Trotzdem hast Du nicht ganz recht:

Im ersten Fall wird in der Schleife verblieben, solange mindestens eine
der zwei Bedingungen True ist: (PINC.1=High) und/oder (Start!=0)

Im zwitenFall wird in der Schleife verblieben, solange beide
Bedingungen True sind: (PINC.1=High) und (Start==1)

Gruss Peter

von Marco S (Gast)


Lesenswert?

Erst mal frohe Weihnachten!

@Peter

In der Tat weicht meine Lösung von der Aufgabenstellung ab. Dort steht:
...Warten soll unterbrochen werden, wenn eine der beiden Bedingungen
erfüllt ist: ... Wenn wirklich nur eine der beiden Bedingungen zum
Ausbruch aus der Schleife führen sollte, so müsste wohl irgendwie eine
XOR-Verknüfung eingebaut sein. Zweitens sollte das Warten unterbrochen
werden, wenn start auf 1 geht. Hier sehe ich den Fehler, denn es müsste
(Start == 0) im zweiten Fall heißen.

Und wenn man sich den Assembler-Code ansieht, sieht man, dass beide
Routinen fast gleich sind. Im ersten Fall wird in der Warteroutine
verblieben bei Start==0 (and r24, r24) im zweiten Fall bei Start==1
(cpi r24,0x01). Bei Beiden Routinen kann ein gesetzter Portpin zum rjmp
+8 Befehl führen, wo dann die zweite Bedingung übergangen wird.

Gruß
Marco
-

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.