Forum: Compiler & IDEs Wie macht ihr Zeitreferenzen


von Patrick B. (p51d)


Lesenswert?

Hallo miteinander

Bei einem älteren Projekt habe ich neulich etwas entdeck, was wohl nich 
ganz normal ist (von meiner Programmierart):
Das Programm war durch kein Delay in der Endlosschlaufe gebremmst worden 
(was für die Anwendung zwingend nötig war). Aber bei vielen Funktionen 
musste ich irgendwelche Zeiten abwaretn (z.B. bei der Entprellung) und 
hier habe ich mit einer statischen Variable immer auf einen Timer 
referenziert, welcher auf 1kHz eingestellt war. Da aber vielen Orten 
immer unterschiedliche "Wartezeiten" zwischen 10ms bis 10s vorhanden 
waren und das Programm nicht blockiert werden sollte, hat dieses ewige 
Vergleichen viel Code verbraucht. Alternativ habe ich Software-Timers 
gebastelt, die dann in der 1ms ISR immer schön hochgezähtl wurden. Aber 
hier wurde ebenfalls viel Zeit und Platz verbraucht.
Bei diversen Treibern (z.B LCD) sind ja delays fix vorhanden, aber wie 
kann man diese dann umgehen?

Wie macht ihr das?

Ich hoffe, dass ich mein Problem klar genug beschrieben habe.
MFG
Patrick

von Peter D. (peda)


Lesenswert?

Patrick B. schrieb:
> Aber bei vielen Funktionen
> musste ich irgendwelche Zeiten abwaretn (z.B. bei der Entprellung)

Definitiv nicht, Entprellen gehört in den Timerinterrupt:

Beitrag "Universelle Tastenabfrage"


Patrick B. schrieb:
> Da aber vielen Orten
> immer unterschiedliche "Wartezeiten" zwischen 10ms bis 10s vorhanden
> waren und das Programm nicht blockiert werden sollte, hat dieses ewige
> Vergleichen viel Code verbraucht.

Eine elegante Methode:

Beitrag "Wartezeiten effektiv (Scheduler)"

Patrick B. schrieb:
> Bei diversen Treibern (z.B LCD) sind ja delays fix vorhanden, aber wie
> kann man diese dann umgehen?

Die LCD-Delays sind ja nur ~50µs, da kann man ruhig warten. Und wenn das 
stört, macht man das LCD mit Interrupt, da entfällt das Warten komplett:

Beitrag "Formatierte Zahlenausgabe in C"


Peter

von Simon K. (simon) Benutzerseite


Lesenswert?

Programmstruktur und Organisation überdenken! Du darfst beim 
Programmieren nicht "menschlich" denken.

Algorithmen werden also nicht so geschrieben, dass sie Wartezeiten 
haben, sondern sie werden so gestaltet, dass sie periodisch aufgerufen 
werden (z.B. main loop oder taktbasiert).
Alles wird sozusagen on-demand gemacht. Nirgendwo wird gewartet.

von Patrick B. (p51d)


Lesenswert?

Simon K. schrieb:
> Algorithmen werden also nicht so geschrieben, dass sie Wartezeiten
> haben, sondern sie werden so gestaltet, dass sie periodisch aufgerufen
> werden (z.B. main loop oder taktbasiert).

Das habe ich bis jetzt immer so gemacht, aber wie wird dann eine 
Zeitreferenz erzeugt, beim periodischen aufrufen? Es ist ja je nach 
Funktionen und anderem Zeug nicht die gleiche Durchlaufzeit.

Als kleines Beispiel:
1
int main (void){
2
  SysInit();
3
  while(1){
4
    Switchs();
5
    UART();
6
    SPI();
7
    PI_controller();
8
    LCD();
9
  }
10
  return 0;
11
}
Werden 2-4 Taster entprellt (nicht in einer ISR), werden jeweils soviele 
Timers (Basis ms) benötigt, der Regler soll auch nur alle 1ms neu 
berechnet werden. Dann ist das LCD, welches nur dann neu beschrieben 
werden soll, wenn es etwas neues anzuzeigen hat, Wobei dann aber ein 
LCD_clear über 10ms benötigt...

