mikrocontroller.net

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


Autor: Pawel Ziolkowski (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Variable "start" muss als "volatile" deklariert werden.

Autor: Pawel Ziolkowski (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: asso (Gast)
Datum:

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Pawel Ziolkowski (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marco S (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
-

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marco S (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
-

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.