Forum: Mikrocontroller und Digitale Elektronik Zeitverzögerung in Routine - wie am besten?


von C. L. (calle)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

Ich möchte mit einem EDIP Touch Display (mit Funk) vernünftig 
kommunizieren über RS232. Anbei meine Routine, welche ein Befehl zum 
Display sendet und auf die Antwort wartet. Ist die Antwort korrekt, dann 
beende ich die Routine ordungsgemäß, ansonsten 3 mal den Befehl 
wiederholen und wieder warten. Ist das dann immer noch nicht erfolreich, 
wird die Routine auch beendet und eine Meldung abgesetzt a la "Display 
nicht erreichbar"
Das funktioniert auch genau so, wie ich das möchte.

Nun zur Frage:
Die Wartezeiten für die Antwort vom Display und die Pausenzeiten 
zwischen den Wiederholungen habe ich mit _delay_ms(...) gemacht.
Das ist unschön verhindert kurzzeitig weitere Programmausführungen.

Wie macht man sowas am besten, das mit Wartezeiten in Unterroutinen?
Parameter mit Pointer?
Intterruptschleife, welche im 1ms Takt runterzählt?
...

Mit der Bitte um Erklärung und Vorschläge.

Carsten

von Falk B. (falk)


Lesenswert?

@ C. L. (calle)


>Display_Code_Auschnitt.txt (1,75 KB, 5 Downloads)

Das nächte mal einfach als .c Quelltext anhängen, dann gibt es auch ein 
schönes Syntax Highlighting.

>Die Wartezeiten für die Antwort vom Display und die Pausenzeiten
>zwischen den Wiederholungen habe ich mit _delay_ms(...) gemacht.

>Das ist unschön verhindert kurzzeitig weitere Programmausführungen.

In der Tat, 400ms ist eine Ewigkeit.

>Wie macht man sowas am besten, das mit Wartezeiten in Unterroutinen?
>Parameter mit Pointer?
>Intterruptschleife, welche im 1ms Takt runterzählt?

So in etwa. Siehe Multitasking.

von C. L. (calle)


Lesenswert?

Falk B. schrieb:
> als .c Quelltext
=> ok!

Das Multitasking Thema hatte ich schon mal teilweise angetestet.

Also ich interpretiere mal;
Um die Zeiten in der Unterroutine zu handeln könnte ich erstmal einen 
Zähler machen mit 'static' damit wäre er statisch und hat bei erneutem 
Routinenaufruf noch den Wert, wie beim Verlassen.
Dann Zählerstände abfragen, reagieren, Zähler inkrementieren und dann 
weiter.
Die MAIN ist dann 1ms als Basis.
OK, Verstanden.
Aber ich muss dann den Aufruf der Routine in der MAIN ändern. Die muss 
dann immer durchlaufen werden.

CL

von Falk B. (falk)


Lesenswert?

Genau.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

C. L. schrieb:
> Die muss dann immer durchlaufen werden.
Das ist der Trick und zwar ohne Warten so schnell wie möglich. Und dann 
wird in der Mainloop oder pro Unterroutine kontrolliert, ob schon wieder 
Zeit für eine Aktion oder ob eine Reaktion auf Tasten usw. nötig ist...

von W.S. (Gast)


Lesenswert?

C. L. schrieb:
> Wie macht man sowas am besten, das mit Wartezeiten in Unterroutinen?
> Parameter mit Pointer?
> Intterruptschleife, welche im 1ms Takt runterzählt?

Nein.

Man macht sowas ganz GANZ anders. Guck mal in die Lernbetty hier im 
Forum, da siehst du, wie es geht.

Ganz kurz: man arbeitet ereignisorientiert. Alle möglichen Dinge, die da 
passieren können, haben die Möglichkeit, eine Art Botschaft (vulgo 
"event") in eine Event-Warteschlange einzubringen und diese wird dann 
zum nächstpassenden Zeitpunkt von der Grundroutine in main aus der 
Warteschlange herausgeholt und allen eventuell daran interessiert sein 
könnenden Firmwareteilen mitgeteilt. Zusammen mit einer Systemuhr sind 
auch sogenannte §delayed Events" definiert. Das geht so: der Systemtick 
(das eigentliche Uhrprogramm) führt eine kleine Liste, wo Events mit 
ihrer Uhrzeit drinstehen können. Bei jedem Tick (je nach Implementation 
1 oder 10 ms zum Beispiel) testet der systemtick die Liste. Findet er 
dort einen Event, dessen Uhrzeit abgelaufen ist, dann steckt er diesen 
Event in die Event-Warteschlange und löscht ihn aus seiner Liste.

So geht das ganz bequem.

W.S.

von c-hater (Gast)


Lesenswert?

C. L. schrieb:

> Wie macht man sowas am besten, das mit Wartezeiten in Unterroutinen?

Man programmiert den ganzen Scheiss einfach wie jemand, der von der 
Sache Ahnung hat. Nicht als StiNo-Fluss, sondern ereignisorientiert mit 
Statemachine. Dann bleiben einfach keine Unterroutinen über, in denen 
gewartet werden müsste...

Und ja, das geht meist sogar in C problemlos. Wenn man den ganzen 
zusammeklauten Code nicht nur einfach benutzt, sondern tatsächlich 
versteht...

Sprich: wenn man tatsächlich Programmierer ist...

