Bräuchte mal wieder einen Tip.
Ich möchte gerne eine Variable nach einer bestimmten Zeit (10 sek) auf 1
setzen.
Das ganze soll jedoch im Hintergrund laufen.
Der Zähler soll jedoch immer auf 0 gesetzt werden sobald eine Taste oder
ein Drehgeber betätigt wird.
Kann ich das mit einer IF-Abfrage machen?
1
if(timer!=0)
2
{
3
ntimer++;
4
while(ntimer<100)
5
{
6
ende=1;
7
timer=0;
8
}
9
}
Mir ist jedoch noch nicht klar welchen Interrupt ich dafür nehmen soll.
Kann ich das in ein ISR(TIMER0_OVF_vect) stecken?
Verwendet wird ein ATMEGA 8
Manfred W. schrieb:> Bräuchte mal wieder einen Tip.>> Ich möchte gerne eine Variable nach einer bestimmten Zeit (10 sek) auf 1> setzen.> Das ganze soll jedoch im Hintergrund laufen.
Klarer Fall für einen Timer mit einer zugehörigen ISR.
> Der Zähler soll jedoch immer auf 0 gesetzt werden sobald eine Taste oder> ein Drehgeber betätigt wird.
Ja, kann man machen.
> Kann ich das mit einer IF-Abfrage machen?>> if(timer != 0)
wo kommt die Variable 'timer' her?
> {> ntimer++;> while(ntimer < 100)
No. while Schleife willst du da überhaupt nicht haben. Dazu hast du ja
eine ISR, die regelmässig aufgerufen wird. WEnn die ISR zu oft
aufgerufen wird (zb alle 1 Sekunde), kann man immer noch in der ISR
einen Zähler mitführen und erst beim 10.ten Aufruf das gewünschte tun.
Dann hat man ebenfalls eine Verzögerung von 10 Sekunden.
> Mir ist jedoch noch nicht klar welchen Interrupt ich dafür nehmen soll.
Der mit dem du eine ISR Aufruffrequenz bekommst, mit der du gut rechnen
kannst.
>> Kann ich das in ein ISR(TIMER0_OVF_vect) stecken?
Sicher kannst du.
Du musst nur ausrechnen bzw. den Timer so einstellen, dass die ISR
entsprechend oft und möglichst mit einem für dich brauchbaren Zeitraster
aufgerufen wird.
Hinweis: das werden nicht 10 Sekunden sein, sondern schneller. Aber das
ist ja kein Problem. Auch mit einer Uhr auf der nur 1 Sekundenzeiger
ist, kann man schliesslich 1 Minute abzählen. Man muss nur 60
Sekundenticks abwarten. Und genau das gleiche kann man auch mit einer
Timer-ISR machen
1
volatileuint8_ttimeCount;
2
3
ISR(TIMER0_OVF_vect)
4
{
5
if(timeCount>0){
6
timeCount--;
7
8
if(timeCount==0)
9
machewasauchimmerzumachenist
10
}
11
}
setzt du die Variable timeCount auf einen Wert ungleich 0, so wird diese
variable bei jedem Aufruf der ISR um 1 heruntergezählt. Nach
entsprechend vielen Aufrufen wird die irgendwann zu 0 und wenn das der
Fall ist, löst dann die ISR die Aktion aus.
Wird die ISR jede Sekunde aufgerufen und setzt du timeCount auf 10, dann
erfolgt die Aktion daher 10 Sekunden nachdem du timeCount auf 10 gesetzt
hast. timeCount arbeitet also wie ein Küchentimer, den man auf eine Zeit
einstellt und der langsam bis auf 0 zurückzählt, ehe die Glocke bimmelt
und anzeigt, dass die Eier fertig sind.
Und das alles im Hintergrund und ohne das sich die Hauptschleife darum
kümmern müsste.
Das sind eine Menge Infos, danke das du dir die Mühe gemacht hast.
Also die Variable 'timer' ist dafür gedacht, den Timer nur bei Bedarf zu
starten. Also wenn man sich in einem Untermenüpunkt befindet.
Die Zeitspanne für den ISR kann ich für diese Zwecke nicht ändern da in
der gleichen Routine auch die Abfrage des Tastendruckes passiert.
Vielleicht könnte ich das gleich dazu nutzen den Timer zu resetieren?
Manfred W. schrieb:> Also die Variable 'timer' ist dafür gedacht, den Timer nur bei Bedarf zu> starten.
OK.
Ich denke du hast schon gesehen, dass das gar nicht notwendig ist. Der
Timer kann ruhig ständig laufen, das schadet nicht. Er zählt seine
Zählvariable ja nur dann runter, wenn die ungleich 0 ist.
> Die Zeitspanne für den ISR kann ich für diese Zwecke nicht ändern da in> der gleichen Routine auch die Abfrage des Tastendruckes passiert.
Ja, macht ja nichts.
Dann hast du eben eine andere Zeitkonstante und musst die Zählvariable
mit einem anderen Wert belegen um auf 10 Sekunden zu kommen.
> Vielleicht könnte ich das gleich dazu nutzen den Timer zu resetieren?
lass den Timer in Ruhe
> ISR(TIMER0_OVF_vect)> {> static uint8_t ct0, ct1, rpt, timeCount;> uint8_t i;>> TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);>> i = key_state ^ ~ENCODER_PIN; // Taste gewechselt ?> ct0 = ~(ct0 & i); // Reset oder zähle ct0> ct1 = ct0 ^ (ct1 & i); // Reset oder zähle ct1> i &= ct0 & ct1; // count until roll over ?> key_state ^= i; // then toggle debounced state> key_press |= key_state & i; // 0 -> 1: Tastendruck> registrieren>> if( (key_state & ENC_TASTER) == 0) // Überprüfe> Wiederholfunktion> rpt = REPEAT_START; // Verzögerung starten> if(--rpt == 0)> {> rpt = REPEAT_NEXT; // Wiederhole Verzögerung> key_rpt |= key_state & ENC_TASTER;> }>> if(timer != 0)> {> if(timeCount > 0)> {> timeCount--;>> if(timeCount == 10)
Du hast da etwas misverstanden.
Diese Variable ist ein Rückwärtszähler!
So wie die Schaltuhren auf dem WC.
Du stellst eine Zeit ein und die Uhr läuft rückwärts auf 0.
Und wenn 0 erreicht ist, dann schaltet die Uhr die Lüftung ab.
if( timeCount == 0 )
Cool, das funktioniert schon mal halbwegs. Es reagiert nur etwas seltsam
wenn man vor ablauf der Zeit bereits wieder zurückgesprungen ist. Dann
muß man den taster 2 mal betätigen bis man wieder im Menü landet.
Genau gleich.
Jedesmal, wenn du eine Bentuzeraktion (Taste gedrückt, Encoder gedreht)
feststellst, setzt du den timeCount wieder auf 300
Taste gedrückt ist glaub ich klar.
Am Encoder wurde gedreht, wenn encode_read() etwas anderes als 0 zurück
liefert.
Also
tmp = encode_read();
if( tmp != 0 )
timeCount = 300;
val += tmp;
Du kannst auch eine Hilfsfunktion benutzen:
int8_t encode_read_timeout()
{
int8_t tmp = encode_read();
if( tmp != 0 )
timeCount = 300;
return tmp;
}
und dann einfach encode_read_timeout() anstelle von encode_read()
benutzen
if(get_key_short(ENC_TASTER))
{
timeCount = 300; // entspricht ungefähr 5sek
encode_read_timeout();
while(ende != 1)
{
val += encode_read_timeout();
....
Wichtig ist nur, dass du nach JEDER Benutzeraktion den Timer auch wieder
auf seine 300 setzt. Am einfachsten geht das mit solchen
Hilfsfunktionen, dann kann man das nicht vergessen.
Und wenn kein Timeout mehr notwendig ist, dann setzt du timeCount ganz
einfach auf 0 und der Mechanismus kommt ganz von alleine zum Stillstand.
> Es reagiert nur etwas seltsam> wenn man vor ablauf der Zeit bereits wieder zurückgesprungen ist. Dann> muß man den taster 2 mal betätigen bis man wieder im Menü landet.
Das hat aber nichts mit dem Timeout zu tun, sondern damit wie du die
while Schleife da drüber gelegt hast, und dass du aus der nur raus
kommst, wenn ende gleich 1 geworden ist.
Karl Heinz Buchegger schrieb:> Das hat aber nichts mit dem Timeout zu tun, sondern damit wie du die>> while Schleife da drüber gelegt hast, und dass du aus der nur raus>> kommst, wenn ende gleich 1 geworden ist.
Ja, da ist irgendwas durcheinander.
Der Timer funktioniert zumindest schon mal.
Könnte mir da vielleicht jemand noch unter die Arme greifen.
Wie gesagt, die Zeitschleife funkltioniert perfekt.
Das Programm wechselt jedoch nicht korrekt in die gewünschte Menüebene.
Nach zeitablauf springt er mir nur eine Ebene zurück und wenn ichw eiter
Navigieren möchte werden auch sporadisch verschiedene Menüs
angesprungen.
Hab den Fehler gefunden.
timeCount darf natürlich nicht auf 0 gesetzt werden sondern auf 1. Sonst
wird die Variable ende nie auf 1 gesetzt.
Das einzige was nun jedoch nicht mehr funktioniert ist das sich der
Encoderwert encode_read() nicht mehr zurücksetzen läßt.
So springt er mir immerwieder in das zuletzt aufgerufene Menü nach dem
Tastendruck.
Manfred W. schrieb:> Hab den Fehler gefunden.> timeCount darf natürlich nicht auf 0 gesetzt werden sondern auf 1. Sonst> wird die Variable ende nie auf 1 gesetzt.
Tip:
Nichts und niemand hindert dich daran, die Variable ende auch ausserhalb
der ISR auf 1 zu setzen. Zb dann, wenn der Benutzer einen Menüpunkt
angewählt hat mit dem das Menü abgebrochen wird. Du musst das nicht über
den Timer regeln.
> So springt er mir immerwieder in das zuletzt aufgerufene Menü nach dem> Tastendruck.
Ich denke du bist langsam an einem Punkt an dem du merkst, dass eine
Modularisierung deines Programmes in einzelne Funktionen gut tun würde.
Du veränderst unabsichtlich zu viele Dinge, weil du alles in einer
Hauptschleife hast und den Überblick verlierst.
Jedes einzelne Menü als eigene Funktion wäre schon mal ein Anfang.
Daran hatte ich schon gedacht, will mir das aber jetzt nicht mehr antun
alles umzustricken. Abgeshen davon ist das Programm schon mehr oder
weniger fertig.
In den Funktionen müßte ich dann ja wieder mit SWITCH CASE hantieren.
Bis auf diesen kleinen Schönheitsfehler mit dem Encoder läuft es schon
so wie ich gern möchte.