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
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
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.
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
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.
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 | }
|
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.