von C. L. (calle)


Lesenswert?

W.S. schrieb:
> Guck mal in die Lernbetty hier im
> Forum, da siehst du, wie es geht.

Werde ich gleich mal machen...... Thx

c-hater schrieb:
> Nicht als StiNo-Fluss, sondern ereignisorientiert mit
> Statemachine. Dann bleiben einfach keine Unterroutinen über, in denen
> gewartet werden müsste..

Muss ich auch checken, nie gehört! Das keine Unterroutinen überbleiben, 
in denen gewartet werden muss klingt interessant!

c-hater schrieb:
> Wenn man den ganzen
> zusammeklauten Code nicht nur einfach benutzt, sondern tatsächlich
> versteht...

Cool bleiben, hier ist nichts geklaut sondern selbst geschrieben, nur 
nicht wie ein Profi, deswegen frage ich ja hier.

Gruß Carsten

von C. L. (calle)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe mir nun belesen und noch einige Fragen dazu:
Mit den Eventlisten usw. ist ja sehr auffwendig und ich frage mich, ob 
ich das so umsetzen will (oder muss).
Die angehängte Routine funktioniert soweit und das auch kombiniert mit 
dem "LED Blink Beispiel" aus dem Artikel Multitasking. Damit bin ich 
zufrieden.
Könnt Ihr mal drüberschauen, ob man das so machen kann, ist ja nur fürs 
Hobby und nicht komerziell. Die ms in der MAIN kann ich akzeptieren, 
vlt. verwende ich doch mal den Timer0 um die noch wegzubekommen.
Meines Erachtens wäre das ja dann kooperatives Tasking, oder?

In dem Dokument zur Lernbetty stand der Ansatz mit den Ticks, hierzu 
habe ich aber noch ein Verständnissproblem was dann die Verarbeitung in 
den Routinen angeht. Muss ich da nur die Ticks benutzen und in den 
Routinen selbst einen statischen Zähler erzeugen, oder den Tickzähler 
plus Offset speichern und abfragen ob es soweit ist, diese Routine 
auszuführen?
Wer hat hier mal eine Antwort?

Noch eins:
Beim Rumtesten mit dem Tickzähler habe ich folgendes geschrieben bzw. 
hier aus dem Forum benutzt, aber erhalte nur "krumme" Zeitticks von 
8.2ms.
Ich verwende das Olimex Devboard mit dem AT90CAN128 mit 16Mhz XT.

   void timer_init()
   {
     TCCR1A  = 0;
     TCCR1B = 1 << CS10;
     TCNT0 = 0xf0;
     TIMSK1 = (1 << TOIE1);
      sei();
   }

Die ISR ist dann:

    ISR(TIMER1_OVF_vect)
    {
      static uint8_t test = 0;

      timer_ovl_cnt++;
    }


Macht doch Sinn, alls 1ms oder 10ms zu nutzen. Komm da nicht weiter, was 
muss ich wo einstellen?

Danke für Eure Hilfe bisher!

CL

von W.A. (Gast)


Lesenswert?

C. L. schrieb:
> Noch eins:
> Beim Rumtesten mit dem Tickzähler habe ich folgendes geschrieben bzw.
> hier aus dem Forum benutzt, aber erhalte nur "krumme" Zeitticks von
> 8.2ms.

Dann guck mal ins Datenblatt, nach wie viel Takten der Overflow-IRQ 
ausgelöst wird. Da der Timer ein Binärzähler ist, läuft der nach einer 
Zweierpotenz von Takten über und wenn dann dein CPU-Takt nicht speziell 
darauf abgestimmt ist, wäre es eher Zufall, wenn da 1ms oder 10ms Takt 
rauskommen würde ;-)

von C. L. (calle)


Lesenswert?

OK,

Das mit dem 1ms Tick habe ich jetzt hinbekommen mit:

  TCCR0A = (1<<WGM01); // CTC
  TCCR0A |= 0x03;      // Teiler 64
  OCR0A = 125-1;
  TIMSK0 |= (1<<OCIE0A);// Vergleichs INT
  sei();

und dann noch die ISR:
        ISR (TIMER0_COMP_vect)
        {
        tick++;
        }
auf dem OSCAR habe ich nun einen sauberen 1ms Tackt.

Jetzt geht es mir aber nochmal um den Kern.
Eventlisten usw. ist ja sehr auffwendig und ich frage mich, ob
ich das so umsetzen will (oder muss).
Habe eine Routine soweit am laufen und auch kombiniert mit
dem "LED Blink Beispiel" aus dem Artikel Multitasking.
Alles schön "unabhängig" und schnell.

In dem Dokument zur Lernbetty stand der Ansatz mit den Ticks, hierzu
habe ich aber noch ein Verständnissproblem was dann die Verarbeitung in
den Routinen angeht. Muss ich da nur die Ticks benutzen und in den
Routinen selbst einen statischen Zähler erzeugen, oder den Tickzähler
plus Offset speichern und abfragen ob es soweit ist, diese Routine
auszuführen?

Kann mir mal jemand prinzipiell helfen was das Timing in den Routinen 
selbst angeht, wie macht man das mit den Ticks.
Ich würde gerne Zeichen vom UART empfangen, diese kommen aber zeitlich 
unterschiedlich und ich benötige auch eine Art Timeout.

CL

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.