Forum: Compiler & IDEs UART-Senden und LED-Blinken gleichzeitig


von Peter G. (Gast)


Lesenswert?

Hallo,

ich bin grad dabei in die Welt der ATmegas und C einzusteigen und will 
ein wenig probieren.
Allerdings häng ich jetzt fest:
Ich möchte Messdaten eines Eingangs über RS232 an einen PC schicken, 
soweit kein Problem, das würde ja über etwas wie
1
    while(1)
2
    {
3
        for(i=0;i<6;i++)
4
        {
5
            uart_puti(adc(i));
6
            uart_putc(' ');
7
        }
8
        uart_putc('\n');
9
        _delay_ms(200);
10
    }

gehen.
Gut, gut...Nun möchte ich aber auch gleichzeitig das eine LED 
blinkt...das würde ja nun so gehen
1
    DDRD |= (1 << PD0); 
2
    while(1) 
3
    {
4
        PORTD |= (1 << PD0);
5
        _delay_ms(50);
6
        PORTD &= ~(1 << PD0);
7
        _delay_ms(1000);
8
    }

Nun gut, aber wie bekomme ich beides gleichzeitig hin? Denn, wenn ich 
das richtig verstanden habe, so werden doch die Schleifen nie verlassen, 
oder?
Ich hätte da so eine Idee wie es gehen würde, weiß aber nicht genau ob 
das sinnvoll ist und ob es denn überhaupt funktionieren würde. Meine 
Idee ist, dass in der Schleife mit dem Senden der Daten ja ein _delay_ms 
ist. Nun könnte ich ja folgendes machen, eine Funktion definieren die 
mir den Pin der LED toggelt, in der Schleife des uarts eine Variable 
hochzählen lasse, und wenn die Variable einen bestimmten Wert übersteigt 
wird die toogle funktion ausgeführt. Das würde doch aber eigentlich nur 
funktionieren wenn zwischen Ein- und Ausschalten der LED die gleiche 
Zeit liegen sollte, oder?

Ich hoffe ihr könnt mir helfen!
Grüße
Peter

von Tom M. (Gast)


Lesenswert?

Schau dir mal Multitasking an.

von Karl H. (kbuchegg)


Lesenswert?

Peter G. schrieb:

> wird die toogle funktion ausgeführt. Das würde doch aber eigentlich nur
> funktionieren wenn zwischen Ein- und Ausschalten der LED die gleiche
> Zeit liegen sollte, oder?

Probiers aus, dann weißt du es genauer :-)

> Ich hoffe ihr könnt mir helfen!

Im Idealfall wechselst du die Strategie.
Du musst weg von der Denkweise: Ich lese jetzt 6 mal den ADC ein, gib 
das aus und warte ein wenig. Warten ist sowieso generell schlecht und 
der Tod jedes Programms, welches mehrere Dinge scheinbar gleichzeitig 
machen soll.

Deine Denkweise muss sein:
Genau jetzt, zu diesem Zeitpunkt, was gibt es jetzt zu tun?

Dazu benötigt man des öfteren ein Art Basistakt, eine innere Uhr, im 
Programm. Die realisiert man zb mit einem Timer, der (hausnummer) alle 
10 Millisekunden einen Interrupt auslöst, in dem eine oder mehrere 
Variablen hochgezählt werden. Erreichen diese Variablen bestimmte Werte, 
dann setzen sei Jobflags, als Zeichen für die Hauptschleife: Jetzt gibt 
es etwas zu tun.

Die Hauptschleife sieht dann so aus
1
  ...
2
3
  while( 1 ) {
4
5
    if( needToSampleADC == 1 ) {
6
      uart_puti(adc(i));
7
      uart_putc(' ');
8
      needToSampleADC = 0;
9
    }
10
11
    if( needToToggleLED == 1 ) {
12
      PORTD |= (1 << PD0);
13
      needToToggleLED = 0;
14
    }
15
  }

Wenn jetzt die Timer-ISR (die [hausnummer] alle 10ms aufgerufen wird) 
dafür sorgt, dass needToSampleADC alle 200 Millisekunden, 
needToToggleLED alle 500 Millisekunden auf 1 geht, dann macht dein 
Programm scheinbar 2 Dinge 'gleichzeitig' in unterschiedlichen 
Zeitintervallen.

Dreh und Angelpunkt ist aber ein Timer mit einer ISR-Funktion, die in 
regelmässigen Zeitabständen von der Hardware automatisch aufgerufen 
wird.


> Grüße
> Peter

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du könntest das Blinken im Timerinterrupt ablaufen lassen. Dann 
brauchst Du auch keine delay-Funktionen zu verwenden.

Die serielle Schnittstelle bedienst Du wie gewünscht in Deinem 
Hauptprogramm.

Alternativ könntest Du auch interruptgesteuert senden, d.h. die zu 
sendenden Daten in einen Puffer ablegen, der interruptgesteuert von der 
UART geleert wird.

Wenn Du beides kombinierst, kannst Du in Deinem Hauptprogramm sogar 
noch was anderes gleichzeitig machen.

von Peter G. (Gast)


Lesenswert?

Puh, das scheint ja doch komplizierter als ich dachte. Und ich versteh 
nur halb so viel wie ich gern möchte, trotzdem Danke für die Mühe.
Ich denke ich sollte mir die Howtos und Tutorials nocheinmal alle 
durchlesen, damit ich einigermaßen ne Ahnung habe.

Karl Heinz, kannst du mir nocheinmal erläutern wie das mit der Timer-ISR 
aussehen soll?

Rufus, kannst du mir auch nochmal erklären was du mit "im 
Timerinterrupt" meinst?

grüße
Peter

von Falk B. (falk)


Lesenswert?

@ Peter G. (Gast)

Schau dir erstmal das Beispiel im Artikel Multitasking an. Dort wird 
noch mit dem bösen _delay_ms() gearbeitet, das ist aber für den Anfang 
OK. Wenn du das Konzept WIRKLICH verstanden hast, bau es in dein 
Programm ein. Wenn das WIRKLICH solide läuft, kannst du dich mit dem 
Thema Interrupt und Timer beschäftigen. Und mit dem Thema 
Statemachine. Viel Holz fürs Erste.

MFG
Falk

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.