Hallo
Innerhalb einer statemaschine erfolgt die Verzweigung mit switch und
case.
Wieviel mal kann man case nehmen? So oft wie nötig? Wie ist es mir der
Übersichtlichkeit und Fehlersuche? Wie kann man eine Hierarchie
vernünftig machen?
Leider habe ich bei go.. sehr wenig dazu gefunden. Vielleicht kann mir
das jemand erklären.
achim
nicht vergessen hast.
Schaue in ein beliebiges C-Buch und dann weißt Du die Antwort auf Deine
Frage.
Wenn Du objektorientiert arbeitest dann packe Deine Übergänge in die
jeweiligen Klassen, ist übersichtlicher, wartbarer und einfacher zu
erweitern.
Ansonsten weiß keiner welches eigentliche Problem Du hast ?
Keine Angst, break habe nicht ich vergessen. Leider hält sich mein C
Buch an dieser Stelle ziemlich raus. Entsprechende (speziel) Bücher kann
ich mir leider nicht leisten. Noch mal, damit es klar wird.
Bei einer statemschine erfolgt die verzweigung innerhalb der switch /
case und endet jeweils mit braek (so richtig?). Wieviel mal kann man
case auswerten, ohne das es unübersichtlich wird (alles bei C)? Wie kann
ich am besten eine Hierarchie machen? Bei meinem C-Buch (c von a bis z)
steht nichts drin.
achim
switch-case taugt höchtens was für ganz kleine state-machines. Für mehr
als 3 states würde ich mit funktionspointern arbeiten und für jeden
state eine eigene funktion anlegen.
Ob das übersichtlich ist bleibt geschmackssache, schau Dir die C++
Tutorien aml durch und versuche den Unterschied zu verstehen.
Wenn Du nicht genügend Platz hast Dein Projekt in OO umzusetzen nimm
einfach aussagefähige Statebeschreibungen.
Claus M. schrieb:> Für mehr> als 3 states würde ich mit funktionspointern arbeiten und für jeden> state eine eigene funktion anlegen.
Hast du dazu mal ein Beispiel?
Claus M. schrieb:> switch-case taugt höchtens was für ganz kleine state-machines. Für mehr> als 3 states würde ich mit funktionspointern arbeiten und für jeden> state eine eigene funktion anlegen.
Das stimmt so nicht, in jeder Fensterapplikation können schon sehr große
Konstrukte stehen, für jeden Menueintrag/Schaltfläche eben ein case.
Das ist auch nichts anderes als eine Statemachine.
Es wird halt unübersichtlicher, vor allem wenn man unsinnige
Bezeichnungen wählt.
Das mit den Funktionspointern entspricht ja meiner Empfehlung das in
Klassen zu kapseln und darin dann die Übergänge zu realisieren.
Nur hat OO halt noch mehr Vorteile.
Robert L. schrieb:>>switch(actualstate)>> case MOTORAN:{>> startmotor();>> interessante taktik ;-)
Jaja "shoot yourself in the foot" :-P
Aber das Prinzip ist dem TO hoffentlich klar geworden ;-)
Hallo
Das Prinzip ist mir klar. Verwende jetzt bis zu 8x case. Das mit
Funktion werde ich testen. Habe bisher alles in c gemacht. Konnte mich
leider nicht mit C++ anfreunden.
Bleibt nur noch die Frage offen, wie ich am besten eine
/ Auswahl 1
Haupsteuerung /
\ Auswahl 2
machen kann.
achim
Achim Seeger schrieb:> Das mit> Funktion werde ich testen.
Er meinte Funktionspointer !
Bleibe erstmal beim case bis Du Dich in OO eingearbeitet hast.
Dann machst Du für jeden Zustand ein eigenes Objekt welches dann jeweils
zum nächsten Zustandsobjekt wechselt.
@ Achim Seeger (achims)
>Das Prinzip ist mir klar. Verwende jetzt bis zu 8x case.
Das ist voll OK, selbst das Dreifache und mehr ist OK. Nur dass man in
die einzelnen case Zweigen keine Abläufe packt, die über mehr als 1/2
Bildschirmseite gehen. Dort kommt nur ein aussagekräftiger
Funktionsaufruf rein.
>Das mit>Funktion werde ich testen. Habe bisher alles in c gemacht. Konnte mich>leider nicht mit C++ anfreunden.
Ist auch besser so, du musst erstmal mit C programmieren lernen. Wenn du
das mal sicher beherrscht, kannst du über C++ nachdenken.
>Bleibt nur noch die Frage offen, wie ich am besten eine> / Auswahl 1>Haupsteuerung /> \ Auswahl 2>machen kann.
Was meinst du damit? Verschachtelte Menus?
Falk Brunner schrieb:> Ist auch besser so, du musst erstmal mit C programmieren lernen. Wenn du> das mal sicher beherrscht, kannst du über C++ nachdenken.
Frag mal KarlHeinz was er dazu meint ...
Das Kind ist jetzt zwar schon in den Brunnen gefallen, aber trotzdem mit
OO anzufangen macht wesentlich mehr Sinn.
Auch bei µCs !
Dabei kommt es nicht darauf an das C ein subset von C++ ist !
Dadurch wird es strukturierte als mit losen Defines.
Deine offenen Fragen verstehe ich auch nicht, vielleicht solltest du
dazu auch ein Codeschnispel posten wie du es momentan gelöst hast oder
was noch fehlt.
@ cppler (Gast)
>> Ist auch besser so, du musst erstmal mit C programmieren lernen. Wenn du>> das mal sicher beherrscht, kannst du über C++ nachdenken.>Frag mal KarlHeinz was er dazu meint ...>Das Kind ist jetzt zwar schon in den Brunnen gefallen, aber trotzdem mit>OO anzufangen macht wesentlich mehr Sinn.
Kaum. Das Kind muss erstmal laufen lernen. Ich kenn den OP ein wenig,
wir haben mehrfach per Email kommuniziert. Er muss erst noch einige
Grundlagen der allgemeinen Programmierung lernen. Das geht besser mit C.
C++ überfordert die Leute.
>Auch bei µCs !>Dabei kommt es nicht darauf an das C ein subset von C++ ist !
Darum geht es nicht.
Hallo
Danke Falk. Ein C-Buch ist gut und ich verwende es. Die Grundlagen
stehen drin. Aber das eigentliche programmieren und die notwendige
Übersicht fehlen dazu. Ich versuche die Sachen zu lösen. Dazu nehme ich
mir ein Stück Papier und schreibe was ich erreichen will, dann versuche
ich den weg zu machen, so mit notwendigen Variablen und Schema. Je
komplizierter die Programme werden, um so schlimmer. Da hilft manchmal
nur Funktion und Fehler zu machen. Aus Fehlern lernt man. Dann bleibt
noch Falk und Karl Heinz und einige andere.
Zu der Umschaltung. Habe in der Literatur den Hinweis gefunden eine
Hierarchie zu machen. Beispiel: Ich verwende an einer Ampel zwei
verschiedene Funktionen, den Regelbetrieb und den Notbetrieb.
Regelbetrieb ist klar mit den Folgen Rot, Grün usw. Beim Notbetrieb wird
nur Gelb blinkend geschaltet. Die Umschaltung erfolgt dabei mit einem
Taster. Der Start erfolgt mit Gelb Blinkend, Beim Umschalten erfolgt
erst Rot auf beiden danach normale Folge, beim Rückschalten auf Not
erfolgt der übergang wenn beide rot sind. Code haben ich für die
einzelnen Funktionen und ein Teil/Versuch beides zu machen. Leider mit
vielen Fehlern. Versuche jetzt den Ablauf als Tabelle zu machen. Habe
jetzt sogar 2 Tabellen, doch wie kann man die zusammen machen? Ist der
Begriff - verschachtelte Menüs -an dieser Stelle richtig? Dachte dabei
an zwei verschiedenen Abläufen, die an einer Stelle gekoppelt sind, wenn
die Bedingungen erfüllt sind.
achim
@ Achim Seeger (achims)
>Danke Falk. Ein C-Buch ist gut und ich verwende es. Die Grundlagen>stehen drin.
Schön, aber das allein richt nicht.
> Aber das eigentliche programmieren und die notwendige>Übersicht fehlen dazu.
Genau das ist das Problem. Aus den Informationen im Buch und anderswo
muss anwendungsbereits Wissen in deinem Kopf werden. Das nennt man
Lernprozess ;-)
> Ich versuche die Sachen zu lösen. Dazu nehme ich>mir ein Stück Papier und schreibe was ich erreichen will, dann versuche>ich den weg zu machen, so mit notwendigen Variablen und Schema.
Richtiger Ansatz.
> Je>komplizierter die Programme werden, um so schlimmer. Da hilft manchmal>nur Funktion und Fehler zu machen.
Ja.
> Aus Fehlern lernt man.
Hoffentlich ;-)
> Dann bleibt>noch Falk und Karl Heinz und einige andere.
Fragen ist nicht schlimm, im Gegenteil. Es ist richtig. Natürlich nur,
wenn man einen ausreichenden Eigenanteil zur Problemlösung mitbringt.
>Zu der Umschaltung. Habe in der Literatur den Hinweis gefunden eine>Hierarchie zu machen. Beispiel: Ich verwende an einer Ampel zwei>verschiedene Funktionen, den Regelbetrieb und den Notbetrieb.>Regelbetrieb ist klar mit den Folgen Rot, Grün usw. Beim Notbetrieb wird>nur Gelb blinkend geschaltet. Die Umschaltung erfolgt dabei mit einem>Taster. Der Start erfolgt mit Gelb Blinkend, Beim Umschalten erfolgt>erst Rot auf beiden danach normale Folge, beim Rückschalten auf Not>erfolgt der übergang wenn beide rot sind. Code haben ich für die>einzelnen Funktionen und ein Teil/Versuch beides zu machen. Leider mit>vielen Fehlern. Versuche jetzt den Ablauf als Tabelle zu machen. Habe>jetzt sogar 2 Tabellen, doch wie kann man die zusammen machen?
Steht alles im Artikel statemachine und wie es der Zufall will, auch
mit einem Ampelbeispiel.
> Ist der>Begriff - verschachtelte Menüs -an dieser Stelle richtig?
Für deine Ampel? Nein, natürlich nicht. Das ist ein ganz normaler Ablauf
mit bedingter Verzweigung (Wenn das -> tu dies etc.)
>Dachte dabei>an zwei verschiedenen Abläufen, die an einer Stelle gekoppelt sind, wenn>die Bedingungen erfüllt sind.
Ja, aber das ist dennoch eine State Machine. So ein einfaches Beispiel
auseinanderzureißen ist nicht sinnvoll. Das ist erst bei DEUTLICH
größeren state machines sinnvoll.
Poste vollständigen Code als Anhang, darüber kann man klar reden. Alles
andere ist bisweilen zu abstrakt und allgemein. Zeichne dir ein
Zustandsdiagramm mit den Übergängen, das kann man dann leicht in ein
C-Programm umsetzen.
Vergiß das mit den Funktionspointern, das ist für Dich nur eine
zusätzliche Fehlerquelle.
Sind viele aufeinander folgende Case, macht der Compiler schon selber
eine Sprungtabelle daraus. Du verlierst also keinerlei Performance.
Man kann mehrere Statemaschinen ineinander verschachteln, z.B. eine für
das Hauptmenü und dann weitere für die Untermenüs.
Hallo Falk
Dein Zufall ist einfach. Lerne an deinen Beispielen und passe es an und
verändere es. Am konkreten Beispiel kann man am meisten Fehler machen
und am besten lernen. Ansonsten ist es sehr interessantes Thema mit
vielen Möglichkeiten.
Mit dem Code kann ich nicht so schnell dienen. Komme erst heute abend
wieder an "meinen" Rechner. Im Moment besteht er aus vielen versuchen
und Irrtümern mit viel Spagetti dazwischen. Reiche es nach (noch
sortieren und ändern).
Bedingte Verzweigungen habe ich bereits drin, auch mit einer Änderung
der state Nr. Bin auch noch an der Zeiteinstellung und den Tabellen
dran.
Danke
achim
Sorry, Peter habe es erst jetzt gesehen.
In der Literatur war so was drin, aber ohne konkretes zu sagen. Unter
einem Menü oder Steuerung stellt man sich eine anzeige mit was drauf
vor, was man ändern oder auswählen kann.
Aber eine Verschachtelte statemaschine, sorry keine Peilung. Ist
eigentlich auch die Anfangsfrage gewesen. Wenn der Aufwand grösser ist,
als der Nutzen, löst sich das Problem von allein. Zu diesem Thema habe
ich nichts, auch keinen Ansatz.
achim
> Wieviel mal kann man case auswerten, ohne das es unübersichtlich wird.
Dem Compiler ist es ziemlich egal. Wieviel Du noch übersichtlich
findest, kannst nur Du sagen.
Die Abfrage von Ereignissen und Aktionen kannst Du in
Prozeduren/Funktionen auslagern wie im obigen Beispiel von cppler.
Sprechende namen für die States helfen sehr, um die Übersichtlichkeit zu
verbessern. Außerdem kannst Du den Zustandsautomaten möglicherweise in
mehrere Unter-Automaten aufsplitten. Wenn man das übertreibt, wird's
aber wieder unübersichtlicher, als ein größerer.
Letztendlich kommt es auf DEINE Vorlieben an. Oder die deines Prüfers,
falls es darum geht, eine gute Bewertung für die Arbeit zu bekommen.
@Achim Seeger (achims)
>und am besten lernen. Ansonsten ist es sehr interessantes Thema mit>vielen Möglichkeiten.
In denen man sich vor allem an Anfang schnell verlieren kann.
>Bedingte Verzweigungen habe ich bereits drin, auch mit einer Änderung>der state Nr. Bin auch noch an der Zeiteinstellung und den Tabellen>dran.
Mach erstmal nur EINE Variante. Mit switch, ohne Tabelle. Wenn das gut
läuft geht es weiter.
Er ist so wie angegeben lauffähig. Es erfolgt ein Verzweigung und Aufruf
von void und eine Abfrage des Tasters S3. Wie (Wo) kann ich am besten
die Umschaltung zu Gelb blinken einbauen bzw. eine verschachtelte State
machine?
achim
So ganz verstanden habe ich deine Ampel nicht:
wozu 7 LEDs, eine Ampel hat doch Rot, Gelb, Grün, also drei LEDs
was meinst du mit "Beim Umschalten erfolgt
erst Rot auf beiden danach normale Folge, beim Rückschalten auf Not
erfolgt der übergang wenn beide rot sind", also was ist beiden? Wie
sieht deine Ampel denn aus?
generell etwas zum Programm:
Würdest du anstatt 0, 1, 2, 3 deine Defines für rot, grün, ... (Define 0
für aus hast du noch vergessen) verwenden, so könntest du dir die
Kommentare hinter den Funktionsaufrufen sparen, da die Zeilen dann
selbsterklärend werden.
Deine Funktionsnamen sind kryptisch und tragen nichts zum
Programmverständnis bei. Entweder du gibst ihnen aussagekräftige Namen,
oder, da die Funktionen eh nur aus zwei drei Zeilen bestehen, lässt sie
ganz weg und packst die Zeilen in die State Machine, wobei du hinter
case 1: case 2: etc jeweils ein Kommentar für seine Funktion schreibst.
Da die State Machine selbst kryptisch ist (aufgrund der Verwendung von
Zahlen) könntest du hier auch anstatt Zahlen aussagekräftige Defines
verwenden (dadurch kannst du die zuvor genannten Kommentare dann wieder
weg lassen, da es selbsterklärend wird) oder, meiner Meinung nach
besser, mit dem typedef enum wie ich in einem Post weiter oben
aufgeführt habe.
In Mikrocontrollern verwendet man ungern so harte Pausen, da sie schnell
alles sehr unflexibel machen. Kennst du Timer, hast du damit Erfahrung?
Falls nein, dann vergiss sie erst mal wieder und bringe erst deine State
Machine fertig, und nimm dir als nächste Aufgabe Timer anstatt Pausen zu
verwenden.
Ein bisschen schöner Einrücken, damits leserlicher wird. Denn Case 3
sieht unleserlich und auch falsch aus (sofern ich verstanden habe was du
damit bezwecken willst). Wenn man es richtig einrückt und mit den
geschweiften Klammern nicht so sparsam ist wird's offensichtlich.
Warum fragst du den Taster in der State Machine ab? Sollte er nicht
immer in den Notbetrieb wechseln können, egal in welchem Zustand die
Ampel sich momentan befindet?
Zum Gelb blinken:
Du nennst einen Zustand in deiner State Machine 'gelb_blinken' bei dem
du dann eben den Ausgang jedes mal invertierst und den Taster noch
überprüfst. Nur wenn der der Taster gedrückt wird kommt er weiter,
ansonsten bleibt deine 'state' Variable unverändert, d.h. die LED blinkt
dann mit 1Hz da der Zustand ständig aufgerufen wird (mit einer 1s Pause
dazwischen) bis der Taster eben gedrückt wird.
Hallo Frank
das Programm entwickel ich langsam. Vorher habe ich die anweisungen der
LED direkt hinter die case geschrieben. In diesem wollte ich die
Funktionrn über void testen.
Meine Ampel besteht jeweils aus 3 verschiednen LED. Die LED haben die
Farbe rot, grün und orange. Orange verwende ich für gelb. Daher auch die
Zahlen. Ich habe einen Start Zustand definiert, beide auf Rot. danach
geht eine Ampel auf grün, bleibt so lange grün bis die umschaltung durch
den taster erfolgt. Wenn ich die Funktionen einer echten Ampel zu Grunde
lege, erfolgt eine Umschaltung nicht willkürlich innerhalb des
Programmes. Die Farben beider Ampeln müssen auf rot schalten und erst
dann auf gelb(orange) blinken gehen. Die Funktion des Tasters wird dann
anders genutzt.
case3 habe ich bereits eingerückt, leider hat das Prg es nicht ganz
korrekt genommen. An einem Timer arbeite ich bereits. Bin leider mit dem
Ablauf noch nicht zufrieden. Es geht dabei um unterschiedliche Zeiten,
z.B. grün 6 s, wechsel rot-gelb-grün je 1s, wobei die Angabe der Zeiten
extra erfolgen kann. Die Umschaltung zum Notbetrieb ist hier noch nicht
drin.
achim
Achso, du hast zwei Ampeln :-D das wird aus deinem Programm nicht
ersichtlich, denn welche LED gehört zu welcher Ampel?
Und so lange das so kryptisch bleibt wird das nichts.
So kurz aus dem Ärmel geschüttelt würd ich es so machen: (nicht
vollständig, d.h. du musst es schon noch schöner wie im Beispiel machen,
dass nicht plötzlich mehrer LEDs gleichzeitig leuchten)
Nicht optimal, aber vielleicht das was du willst?
Deine leds_set_status Routine ist noch ein kryptische, versuche so eine
wie im Beispiel:
http://www.mikrocontroller.net/articles/Statemachine
zu ersetllen, d.h. dass du gezielt Ampel1 auf eine Farbe setzen kannst
und nicht Ampel2 durch LED7 ansprechen musst, sondern durch Ampel2 auf
Rot,
bspw:
Und, wie oben schonmal angedeutet: Nimm ein enum statt einem Haufen
#defines für die States, wenn möglich.
Der Compiler generiert daraus zwar exakt den gleichen Code, aber: Bei
einem Enum kann dich der Compiler WARNEN, wenn du einen State vergessen
hast.
@ Achim Seeger (achims)
>Wie versprochen stelle ich den ersten Code rein. Sorry, musste es noch>"schön" machen.
Warum nicht als Anhang? Egal.
>void uprg1()> {> leds_set_status(2, 2); // setzt LED 2 auf rot ein> leds_set_status(2, 7); // setzt LED 7 auf rot ein> }
Hier ist schon das erste Problem. Warum nichtsagende Zahlen anstatt
aussagekräftiger defines bei den Funktionsaufrufen? Somit musst du
überall noch einen Kommentar schreiben, damit man es versteht, und der
Kommentar kann falsch sein, weil du mal was geändert hast, aber nicht
den Kommentar angepasst hast. Ebenso bei den case, Nummern sind
nichtssagend, symbolische Namen per enum oder define sind 100mal besser.
>void stateMaschine()>{> switch (state)> {> case 1: // nur beim start aktiv> uprg1();> state = 2;> break;
Hier das Gleiche. uprg1 ist nichtssagend. leds_reset() ist da deutlich
besser. Nomen est omen!
> case 2:> uprg2();> state = 3;> break;
Eine Einrückung macht es leserlicher.
> case 3:> uprg3();> if (!get_input_bit(IO_INPUT_1)) // Abfrage S3 Port> delay(20); // Pause Entprellung 20 ms
MÖÖP! Hier nicht!
> if (!get_input_bit(IO_INPUT_1)) // Abfrage S3 bei loslassen> while (!get_input_bit(IO_INPUT_1)) // Wiederholung Schleife> { state = 4 ; } // ohne klammer geht nicht> break;
MÖÖÖP MÖÖÖP! Endlose Warteschleifen auch nicht!
>int main() // Start des Programms>{> leds_init(); // LED`s initiiert> bot_init();> while(1==1) // Endlosschleife
Ein while(1) reicht.
> { // Klammer Anfang
So ein Kommentar ist hyperliquide
> // LED Anweisung: Farbe / LED> // 0 = aus, 1 = grün, 2 = rot, 3 = orange> stateMaschine();
Was denn nun? Englisch oder Deutsch? statemachine oder Zustandsautomat?
Denglisch ist bäh.
> delay(1000); // Pause 1000 ms> } // Klammer Ende
OK, kann man fürs erste machen, Timer ist aber besser.
>Er ist so wie angegeben lauffähig.
Und blockierend. -> Durchgefallen!
Lies den Artikel statemachine, dort wird EXPLIZIT gezeigt und
geschrieben, dass in der Statemachine NIE gewartet wird. Die
Tastenerkennung kann und muss man anders machen.
>Es erfolgt ein Verzweigung und Aufruf>von void
NEIN! VERDAMMT NOCHMAL! Gewöhn dir diese Unsinnssprache ab!
> und eine Abfrage des Tasters S3. Wie (Wo) kann ich am besten>die Umschaltung zu Gelb blinken einbauen bzw. eine verschachtelte State>machine?
Du brauchst keine verschachtelte statemachine. Du brauchst nur
gescheite, NICHT blockierende Tastenauswertung. Der Rest ist dann
einfach.
Wie das geht? Siehe Anhang. Ist aber nur hingeschrieben, die Tippfehler
sind noch drin. Ist zwar keine perfekte Entprellung, aber immer noch
viel besser als der jetzige Zustand. Ich habe auch versucht, dir zu
zeigen, dass Symbole deutlich besser als reine Zahlen sind.
Enum schrieb:> Der Compiler generiert daraus zwar exakt den gleichen Code,
Nachtrag: Am AVR nicht unbedingt, da kann es sein, dass aus dem enum ein
16-Bit-int wird... => Feintuning für später, ggfs. per Compilerswitch
umschaltbar.
Wenn du Falks Code zur Tastenabfrage verwendest (welche sicherlich zu
bevorzugen ist), so darfst du natürlich keine Pause in der State Machine
mehr machen, da Falks Code davon lebt, dass die Tastenroutine alle 10ms
gestartet wird.
Das verkompliziert natürlich Pausen vorerst für dich und Falk hat es
auch in seinem Beispielcode auch nicht implementiert, wäre aber schon
ein Schritt in Richtung Timern.
Deine Methode die Taste abzufragen ist schlampig und unzuverlässig, aber
ich würde es für den ersten Versuch so lassen, denn dann kannst du
Pausen vorerst in der State Machine lassen, was man zwar nicht macht,
aber man hat nie das perfekte Ergebnis von Anfang an.
Wenn es dann so funktioniert würde ich versuchen die Pausen aus der
State Machine raus zu nehmen (wie das geht steht im Artikel) und die
Tastenroutine von Falk zu implementieren.
Wenn das funktioniert würde ich die 10ms Pause in der While Schleife
raus nehmen und die Zeit über Timer steuern.
Hallo
Danke für eure Meinung zum Thema. Geht nicht gleich zu streng mit mir
um. Vermute, das ihr auch mal angefangen habt. Noch dazu, das es wenig
Info gibt, die ich auch verstehe.
Zur Tasterauswertung. Es ist nur eine einfache Sache. Reicht zum ersten
Test aus. In anderen Projekten habe ich die Auswertung von Peter drin,
wodurch selbst die Länge zum auswerten ist (mit Timer). Nicht alles
gleich sofort. Es erfolgt keine Blockierung der Auswertung. Habe es
getestet und einen anderen state reingeschrieben. An dem Timer arbeite
ich bereits. Es ist mir klar, das man so nicht macht. Ein
Programmdurchlauf dauert jetzt wenigstens 1s. Zur Auswertung der Taste
ist das zu lang. Ist mir klar. Nach dem Vorbild von Frank wird es
geändert. Bitte, alles nacheinander. Kommt wieder das gesagte, aus
Fehlern lernen.
Die Bezeichnungen erscheinen jetzt kompliziert. Habe sie vom Hersteller
übernommen. Da ich damit umgehe sind sie mir geläufig. Kann man später
alles noch ändern (optimieren). Jetzt muss erst mal der Timer laufen.
achim
Ich denke als erst sollte deine State Machine laufen. Wenn du es mit so
harten Pausen wie in deinem ersten Beispiel und in meiner Version
machst, brauchst du auch gar keine Tastenentprellung wenn du nur auf das
Drück-Ereignis des Taster reagierst (danach kommen ja wieder lange
Pausen und dein Programm reagiert auf keine Tasten für ein paar Sekunden
lang, daher ist eine Entprellung vorerst nicht notwendig, was die Sache
weiter vereinfacht)
Auch solltest du, wenn du weiterhin Hilfe von uns willst, die
Kryptischen Bezeichnungen entfernen. Du magst es so nachvollziehen
können, wir und jeder andere aber nicht. Somit ist eine weitere Hilfe
für uns unmöglich.
Wenn deine State Machine soweit funktioniert würde ich weiterhin ohne
Timer die Sache von Falk implementieren.
Wenn das fertig ist, Timer.
Wie willst du denn den Timer bei dir überhaupt dann einsetzen? Man kann
die Sachen nämlich auch mit einem Timer blockierend und somit falsch
implementieren :-)
Hallo Frank
als erstes will delay durch einen Timer ersetzen. Basis ist dabei 1ms.
Als nächstes soll nach Falk innerhalb jeder case eine extra Zeit drin
sein. Dabei geht es um unterschiedliche Zeiten z.B. Umschaltung
rot-gelb-grün und grün Pause 6s und dabei besonders um die
Zeiteinstellung. Dann soll die gesamte stop Funktion mit rot auf beiden
Ampeln erfolgen bis zum übergang auf gelb blinkend. Da brauche ich aber
noch Zeit um das alles zu machen und zu begreiffen.
Wenn ich delay erst mal durch einen Timer ersetze und dann erweitere
dürfte es zu keiner Blockade kommen, hoffe ich.
achim
@ Achim Seeger (achims)
>Zur Tasterauswertung. Es ist nur eine einfache Sache. Reicht zum ersten>Test aus.
Nein, reicht es nicht! Denn damit killst du an einer zentralen Stelle
die Leistung des ganzen Konzepts! Und es ist ja nicht wirklich schwer,
es gleich richtig zu machen! DU hast dich doch mit dem Thema
Multitasking lange ebschäftigt! Alles wieder vergessen?
>In anderen Projekten habe ich die Auswertung von Peter drin,>wodurch selbst die Länge zum auswerten ist (mit Timer). Nicht alles>gleich sofort. Es erfolgt keine Blockierung der Auswertung. Habe es>getestet und einen anderen state reingeschrieben. An dem Timer arbeite>ich bereits. Es ist mir klar, das man so nicht macht. Ein>Programmdurchlauf dauert jetzt wenigstens 1s. Zur Auswertung der Taste>ist das zu lang. Ist mir klar. Nach dem Vorbild von Frank wird es
Mein Gott, wenn du es nicht schaffst, so einen simplen Namen wie den
meinen (F A L K) mit VIER Buchstaben richtig zu wiederholen, sehe ich
für deine (Hobby)programiererzukunft schwarz! Kann es sein, dass du
generell Schwierigkeiten beim Lernen von abstrakten Sachverhalten hast?
Das ist eine ernste Frage, keine Polemik.
>geändert. Bitte, alles nacheinander. Kommt wieder das gesagte, aus>Fehlern lernen.
Nö, du ignorierst KONSEQUENT die Beispiele, die es schon nahezu
idiotensicher erklären. Den Artikel statemachine finde ich
eigentlich schon recht anschaulich, wenn gleich ich das nicht endgültig
beurteilen kann, denn ich weiß ja wie es funktioniert. Richtigerweise
müssten mehrere Leute, welche eben das Thema noch nicht verstanden
haben, diesen Artikel lesen und danach kann man prüfen, wie gut sie ihn
verstanden haben. Wenn ich mich aber dich so ansehe, ist der Artikel
scheinbar grottenschlecht. Das kann ich aber nicht so recht glauben.
>Die Bezeichnungen erscheinen jetzt kompliziert. Habe sie vom Hersteller>übernommen. Da ich damit umgehe sind sie mir geläufig. Kann man später>alles noch ändern (optimieren).
FALSCH! Man muss es GLEICH gut lesber hinschreiben, sonst verzettelt man
sich in seinem eigenen, undurchsichtigen Geschreibsel! Und kommunizieren
kannst du deinen Code dann auch nicht. Deine Beispiel oben ist nicht
besonders anschaulich lesbar (ok, es gibt deutlich schlimmere, aber das
ist nicht der rechte Massstab).
>Jetzt muss erst mal der Timer laufen.
Mein Gott, das ist in einer Viertelstunde vergessen. Es gibt ÜBERALL
komplette Beispiele! U.a. in dem dir bekannten Artikel Multitasking.
UNd selbst wenn man mit einem einfachen Delay arbeitet, kann man es
DEUTLICH besser machen. Ich hab dir das Beipiel gezeigt.
Multitasking und statemachine hängen sehr eng zusammen.
Achim Seeger schrieb:> stateMaschine();> delay(1000); // Pause 1000 ms
Das ist nicht Dein Ernst?
Da muß man ja auf der Taste einschlafen, eh sie erkannt wird.
Ein Mensch drückt typisch nur etwa 300ms lang. Dir gehen also 3
Tastendrücke verloren.
So geht das auf keinen Fall.
Eine Statemaschine hat keinerlei Delays, sie läuft immer mit voller
Geschwindigkeit durch.
Delays macht man mit Timern, irgendwann setzt der Timer ein Flag und die
Statemaschine testet bei jedem Durchgang dieses Flag und macht dann die
gewünschte Aktion.
Nebenbei, Tasten Entprellen macht man vorzugsweise nicht in der
Statemaschine, sondern im Timerinterrupt.
Die Statemaschine testet auch wieder nur das Ereignis-Flag: Taste wurde
gedrückt.
Eine Statemaschine wartet niemals und nirgends.
Hallo Peter
das ist einer meiner ersten Versuche dazu. Habe eine delay eingesetzt
für den ersten Lauf. So bald der Timer geht und die Zeit in jeder case
ist, gibt es die delay nicht mehr. Für mich war in dieser Stelle erst
einmal die Funktion wichtig. Damit kann ich auch verschiedene andere
Sachen testen. Die Tastenabfrage von dir habe ich im Multitasking drin,
im Interrupt, diese soll auch hier rein. Vorher muss einiges anderes
gehen.
Hab ein bisschen Geduld mit mir.
achim
@Achim Seeger (achims)
>Zur Entprellung verwende ich dieses Prg.
Brauchbar. Aber deine Einrückung des Quelltextes ist sehr eigen, ich
finde sie nicht günstig. Die öffnenen und schließenden Klammern sollten
die gleiche Ebene wir die Funktionsnamen bzw. Strukturköpfe
(for/while/switch) haben. Ahhh, wahrscheinlich hast du echte Tabulatoren
drin, aber mit einer anderen Einstellung als die Forensoftware. Darum
sollte man beim Editor besser einstellen, dass die Tabs in echte
Leerzeichen umgewandelt werden, dann passiert sowas nicht. Siehe
http://www.mikrocontroller.net/articles/Strukturierte_Programmierung_auf_Mikrocontrollern#Formatierung_des_Quelltextes
Ausserdem sind in dem Quelltext ein paar böse C-Fallstricke drin. if
Anweisungen ohne Klammern für den "then" Block sind GEFÄHRLICH!
Gerade Anfänger sollten IMMER Klammern für den then/else Block setzen!
Eine saubere Formatieruing des Quelltextes ist SEHR wichtig! Ein paar
Leerzeichen erhöhen die Lesbarkeit bei Zuweisungen und Vergleichen.
// setzt wait auf 0
uint8_t get_key_short(uint8_t key_mask) // Taste short
Solche Kommentare kann man sich sparen!
1
voidnibo_timer2()// Timer 1ms
2
{
3
TCNT2=0;
4
OCR2=249;
5
TCCR2=(1<<WGM21)|(1<<CS21)|(1<<CS20);
6
TIMSK|=(1<<OCIE2);
7
}
8
9
ISR(TIMER2_COMP_vect)// ISR wait1=1ms,
10
{
11
staticuint8_tct0,ct1,rpt;
12
uint8_ti;
13
if(wait<=5)// Einstellung Takt
14
{// 9=langsam
15
wait++;// 5=relativ schnell
16
}// erhöht
17
else// wenn dann ...
18
{
19
wait=0;
20
wait1=0xFF;
21
i=key_state^~KEY_PIN;
22
ct0=~(ct0&i);// Tasten abfragen
23
ct1=ct0^(ct1&i);
24
i&=ct0&ct1;
25
key_state^=i;
26
key_press|=key_state&i;
27
if((key_state&REPEAT_MASK)==0)
28
{
29
rpt=REPEAT_START;
30
}
31
if(--rpt==0)
32
{
33
rpt=REPEAT_NEXT;
34
key_rpt|=key_state&REPEAT_MASK;
35
}
36
}
37
}
38
39
uint8_tget_key_press(uint8_tkey_mask)
40
{
41
cli();
42
key_mask&=key_press;
43
key_press^=key_mask;
44
sei();
45
returnkey_mask;
46
}
47
48
uint8_tget_key_rpt(uint8_tkey_mask)
49
{
50
cli();
51
key_mask&=key_rpt;
52
key_rpt^=key_mask;
53
sei();
54
returnkey_mask;
55
}
56
57
uint8_tget_key_short(uint8_tkey_mask)
58
{
59
returnget_key_press(~key_state&key_mask);
60
}
61
62
uint8_tget_key_long(uint8_tkey_mask)
63
{
64
returnget_key_press(get_key_rpt(key_mask));
65
}
>Das kommt rein. Damit habe ich auch einen Timer
Gut!