Wie würdet ihr das lösen?
MFG
Patrick

von Simon K. (simon) Benutzerseite


Lesenswert?

Je nach Anforderung. Generell geh ich gerne so vor:
1
while(1) {
2
    if (<Timer-Interruptflag gesezt?>) {
3
        Interruptflag zurücksetzen;
4
        Entsprechende Aktionen ausführen
5
    }
6
}

Jetzt hast du immer nur noch einen Takt (z.B. 10ms ist ein praktischer 
Wert) zur Verfügung. Jetzt musst du diesen herunterteilen. Das kannst du 
entweder global machen:
1
while(1) {
2
    if (<Timer-Interruptflag gesezt?>) {
3
        Interruptflag zurücksetzen;
4
        
5
        static uint8_t Prescaler = 0;
6
        if (Prescaler-- == 0) {
7
            Prescaler = 100;
8
            Aktionen alle Sekunde ausführen
9
        }
10
    }
11
}

Oder du machst das Prescaling innerhalb des "Moduls":
1
while(1) {
2
    if (<Timer-Interruptflag gesezt?>) {
3
        Interruptflag zurücksetzen;
4
        
5
        LedPeriodic();
6
    }
7
}
1
void LedPeriodic() {
2
    static uint8_t Prescaler = 0;
3
    if (Prescaler-- == 0) {
4
        Prescaler = 100;
5
        LED_PORT ^= LED_MASK; /* LEDs invertieren */
6
    }
7
}


Wenn das Modul mehrere Takte benötigt kann man beispielsweise die Zweite 
Variante nehmen. Wenn mehrere Module den gleichen Takt benötigen kann 
man auch die erste Variante nehmen.

von (prx) A. K. (prx)


Lesenswert?

Patrick B. schrieb:

> Werden 2-4 Taster entprellt (nicht in einer ISR), werden jeweils soviele
> Timers (Basis ms) benötigt,

Einer reicht für alle. Wenn Taster nur alle zig Millisekunden abgefragt 
werden, dann hat sich die Entprellung ohnehin gleich mit erledigt. Die 
entsprechende Verzögerung ist in vielen Controller-Anwendungen nicht 
störend.

> Dann ist das LCD, welches nur dann neu beschrieben
> werden soll, wenn es etwas neues anzuzeigen hat, Wobei dann aber ein
> LCD_clear über 10ms benötigt...

Ich implementiere oft einen Zähler, der in einer Timer-ISR regelmässige 
Ticks ab Systemstart zählt. Der sollte idealerweise breit genug sein, 
damit in realistischer Zeit kein Überlauf auftritt - schmaler geht zwar 
auch, aber dann kann man keine einfachen C-Vergleiche verwenden.

Damit lassen sich Zeitverriegelungen ziemlich einfach abwickeln:
1
  if (uptime() >= lcd_busy) {
2
     ...LCD-Kommando...
3
     lcd_busy = uptime() + ...Ausführungszeit...;
4
  }

von Matthias L. (Gast)


Lesenswert?


von Niffko _. (niffko)


Lesenswert?

Simon K. schrieb:
1
 while(1) {
2
     if (<Timer-Interruptflag gesezt?>) {
3
         Interruptflag zurücksetzen;
4
         
5
         static uint8_t Prescaler = 0;
6
         if (Prescaler-- == 0) {
7
             Prescaler = 100;
8
             Aktionen alle Sekunde ausführen
9
         }
10
     }
11
 }

Hi Simon,

kann es sein, dass deine Sekunde eine Winzigkeit zu lange dauert? 
Stichwort Post-Dekrement.


//Niffko

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.