Moin, ich wollte mir ein Gerät basteln wo ich ein Menü habe. Soll son Gleichstromzähler mit Display und paar Tasten werden. Dort kann man auch Konfigurationen ändern (Shunt Widerstand ändern, Abfragintervall usw.). Frage: Wie mache ich für das Konfiguration Menü ein Timeout? Bin noch relativ ein Anfänger und möchte nachher nicht alles neu machen müssen. Das verdirbt mir ein bisschen den Spass und darum gehts mir eigentlich. Daher wollt ich mir von euch ein paar Ideen holen die sowas schon öfter gemacht haben. Ich hätte nun vor eine Statemaschine für das Menü zu machen das alle 100mS ausgeführt wird. Wenn er in einem Konfigurations State ist, wird ein Counter hochgezählt und wenn dieser z.B. auf 300 ist (30 Sekunden) springt er wieder in das "Hauptmenü". Bei jedem Tastendruck oder Aktion wird der Counter dementsprechend wieder zurück gesetzt auf 0. Ist das schon die "beste" Lösung? Oder gibt es noch andere interessante Lösungen? Hatte vorher mal ein Menü programmiert (bei einer Uhr für Alarm Setzung usw.) was ich mit while Schleifen realisiert habe. Dies fand ich unschön und wollte diesmal ein bisschen professioneller angehen. Gruß
:
Verschoben durch Admin
Beitrag #4946060 wurde von einem Moderator gelöscht.
Wolfsente schrieb: > Ich hätte nun vor eine Statemaschine für das Menü zu machen das alle > 100mS ausgeführt wird. Das ist zu einstrassig gedacht. Du brauchst eine Timeoutfunktion, also einen Timer, der z.B. alle 10 ms einen Time-Interrupt auslöst. In der Interruptroutine zählst du einen Zähler hoch, und vielleicht noch hundert andere Dinge, die zeitabhängig ablaufen sollen, da fällt einem immer noch was ein. Die Main Loop mit dem Menü kann ganz unabhängig davon ablaufen und braucht sich auch um die Zeit nicht zu kümmern. Sie schaut bloss in jedem Umlauf mal nach, ob der Zähler > x ist, wenn ja springt die Statemachine zurück ins Hauptmenü. Und bei jedem Tastendruck wird der Zähler auf Null gesetzt. So ist die main Loop von der Laufzeit unabhängig, auch bei Änderungen und Erweiterungen, und While-Schleifen braucht man weder da noch in der Interruptroutine (da sind sie verboten). Georg
Den Ansatz find ich gut! Der passt auch gut auf mein Projekt. Danke!
Wolfsente schrieb: > Daher wollt ich mir von euch ein paar Ideen holen die sowas > schon öfter gemacht haben. Kommt drauf an, ob du diese Ideen auch wirklich hören willst. Also: Ich baue mir in den meisten Fällen (mal ganz kleine µC ausgenommen) zu allererst eine Systemuhr in die Firmware, die mit 1 oder 10 ms Intervallen läuft und eben die Zeit in einer 32 Bit Variable hochzählt. Als nächstes arbeite ich mit Events, also ereignisgesteuert. So, nun hab ich es so eingerichtet, daß die Systemuhr etwas kann, das ich salopp "verzögerte Events" nenne: Die Systemuhr hat eine kleine Liste, wo man mit einer ihrer Methoden (etwa so: AddDelayedEvent(aEvent, aDelay);) ein Ereignis hineinschreiben kann. Mit jedem Uhr-Tick gucht die Systemuhr in diese Liste und wenn sie dort ein Ereignis findet, dessen Zeit abgelaufen ist, dann holt sie sieses Ereignis aus der Liste und schmeißt es in die Liste der grad anstehenden Ereignisse. Von dort holt die Grundschleife in main das Ereignis heraus und bringt es zur Abarbeitung. Länglicher Text, hoffentlich trotzdem verständlich. Willst du einen Timeout haben, dann sagst du das der Systemuhr und programmierst deine Menübedienung ereignisgesteuert und eben nicht blockierend. W.S.
Dein erster Ansatz ist schon sehr, sehr gut. Wenn Du genügend Rechenzeit hast, die 100ms immer einzuhalten. Falls nein, dann den "System-Ticker" einführen. Eine ISR im 1ms oder 10ms-Takt, die den SysTicker hochzählt. Soweit ist Konsens in den Antworten. Ab da gibt es mehrere Fallstricke und Ideologien a) Beim Vergleichen von aktueller Zeit und Endzeit immer erst die Differenz bilden: if((SysTicker-Startzeit)>300) ... Niemals: if(SysTicker>Startzeit+300) ... --> Am Ende funktionieren es trotzdem nicht. Wenn es eben geht, würde ich bei einem ms-Ticker alle 20 Tage einen Geräte-Reset erzwingen. Die allermeisten "und nach Drei Wochen (6Wochen/42Tage) gehen auf einmal ...."-Fehler gehen auf durchgegangene Überläufe 32-Bit-ms. b) Events vs. brotlose Timer Ich kann immer nur brotlose Timer empfehlen, die ein Satz (optionaler) Informationen kapseln und zur Laufzeit der Statemaschine abgefragt werden: - Endzeit (oder Startzeit - Reload-Zeit - ein paar Flags (ob gestartet, ob retriggerbar, ggf. eine Funktion, ...) Brotlos genannt werden die Timer, da sie kein Brot fressen (keine Laufzeit kosten), wenn sie 3 Tage nicht aufgerufen werden. Auch brauche sie abgesehen vom Sys-Ticker keine zentralen Resourcen, können auch static in einem Unter-Unter-Unterblock existieren oder gar auf dem Stack. a) ein oder mehrer Ticker: Ich nutze immer nur einen SysTicker und vergleiche Manche zählen mehrere Timer in der ISR rauf (oder runter). Bei einem einzigen SysTicker errechnet man ei: [c] /* Timer setzen */ int
Achim S. schrieb: > würde > ich bei einem ms-Ticker alle 20 Tage einen Geräte-Reset erzwingen Wo du recht hast: Überlauf ist ein Problem. Dafür gibt es nach meinem obigen Konzept 2 Lösungen: 1. Man zählt nicht weiter, wenn der Timer die gewünschte Zahl (Zeit) erreicht hat. Ist fehleranfällig, wenn man die Zeit ändern will, die Verwendung von definierten Konstanten ist obligatorisch. 2. Bei jedem Tastendruck wird der Timer auf die gewünschte Zahl gesetzt und man zählt abwärts bis 0, das ist der Wert bei dem ins Hauptmenü zurückgesprungen wird. Man muss aber auch hier dafür sorgen, dass bei 0 nicht weiter dekrementiert wird. Achtung: ich habe KEINEN Systemtick vorgeschlagen, sondern eine Zählvariable extra und ausschliesslich für diesen Zweck. In der Timerroutine kann man durchaus einige solche Zähler bearbeiten, falls man anderweitig noch Timeouts braucht. Damit entfällt auch jede Timetick-Arithmetik. Ich brauche nie mehr als 5 solche Timeoutvariablen. Georg
Achim S. schrieb: > Wenn es eben geht, würde > ich bei einem ms-Ticker alle 20 Tage einen Geräte-Reset erzwingen. So einen Bullshit sollte man ganz schnell wieder vergessen. Geräte müssen durchlaufen können, ohne jemals ein Reset zu benötigen. Wenn man das Konzept der Differenzbildung einmal verstanden hat, schreibt man sich ne Funktion dafür. Oder man nimmt einen Scheduler, der die gewünschte Zeitverzögerung abwärts zählt und dann die Task aufruft. Einen Scheduler finde ich sehr bequem. Man stellt eine Timeout-Task hinein und löscht sie wieder, wenn die zu überwachende Task vor Ablauf beendet wurde.
Peter D. schrieb: > Wenn man das Konzept der Differenzbildung einmal verstanden hat Eben - bei der Differenz zweier jeweils x Bit breiter Zahlen (Edit: mit ebenso x Bit breitem Ergebnis) gibt es kein Überlaufproblem, es sei denn, die Differenz selbst (hier: Delay-Zeit) überschreitet die halbe Periodendauer des Überlaufs. Wenn man nie Zeiten messen will, die länger als eine halbe Minute sind, reicht es also, bei einem Millisekunden-Ticker mit 16 Bit Variablen zu arbeiten.
:
Bearbeitet durch User
Peter D. schrieb: > So einen Bullshit sollte man ganz schnell wieder vergessen. > Geräte müssen durchlaufen können, ohne jemals ein Reset zu benötigen. LOL. Genau. Was ich aber nicht verstehe: Wieso versuchen manche immer wieder mit vielen Worten nichts zu sagen und dabei den Eindruck zu erwecken, als wüssten sie auch noch wovon sie reden ? Timeout ohne Systick ist Blödsinn, da blockierend - ein Timer dafür verstehst sich von selbst. Und ein Timeout braucht keine Differenz, da wird einfach eine Variable dekrementiert. Wenn ich einen Timeout brauche, dann wird die Variable auf diesen Wert gesetzt, ein Flag auch und in der ISR wird geprüft, ob der Flag gesetzt ist, falls ja, wird die Variable um 1 dekrementiert. Wenn Variable==0, wird der Überlaufflag für entspr. Timeout gesetzt und das wars dann.
1 | #define CHK_BIT(var,pos) ((var) & (1<<(pos)))
|
2 | #define SET_BIT(var,pos) ((var) |= (1<<(pos)))
|
3 | #define RES_BIT(var,pos) ((var) &= ~(1<<(pos)))
|
4 | |
5 | // Die oberen 4 bits starten entspr. Counter
|
6 | const mnuOn = 7; |
7 | const tstOn = 6; |
8 | const EvtOn = 5; |
9 | const WasAuchImmerOn = 4; |
10 | // Die unteren 4 bits werden gesetzt wenn Zeit abgelaufen ist
|
11 | const mnuRdy = 3; |
12 | const tstRdy = 2; |
13 | const EvtRdy = 1; |
14 | const WasAuchImmerRdy = 0; |
15 | |
16 | volatile uint8_t MyFlag=0; |
17 | volatile int16_t MenuCnt, TastCnt, EventCnt, WasAuchImmerCnt; |
18 | |
19 | /* in der main() soll 10sec auf Taster gewartet werden - kann auch
|
20 | als Routine geschrieben werden: StartTimer(tstOn, 10000) oder so... */
|
21 | TastCnt = 10000; |
22 | SET_BIT(MyFlag, tstOn); |
23 | |
24 | //es wird auf Ablauf der Tasterzeit geprüft...
|
25 | if(CHK_BIT(MyFlag, tstRdy) { |
26 | RES_BIT(MyFlag, tstRdy); |
27 | ...
|
28 | }
|
29 | |
30 | /* in der ISR wird die Variable nur dekrementiert, bzw.
|
31 | geprüft, wenn > 0 und entspr. Flag gesetzt ist... */
|
32 | if(CHK_BIT(MyFlag, tstOn) && (TastCnt>0)) { |
33 | TastCnt--; |
34 | if(TastCnt<1) { |
35 | SET_BIT(MyFlag, tstRdy); |
36 | RES_BIT(MyFlag, tstOn); |
37 | }
|
38 | }
|
P.S. Apropos Reset - da wir mit Industriesteuerungen zu tun haben: Ein Systest (inkl. gewolltem Reset mittendrin um Stromausfall zu simulieren) kann schon nützlich sein...
Peter D. schrieb: > Wenn man das Konzept der Differenzbildung einmal verstanden hat ich habe das (wie Du lesen kannst) verstanden und beschrieben. Trotzdem wirst Du bei größeren Projekten immer ein paar faule Stellen haben. Entweder weil mehrere Leute daran arbeiten (nicht nur Du und ich) oder weil es nicht so offensichtlich ist. Die meisten Fehler sind so selten, dass sie trotzdem nicht reproduzierbar auftreten. Schlimm ist es, wenn nach einiger Zeit Türen nicht mehr zu gehen oder dergleichen. Und die wenigsten Geräte müssen durchlaufen. Reset heisst ja nicht, dass man Uhrzeit oder Parameter verliert. Oftmals gibt es mehrere Phasen pro Tag, an denen ein kurzer Reset problemlos möglich wäre. Ab Tag 10 nutzt man dann halt eine davon.
Marc V. schrieb: > da wird einfach eine Variable dekrementiert. > Wenn ich einen Timeout brauche, dann wird die Variable auf diesen > Wert gesetzt, ein Flag auch und in der ISR wird geprüft, ob der > Flag gesetzt ist, falls ja, wird die Variable um 1 dekrementiert. > Wenn Variable==0, wird der Überlaufflag für entspr. Timeout gesetzt > und das wars dann. Der Weg ist zwar Überlauf-sauber, hat aber folgende Nachteile: - feste Rechenzeiten je Tick und Timer notwendig (was andere Probleme nach sich zieht) - Eingriff in die ISR (relativ tiefer Eingriff in untere Schichten) - asynchrone Schreibzugriffe (also Locks erforderlich) Je nach Aufgabe, Menge der Zeitüberwachungen und SW-Architektur ist dieser Ansatz problematisch (und wäre es bei uns, aus jedem der 3 Gründe). Zur Info: Beim free running SysTicker-Ansatz muss nur das einmalige Lesen atomar erfolgen. Dies ist bei den meisten µC für bis zu 32Bit-Variablen problemlos möglich ohne weitere Lock-Mechanismen.. Das meinte ich mit (offensichtlich zu Recht) mit > Ab da gibt es mehrere Fallstricke und Ideologien
Achim S. schrieb: > Und die wenigsten Geräte müssen durchlaufen. Reset heisst ja nicht, dass > man Uhrzeit oder Parameter verliert. Oftmals gibt es mehrere Phasen pro Reset heisst, dass der Anfangszustand unbekannt ist. Das schliesst alle Parameter die sich im RAM befinden, ein. Sich darauf zu verlassen, dass irgendwelche Parameter beim Reset nicht verlorengegangen sind, wäre ein bisschen leichtsinnig, oder ?
Achim S. schrieb: > Entweder weil mehrere Leute daran arbeiten Willst du damit sagen, daß der TO, der seine erste Menuesteuerung realisieren will, eine multiple Persönlichkeit ist? MfG Klaus
Achim S. schrieb: > Der Weg ist zwar Überlauf-sauber, hat aber folgende Nachteile: > - feste Rechenzeiten je Tick und Timer notwendig (was andere Probleme > nach sich zieht) Bin nicht sicher, dass ich dich richtig verstanden habe aber nein, fest steht nur, dass ein Flag abgefragt werden muss und das ist von der Anzahl der Takte her kaum merkbar. Solltest du es andersrum gemeint haben - feste Rechenzeiten gibt es kaum - Ausführungszeiten schon - wozu das auch immer in einer Timer ISR gut sein sollte... > - Eingriff in die ISR (relativ tiefer Eingriff in untere Schichten) Wenn man mit SysTick und Timer-ISR arbeitet, muss man sowieso in der ISR rumwurschteln. Ohne Timer-ISR hat das Ganze auch wenig Sinn. > - asynchrone Schreibzugriffe (also Locks erforderlich) Nein, ISR kann nicht unterbrochen werden (oder es kann verhindert werden) und solange der entsprechende Flag nicht gesetzt ist, fummelt die ISR auch nicht am Cnt rum - und wenn der Flag dann gesetzt wird, fummelt die main() aber nicht mehr daran ;-) Der Schreibvorgang selbst kann natürlich atomar erfolgen, muss aber nicht, da zuerst der Wert gesetzt wird, erst danach der Flag. Und dieser Flag wird dann gleich in der ISR zurückgesetzt, nicht in main(), es kann also in der ISR nichts mehr an Cnt Variable verändert werden.
:
Bearbeitet durch User
Moin Leute, vielen Dank für die Anregungen! Also von allen Antworten picke ich mir mal raus, wie ich das nun umsetzen würde: In der Timer ISR (10mS) wird ein Counter immer um 1 dekrementiert und wenn (counter < 1) ist, wird nicht mehr dekrementiert. In meiner Statemaschine (bei den Konfigurationssachen) prüf ich ob (counter < 1), wenn das zutrifft spring ich in den State "Hauptmenü". Der Counter wird immer auf 3000 gesetzt, wenn eine Taste gedrückt wird. Würde hier also kein Flag für dieses Timeout verwenden. Ich würde bei den counter int16_t verwenden, falls irgendwo doch nochmal eine 0 dekrementiert wird. (Sollte aber nicht passieren (aber vorsicht lieber als nachsicht :D)) Die Timer ISR würde ich dann noch für mehrere Counter Sachen verwenden. Brauche z.B. noch ein Event für alle 3,5 Sekunden. Dafür würde ich aber dann doch ein Flag setzen :D Und ich würde die Statemaschine nicht alle 10mS durchlaufen lassen, sondern ständig in der Mainloop . Ich hoffe das wäre so gut umgesetzt und habe es richtig verstanden. Das mit den addieren/subtrahieren der Systemticker ist MIR zu gefährlich wegen den genannten Überlauf Problem was ihr ja diskutiert (habt). Hat jemand noch Tipp zur Display Aktualisierung? Soll ich in der Statemaschine immer ein Flag setzen das eine Display Aktualisierung fällig ist und wenn es aktualisiert worden ist das Flag rücksetzen? Oder geht das auch eleganter? Btw.: Klaus schrieb: > Willst du damit sagen, daß der TO, der seine erste Menuesteuerung > realisieren will, eine multiple Persönlichkeit ist? Noch bin ich übrigens nicht schizophren :D
Wolfsente schrieb: > Hat jemand noch Tipp zur Display Aktualisierung? > Soll ich in der Statemaschine immer ein Flag setzen das eine Display > Aktualisierung fällig ist und wenn es aktualisiert worden ist das Flag > rücksetzen? Oder geht das auch eleganter? Nein, das ist so weder elegant noch clever. Es setzt voraus, dass du deinen kompleten Displayinhalt im RAM aufbewahrst. Das mag bei einem 2x16 LCD noch nicht so schlimm sein, aber bei 8x40 oder gar 16x40 macht das schon keinen Sinn mehr - ausser viel mehr benötigtem RAM wird die Geschwindigkeit auch zu einem Problem. Und ob du einen Flag für DisplayRefresh setzst oder gleich die Routine zum Refreshen aufrufst ist vom Standpunkt der zeitlichen Ausführung absolut egal Ob du aber nur 4 Digits für einen Wert neu schreiben musst oder gleich 320 oder 640 Zeichen weil dein ganzes Display neu gezeichnet werden muss - das kann niemals egal sein. Wolfsente schrieb: > Also von allen Antworten picke ich mir mal raus, wie ich das nun > umsetzen würde: > In der Timer ISR (10mS) wird ein Counter immer um 1 dekrementiert und > wenn (counter < 1) ist, wird nicht mehr dekrementiert. Ja, kommt mir irgendwie bekannt vor... > In meiner Statemaschine (bei den Konfigurationssachen) prüf ich ob > (counter < 1), wenn das zutrifft spring ich in den State "Hauptmenü". Natürlich nicht, die ISR prüft das und setzt den entspechenden Flag. > Der Counter wird immer auf 3000 gesetzt, wenn eine Taste gedrückt wird. > Würde hier also kein Flag für dieses Timeout verwenden. Und damit hast du schon alle Vorteile die mein Vorschlag bietet aus dem Fenster geworfen... > Ich würde bei den counter int16_t verwenden, falls irgendwo doch nochmal > eine 0 dekrementiert wird. (Sollte aber nicht passieren (aber vorsicht > lieber als nachsicht :D)) Kommt mir auch sehr bekannt vor... > Die Timer ISR würde ich dann noch für mehrere Counter Sachen verwenden. > Brauche z.B. noch ein Event für alle 3,5 Sekunden. Dafür würde ich aber > dann doch ein Flag setzen :D Ja kommt mir auch sehr bekannt vor... > Und ich würde die Statemaschine nicht alle 10mS durchlaufen lassen, > sondern ständig in der Mainloop . Die Statemachine wird sowieso in einer while schleife durchlaufen... P.S. Nur aus Neugierde: Was hast du denn aus anderen Antworten genau übernommen ?
:
Bearbeitet durch User
Achim S. schrieb: > - asynchrone Schreibzugriffe (also Locks erforderlich) Dass hält genauerem Nachdenken nicht stand. Z.B. kann die ISR ja nicht vom Hauptprogramm unterbrochen werden, also ist da Read-Modify-Write safe. Und im Hauptprogramm gibt es kein Read-Modify-Write, sondern nur Lesen oder nur Schreiben, und das sind bei 8 oder 16 bit Variablen fast immer atomare Zugriffe, da kann auch nichts passieren. Notfalls könnte man ja Enable/Disable Interrupt verwenden, aber auch das ist nur in seltenen Sonderfällen notwendig. Aber toll wenn man den Chef mit Buzz-Wörtern wie "notwendige Locks" beeindrucken kann. Dass feste Rechenzeiten notwendig wären ist sowieso nur totaler Blödsinn. Aber von deinem Standpunkt hast du schon recht, wenn du die Software so kompliziert machst, dass sie ausser dir keiner versteht, sicherst du deinen Arbeitsplatz - zumindest wenn dein Chef keine Ahnung von der Sache hat. Ich arbeite seit Jahrzehnten bei Timeouts mit weniger als 10% deiner Software, bei absolut zuverlässiger Funktion, aber ich habe ja auch keinen Chef. Georg
Sobald man sich nicht sicher ist, kapselt man einen Mainzugriff auf eine Interruptvariable atomar. Für den AVR gibt es dazu die "atomic.h". Auch ein nur Lesen oder nur Schreiben von 16Bit muß auf nem 8Bitter atomar gekapselt werden. Es gibt beim AVR auch noch notwendige atomare Kapselung, die nicht offensichtlich ist. Z.B. bei den Timern wird für das High-Byte ein gemeinsames temporäres Register verwendet. D.h. wenn z.B. ein Interrupt das ICR1 ausliest, muß das Main das Setzen des OCR1A atomar kapseln.
Georg schrieb: > Dass hält genauerem Nachdenken nicht stand. Z.B. kann die ISR ja nicht > vom Hauptprogramm unterbrochen werden, also ist da Read-Modify-Write > safe. Du wirst bei der Implementierung in ISR entweder den neuen Timerwert und/oder das Kontrollflag in der Main-Routine UND im ISR setzen. Bsp: Timerwert in Main auf 300 setzen, in jeder ISR dekrementieren. Es gibt dabei zuweilen atomare Möglichkeiten, aber nicht immer und nicht immer denkt jeder daran. > Dass feste Rechenzeiten notwendig wären ist sowieso nur totaler > Blödsinn. Wenn Du 100 Zeitüberwachungen hast (Steuerungstechnik, parallele Module/Prozesse), dann müssen diese alle und in jedem ISR-Durchlauf geprüft und ggf. decrementiert werden. Bei zwei oder 5 spielt es *keine Rolle* (!). > Ich arbeite seit Jahrzehnten bei Timeouts mit weniger als 10% > deiner Software, bei absolut zuverlässiger Funktion, aber ich habe ja > auch keinen Chef. Bei größeren Projekten sind brotlose Timer eleganter und effizienter. Habe ich auch nicht geglaubt, bis ich entsprechende Software gesehen habe. Der Aufwand in Code insgesamt ist vergleichbar (falls Du das meintest). Aber brotlose Timer bleiben im Modul gekapselt, die ISR weiss davon nichts und muss es auch nicht. Aber wie gesagt, bei 5 Timern ist jede Diskussion überflüssig. Dein Ansatz hat kein Überlaufproblem und ist damit robust!
Achim S. schrieb: >> Dass feste Rechenzeiten notwendig wären ist sowieso nur totaler >> Blödsinn. > Wenn Du 100 Zeitüberwachungen hast (Steuerungstechnik, parallele > Module/Prozesse), dann müssen diese alle und in jedem ISR-Durchlauf Wenn du 100 Zeitüberwachungen hast, stimmt meistens etwas nicht. Und wenn man das alles auch noch in einer einzigen ISR abarbeiten will - von welcher Steuerungstechnik redest du, wem willst du so etwas andrehen ? Entweder teilen sich mehrere uC die Aufgaben oder man fragt jemanden aus der Branche wie so etwas normalerweise gelöst wird. Übrigens, wie passt das zu deiner Aussage: - Eingriff in die ISR (relativ tiefer Eingriff in untere Schichten) Achim S. schrieb: > meintest). Aber brotlose Timer bleiben im Modul gekapselt, die ISR weiss > davon nichts und muss es auch nicht. Auch diese Timer befinden sich in der ISR, werden nur durch entsprechend gesetzte Flags gestartet, angehalten, aktualisiert oder abgefragt, die ISR weiss also sehr wohl davon - es wird nur keine Zeit verbraucht wenn diese inaktiv sind...
:
Bearbeitet durch User
Marc V. schrieb: > Wolfsente schrieb: >> Hat jemand noch Tipp zur Display Aktualisierung? >> Soll ich in der Statemaschine immer ein Flag setzen das eine Display >> Aktualisierung fällig ist und wenn es aktualisiert worden ist das Flag >> rücksetzen? Oder geht das auch eleganter? > > Nein, das ist so weder elegant noch clever. > > Es setzt voraus, dass du deinen kompleten Displayinhalt im RAM > aufbewahrst. > Das mag bei einem 2x16 LCD noch nicht so schlimm sein, aber bei 8x40 > oder gar 16x40 macht das schon keinen Sinn mehr - ausser viel mehr > benötigtem RAM wird die Geschwindigkeit auch zu einem Problem. > > Und ob du einen Flag für DisplayRefresh setzst oder gleich die > Routine zum Refreshen aufrufst ist vom Standpunkt der zeitlichen > Ausführung absolut egal > Ob du aber nur 4 Digits für einen Wert neu schreiben musst oder gleich > 320 oder 640 Zeichen weil dein ganzes Display neu gezeichnet werden > muss - das kann niemals egal sein. > Also einfach gleich den neuen Wert nur an der entsprechenden Stelle aktualisieren? > Ja, kommt mir irgendwie bekannt vor... > Kommt mir auch sehr bekannt vor... > Ja kommt mir auch sehr bekannt vor... > Vllt liegts daran das auch vieles von dir kommt. Lag vllt daran das mir das am besten gefallen hat und sauber klang. Kommt so rüber als denkst du ich hätte mir das aus den Fingern gesogen, aber wollte doch nur mitteilen wie ich das nur vorhabe... >> Der Counter wird immer auf 3000 gesetzt, wenn eine Taste gedrückt wird. >> Würde hier also kein Flag für dieses Timeout verwenden. > > Und damit hast du schon alle Vorteile die mein Vorschlag bietet aus > dem Fenster geworfen... > Siehe: Wolfsente schrieb: > Ich hoffe das wäre so gut umgesetzt und habe es richtig verstanden. Dann hab ich ja doch nicht alles so richtig verstanden :D Was habe ich denn für ein Vorteil das ich ein Flag in der Main prüfe anstatt den Counter selbst? Hat doch jeder sein eigenen Counter. Wenn ich das richtig verstanden habe setzt du denn Counter ja auch bei jedem Tastendruck. Würde die Abfrage in der ISR so machen: if(!(counter<0)) { counter--; } Wofür die Flags? Btw. die counter würden verständliche Namen kriegen. Darfst dich gerne selber Zitieren wenn du das genau beschrieben hast warum das besser ist. Ich finde es nicht :( >> Und ich würde die Statemaschine nicht alle 10mS durchlaufen lassen, >> sondern ständig in der Mainloop . > > Die Statemachine wird sowieso in einer while schleife durchlaufen... Hatte aber vor mit einem Flag sie nur alle 10mS auszuführen. Was ich nicht mehr machen werde. > P.S. > Nur aus Neugierde: > Was hast du denn aus anderen Antworten genau übernommen ? Ich habe nicht auf die Namen der Antworten geachtet. Wenn das meiste von dir kommt ist doch schön, das ich am meisten auf dich gehört habe! :D Aber anscheinend nicht alle Vorteile entdeckt habe.
Wolfsente schrieb: > Kommt so rüber als denkst du ich hätte mir das aus den Fingern gesogen, > aber wollte doch nur mitteilen wie ich das nur vorhabe... LOL. Nein, Georg hat auch so etwas ähnliches vorgeschlagen, deswegen. > Was habe ich denn für ein Vorteil das ich ein Flag in der Main prüfe > anstatt den Counter selbst? Hat doch jeder sein eigenen Counter. Weil der Zugriff auf diesen 16bit Counter ausserhalb der ISR nicht atomar erfolgt, ein Flag ist aber meistens nur ein bit in einer 8bit Variable. > Würde die Abfrage in der ISR so machen: > if(!(counter<0)) > { > counter--; > } Wirklich ? > Wofür die Flags? a) Weil es übersichtlicher ist. b) Weil es sicherer und schneller ist einen Byte zu prüfen als z.B. einen 32bit Zähler. c) Wenn sich alle Flags (bits) in einer Variable befinden, dann sagt dir ein einfacher Test auf Null ob du überhaupt etwas laufen hast ;-) Reicht das ? > Also einfach gleich den neuen Wert nur an der entsprechenden Stelle > aktualisieren? Ja.
:
Bearbeitet durch User
Marc V. schrieb: > Achim S. schrieb: >> meintest). Aber brotlose Timer bleiben im Modul gekapselt, die ISR weiss >> davon nichts und muss es auch nicht. > > Auch diese Timer befinden sich in der ISR, werden nur durch entsprechend > gesetzte Flags gestartet, angehalten, aktualisiert oder abgefragt, die > ISR weiss also sehr wohl davon Du verwechselst da etwas. Ich war einer derjenigen mit ausschließlich einem SysTicker++ in der ISR. Und der mit mehreren Timern da größere (Industrie-)Software. Kein Arduino in einem Nachtlicht oder so.
Achim S. schrieb: > - feste Rechenzeiten je Tick und Timer notwendig (was andere Probleme > nach sich zieht) Achim S. schrieb: > Wenn Du 100 Zeitüberwachungen hast Mal abgesehen davon, dass das in der Praxis ziemlich selten vorkommt, redest du an deiner eigenen Forderung vorbei. Es ist klar, dass in einer ISR alles so schnell wie möglich abgearbeitet werden muss, das ist Anfängerwissen. Du hast aber feste Rechenzeiten verlangt, dafür gibt es nicht den geringsten Grund, weder in der ISR noch im Hauptprogramm. Georg
Achim S. schrieb: > Kein Arduino in einem Nachtlicht oder so. Ich wäre aber an so etwas sehr interessiert. Ist es möglich, ein fertiges Projekt mit Code und ausführlichen Erklärungen (für uns Anfänger) zu kriegen ?
Marc V. schrieb: > Wolfsente schrieb: >> Kommt so rüber als denkst du ich hätte mir das aus den Fingern gesogen, >> aber wollte doch nur mitteilen wie ich das nur vorhabe... > > LOL. > Nein, Georg hat auch so etwas ähnliches vorgeschlagen, deswegen. Sehr gut, dann hatte ich mich doch nicht ungünstig formuliert :D Marc V. schrieb: >> Würde die Abfrage in der ISR so machen: >> if(!(counter<0)) >> { >> counter--; >> } > > Wirklich ? Sorry meinte counter<1 Ohne Flags zu setzen wäre das doch in Ordnung gewesen. Marc V. schrieb: >> Wofür die Flags? > > a) Weil es übersichtlicher ist. Wo ich jetzt über den Punkt richtig nachgedacht habe (mit deinem Punkt c) zusammen) finde ich, hast du da recht. Fand aber vorher aber nämlich.. (menueTimeOut<1) übersichtlicher als (CHK_BIT(MyFlag, tstOn)) > b) Weil es sicherer und schneller ist einen Byte zu prüfen als z.B. > einen 32bit Zähler. Mh... ok... Da die ISR ja nur alle 10mS aufgerufen wird um zu vergleichen, macht das Sinn. > c) Wenn sich alle Flags (bits) in einer Variable befinden, dann sagt > dir ein einfacher Test auf Null ob du überhaupt etwas laufen hast ;-) > Nagut hast mich ja überzeugt :D Vielen Dank für deine Erklärungen! Ich werde versuchen diesen "Stil" dann zu übernehmen.
Wolfsente schrieb: > Nagut hast mich ja überzeugt :D > > Vielen Dank für deine Erklärungen! > Ich werde versuchen diesen "Stil" dann zu übernehmen. Solange du ein paar simple Grundregeln befolgst, kannst du es machen wie es für dich am übersichtlichen ist. Nur nicht vergessen, dass schon nach ein paar Wochen und erneutem Blick aufs Programm die Frage kommt: Welcher Idiot hat das geschrieben, warum ist das so und wo sind die Kommentare dazu ? P.S. Ich packe alle Flags zum Timer starten in einen Byte, alle Flags zum Abfragen des Zustands in einen anderen. Auf diese Weise kannst du in der ISR gleich die komplette Abfrage auf Timerzustände mit if(MyFlag != 0) { ... } überspringen. Macht schon was aus bei 5-8 Timern. War unheimlich stolz damals als ich darauf gekommen bin...
:
Bearbeitet durch User
Marc V. schrieb: > Achim S. schrieb: >> Und die wenigsten Geräte müssen durchlaufen. Reset heisst >> ja nicht, dass man Uhrzeit oder Parameter verliert. > > Reset heisst, dass der Anfangszustand unbekannt ist. Das heisst es wohl beim Mikrocontroller. Bei der SPS - die je offenbar nach (hier) herrschender Meinung hoffnungslos veraltet und dem Mikrocontroller hoffnungslos unterlegen ist - heisst es das nicht. > Das schliesst alle Parameter die sich im RAM befinden, > ein. Mal was von gestuetztem RAM gehoert? > Sich darauf zu verlassen, dass irgendwelche Parameter > beim Reset nicht verlorengegangen sind, wäre ein bisschen > leichtsinnig, oder ? Wieso sollte man sich denn NICHT darauf verlassen, dass remanente Merker nach dem RESET noch da sind? Deswegen heissen sie ja "remanent".
Marc V. schrieb: > Achim S. schrieb: >>> Dass feste Rechenzeiten notwendig wären ist sowieso nur >>> totaler Blödsinn. >> Wenn Du 100 Zeitüberwachungen hast (Steuerungstechnik, >> parallele Module/Prozesse), dann müssen diese alle und >> in jedem ISR-Durchlauf > > Wenn du 100 Zeitüberwachungen hast, stimmt meistens etwas > nicht. Hier kann man exemplarisch studieren, was passiert, wenn "total veraltete und unmoderne" SPS-Leute mit "modernen, leistungsfaehigen, zukunftstraechtigen" µC-Leuten aneinander vorbei reden. In einer auch nur mittelgroszen Maschinensteuerung kommen leicht dutzende bis hunderte "Zeitueberwachungen" vor. Und eine SPS hat damit keine nennenswerten Probleme; das schafft die in Echtzeit (=Laufzeitgarantie). Die "Zeitueberwachungen" heissen im SPS-Slang uebrigens "Timer" :) > Und wenn man das alles auch noch in einer einzigen ISR > abarbeiten will - von welcher Steuerungstechnik redest > du, wem willst du so etwas andrehen ? Das wiederum ist richtig. Eine klassische SPS macht fast nichts im Interrupt - schon gar nicht das Pruefen der Timeouts. Das wird in der Hauptschleife gemacht.
Possetitjel schrieb: >> Reset heisst, dass der Anfangszustand unbekannt ist. > > Das heisst es wohl beim Mikrocontroller. Bei der SPS - die > je offenbar nach (hier) herrschender Meinung hoffnungslos > veraltet und dem Mikrocontroller hoffnungslos unterlegen > ist - heisst es das nicht. Hier ist aber nicht von PLC die Rede. >> Das schliesst alle Parameter die sich im RAM befinden, >> ein. > > Mal was von gestuetztem RAM gehoert? Ja, warum ? > Wieso sollte man sich denn NICHT darauf verlassen, dass > remanente Merker nach dem RESET noch da sind? Deswegen > heissen sie ja "remanent". Ich habe 5 Mal diese Seite mit Suchfunktion nach "SPS", "PLC", "remanent" und "Marker" durchsucht. Ausser in deinem Beitrag ist auf dieser Seite nichts davon zu finden. Was wolltest du eigentlich sagen ?
Marc V. schrieb: > Possetitjel schrieb: >>> Reset heisst, dass der Anfangszustand unbekannt ist. >> >> Das heisst es wohl beim Mikrocontroller. Bei der SPS - die >> je offenbar nach (hier) herrschender Meinung hoffnungslos >> veraltet und dem Mikrocontroller hoffnungslos unterlegen >> ist - heisst es das nicht. > > Hier ist aber nicht von PLC die Rede. Gewoehne Dir diesen Kasernenhof-Ton ab. Du bestimmst nicht, wovon hier die Rede ist. >> Wieso sollte man sich denn NICHT darauf verlassen, dass >> remanente Merker nach dem RESET noch da sind? Deswegen >> heissen sie ja "remanent". > > Ich habe 5 Mal diese Seite mit Suchfunktion nach "SPS", > "PLC", "remanent" und "Marker" durchsucht. > Ausser in deinem Beitrag ist auf dieser Seite nichts davon > zu finden. > > Was wolltest du eigentlich sagen ? Das war ein Test. Ich habe Deine Faehigkeit zu mentalen Transfer-Leistungen getestet. Leider bist Du durchgefallen. Denn Du hast weder erkannt, dass Achim offensichtlich einen SPS-Hintergrund hat (was sich auch in seiner Wortwahl niederschlaegt), noch, dass ich Dich subtil auf diese Tatsache hinweisen wollte.
Marc V. schrieb: > Ich habe 5 Mal diese Seite mit Suchfunktion nach "SPS", "PLC", > "remanent" und "Marker" durchsucht. > Ausser in deinem Beitrag ist auf dieser Seite nichts davon zu finden. > > Was wolltest du eigentlich sagen ? Er wollte sagen, dass die Methoden jeder SPS auch ihre Entsprechung und µC-Programmen haben und dort genauso gewinnbringend genutzt werden können, wenn es um echte Steuerungen und nichttriviale Aufgaben geht. a) remanent = non volatile RAM (das beim erstmaligen Start eines Programmes genullt wird, aber nicht bei jedem Reset. Ja, auch das geht in C, **kopfschüttel**) b) PLC: loop control, auch in µC-SW eine erfolgreiche Alternative zu vielen Task-Konstrukten. In autosar "basic Task" genannt. btw.: wer sich an "festen Rechenzeiten" störte: Hier ist der (konstante) Aufwand für jeden einzelnen Timer-Decrement (oder Flag-Abfrage) in der ISR gemeint. Dieser Aufwand ist bei 5 Timern (wie schon häufig gesagt) vernachlässigbar. Schön ist die Vermischung von Modulen und ISR trotzdem nicht.
Georg schrieb: > Achim S. schrieb: >> - asynchrone Schreibzugriffe (also Locks erforderlich) > > Dass hält genauerem Nachdenken nicht stand. Z.B. kann die > ISR ja nicht vom Hauptprogramm unterbrochen werden, also > ist da Read-Modify-Write safe. In meinem Universum gibt es sowohl unterschiedliche Interruptprioritaeten als auch nichtmaskierbare Interrupts. In Deinem auch? > Notfalls könnte man ja Enable/Disable Interrupt verwenden, > aber auch das ist nur in seltenen Sonderfällen notwendig. Das waere dann genau der "notwendige Lock", von dem Achim geredet hat. > Aber toll wenn man den Chef mit Buzz-Wörtern wie > "notwendige Locks" beeindrucken kann. Geht's auch etwas weniger abschaetzig? Besonders dann, wenn Du (ungewollt) genau das bestaetigst, was Achim vor Dir geschrieben hat? > Dass feste Rechenzeiten notwendig wären ist sowieso nur > totaler Blödsinn. Vielleicht TUST Du in Zukunft wenigstens mal so, als ob Du VERSUCHEN wuerdest zu verstehen, was Dein Gegenueber gemeint hat!? Achim hat KRITISIERT, dass bei Deinem Vorschlag (je ein Countdown-Zaehler pro Timeout) fuer jeden laufenden Countdown Rechenzeit in der ISR verbraten wird. Das ist bei der von ihm vorgeschlagenen Zeitstempel-Methode nicht der Fall. > Aber von deinem Standpunkt hast du schon recht, wenn du die > Software so kompliziert machst, dass sie ausser dir keiner > versteht, [...] Einfach mal die Baelle flachhalten. Es hat schon jeder gemerkt, dass Du Achim nicht verstehst; das musst Du nicht noch besonders betonen. Aber was Du nicht verstehst, muss deswegen noch lange nicht falsch sein.
Possetitjel schrieb: > Es hat schon jeder gemerkt, dass Du Achim nicht verstehst; das > musst Du nicht noch besonders betonen. Possetitjel schrieb: > Denn Du hast weder erkannt, dass Achim offensichtlich einen > SPS-Hintergrund hat (was sich auch in seiner Wortwahl > niederschlaegt), noch, dass ich Dich subtil auf diese Tatsache > hinweisen wollte. Macht ja nichts, Hauptsache du verstehst Achim sehr gut und dir gefällt sein Hintergrund. Weiter so. P.S. Wer ist Junge und wer ist Mädchen ?
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.