Ich habe eine for-Schleife mit integriertem Delay die für eine Ausgabe
auf einem Display verantwortlich ist.
1
uint8_tk,j;
2
for(k=0;k<23;k+=2){
3
for(j=0;j<7;j++){
4
DisplaySet(k,1<<j);
5
wait_ms(200);
6
}
7
for(j=0;j<3;j++){
8
DisplaySet(k+1,1<<j);
9
wait_ms(200);
10
}
11
}
Wenn ich nun die Möglichkeit haben möchte, diese Schleife mit einem User
Input zu unterbrechen respektive in eine andere State der Statemachine
wechseln möchte, wie löse ich das elegant?
Grundsätzlich komme ich ja wohl nicht darum herum meine Buttons anstatt
zu pollen über Interrupts einzulesen?
@ King Julian (Gast)
>Wenn ich nun die Möglichkeit haben möchte, diese Schleife mit einem User>Input zu unterbrechen respektive in eine andere State der Statemachine>wechseln möchte, wie löse ich das elegant?
ohne wait_ms(200);
Siehe Multitasking>Grundsätzlich komme ich ja wohl nicht darum herum meine Buttons anstatt>zu pollen über Interrupts einzulesen?
Doch, Interrupts sind nicht zwingend nötig.
King Julian schrieb:> Wenn ich nun die Möglichkeit haben möchte, diese Schleife mit einem User> Input zu unterbrechen respektive in eine andere State der Statemachine> wechseln möchte, wie löse ich das elegant?
Mit einem "break"? (;
> Grundsätzlich komme ich ja wohl nicht darum herum meine Buttons anstatt> zu pollen über Interrupts einzulesen?
Du wirst ja ohnehin einen Systemtimer haben. In dessen ISR kannst Du die
Buttons pollen und das Debouncing machen. Wenn Du die Buttons direkt auf
Interrupts legst, wird das Debouncing komplizierter.
Aus der ISR schiebst Du den einen Tastendruck in eine lockless queue.
Die kannst Du dann abfragen, ob was drin ist, in den betreffenden
Zustand springen und dort den Tastendruck aus der Queue holen.
So in der Art. Die Variable 'event' wird z.B. aus einem
Interrupt-Handler beschrieben.
Alternativen und spielweisen gibt es davon unendlich viele. Z.b. könnte
man aus wait_event_ms() auch einen entsprechenden Event-Handler direkt
aufrufen, oder, oder, oder.
Also ich hab nun meinen Code umgestellt um etwas näher am Multitasking
zu sein, und zwar hab ich meine Funktion, nennen wir sie mal foo(), mit
einer Statemachine versehen. Das heisst ich habe die Funktion in
einzelnen Unterfunktionen gegliedert von denen keine mehr die
timeconstraints verletzen sollte.
Das Problem das ich nun habe ist, an der Stelle an der ich zuvor foo()
einmal aufgerufen habe, muss ich foo() nun x-mal aufrufen (für alle
Iterationen eben), aber wie teile ich dem darüber liegenden Code mit
wenn aller Iterationen durchlaufen sind?
Ich hoffe das ist einigermassen Verständlich formuliert?
> Das Problem das ich nun habe ist, an der Stelle an der ich zuvor foo()> einmal aufgerufen habe, muss ich foo() nun x-mal aufrufen (für alle> Iterationen eben)
Wie meinst Du das? Ich würde die Funktion timergesteuert alle 200ms
aufrufen und in der Funktion die Statusvariablen k und j entsprechend
modifizieren. Die beiden können dann natürlich nicht mehr lokal
deklariert werden, da sie anfangs initialisiert und später immer wieder
wiederverwendet werden sollen.
Eine Schleife (Iterationen) gibt es dann keine mehr, einen wait-Aufruf
dann schon zweimal nicht mehr.
> aber wie teile ich dem darüber liegenden Code mit> wenn aller Iterationen durchlaufen sind?
Versteh ich nicht. Ich würde die Funktion pauschal immer aufrufen, auch
wenn sie dann feststellen sollte, daß es nix zu tun gibt. Wieso soll das
der darüber liegende Code festellen? Der ruft ja wohl auch noch ganz
andere Sachen auf. Der braucht die Funktionsweise der Funktion nicht zu
kennen, denn dann müßte er sie potentiell alle kennen, die er aufruft.
Das wäre dann Spaghetti-Code, unübersichtlich, fehleranfällig. Die
Funktion kann ja ein beliebiger Handler für einen Timer-Event sein, und
der darüber liegende Code - also der Aufrufer - wäre die Event-Loop, die
nur den Typ Event-Handler kennt.
King Julian schrieb:> wait_ms(200);
Du hast offenbar Zeit, "wait_ms(200);". Sollte reichen, in eine andere
Routine zu springen und die Tasten abzufragen (aka pollen). Dein wait
muß dann natürlich auf einen absoluten Timer umgebaut werden.
Markus L. schrieb:>> Das Problem das ich nun habe ist, an der Stelle an der ich zuvor> foo()>> einmal aufgerufen habe, muss ich foo() nun x-mal aufrufen (für alle>> Iterationen eben)> Wie meinst Du das? Ich würde die Funktion timergesteuert alle 200ms> aufrufen und in der Funktion die Statusvariablen k und j entsprechend> modifizieren. Die beiden können dann natürlich nicht mehr lokal> deklariert werden, da sie anfangs initialisiert und später immer wieder> wiederverwendet werden sollen.> Eine Schleife (Iterationen) gibt es dann keine mehr, einen wait-Aufruf> dann schon zweimal nicht mehr.
Vielleicht ist das Problem nicht mehr ganz dasselbe wie im
ursprünglichen Post. Also was ich machen will, ist im Prinzip eine LED
faden ohne dabei andere zeitkritische Funktionen zu vernachlässigen. Das
Faden ist aber auch nur ein Teil einer darüberliegenden Statemachine.
>> aber wie teile ich dem darüber liegenden Code mit>> wenn aller Iterationen durchlaufen sind?> Versteh ich nicht. Ich würde die Funktion pauschal immer aufrufen, auch> wenn sie dann feststellen sollte, daß es nix zu tun gibt. Wieso soll das> der darüber liegende Code festellen? Der ruft ja wohl auch noch ganz> andere Sachen auf. Der braucht die Funktionsweise der Funktion nicht zu> kennen, denn dann müßte er sie potentiell alle kennen, die er aufruft.> Das wäre dann Spaghetti-Code, unübersichtlich, fehleranfällig. Die> Funktion kann ja ein beliebiger Handler für einen Timer-Event sein, und> der darüber liegende Code - also der Aufrufer - wäre die Event-Loop, die> nur den Typ Event-Handler kennt.
Damit meine ich, wenn die oben gelistete Statemachine im State
state_complete angelangt ist, müsste die höherliegende Statemachine in
einen anderen State wechseln, sonst beginnt das Faden ja wieder von
vorne.
King Julian schrieb:> Wenn ich nun die Möglichkeit haben möchte, diese Schleife mit einem User> Input zu unterbrechen respektive in eine andere State der Statemachine> wechseln möchte, wie löse ich das elegant?
Indem du keine solche Schleife schreibst.
So wie es aussieht, passiert nur alle 200ms etwas in dieser Schleife.
Statt das nun in ein statische Gerüst zu zwängen, solltest du lieber
eine Funktion schreiben, die die Schleifenvariablen als lokale Variablen
hält und bei jedem Aufruf genau einen Interationsschritt macht. Diese
Funktion mußt du dann nur einmal alle 200ms aufrufen. Z.B. aus einem
Timerinterrupt. Oder - wenn das Timing paßt - aus deiner Hauptschleife.