Hallo zusammen, wenn man auf einem AVR eine bestimmte Aktion jede Sekunde ausfuehren will, setzt man ja meist einen/mehrere Timer ein. Gibt es fuer sowas unter Linux auf dem PC einen anderen Ansatz als immer wieder die Sekunde per Polling abzufragen? wendelsberg
1 | #include <stddef.h> |
2 | #include <stdio.h> |
3 | #include <inttypes.h> |
4 | #include <unistd.h> |
5 | #include <sys/time.h> |
6 | |
7 | int64_t getTime() |
8 | {
|
9 | struct timeval tv; |
10 | gettimeofday(&tv, NULL); |
11 | |
12 | static time_t start_sec = 0; |
13 | if (start_sec == 0) |
14 | start_sec = tv.tv_sec; |
15 | |
16 | return (int64_t)(tv.tv_sec - start_sec) * 1e6 + (int64_t)(tv.tv_usec); |
17 | }
|
18 | |
19 | int main() |
20 | {
|
21 | int64_t correction = 0; |
22 | |
23 | for (int64_t i = 1;; i++) |
24 | {
|
25 | int64_t target = i * 1e6; |
26 | int64_t now = getTime(); |
27 | int64_t delay = target - now - correction; |
28 | |
29 | usleep(delay); |
30 | |
31 | int64_t error = getTime() - target; |
32 | correction += error / 10; |
33 | |
34 | printf("%0ld: %+ld\n", i, error); |
35 | }
|
36 | }
|
Heiner schrieb: > Wie wäre es mit einem cronjob? Scheidet aus, weil dort die kleinste Einheit 1 Minute ist. Kleiner Test schrieb:
1 | int64_t delay = target - now - correction; |
2 | |
3 | usleep(delay); |
In diese Richtung hatte ich auch schon ueberlegt, aber mir gedacht, dass es doch sowas wie ein Sekundensignal geben koennte. Im Moment scheint mir der Weg ueber Timer der Richtige zu sein, sehe mir grad das Beispiel aus man 2 timer_create an. Danke an mikro77 fuer den Anstoss in diese Richtung. wendelsberg
wendelsberg schrieb: > sehe mir grad das Beispiel aus man 2 timer_create an Siehe auch https://man7.org/linux/man-pages/man2/setitimer.2.html
Kleiner Test schrieb: > for (int64_t i = 1;; i++) > { > int64_t target = i * 1e6; > int64_t now = getTime(); > int64_t delay = target - now - correction; > > usleep(delay); Man kann auch die realtime-Funktionen dafür verwenden, also clock_gettime und clock_nanosleep. Letztere hat auch den Vorteil, dass man auf einen absoluten Zeitpunkt warten kann, so dass man die "correction" nicht braucht, die eh immer nur eine begrenzte Genauigkeit bietet. PS: Also ungefähr so:
1 | #include <time.h> |
2 | #include <stdio.h> |
3 | |
4 | int main() |
5 | {
|
6 | struct timespec ts; |
7 | |
8 | clock_gettime(CLOCK_MONOTONIC, &ts); |
9 | |
10 | for (;;) |
11 | {
|
12 | printf("Sekunde...\n"); |
13 | ts.tv_sec++; |
14 | clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL); |
15 | }
|
16 | }
|
:
Bearbeitet durch User
Rolf M. schrieb: > Man kann auch die realtime-Funktionen dafür verwenden, also > clock_gettime und clock_nanosleep. Vielen Dank für den Tipp. Ich wusste, es lohnt sich, ein Stückchen Code zu posten... ;) Rolf M. schrieb: > Letztere hat auch den Vorteil, dass > man auf einen absoluten Zeitpunkt warten kann, so dass man die > "correction" nicht braucht, die eh immer nur eine begrenzte Genauigkeit > bietet. Ich hab's ausprobiert. Ja, "correction" braucht man damit nicht. Aber die Genauigkeit bzw. Offset bzw. Jitter ist gleich. Er schwankt im Durchschnitt etwa 100 Mikrosekunden mit einer Periode von etwa 10 bis 20 Sekunden, mit einigen, heftigen Ausreißern (Spitze: 70000 Mikrosekunden). Ansonsten finde ich es erstaunlich, wie gut man hier auch unter Last in einem Multitasking-System periodische Tasks einfach steuern kann. Ich habe noch einen andere Regel-Algorithmus für "correction" ausprobiert, der sich weniger durch Ausreißer stören lässt. Was wirklich weniger Jitter bringt, ist sched_setscheduler(SCHED_FIFO). Das eliminiert die Ausreißer komplett und reduziert den Jitter. Aber die langsame Schwingung auf dem Jitter ist dennoch vorhanden. Spannend. Vielleicht probiere ich auch noch SCHED_DEADLINE aus. Mal sehen...
Kleiner Test schrieb: > Was wirklich weniger Jitter bringt, ist sched_setscheduler(SCHED_FIFO). > Das eliminiert die Ausreißer komplett und reduziert den Jitter. Ja, genau, das bringt einiges. > Aber die langsame Schwingung auf dem Jitter ist dennoch vorhanden. > > Spannend. War das mit einem RT-Kernel und hast du mal die Prio des Thread erhöht? Ich hab sowas noch nicht feststellen können.
Kein RT-Kernel, und ziemlich alte Möhre. Ich werde berichten, sobald ich neue Experimente gemacht habe.
Ich habe jetzt den Vorschlag von Rolf M. umgesetzt, funktioniert problemlos, der Aufwand haelt sich in Grenzen, fuer mich die perfekte Loesung. Genauigkeit ist dabei kein so grosses Thema, solange dabei 3600 Abfragen pro Stunde herauskommen. Und das klappt. Vielen Dank fuer die Unterstuetzung, wieder was gelernt. wendelsberg
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.