Forum: Mikrocontroller und Digitale Elektronik Wie macht ihr ein Menü Timeout? Möglichkeiten?


von Wolfsente (Gast)


Lesenswert?

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.
von Georg (Gast)


Lesenswert?

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

von Wolfsente (Gast)


Lesenswert?

Den Ansatz find ich gut!
Der passt auch gut auf mein Projekt.
Danke!

von W.S. (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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

von Georg (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von Thomas E. (picalic)


Lesenswert?

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
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

von A. S. (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von Klaus (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von Wolfsente (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von Georg (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von Wolfsente (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von A. S. (Gast)


Lesenswert?

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.

von Georg (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von Wolfsente (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von Possetitjel (Gast)


Lesenswert?

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".

von Possetitjel (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von Possetitjel (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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.

von Possetitjel (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
Noch kein Account? Hier anmelden.