Hallo,
ich weiß, dass Tasterentprellung softwareseitig mittels Timer hier schon
1000-mal durchgekaut wurde, aber ich weiß nicht wie ich in meinem
Anwendungsfall die Entprellroutinen integrieren kann.
Ich habe 2 Taster, jeweils ein UP und ein DOWN Taster, die eine globale
Variable inkrementieren bzw. dekrementieren sollen. Es soll nichts
passieren wenn beide Tasten gleichzeitig gedrückt werden (UP und DOWN
gleichzeitig macht keinen Sinn). Außerdem soll, auf einen Tastendruck
egal welcher Länge, nur einmal reagiert werden (als einmal inkrement
oder dekrement).
Ich habe bereits einen Timer in Verwendung der alle 1,43ms ausgelöst
wird und möchte dort die Entprellroutine integrieren.
Ich dachte mir, dass so etwas schon sicher mal von jemandem hier
programmiert wurde und würde mich freuen wenn hier jemand seinen C Code
posten könnte.
mfg
t3sla
PS.: Beide Taster hängen an einem Port (Port D)!
1,4ms ist etwas kurz. Besser 4-6ms.
Manche Tater prellen mehrere ms lang.
Wenn Int kommt, Tasten einlesen. Status festhalten und wieder warten.
Dann wieder lesen, vergleichen mit alt wenn gut dann gedrückt, wenn
nicht dann wieder neu warten.
Baue Dir ein Stausregitser, ähnlich wie bei Dannis Entprellung.
t3sla schrieb:
> programmiert wurde und würde mich freuen wenn hier jemand seinen C Code> posten könnte.
Was gefällt dir an der Forums-Standard-PeDa-Lösung nicht?
http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29
Zuverlässig, schnell, simpel in der Anwendung, 1000fach im Einsatz
PS: Wenn du bereits einen 1.4ms Timer in der Verwendung hast, kannst du
den Code einfach in dessen ISR einfügen. Die im Code erwähnten 10ms
musst du nicht so eng sehen. Ev. noch einen kleinen Zähler davor, sodass
der Entprellcode in der ISR nur bei jedem 3ten oder 4ten Aufruf
ausgeführt wird, dann reicht das schon.
Die Standard Lösung gefällt mir schon, nur verstehe ich sie nicht recht
und ist außerdem viel zu komplex und umständlich für meinen Fall. Es
soll zudem alles in der ISR erfolgen, auch die Manipulation der globalen
Variable. Außerdem muss die ISR selbst, so kurz wie möglich sein. In der
main wird dann nur der Wert der globalen Variable abgefragt.
Ich will wirklich nur die spezielle UP-, DOWN Taster Lösung. Ich
verlange nicht, dass jemand den Code für mich schreibt, aber ich bin mir
fast sicher das soetwas schon von irgendjemand hier, für irgendein
Projekt, geschrieben wurde.
mfg
t3sla
Karl heinz Buchegger schrieb:
> Ev. noch einen kleinen Zähler davor, sodass> der Entprellcode in der ISR nur bei jedem 3ten oder 4ten Aufruf> ausgeführt wird, dann reicht das schon.
na ob das bei seinem Wissensstand eine gute Idee ist.....
Ich denke den Timer zu ändern dürfte für ihn einfacher sein.
Auf der anderen Seite ist es natürlich der beste Weg unterschiedliche
Zeitkonstanten mit einem Timer zu erzeugen, ohne ihn ständig
umzukonfigurieren. Lernen muß er das ja doch mal.
t3sla schrieb:
> Die Standard Lösung gefällt mir schon, nur verstehe ich sie nicht recht> und ist außerdem viel zu komplex und umständlich für meinen Fall.
?
Die Funktionalität ist clever aufgebaut, zugegeben.
Nur kriegst du das mit anderem Code auch nicht einfacher hin, selbst
wenn du nur 2 Taster hast.
> Es> soll zudem alles in der ISR erfolgen, auch die Manipulation der globalen> Variable.
Macht die Lösung doch.
Die komplette Auswertung der Tasten findet in der ISR statt.
> Außerdem muss die ISR selbst, so kurz wie möglich sein. In der> main wird dann nur der Wert der globalen Variable abgefragt.
Auch das ist doch genau das, was die PeDa Lösung macht.
Reden wir wirklich vom selben Code?
Und wenn wir von 'so kurz wie möglich' reden.
Noch simpler (im Sinne von: schneller) als die PeDa Lösung geht schon
fast nicht mehr. Das Teil ist extrem ausgefuchst.
Und wenn du den Autorepeat Teil nicht brauchst, dann lass ihn einfach
weg
1
uint8_tISR_count;
2
3
ISR(TIMER0_OVF_vect)
4
{
5
staticuint8_tct0,ct1;
6
uint8_ti;
7
8
ISR_count++;
9
if(ISR_count==4)
10
{
11
ISR_count=0;
12
13
i=key_state^~KEY_PIN;// key changed ?
14
ct0=~(ct0&i);// reset or count ct0
15
ct1=ct0^(ct1&i);// reset or count ct1
16
i&=ct0&ct1;// count until roll over ?
17
key_state^=i;// then toggle debounced state
18
key_press|=key_state&i;// 0->1: key press detect
19
20
}
21
22
...deinbisherigerISRCode
23
}
das möchte ich sehen, wie du eine Tastenauswertung/Entprellung für 2
Tasten noch kompakter und auch mit weniger Rechenzeitverbrauch
hinkriegst.
Stephan Henning schrieb:
> Karl heinz Buchegger schrieb:>> Ev. noch einen kleinen Zähler davor, sodass>> der Entprellcode in der ISR nur bei jedem 3ten oder 4ten Aufruf>> ausgeführt wird, dann reicht das schon.>> na ob das bei seinem Wissensstand eine gute Idee ist.....
lol
t3sla schrieb:
> Die Standard Lösung gefällt mir schon, nur verstehe ich sie nicht recht> und ist außerdem viel zu komplex und umständlich für meinen Fall.
Das liegt im Auge des Betrachters.
99% der anderen Lösungen sind deutlich umständlicher oder weniger
wirksam.
Die Repeat-Funktionen lösche einfach, wenn Du sie nicht benötigst.
Allerdings stört das bischen toter Code nicht, wenn Du nicht grade nen
ATtiny13 nimmst.
> Es> soll zudem alles in der ISR erfolgen, auch die Manipulation der globalen> Variable.
Es hindert Dich niemand daran, get_key_press() gleich mit im Interrupt
aufzurufen. Allerdings sind dann das cli() und sei() zu entfernen, da im
Interrupt immer Interruptsperre herrscht.
> Ich will wirklich nur die spezielle UP-, DOWN Taster Lösung.
Das ist ja gerade der Witz an der universellen Lösung, man braucht keine
speziellen Lösungen mehr.
One size fits all!
> Ich> verlange nicht, dass jemand den Code für mich schreibt
Wenn Du die universelle Lösung nicht willst, schon.
> aber ich bin mir> fast sicher das soetwas schon von irgendjemand hier, für irgendein> Projekt, geschrieben wurde.
Denke ich auch, daß von den entprellten Tasten oft 2 für up/down
verwendet werden.
Sieht dann etwa so aus:
Karl heinz Buchegger schrieb:
>> Es>> soll zudem alles in der ISR erfolgen, auch die Manipulation der globalen>> Variable.
Ach jetzt versteh ich erst.
Du hast eine globale Variable und willst die mit den Tasten rauf/runter
zählen.
Warum muss das in der ISR passieren?
Das kann doch in der Hauptschleife (wo es auch hingehört) genausogut
erledigt werden.
Aber seis drumm
Peter Dannegger schrieb:
> Die Repeat-Funktionen lösche einfach, wenn Du sie nicht benötigst.
Wobei ich auch mal sagen muss, das gerade diese Funktionalität für mich
das Geilste überhaupt in deinem Code ist.
Die Einstellung irgendwelcher Konfigurationsparamter mit einem
Wertebereich von 0 bis 1000 wird so deutlich vereinfacht. Anstatt sich
die Finger wundzutippen einfach auf dem Taster bleiben und schon zählt
der Parameter hoch. Die letzten Feinheiten mit einzelnen Tastendrücken
erledigen und fertig.
Schon alleine für dieses Feature hast du dir ein Bier verdient.
Kurzen und Langen Tastendruck unterscheiden zu können hab ich bisher
noch nie benötigt :-)
Hier mal ein Lösungsansatz oder Hinweis oder Denkanstoß.
Erfahrungsgemäß ist es von Vorteil, so wenig wie möglich in der ISR zu
machen. Ich mach das immer so, dass ich in der ISR in einem Statusbyte
Merkerbits setzte bzw. nur das minimal notwendigste mach und dann später
im Programm drauf reagiere.
1
ISR(TIMER0_OVF_vect)
2
{
3
++ucTimerInt;
4
}
5
6
voidmain(void)
7
{
8
time();
9
10
if(ucTimerInt==7)// sind dann ca 10ms
11
{
12
SetBit(ucTimeControl,b10msOvr);
13
ucTimerInt=0;
14
}
15
16
if(CheckBit(ucTimeControl,b10msTimer))
17
{
18
if(CheckBit(PORTD,0)
19
{
20
++ucCounter;
21
}
22
}
23
24
if(ucCounter>6)
25
{
26
//hier ist dann der Tastendruck gültig
27
}
28
}
29
30
31
voidtime(void)
32
{
33
ClearBit(ucTimeControl,b10msTimer);
34
35
if(CheckBit(ucTimeControl,b10msOvr))
36
{
37
SetBit(ucTimeContrl,b10msTimer));
38
}
39
}
Einziger vernachlässigbarer Nachteil ist dabei, dass ich einen
kompletten Programm Durchlauf unter 10ms (in meinem Beispiel)
garantieren muss.
Wesentlicher Vorteil ist, dass ich das b10msTimer Bit einen
Programmdurchlauf an jeder Stelle abfragen kann.
Ich Entprell meine Taster immer bis 60ms. Unter 10ms find ich es fast zu
knapp.
//(in der Main dann Key1pressed=false; zum zuruecksetzen)
13
}
Key2Counter gibt auch auskunft ob lang oder kurz gedückt(oh Gott noch
mehr ifs)
will man verhindern das ein langes Festhalten der Taste noch ein Event
auslöst muss man am einfachsten das if erweitern:
[c]
if (Key2Counter>=Zählerstand_entsprechent_für_100ms)
{
Key2pressed=true;
Key2Counter=Zählerstand_entsprechent_für_100ms; //Zähler halt!
} else Key2pressed=false;
Aber es gibt viele Lösungen such dir was aus.
Taz schrieb:
> Key2Counter gibt auch auskunft ob lang oder kurz gedückt(oh Gott noch> mehr ifs)>> will man verhindern das ein langes Festhalten der Taste noch ein Event> auslöst muss man am einfachsten das if erweitern:
Ja, so ist das eben, wenn man unbedingt bei jedem Projekt seine
Speziallösungen von neuem entwickeln will.
Man pappt hier und da noch was ran, bis man völlig den Überblick
verloren hat. Und mit jeder weiteren Taste bläht sich das Ganze umso
mehr auf.
Man könnte seine Zeit aber auch nutzbringender oder angenehmer
verbringen.
Peter
tja Peter,
mit "Copy and Paste" kommt man auf Dauer aber auch nicht weiter.
Für das Verständnis ist es schon gut. Wenn er weis wie es geht, weis er
auch Deine zu schätzen....hoffe ich. Dann kann er sie immer noch nehmen.
Lieber so, als wenn jemand alles von hier wild zusammenkopiert und sich
dann wundert das sein Temp. messender DCF77 Empfänger die per USB
erhaltenen Daten vom PC nicht an die Funkwetterstation per WLAN senden
kann und der Schrittmotor nicht den richtigen Wochentag anzeigt weil die
LED´s mit 10 Ohm an 24V geschaltet wurden. :-))
Und dann sollen wir den Fehler finden...
Ich hab mein "Entprell-Rad" einmal erfunden und nutze dies immer wieder.
Kann damit beliebig viele PINS auf verschieden PORTS entprellen. Sehr
übersichtlich und auführlich gecodet. Reagiert auf fallende oder
steigende Flanke des PINS.
Mein Beispiel oben soll keine komplett Lösung darstellen sondern nur
einen Lösungsansatz für Anfänger sein.
Ich wollte das Augenmerk auf die ISR legen. Das ist eine Einsteigerfalle
die gefährlicher wird, je größer das Projekt wird. Auch wenn dann
mehrere ISR ins Spiel kommen die nicht priorisiert werden können (auf
den ATMEGAS).
Peter Dannegger schrieb:
> Taz schrieb:>> Key2Counter gibt auch auskunft ob lang oder kurz gedückt(oh Gott noch>> mehr ifs)>>>> will man verhindern das ein langes Festhalten der Taste noch ein Event>> auslöst muss man am einfachsten das if erweitern:>> Ja, so ist das eben, wenn man unbedingt bei jedem Projekt seine> Speziallösungen von neuem entwickeln will.
Ich mag mich irren. Bei Prozessen, die über mehrere Funktionsaufrufe
gehen ist das nur durch Codebetrachtung immer etwas schwer zu sagen,
aber ich bin der Meinung, dass diese Lösung so wie sie gepostet wurde,
nicht funktioniert. Bleibt man länger als 0.1 Sekunden auf der Taste,
dann werden viele, viele Tastendrücke registriert.
Hi Karl heinz Buchegger
ich weiss nicht was mit 'Bei Prozessen, die über mehrere
Funktionsaufrufe gehen..' gemeint sein soll, aber ich wette das der Code
funktioniert ob er das tut was t3sla will sei dahingestellt.
ich hatte geschrieben :
" will man verhindern das ein langes Festhalten der Taste noch ein Event
auslöst muss man am einfachsten das if erweitern:
if (Key2Counter>=Zählerstand_entsprechent_für_100ms)
{
Key2pressed=true;
Key2Counter=Zählerstand_entsprechent_für_100ms; //Zähler halt!
} else Key2pressed=false;
"
Das Event das ausgelöst wird heisst Key_pressed (OK ich hätte besser
Key_Down geschrieben) bedeutet Taste ist gedrückt und nicht es wurde
eine Taste gedrückt (Key_click oder so) es ist Aufgabe der Main Routine
entsprechend auf das Event zureagieren, das hängt aber vom Anwendungfall
ab.
Und über so etwas einfaches brauche ich nicht lang drüber nachzudenken,
den Code schreib ich einfach so runter. Schwieriger ist immer
herauszufinden was das Programm machen soll - die Anforderungen.
Aber um nochmal auf die Ursprüngliche Frage zurückzukommen, es sollte
eine Variable hoch bzw runtergezählt werden und das nur einmal.
einfach in der ISR:
wenn Key1pressed = true ist Variable++
wenn Key2pressed = true ist Variable--
am Anfang der ISR Key1pressed & Key2pressed abfragen und die ISR
vorzeitig verlassen, so wird der Tastendruck nur einmal gesehen.
Zweites Problem beide Tasten gleichzeitig, wenn ich das mal umsetze
bedeutet das, wenn innerhalb von den ersten 100ms beide Taster gedrückt
werden, soll nicht passieren -> ISR vorzeitig verlassen wenn beide
Tastencounter ungleich 0 sind. (if (Key1Counter&Key2Counter) return;)
Ich möche keinen Copy und Paste Code hier posten
1. schreibe ich nicht für AVRs
2. müste ich den Code durchtesten (keine Zeit)
3. wenn ihr keine Anfänger seid sollt ihr euch selber Gedanken machen
4. lernt man nichts, wenn man Code einfach so übernimmt
ich hoffe das hilft jedem eine Lösung zu finden, sonst muss ich doch mal
die ganze Routine als Copy und Paste Version posten.
Taz schrieb:
> Hi Karl heinz Buchegger> ich weiss nicht was mit 'Bei Prozessen, die über mehrere> Funktionsaufrufe gehen..' gemeint sein soll, aber ich wette das der Code> funktioniert ob er das tut was t3sla will sei dahingestellt.>> ich hatte geschrieben :> " will man verhindern das ein langes Festhalten der Taste noch ein Event> auslöst muss man am einfachsten das if erweitern:>> if (Key2Counter>=Zählerstand_entsprechent_für_100ms)> {> Key2pressed=true;> Key2Counter=Zählerstand_entsprechent_für_100ms; //Zähler halt!> } else Key2pressed=false;> "> Das Event das ausgelöst wird heisst Key_pressed (OK ich hätte besser> Key_Down geschrieben) bedeutet Taste ist gedrückt und nicht es wurde> eine Taste gedrückt (Key_click oder so) es ist Aufgabe der Main Routine> entsprechend auf das Event zureagieren, das hängt aber vom Anwendungfall> ab.
Gut.
Die Hauptschleife wird also so aussehen
while( 0 ) {
if( Key2pressed ) {
Key2pressed = false;
// mach was, wenn Taste 2 gedrückt wurde
}
schön.
In der ISR wurde Key2Counter auf Zählerstand_entsprechent_für_100ms
gesetzt. Das hindert aber
if (Key2down()) Key2Counter++); // dasselbe in grün
else Key2Counter=0;
in der ISR, beim nächsten Aufruf, nicht daran Key2Counter wieder zu
erhöhen, wenn die Taste immer noch gedrückt ist.
Als Folge davon ist dann
Key2Counter>=Zählerstand_entsprechent_für_100ms
wieder true (*), und
Key2pressed=true;
zeigt der Hauptschleife den nächsten Tastendruck an (Hinweis: Die Taste
wurde bisher nicht losgelassen, sondern ist immer noch gedrückt.
Trotzdem hat die Hauptschleife bisher 2 Tastendrücke registriert. Und
wenn die Taste noch länger gedrückt gehalten wird, registriert die
Hauptschleife weitere keypress Events)
> Ich möche keinen Copy und Paste Code hier posten> 1. schreibe ich nicht für AVRs> 2. müste ich den Code durchtesten (keine Zeit)
Geht mir auch so.
Schau, mir ist es im Grunde egal ob deine Tastenauswertung funktioniert
oder nicht. Aber einen Anfänger kann sowas zur Verzweiflung bringen.
Denn auch wenn du das anders siehst: Auch Copy&Paste Code hat seinen
Wert, WENN sich der OP die Mühe macht ihn zu analysieren, wie er
funktioniert, vorausgesetzt dass er funktioniert.
(*) Im Grunde ist das Hochzählen des Key2Counter völlig irrelevant.
Schon alleine die Sequenz
if (Key2Counter>=Zählerstand_entsprechent_für_100ms)
{
Key2pressed=true;
Key2Counter=Zählerstand_entsprechent_für_100ms; //Zähler halt!
} else Key2pressed=false;
sorgt dafür, dass Key2pressed bei jedem ISR Aufruf Key2pressed mit true
hinterlässt, wenn Key2Counter erst einmal
Zählerstand_entsprechent_für_100ms erreicht hat.
Wie gesagt: Ich mag falsch liegen. Ich habs nicht tatsächlich
ausprobiert. Es steht auch ausser Frage, dass man das alles auf deiner
Basis funktionierend hinkriegen kann. Nur eine Lösung, die man zu einer
funktionierenden Lösung umbauen kann, ist kein guter Kandidat um einem
Newbie eine Anregung zu geben.
Taz schrieb:
...
> delay_ms(100); // wegen Schalterprellen 100ms warten
...
Genau das ist das was ich an Code hasse den ich nicht selbst geschrieben
hab.
Das mag ja funktionieren, hält aber mein Programm für 100ms auf. In
dieser Zeit kann ich NICHTS anders machen.
OK seh ich ein wenn ich 2 Tasten hab die eine LED ein oder aus schalten.
Wird das Programm aber etwas umfangreicher, was meiner Erfahrung nach zu
Beginn nur bedingt abschätzbar ist, wird man an den delay_ms zu Grunde
gehen.
Das ist meiner Meinung nach absoluter Schwachsinn.
Korrigier mich einer wenn ich falsch liege.
>ich würde keine ISR verschwenden.
Der Timer und dessen Interrupt ist doch dazu da um ihn zu verwenden.
Wenn man einen Timer mit 10ms Interrupt hat kann daraus ja sämtliche
Zeiten generieren.
"Korrigier mich einer wenn ich falsch liege."
du liegst falsch, wenn ich als User eine Taste drücke spielen 100ms
überhaupt keine Rolle der Mensch ist viel zu langsam. Wie oft kann ich
den die Taste in 100ms drücken ? mal von Schalterprellen abgesehen wo
ich sowieso warten muss.
Natürlich muss man dafür sorgen das wichtig Prozesse nicht unterbrochen
werden. Deshalb sollten die wichtigen Funktion in einer ISR abgearbeitet
werden (Datenaufnahe Verarbeitung speichern) und unwichtige Funktion wie
Taster einlesen Bildschirmausgaben u.s.w. eben nicht oder in ISR mit
einer niedrigen Priorität (der darf die andern ISR natürlich nicht
sperren).
Und ich als Programmierer lege die Prioritäten fest.
(nebenbei ein NotAus Schalter hat die höchste Priorität).
Taz schrieb:
> Natürlich muss man dafür sorgen das wichtig Prozesse nicht unterbrochen> werden.
genau das ist der springende Punkt.
> Deshalb sollten die wichtigen Funktion in einer ISR abgearbeitet> werden (Datenaufnahe Verarbeitung speichern) und unwichtige Funktion wie> Taster einlesen Bildschirmausgaben u.s.w. eben nicht oder in ISR mit> einer niedrigen Priorität (der darf die andern ISR natürlich nicht> sperren).
Tastenabfrage in einer ISR verbraucht weniger als 1% Rechenzeit. Ist
also völlig vernachlässigbar.
Ganz abgesehen davon, dass viele Programm sowieso sowas wie eine langsam
mitlaufende 'Uhr' in einer ISR haben um einen Zeit-Basistakt zu haben.
@Taz
Ich hab nicht behauptet, dass das Entprellen nicht notwendig ist. Das
muss sein natürlich. Aber der weg mit delay_ms ist denkbar ungünstig.
Die 100ms spielen für den User keine Rolle halten aber das Programm
sinnlos auf.
Grundsatz Nummer eins ist: Ein Programm muss so schnell wie möglich
durchlaufen und darf nicht angehalten werden um z.B. auf ein Ergebnis zu
warten. Wenn ich "warten" muss dann reagiere ich meinetwegen 1000
Programmdurchläufe später darauf. Schau dir meinen Ansatz weiter oben
an.
>Deshalb sollten die wichtigen Funktion in einer ISR abgearbeitet>werden (Datenaufnahe Verarbeitung speichern)
NEIN:
Wenn z.B. eine Timer mit 2ms Interrupt am Laufen hast und in diesem Int
einen Wert ins EEPROM schreiben will dann wird dieses Vorhaben
scheitern. Ein Schreibzyklus aufs EEPROM dauert ca. 8ms.
Glaub mir in einer ISR darf nur so wenig wie möglich Code stehen.
Taz schrieb:
> Natürlich muss man dafür sorgen das wichtig Prozesse nicht unterbrochen> werden. Deshalb sollten die wichtigen Funktion in einer ISR abgearbeitet> werden (Datenaufnahe Verarbeitung speichern) und unwichtige Funktion wie> Taster einlesen Bildschirmausgaben u.s.w. eben nicht oder in ISR mit> einer niedrigen Priorität (der darf die andern ISR natürlich nicht> sperren).
delay_ms(100); // wegen Schalterprellen 100ms warten
UpDownCounter++;
if(UpDownCounter > Maximum)
UPDownCounter=Maximum;
while(PortA&TasteUp); // nichtstun solange Taste noch gedrückt
Du denkst also dein Benutzer ist begeistert, wenn er seine UART-Buffer
dadurch zum Überlaufen bringen kann, indem er eine Taste drückt :-) und
somit die Verarbeitung von Kommandos, die über die UART hereinkommen und
deren Bearbeitung schon mal etwas länger dauert (und daher nicht in
einer ISR passiert), blockiert.
Und das alles nur, weil er das LCD heller stellen wollte :-)
@ Andy Andy
Dein Grundsatz Nummer Eins gefällt mir nicht weil es doch stark
Anwendungsabhängig ist. Und als Anfänger direkt so zu programmieren auch
wenn unnötig ist macht einfach keinen Spass. Du gehst von Profis aus und
ich habe extra betont 'Lösung für Anfänger'.
Und dein Beispiel: in 2ms Takt auf ein EEPROM zuschreiben das 8ms
braucht würde doch nie funktionieren. Die Aussage das in der ISR
möglichst wenig Code stehen darf ist natürlich nur ein Ratschlag. Die
Zeit die eine ISR verbraucht darf natürlich nicht länger sein als die
Zeit zwischen den ISRs plus etwas Zeit für den Rest. Meine ISR braucht
etwa 90% der Zeit (ADC lesen verarbeiten speichen..bei f=10kHz) der Rest
ist für RS232 u.s.w.
@ Karl heinz Buchegger
wie ich schon geschrieben habe das war eine einfache Lösung für einen
Anfänger.
noch schlimmer als das Delay ist das while solang der Taster gedrückt
ist läuft nichts mehr.
Wenn Du jetzt RS232 Funktionen ins Spiel bringst kann ich natürlich
wieder duzende von Lösungen präsentieren aber immer wieder kann man
einen Einwand machen. z.B. könnte die RS232 kann auch einen ISR auslösen
(wäre eine Möglichkeit), aber dann ......u.s.w.
wenn dir das delay nicht gefällt dann vielleicht so:
1
.
2
unsignedlongTaste1Counter=0;
3
4
if(PortA&TasteUp)// TasteUp gedrückt
5
Taste1Counter++;
6
elseTaste1Counter=0;
7
8
if(Taste1Counter==80000)// Wert 80000 ist experimentel ermittelt
9
{
10
UpDownCounter++;
11
}
12
if(UpDownCounter>Maximum)
13
UPDownCounter=Maximum;
14
.
15
.
1.Problem dabei TastenCounter zählt weiter und wird irgendwann
überlaufen, kann man mit einem weiterm if und einem Flag lösen bei 32Bit
wird das aber sehr lange dauern.
2.Problem die 80000 sind laufzeitabhängig und somit nicht ganz konstant
und wenn die Schleife grösser wird muss man den Wert neu bestimmen.
Diese Lösung, denke ich kann man einem Anfänger auch noch anbieten.
Sonst habe ich keine einfache, leichtverständliche, Anfängertaugliche
Lösung mehr parat.
Taz schrieb:
> wieder duzende von Lösungen präsentieren aber immer wieder kann man> einen Einwand machen.
Siehst du.
Und genau jetzt kommen wir zum springenden Punkt.
Diese Lösung hier
http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29
funktioniert immer. Alles was ich dazu brauche ist ein Timer. Noch
nicht mal die Taktung des Timers ist besonders kritisch.
Sie verbraucht minimal Rechenzeit, entprellt zuverlässig 1 bis 8 Tasten
und behindert das restliche Programm in keinster Weise (wenn wir mal
davon ausgehen, dass ein Zeitverbrauch < 1% akzeptabel ist).
Ganz im Gegenteil: Das Kochrezept über Jobflags (den um etwas anderes
handelt es sich hier konzeptionell nicht), verallgemeinert hervorragend,
sodass ein Newbie daraus nur lernen kann, wie er seinen Programmen eine
Grundstruktur geben kann, mit der er nicht allzu falsch liegen wird.
Es handelt sich dabei also tatsächlich um eine "One size fits all"
Lösung. Und sowas ist wahrlich selten.
Und wenn ich mir die Ansätze ansehe, die zum Fixen der kleinen
Wehwehchen der vorgestellten Lösungen immer wieder nachgeschoben wurden
- dagegen ist die PeDa Lösung eigentlich schon als simpel anzusehen.
Gut, im genannten Artikel könnte man noch detaillierter ausführen, wie
dieser vertikale Zähler funktioniert. Gestehe ich gerne zu. Am Anfang
sieht das alles verwirrend aus, aber wenn man das erst mal durchschaut
hat, ist es eigentlich ganz einfach.
@Karl heinz Buchegger
glaubst du wirklich das ein Newbi also ein absoluter Anfänger das hier
versteht?
1
ct0=~(ct0&i);// reset or count ct0
2
ct1=ct0^(ct1&i);// reset or count ct1
3
i&=ct0&ct1;// count until roll over ?
4
key_state^=i;// then toggle debounced state
5
key_press|=key_state&i;
6
...
ich habe gar nicht gegen diese Lösung im Gegenteil finde sehr gut aber
eben nicht Anfängertauglich.
PS: wieso steht da count ct0 ? wird doch garnicht gezählt oder.
Taz schrieb:
> Und über so etwas einfaches brauche ich nicht lang drüber nachzudenken,> den Code schreib ich einfach so runter.
Wenn man nicht darüber nachdenkt, dann ist Tasten einlesen schwierig.
Das sieht man leider an vielen kommerziellen Geräten, wo die Entwickler
der irrigen Meinung sind, man müsse dem keine Bedeutung beimessen.
Ich ärgere mich regelmäßig darüber, wenn z.B Tastendrücke verloren
gehen.
Wenn man aber einmal richtig drüber nachgedacht hat, dann ist Tasten
einlesen popel einfach und vor allem nicht Ressourcen fressend.
Und dann muß man einfach nur noch die Tastenpins anpassen und die
gewünschten Funktionen aus der Tasten-Lib aufrufen.
> Schwieriger ist immer> herauszufinden was das Programm machen soll - die Anforderungen.
Deshalb ist es sinnvoll, universelle Tastenfunktionen zur Verfügung zu
haben, auch wenn man nicht alle braucht.
Und es ist sehr nützlich, wenn diese Funktionen dann nicht viele
Ressourcen (CPU-Zeit) belegen, damit es zu möglichst wenig
Seiteneffekten mit den anderen Programmroutinen kommt.
Man sieht leider oft bei vermeintlich "einfachen" Tastenroutinen, daß
z.B. Displays hängen oder LEDs flackern, wenn man ne Taste drückt.
Nebenbei ist die universelle Tastenabfrage auch noch sehr portabel, also
sehr leicht auf verschiedene MCs anzupassen.
Peter
Peter Dannegger schrieb:
" Wenn man nicht darüber nachdenkt, dann ist Tasten einlesen schwierig.
....
Wenn man aber einmal richtig drüber nachgedacht hat, dann ist Tasten
einlesen popel einfach .... "
Also wenn man es kann ist es einfach, dann nehme ich das mal als
Kompliment.
Ich bin auch für universelle Lösungen wenn:
1. ich sie verstehe
2. wenn ich mich nicht an der Leistungs- bzw. Grössengrenze bewege
Ich habe viele vorgefertigte Routinen die ich einfach einbinde.
Aber die universellen ADC Routinen muss ich regelmässig anpassen wenn
ich richtig schnell werden will. Du hast aber Recht man sollte schon
versuchen Funktionen so zuschreiben das man sie universell benutzen
kann.
Taz schrieb:
> @Karl heinz Buchegger> glaubst du wirklich das ein Newbi also ein absoluter Anfänger das hier> versteht?
Glaub ich ehrlich gesagt nicht.
Aber ein Newbie versteht auch nicht wie itoa arbeitet.
Aber ich versteh schon, worauf du hinaus willst. Und deine Intention ist
absolut zu begrüssen. Der Punkt ist nur: Eine saubere, gut
funktionierende Tastenroutine, die im Nähkästchen liegt und abgerufen
werden kann, ist gar nicht so simpel zu finden.
> PS: wieso steht da count ct0 ? wird doch garnicht gezählt oder.
Doch, wird es.
Aber anders. ct0 und ct1 bilden gemeinsam acht Stück 2-Bit Zähler
Bit 0 von ct0 und Bit 0 von ct1 gehören zusammen und bilden einen
Zähler, Bit 1 von ... etc
Bit 7 6 5 4 3 2 1 0
#########
+---+---+---+---+---+---+-#-+---+ #
ct0 | | | | | | | # | | #
+---+---+---+---+---+---+-#-+---+ #
# #
+---+---+---+---+---+---+-#-+---+ #
ct1 | | | | | | | # | | #
+---+---+---+---+---+---+-#-+---+ #
#########
^
|
+--- diese beiden Bits sind 1 Zähler
Der restliche ^ und & sind nichts anderes als ein 2 Bit Zähler, der auf
allen 8 Bit dieser 8 'Counter' parallel arbeitet.
Auf sowas muss man erst mal kommen!
Danke für die Erklärung aber da ich kein AVR programmiere fällt es mir
etwas schwer das Programm im Kopf 'ablaufen' zulassen - zu viele
Unbekannte zu viele Variablen (und die auch noch vom Type static).
Trotzdem erkenne ich nicht das ct0 hochzählt also 0,1,2,3..
Aber von der Programmierung her sieht es schon verdammt gut aus, hat
bestimmt viel Mühe gekostet. Ich hätte es bei weitem nicht so gut
hinbekommen - Respekt.
Ahhh eine halbe Tasse Kaffe später hab ich verstanden.
Ich hab verstanden das '// reset or count ct0' sich auf ct0 bezieht,
deshalb hab ich ein ct0++ erwartet, was Blödsinn wäre.
ct0 gibt seinen Status an ct1 weiter und bildet so mit ct1 einen Zähler.
Danke
Karl heinz Buchegger schrieb:
> Der Punkt ist nur: Eine saubere, gut> funktionierende Tastenroutine, die im Nähkästchen liegt und abgerufen> werden kann, ist gar nicht so simpel zu finden.
Man kann bei einer Aufgabe nie alle Parameter optimieren, man muß daher
Prioritäten setzen, z.B.:
1. gut funktionierend
2. universell
3. Ressourcen schonend
4. leicht verständlich
Ich denke, das Häckchen für meine Routine bei 1. - 3. steht außer Frage.
Ich habe bisher auch keine andere Routine gesehen, die bei 4. besser
abschneidet ohne bei den anderen Punkten erhebliche Abstriche in Kauf zu
nehmen.
Peter