Ein Programm im STM32 soll an bestimmten Stellen warten, um zB Timeouts
zu realisieren oder periodisch Aktionen auszuführen. Das Warten darf
nicht blockieren (Also nicht einfach delay). Dafür kann ich gut den
Systick Timer benutzen, der zB jede Millisekunde einen Zähler
inkrementiert. Im Programm kann ich zu gegebener Zeit den Zählerstand
speichern und damit bei den nächsten Durchläufen die verstrichene
Wartezeit ermitteln, und zwar auch, wenn sehr viele Funktionen
gleichzeitig warten sollten.
1
if(systickcounter>systickcounter_old+PERIOD)
2
{
3
systickcounter_old=systickcounter;
4
5
//Do your thing
6
}
Wie kann ich sowas in eine Funktion verpacken, die ich beliebig oft
parrallel von verschiedenen Stellen aus im Code aufrufen kann?
Prinzipiell muss ja bei jedem neuen Aufruf eine neue Instanz erzeugt
werden, die eine eigene systickcounter_old-Variable hat, bzw jeder
Aufrufer braucht seine eigene Instanz.
Klassenletzter schrieb:> Wait Klasse erzeugen
Ne simple Variable tuts auch um sich die Startzeit zu merken. Und ob man
das eine kleine if() nun als nacktes if() direkt hinschreibt oder als
Aufruf einer Funktion die nur existiert um ein einziges if() zu
beinhalten oder gar als einen Aufruf einer Methode eines Objekts das nur
für den einen Zweck existiert ein Feld und eine Methode zu haben die nur
dem Zweck dient eine einzige winzige kleine Zeile mit einem einzigen
if() zu "abstrahieren", mithin also drölfzig und nochmal zwei Zeilen
Boilerplate um ein einziges if() zu kapseln oder das eine if() direkt
hinzuschreiben ist reine Geschmackssache.
Machen wir doch mal die Bilanz:
OP: 1 Variable und 1 if()
Du: 1 Objektinstanz und immer noch ein if() (oder while) um das Ergebnis
des gekapselten ursprünglichen if() abzufragen das jetzt irgendwo anders
sein Dasein fristet.
>Ein Käse wird da erklärt, völlig nicht-relevant zum Thema.
Das zeigt, dass du es nicht gelesen hast. Es wird genau das erklärt was
er braucht.
Allerdings muss er natürlich noch den SysTick Counter in die Funktion
millis() wrappen.
Falls das zu schwierig ist, empfehle ich eher Häkeln als Hobby.
Hier die Zusammenfassung des Artikels:
> We’ve learned how to time things using millis() instead of delay()> so we can free up the processor to do other things.> We’ve learned how to define tasks as state machines that can execute> independently of other state machines at the same time.> And we’ve learned how to encapsulate these state machines> into C++ classes to keep our code simple and compact.
Jetzt noch die Hausaufgaben für den STM-User:
- schreiben sie die Funktion millis() welche den SysTick Counter
ausliest und den Wert als long int zurück gibt.
- die Beispiele nutzen Servos und LEDs. Beantworten Sie die Frage, ob
auch andere Funktionen genutzt werden können.
- Überlegen Sie sich weitere Klassen und schreiben Sie Beispiele
https://learn.adafruit.com/multi-tasking-the-arduino-part-1/conclusion
In C mache ich das so : In den interrupt handler von Systick verwende
ich eine Variable (volatile !) für ein "Timer" :
void SysTick_Handler(void)
{
if (Delay != 0x00) Delay--;
milli_seconds++;cal_timer++;speed_timer++;watchdog_gps++;
MPU_print++;timer_0++;mpu_timer++;Tx_timer++;
}
In main wird das dan so gemacht :
if(milli_seconds>100){milli_seconds=0;do_stuff();}
...wenn man bei C bleiben möchte, kann man eine Art Klasse auch so
programmieren:
- Datenstruktur "timer" definieren
- Funktionen schreiben, die mit dieser Datenstruktur arbeiten, wobei
jeweils beim Aufruf ein Zeiger auf die Datenstruktur übergeben wird
- Datenstruktur beliebig oft instaniziieren und dann mit den Funktionen
verwenden
Abhängig davon wie genau die Intervalle sein sollen, könnte diese timer
Bibliothek auch die einzelnen "timer" in einer Liste verwalten und dann
im systick Interrupt bearbeiten (checken ob Timer abgelaufen etc).
OP schrieb:> Wie kann ich sowas in eine Funktion verpacken, die ich beliebig oft> parrallel von verschiedenen Stellen aus im Code aufrufen kann?
garnicht. Mach es genau anders herum.
1. schreibe dir eine Systemuhr, die die Uhrzeit in ms zählt.
1a. ordne dort auch ne stupide Warterei ein, für den Fall, daß irgendwas
ein Warten benötigt, bevor die Uhr komplett aufgesetzt ist.
2. lasse diese Systemuhr eine Liste führen, wo Ereignisse eingetragen
werden können, die zu einer bestimmten Uhrzeit in Erscheinung treten
sollen. Dazu gehört: Liste bei jedem (oder jedem 10. oder so) Timertick
durchsehen und Ereignis ggf. werfen, Liste zu Mitternacht zusammen mit
der Uhrzeit um 24h zurücksetzen, Methode zum Listeneintrag, Methode zum
löschen eines Ereignisses aus der Liste.
3. schreibe dir eine kleine Ereignisverwaltung. Also Definition von
Ereignissen, Ereignis-Warteschlange, Methoden zum einwerfen von
Ereignissen in die Warteschlange und zum Auslesen der Warreschlange.
4. frage in deiner Grundschleife die Ereigniswarteschlange ab und
reagiere, wenn du dort ein Ereignis findest. Etwa so:
1
if(EventAvailable())
2
{switch(GetEvent())
3
caseevMachsLichtAus:MachsLichtAus();
4
AddDelayedEvent(evMachTürZu,5000);// nach 5 sek
5
break;
6
caseevTürklingel:SiehNach(Haustür);
7
};
8
}
Das war's.
Ich hänge dir mal was dran, was du seit Jahren auch schon in der
Lernbetty hättest finden können.
W.S.
Bernd K. schrieb:> Ne simple Variable tuts auch um sich die Startzeit zu merken. Und ob man> das eine kleine if() nun als nacktes if() direkt hinschreibt oder als> Aufruf einer Funktion die nur existiert um ein einziges if() zu> beinhalten oder gar als einen Aufruf einer Methode eines Objekts das nur> für den einen Zweck existiert ein Feld und eine Methode zu haben die nur> dem Zweck dient eine einzige winzige kleine Zeile mit einem einzigen> if() zu "abstrahieren", mithin also drölfzig und nochmal zwei Zeilen> Boilerplate um ein einziges if() zu kapseln oder das eine if() direkt> hinzuschreiben ist reine Geschmackssache.>
Cool ;-))))