Hallo,
ich möchte eine neues Projekt starten.
hierzu erzeugt ein Timer jese millisekunde ein Interrupt.
In diesem Interrupt wird eine volatile varriable um 1 hochgezählt.
Dass der Interrupt jede ms ausgeführt wird, habe ich überprüft, indem
ich eine LED immer toggle und das Signal mit einem Oszzi überprüft habe.
Passt, jede ms ein Flankenwechsel high>low oder low>high.
Dann erfolgt im zyklischen Programmteil eine Logic, die nach 1000 ms
eine andere LED toggelt.
Was nicht stimmt, dass die Zeit zum Toggeln 2 Sekunden dauert, es sollte
aber 1 Sekunde sein.
Jetzt könnte man denken, dass irgendwo anders im Zyklus eine Sekunde
gewartet wird. Ist es aber nicht, weil wenn ich den Zähler (COUNT) von
1000 auf 500 reduziere, dass beträgt die Toggelzeit exact 1 Sekunde.
Also Fehler Faktor 2.
Bin für jeden Hinweis dankbar......
Hier ein Teil des Codes:
Dirk F. schrieb:> Also Fehler Faktor 2.> Bin für jeden Hinweis dankbar......
Du macht es auch maximal kompliziert und auch resourcenhungrig. Du
zählst DOPPELT! In der ISR UND im Hauptprogramm! Setz doch einfach nach
500ms ein Flag, da im Hauptprogramm erkannt wird und die LED schaltet.
Das ist DEUTLICH einfacher und braucht weniger CPU-Last.
Dein Zugriff auf zeit bei "if (zeit>=1)" ist nicht atomar und könnte,
weil int zeit aus mehreren Bytes besteht, inmitten des Vergleichs
unterbrochen werden.
LG, Sebastian
Sebastian W. schrieb:> Dein Zugriff auf zeit bei "if (zeit>=1)" ist nicht atomar und könnte,
Kann sein, muss nicht. Wir kennen die CPU nicht. NAch den ISR-Namen zu
Urteilen ein ARM oder MSP430. Die können 16 Bit Vergleiche atomar.
Sebastian W. schrieb:> Dein Zugriff auf zeit bei "if (zeit>=1)" ist nicht atomar und> könnte,> weil int zeit aus mehreren Bytes besteht, inmitten des Vergleichs> unterbrochen werden.>> LG, Sebastian
Hallo, es ist ein 32 Bit MCU.
Habe den teil deaktiviert:
// if (zeit >=1)
// {
Trotzdem ist die Zeit doppelt so lange wie sie sein sollte....
Beim Lesen deines Codes bekomme ich einen Knoten im Hirn. Aber er ist
sicher nicht fehlerhaft.
Die "zeit" wird jede ms um 1 erhöht. Du toggelst die LED nach 500ms. Sie
ist also 500ms AN und dann 500ms AUS. Macht zusammen 1s pro Zyklus, oder
1 Hz.
Dirk F. schrieb:> PIC32MZ
OK, ändert aber nix an meinem Kommentar. Dein Ansatz ist maximal
aufwändig und kompliziert. Warum der jetzt doppelt so lange dauert?
Hmmm?
Deine Klammernsetzung ist auch, "besonders". Würde ich nicht empfehlen.
Stefan F. schrieb:> Die "zeit" wird jede ms um 1 erhöht. Du toggelst die LED nach 500ms. Sie> ist also 500ms AN und dann 500ms AUS. Macht zusammen 1s pro Zyklus, oder> 1 Hz.
Istzustand:
Bei COUNT 1000 : LED 2s an 2s aus
Bei COUNT 100 : LED 200 ms an 200 ms aus
Stefan F. schrieb:> Macht zusammen 1s pro Zyklus, oder> 1 Hz.
Tja, hier liegt vielleicht der Fehler. Die LED "toggelt" nach 500ms,
sprich wechselt den Pegel. Damit ist die Pulsbreite für LOW und HIGH
500ms. Die Periodendauer aus LOW+HIGH ist aber 1000ms, logisch.
VErmutlich hat das der OP verwechselt.
Dirk F. schrieb:> Istzustand:> Bei COUNT 1000 : LED 2s an 2s aus> Bei COUNT 100 : LED 200 ms an 200 ms aus
Hmm, das glauben wir einfach mal. Dann läuft irgendwas nur halb so
schnell wie es soll. Oder es wird immer ein Takt "verdoppelt" ? Komisch.
Möglichwerweise kommt der Timer mit dem dauernden Reset auf 0 aus dem
Takt, das kann mit dem Vorteiler zusammen hängen. Wenn der auch einen
Reset bekommt, kann sowas passieren. So oder so ist dein Ansatz
unsinnig. Pack die Uhr in den Timer-Interrupt und generiere dort Flags
für das Hauptprogramm. Dabei läuft der Zähler durch und alles ist gut.
Falk B. schrieb:> VErmutlich hat das der OP verwechselt.
Nein. Wenn ich im 1ms Interrupt die LED Toggele, dann ist klar, dass
die Periodendauer 2ms ist, aber darum gehts doch nicht.
Gleiches gilt für den main loop Zyklus.
Toggeln nur zur Zeitmessung mit dem Osszi.....
Schreibe mal ein neues Programm, wo nur die für diesen Effekt relevanten
Teile drin sind. Tritt der Fehler dann noch auf, dann zeige und den
kompletten Quelltext dieses Testprogramms. Tritt er nicht mehr auf,
finde den Unterschied.
Und zeige uns dein Oszilloskop-Bild von den 1ms. Vielleicht sind es doch
2ms und du hast dich nur verguckt.
Dirk F. schrieb:> Hmm, die Zeit im Interrupt sollte doch immer so kurz wie möglich> gehalten werden......
Ja mein Gott, was glaubst du wie lange dein PIC32 mit 30MHz++ für so ein
paar Zeilen braucht?
Stefan F. schrieb:> Schreibe mal ein neues Programm, wo nur die für diesen Effekt relevanten> Teile drin sind.
Gute Idee Stefanus. Mache ich in den nächsten Tagen....
Hier als JPG, wenn gleich das auch nur ein Workaround ist. Wie schafft
man es, ein 9,3MB PNG zu erzeugen? OK, bei 4000x2300 Pixel geht das
anscheinend! Und das bei einem Digitaloszilloskop, das saubere
Screenshots erzeugen kann. FAIL!
Dirk F. schrieb:> @Falk:> Und wie soll ich dann die Zykluszeit in ms ermitteln ???
Welche Zykluszeit? In deinem Beispiel zählst du nur eine Uhr hoch. Und
wenn man die Zeitdifferenz zweier Ereignisse messen will, macht man das
wie der Rest der Welt.
Differenz = Endzeit - Startzeit.
Und wenn man periodisch ein Ereignis auslösen will, kann man das auch
über den Interrupt machen. Anstatt des #define für die 1000ms nutzt man
eine Variable. Damit kann man variable Blinkzeiten oder was auch immer
generieren.
Dirk F. schrieb:>> Differenz = Endzeit - Startzeit.>> Und wenn ein Übrlauf stattfindet ?
Passiert die Magie der Integerarithmetik. Solange die Differenz kleiner
als der Zählumfang des Timers ist, ist die Differenz IMMER korrekt!
Dirk F. schrieb:> Die Zykluszeit vom main loop.
Bei jedem Durchlauf zählt man eine Variable um 1 hoch. Ist eine Sekunde
voll gibt man den Wert aus und hat die Anzahl der Durchläufe.
Dirk F. schrieb:> Habe den teil deaktiviert:> // if (zeit >=1)> // {>> Trotzdem ist die Zeit doppelt so lange wie sie sein sollte....
Mmh, seltsam. Was hat es denn mit CLKS_STATE_EVENT auf sich?
LG, Sebastian
Man muss den Interrupt gar nicht sperren wenn man das so macht:
volatile int zeit1;
volatile int zeit2;
int failsafe_exit = 0;
while (1) {
zeit1 = zeit;
zeit2 = zeit;
if (zeit1 == zeit2) {
break;
}
failsafe_exit++;
if (failsafe_exit > 10) {
break;
}
}
failsafe_exit braucht man nicht unbedingt. Ist aber besser. Wobei wenn
der greift, dann gibt es keine konsistente Zeit. Da muss man dann
richtung Fehlerbehandlung gehen.
Die While schleife sollte max 2 mal laufen, wenn der Interrupt ca 1ms
kommt.
Dirk F. schrieb:> 9,3 MB
Herzlichen Glückwunsch. Guck mal rechts unterhalb des Bildschirmes. Da
gibt es eine Schnittstelle für vernünftige Screenshots.
Andras H. schrieb:> Man muss den Interrupt gar nicht sperren wenn man das so macht:
Man muß aber auch keine Angst davor haben. Ein atomarer Zugriff sollte
unter 10 CPU-Zyklen kosten, das dürfte vernachlässigbar sein.
Das von hinten durch die Brust ins Auge zu vermeiden, ist den Aufwand
nicht wert. Und lesbarer wird es auch nicht.
Thomas F. schrieb:> Bei jedem Durchlauf zählt man eine Variable um 1 hoch. Ist eine Sekunde> voll gibt man den Wert aus und hat die Anzahl der Durchläufe.
Aber nicht die aktuelle, minimale, maxixmale und durchschnittliche
Zykluszeit, so wie es eine SPS (z.B. Siemens) auch misst.
Sebastian W. schrieb:> Mmh, seltsam. Was hat es denn mit CLKS_STATE_EVENT auf sich?
Der wechselt einmalig am Anfang (Statusmaschine) vom State Init in
Event.
Dirk F. schrieb:> Der wechselt einmalig am Anfang (Statusmaschine) vom State Init in> Event.
Wenn der Interrupt jede 1ms triggert, wie auf dem Oszi zu sehen, und
also jede 1ms "zeit" um 1 erhöht, und du häufig genug in der
Hauptschleife die in "zeit" gezählten 1ms in appData überträgst und auf
das Erreichen von 1000 überprüfst, dann sollte dieses Erreichen von 1000
jede Sekunde passieren. Wenn es nur alle zwei Sekunden passiert, bzw.
nur jede Sekunde passiert indem du statt auf das Erreichen von 1000 auf
das Erreichen von 500 prüfst, dann ist irgendwo tatsächlich der Wurm
drin.
Hast du eine Möglichkeit, Testausgaben zu generieren? Dann gib an der
Stelle "//---------jede Sekunde------------------------------------" mal
appData.msec_cnt aus.
LG, Sebastian
Sebastian W. schrieb:> Hast du eine Möglichkeit, Testausgaben zu generieren? Dann gib an der> Stelle "//---------jede Sekunde------------------------------------" mal> appData.msec_cnt aus.
Ja, habe ich. Über CDC (USB-Serial) COM Port kann ich Meldungen
ausgeben.
Werde dann das Programm anpassen und diese Werte jede Sekunde ausgeben:
appData.msec_cnt
appData.sec_cnt
Dauert aber noch etwas.....
> dann ist irgendwo tatsächlich der Wurm drin.
Sach ich doch......
Das Programm ist mir viel zu sehr von hinten durch die Brust ins Auge,
da sieht doch keiner durch.
Wenn Du einen Oszi hast, dann setze das Toggle der LED einfach direkt in
den Interrupthandler. Die 500Hz sollten gut zu sehen sein.
Peter D. schrieb:> Wenn Du einen Oszi hast, dann setze das Toggle der LED einfach direkt in> den Interrupthandler. Die 500Hz sollten gut zu sehen sein
Hab ich doch gemacht.... s.oben
Falk B. schrieb:> Na dann probier mal meinen Vorschlag aus, das dauert wenige Minuten!
Ja mach ich über die Feiertage. Habe im Moment keinen Zugriff....
Peter D. schrieb:> Das Programm ist mir viel zu sehr von hinten durch die Brust ins Auge,> da sieht doch keiner durch.
Dann will ich die Programm Logic mal so erklären:
1. Im Interrupt wird eine Varriable (32 Bit) jede ms um 1 erhöht.
2. Der normalen Zyklus (Superloop) kann einige us bis einige ms
dauern.
3. Im normalen Zyklus wird die bisher vergangene Zeit vom letzten Aufruf
in ms übertragen (= aktuelle Zykluszeit in ms).
Wenn diese 0 ist, dann ist noch keine ganze ms vergangen >>> mach nix
Wenn diese 1 oder mehr ist, dann addiere die vergangene Zeit in ms auf
den ms-Zähler.
Wenn der ms Zähler dann z.B 1003 ist (letzter Zyklus dauerte z.B. 3
ms), dann ziehe 1000 ab, bleibt Rest 3 für nächsten Durchlauf, damit
keine 3ms verloren gehen.
4.Erhöhe den Sekundenzähler.
Dirk F. schrieb:> Hab ich doch gemacht.... s.oben
Ja dann liegt es an Deinen undurchschaubaren und unvollständigen
Programmschnipseln.
Bei Schnipseln fehlt immer das Entscheidende.
Ozvald K. schrieb:> Dirk F. schrieb:>> appData.msec_cnt =- COUNT>> von -500 bis + 500
War meine Posting zu subtil? Versuche -= statt =-, oder einfach =0 in
der Zeile. Wenn appData.msec_cnt = -500, dann bis 500 braucht die
doppelte Zeit als von 0, oder lege ich falsch?
Ozvald K. schrieb:> Dirk F. schrieb:>> appData.msec_cnt =- COUNT>> von -500 bis + 500
Wenn Du das wirklich so: =- in Deinem Programm stehen hast, dann kann
Ozvald nur recht geben; das erste Toggeln kommt zwar eventuell noch zum
richtigen Zeitpunkt, aber das übersieht man natürlich leicht, alle
folgenden Intervalle sind immer das doppelte von COUNT.
Sollte das nur ein Tippfehler hier im Post sein, dann weißt Du jetzt,
warum alle nach einem compilierenden Minimalbeispiel verlangen.
Michi S. schrieb:> Sollte das nur ein Tippfehler hier im Post sein,
Müßte man ihm zusätzlich eine Watschen verpassen! Quelltext NIEMALS
abschreiben, immer 100% KOPIEREN! Oder gleich die ganze Datei als Anhang
senden.
Dirk F. schrieb:> Weil ich dann keine Zykluszeiten messen kann.
Verstehe ich nicht. Klar geht das. Wenn Du die Differenz zwischen zwei
Zeitpunkten messen willst wird es sogar noch einfacher. Du brauchst nur
eine einzige "ms" Variable (unsigned) im Interrupt hochzuzählen, und
zwar ohne auf 0 zurückzusetzen. Du merkst Dir den Stand am Anfang und
den Stand am Ende deines Zyklus. Deine Zyklusdauer ist "Ende - Anfang"
Und zwar immer, Overflows usw. werden wegen der Subtraktion implizit
berücksichtigt.
Dirk F. schrieb:> Daher brauche ich diesen ms Tick.
Ein Tickzähler läuft immer nur hoch. Er wird nie zurückgesetzt. Das
Zurücksetzen passiert implizit nur dann, wenn der Zähler überläuft.
Mein Tipp: sieh dir die Implementierung von millis() beim Arduino an.
Damit können sogar blutige Laien mit Zeitdifferenzen ohne
Überlaufprobleme arbeiten.
Also nochmals Danke an alle.
Der Programmteil läuft jetzt fehlerfrei.
War wirklich ein blöder Fehler.
Falk B. schrieb:> Passiert die Magie der Integerarithmetik. Solange die Differenz kleiner> als der Zählumfang des Timers ist, ist die Differenz IMMER korrekt!
Also wenn ich einen 16 Bit Timer, der jede µs um 1 erhöht wird, frei
laufen lasse, und ihn an zwei unterschiedlichen Zeitpunkten auslese,
dann ist das Ergebnis auch noch richtig, auch wenn zwischendurch ein
Überlauf von 0xFFFF auf 0x0000 stattgefunden hat ?
Mal nachrechnen:
1. Zeitpunkt Zähler = 0xfffe (Dezimal 65534)
2. Zeitpunkt Zähler = 0x0005 (Dezimal 5)
Zeitdifferenz Dezimal (65536-65534) + 5 = 7 µs
Zeitdifferenz HEX 0xffe - 0x005 = 0xF007 (Dezimal 61447)
Also Jungs, das war der best Hinweis überhaupt.
Durch das neue System wird der Prozessor gar nicht mehr mit Interrupts
belastet. Und die Messung der aktuellen Zykluszeit hat eine Auflösung
von 1 µs.
Hier ein Teil des Codes:
1
voidCLKS_Initialize(void)
2
{
3
// Timer 2/3 (32 Bit) läuft endlos mit 25 MHz
4
// Konfiguriert mit Harmony für PIC32MZ
5
TMR2_PeriodSet(0xffffffff);
6
TMR2_Start();// Start the timer
7
LogMsg("The 1 microsecond timer has started");
8
}
9
10
11
voidCLKS_SM(void)
12
{
13
staticuint32_tzeit_alt;
14
staticuint32_tzeit_neu;
15
zeit_neu=TMR2_CounterGet();// Aktuelle Zeit holen
16
17
// Vergangene Zeit in us * 25, weil Timer2/3 mit 25 MHz läuft
Dirk F. schrieb:> Also Jungs, das war der best Hinweis überhaupt.> Durch das neue System wird der Prozessor gar nicht mehr mit Interrupts> belastet. Und die Messung der aktuellen Zykluszeit hat eine Auflösung> von 1 µs.
Schöner Unfug. Vor allem, da dein Timer mit 25 MHz läuft. Der hat auch
einen Vorteiler, den kann man einstellen, dann läuft der direkt mit
1MHz, was immer noch Käse ist, aber etwas weniger Käse.
> static uint32_t zeit_alt ;> static uint32_t zeit_neu ;> zeit_neu = TMR2_CounterGet(); // Aktuelle Zeit holen>> // Vergangene Zeit in us * 25, weil Timer2/3 mit 25 MHz läuft> zykuszeit_act = (uint32_t) ( (int32_t) zeit_neu - zeit_alt) / 25;
Was soll der cast-Unsinn? Deine Variablen sind 32 Bit, da braucht man
nix weiter!
> zeit_alt = zeit_neu; // Neue Zeit übertragen>> appData.usec_cnt += zykuszeit_act ;> appData.msec_cnt = appData.usec_cnt/1000;>> if (appData.usec_cnt >= 1000000)> {> //---------jede Sekunde------------------------------------> appData.usec_cnt -= 1000000;> appData.sec_cnt++;> appData.unixsecs++;> clk1000();> }
Jaja, warum nicht gleich Nanosekundenauflösung?
Falk B. schrieb:> einen Vorteiler, den kann man einstellen, dann läuft der direkt mit> 1MHz, was immer noch Käse ist, aber etwas weniger Käse.
Nee, keinen Vorteiler 100, nur 128
Dirk F. schrieb:>> einen Vorteiler, den kann man einstellen, dann läuft der direkt mit>> 1MHz, was immer noch Käse ist, aber etwas weniger Käse.>> Nee, keinen Vorteiler 100, nur 128
Ja und? Dann hättest du 25MHz/128=195,3125kHz (5,12us) Auflösung. Immer
noch mehr als sinnvoll, vor allem für solche Messungen.
Falk B. schrieb:> Ja und? Dann hättest du 25MHz/128=195,3125kHz (5,12us) Auflösung. Immer> noch mehr als sinnvoll, vor allem für solche Messungen.
Woher willst Du das wissen? Wir machen hier z.B. synchrone
Automatisierungstechnik, da messe ich die Laufzeit meiner Software in
"ns". 2us Jitter liegen bei uns schon außerhalb der Spezifikation. 5us
sind ne halbe Ewigkeit.
Andreas M. schrieb:> Woher willst Du das wissen?
Daher!
"Vielen Dank an alle. Ich habe es kapiert.
Bin halt nur Gelegenheitsprogrammierer...."
Das ist nur Hobbyspielerei.
> Wir machen hier z.B. synchrone> Automatisierungstechnik, da messe ich die Laufzeit meiner Software in> "ns". 2us Jitter liegen bei uns schon außerhalb der Spezifikation. 5us> sind ne halbe Ewigkeit.
Von dir und deiner professionellen Anwendung war gar nicht die Rede.
Dirk F. schrieb:>> Das ist nur Hobbyspielerei.>> Nee, industrielle Anwendung mit Profinet Anbindung.
Und darauf lassen die einen Gelegenheitsprogrammierer los. Sehr
professionell!
Falk B. schrieb:> Und darauf lassen die einen Gelegenheitsprogrammierer los. Sehr> professionell!
Falk, ich glaube Du bist etwas frustriert.
Es gibt auch Leute, de neben Programmieren auch noch etwas anders
beruflich machen.
Fachidiot: Kann eine Sache zu 100 %
Guter Mitarbeiter: Kann mehrere Sachen, nicht zu 100 % aber ist bereit
sich neuen Aufgaben zu stellen und sich einzuarbeiten....
dirkf schrieb:
> Fachidiot: Kann eine Sache zu 100 %
Auf den kann man sich also verlassen - liefert stets korrekte
Ergebnisse.
> Guter Mitarbeiter: Kann mehrere Sachen, nicht zu 100 % aber ist bereit> sich neuen Aufgaben zu stellen und sich einzuarbeiten....
Kann also nichts richtig - liefert stets zusammengeschusterten
Laienpfusch und wird in Kürze von ChatGPT/Copilot ersetzt. Diese
Einstellung, dass sowas ein "Guter Mitarbeiter" ist, scheint bei den
Personalern leider weit verbreitet zu sein (er ist halt billiger). Es
wird übersehen, dass das "sich einarbeiten" in Fachgebiete gerne mal
Jahre dauert. Da dafür die Zeit nicht reicht, gibt man sich mit Pfusch
zufrieden - entsprechend ist der aktuelle Stand der Technik.
Ich wüsste auf jeden Fall, wen ich also Mitarbeiter haben wollte ...
Foobar schrieb:> Auf den kann man sich also verlassen - liefert stets korrekte> Ergebnisse.
Kein Mensch liefert stets korrekte Ergebnisse.
Foobar schrieb:>> Guter Mitarbeiter: Kann mehrere Sachen, nicht zu 100 % aber ist bereit>> sich neuen Aufgaben zu stellen und sich einzuarbeiten....>> Kann also nichts richtig - liefert stets zusammengeschusterten> Laienpfusch> [Noch mehr Unsinn]
Nö, genau die Leute die breit Aufgestellt sind werden die einzigen sein,
die zukünftig noch Arbeit haben werden. Denn Gerade die "Fachidioten"
sind die, die man mit KI ersetzen wird. Bisher hat man solche Arbeiten
gerne nach Fernost abgeschoben, aber die Leute dort haben auch keinen
Bock mehr da drauf.
Die Ergebnisse von Entwicklern, die nur in Ihrer eigenen kleinen Welt
leben, darf ich jeden Tag erleben.
Dirk F. schrieb:> Guter Mitarbeiter: Kann mehrere Sachen, nicht zu 100 % aber ist bereit> sich neuen Aufgaben zu stellen und sich einzuarbeiten....
... und findet nötigenfalls schneller eine Ausrede als eine Maus ein
Loch!
Sehr guter Mitarbeiter: kann mehrere Sachen zu 100 %, kann über den
Tellerrand hinausblicken und Zusammenhänge herleiten.
Nachdem das geklärt ist gehen wir mal zur Sache...
Falk B. schrieb:> Schöner Unfug. Vor allem, da dein Timer mit 25 MHz läuft.
Hab ich mir sofort auch gedacht, als ich /25 und /1000 gesehen habe. Arg
viel ineffizienter kann man nicht prorammieren, denn auch heute noch
sind Prozessoren im tiefsten Inneren binär. Eine dezimale Rechnung (oder
allgemeiner einer Rechnung jenseits von Zweierpotenzen) macht ihnen
Aufwand.
Dirk F. schrieb:> Nee, keinen Vorteiler 100, nur 128
Sag ichs noch: ein µC ist binär.
Für eine effiziente Programmierung musst du dich dem Controller
anpassen, denn der Witz ist: du schreibst das Programm nur ein einziges
Mal, der Controller muss es aber zigtausendmal pro Sekunde ausführen.
Ich mache es so: ein Zeitzähler (Timertic) läuft immer hoch. Er wird
niemals von Hand zurückgesetzt. Nur am "Ende" der läuft er implizit
über. Und basierend auf diesem Zähler dann werden alle Zeiten per
Differenz verwaltet. Ein Tipp dazu: sieh dir die Arduino millis()
Funktion und die Arbeit mit Zeitdifferenz mal genauer an.
Andreas M. schrieb:> 2us Jitter liegen bei uns schon außerhalb der Spezifikation. 5us sind ne> halbe Ewigkeit.
Ja, mag sein. Allerdings bin ich mir absolut sicher, dass daran dann
aber auch keine "fortgeschrittenen Laien" arbeiten.
Im Fall hier würde ich mir überhaupt erst mal klar machen, welche
Zeitauflösung denn nötig und welcher Jitter erlaubt ist. Und dann
eine geeignete Zeitbasis aufbauen, die dem Controller "gut liegt" und
mit der er einfach arbeiten kann.
Falk B. schrieb:> Dann hättest du 25MHz/128=195,3125kHz (5,12us) Auflösung
Also könnte ich da einfach einen "hundertstel µs"-Zähler bei jedem
Interrupt um 512 hochzählen. Und wenn der dann über 100000 hinausläuft,
dann würde ich den ms-Zähler um 1 hochzählen und den "hundertstel
µs"-Zähler atomar(!) um 100000 verringern.
Also etwa so:
1
longmillis,lasttoggle;
2
:
3
TimerInterrupt(){// 5.12µs
4
staticlongus100cnt;
5
us100cnt+=512;
6
if(us100cnt>100000){
7
millis++;
8
us100cnt-=100000;
9
}
10
}
11
:
12
// Arbeiten mit Zeitdifferenzen
13
if(millis-lasttoggle>1000){
14
toggleLED();
15
lasttoggle=millis;// Umschaltzeitpunkt merken
16
}
17
:
18
// oder besser so, dann summieren sich Verzögerungen nicht auf,
19
// sondern "verpasste" Toggles werden "nachgeholt"
20
if(millis-lasttoggle>1000){
21
toggleLED();
22
lasttoggle+=1000;// Umschaltzeitpunkte jeweils alle 1000 ms