www.mikrocontroller.net

Forum: Compiler & IDEs Wieso funktioniert dieser Code? (LED-Blinker)


Autor: Markus Hiller (markus-94209-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leutz,

bin grad dabei mich ein wenig mit C zu beschäftigen. Als erstes
"Projekt" hab ich einen Wechselblinker angegriffen. Also zwei Led's
die abwechselnd blinken. Der Code:
int main(void)
{int i, n = 40;
DDRB = 0b00001100;
PORTB = 0x00;
while (1)
{
PORTB ^= 0b00000100;       // EX-OR
for (i=0; i<n; i++){
  _delay_ms(25);
  }
PORTB ^= 0b00001000;       // EX-OR
}
}

Das funktioniert auch, nur warum? Beim zweiten EX-OR springt der doch
sofort nach der Anweisung zurück zur Zeile mit dem ersten EX-OR, oder?
Also müßte nach dem zweiten EX-OR gar keine Verzögerung mehr zu sehen
sein...?!?

Markus

Autor: Joachim Börke (joachimb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Markus,

die beiden LEDs werden getrennt umgeschaltet. Wie Du richtig
feststellst, gibt es keine Pause nach dem 2. EX-OR.
Man könnte das zweite EX-OR streichen und stattdessen mit dem 1. EX-OR
beide LEDs gemeinsam umschalten:
PORTB ^= 0b00001100;

Gruß
Joachim

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hihi, das ist ja mal ein lustiger "logischer" Fehler...

Wir nehmen mal an, wir sind in der Delay-Schleife. Dann passiert
folgendes:

  1.) Delay, lange Pause

  2.) PORTB ^= 0b00001000;   /* Die zweiteLED wird umgeschaltet, es
                                leuchten nun beide LEDs oder keine */

  3.) Ende der while(1)-Schleife und Rücksprung an den Anfang
      der while(1)-Schleife. Es ist nur sehr wenig Zeit vergangen.

  4.) PORTB ^= 0b00000100;  /* Die erste LED wird umgeschaltet, es
                               leuchtet wieder nur eine LED */

  5.) Delay-Schleife, lange Pause.

  6.) Wieder bei Schritt 2 weiter....


Der Fehler ist, dass die beiden Schreibzugriffe auf den Port nicht
untereinander stehen. Die Port-Zugriffe schalten die LED ja nicht an
oder aus, sondern schalten sie um.

Prinzipiell ist die Stelle, an der der Rücksprung der While-Schleife
erfolgt egal. Wichtig ist nur die Anordnung:

   - LED 1 umschalten
   - LED 2 umschlaten
   - Pause machen

Wo nun die Wiederholung der While-Schleife passiert ist egal.

Also, ein sehr "lustiger Fehler"...

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

wieso denn Fehler? Das Programm funktioniert einwandfrei als
Wechselblinker mit zwei LEDs. Eigentlich eine sehr elegante Lösung.

Matthias

Autor: Markus Hiller (markus-94209-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also so richtig kann ich euch nicht folgen...

@Joachim: Dann wäre es ja kein Wechselblinker mehr. Die LED's würden
dann gleichzeitig an oder aus sein.

[ZITAT]
Prinzipiell ist die Stelle, an der der Rücksprung der While-Schleife
erfolgt egal. Wichtig ist nur die Anordnung:

   - LED 1 umschalten
   - LED 2 umschlaten
   - Pause machen
[/ZITAT]
Rein logisch würde das ja bedeuten LED1 würde sofort bei der zweiten
EX-OR Funktion wieder umgeschalten ohne Verzögerung, oder?!?
Oder wird einem PORTB ^= 0b00001000 nur daß gesetzte vierte Bit
"getoogled"???

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

genau so ist das. PORTB ^= 0b00001000 togglet das Bit3, PORTB ^=
0b00000100 das Bit 2. Damit sollte dann die Funktion des
Wechselblinkers klar sein. Wichtig ist natürlich der Ausgangszustand
von PortB. Sind die zwei Bits nicht gleich vor eintritt in die Schleife
ist es kein Wechselblinker mehr.

Matthias

Autor: Markus Hiller (markus-94209-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias:
Ja, so, aah!

Jetzt hab ich's gefressen, danke!

Gruß, Markus

Autor: Olaf Stieleke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ganz am Anfang steht die Zeile DDRB=0x00001100. Im ersten Moment sind
also beide LED eingeschaltet. Einige Mikrosekunden später folgt in der
Schleife das erste XOR, welches eine der LED wieder ausknipst - es
leuchtet nur eine LED.

Es folgt die Verzögerung, dann das zweite XOR. Dieses knipst die zweite
LED aus - beide sind also dunkel. Nur wenige Mikrosekunden später
erreichen wir durch die Schleife wieder das erste XOR, das die erste
LED wieder anknipst, wieder leuchtet nur eine LED.

Erneut die Verzögerung, dann das zweite XOR, beide LED leuchten - aber
nur ein paar µs, denn wir erreichen wieder das erste XOR, das LED
Nummer 1 wieder ausschaltet.

Ein wirklicher Wechselblinker ist das nicht, schließlich sind die LED
manchmal beide an oder aus. Die Zeiträume, in denen das der Fall ist,
sind aber so kurz, das man das optisch nicht mehr wahrnimmt.

Eine elegante und pfiffige Lösung, finde ich - aber nicht wirklich
perfekt. Ich schlage vor, das ganze ein wenig anders zu formulieren:
DDRB=0x00001000;

while(1)
{
   PORTB ^= 0b00001100;
   for (i=0; i<n; i++) _delay_ms(25);
}

Autor: Olaf Stieleke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...und irgendwann lerne ich das mit dem Code-Tag auch noch :-)

Autor: Olaf Stieleke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kleiner Fehler: DDRB bleibt natürlich 0x00001100. Man fügt eine Zeile
dahinter ein: PORTB=0x00001000;.

Sorry dafür...

Autor: Markus Hiller (markus-94209-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Olaf:
Danke nochmal für deine Ausführungen, jetzt hab ich's auf alle Fälle
gefressen. Deine Lösung ist, denke ich, programmiertechnisch die beste.
Das äußert sich für mich daran, das sie sofort durchschaubar ist wie sie
funktioniert.

Gruß, Markus

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.