PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Taster einlesen und entprellen



Razer
26.06.2006, 05:49
Hallo an alle!!

So, ich hab da einmal eine Frage. Ich muss für eine Menüsteuerung 4
Tasten einlesen.

Entweder ich mach es mit externen Interrupts oder ich frage alle zb
10ms die Taster ab.
Was ist da besser geeignet??

Wenn ich das ganze mit dem Timer mach lassse ich den 8 Bit Timer im
Output Compare Modus laufen. Dabei zähle ich von 0 - 99. So treten bei
16MHz Taktfrequens und einem Prescaler von 64 25 Interrupts pro 10ms
auf, oder??

Dann erhöhe ich in der Interruptroutine eine Zählervariabele und prüfe
ob sie größergleich 25 ist. Wenn ja, setze ich die Variable auf 0 und
frage die Taster ab.

Aber die Taster prellen doch meistens mehr als 10ms oder? Also muss ich
das ganze noch Softwaretechnisch entprellen. Oder besser von der
Hardwareseite??

Ich könnte doch zB 10x prüfen ib der Taster gedrückt ist, oder?? Doch
wie mache ich das am besten?? Ich hab eine Variable die mit 10
initialisiert wird. Dazu habe ich noch eine Statusvariable. In der
steht ob der TAster gedrückt war. Wenn in der 0 steht, dann prüfe ich
ob der TAster gedrückt ist. Wenn ja, dann schreibe ich eine 1 in die
Variable. Wenn in der Variable eine 1 steht, dann prüfe ich den Taster,
wenn ja, veringere ich die Zählervariable (die am Anfang auf 10 stehet).
Wenn eine 1 in der Variable steht und der TAster nicht gedrückt ist,
dann schreibe ich wieder eine 0 in die Statusvariable und in die
Zählervariable schreibe ich wieder eine 10.

Kann ich das so machen?? Sind 10 Prüfungen zu wenig?? Das wären 100ms.

Kann ich das noch anderes lösen??

Dank eim Voraus

Gruß Robert

PicNick
26.06.2006, 08:11
Mach's nicht zu kompliziert.
In der an sich beliebigen Timer ISR fragst du jedesmal den Taster ab.
Hat er den gleich Zustand wie zuvor, zählst du auf einen Zähler eins drauf.
Wenn nicht, Zähler wieder auf Null und neuen Zustand merken.

erreicht der Zähler nun irgendeinen ausreichenden Wert (bißchen rechnen, schätzen und probieren) gilt der Zustand 1 oder eben 0.

SprinterSB
26.06.2006, 08:21
Nach meiner Erfahrung reichen 10ms aus: Guckst du: Taster-Abfrage in C (https://www.roboternetz.de/wissen/index.php/Taster-Abfrage_in_C)

[wiki="Taster-Abfrage in C"]

Razer
26.06.2006, 16:01
Hallo an alle

@SprinterB: Meinst du, dass die Taster nach 10ms nicht mehr prellen??

Gruß Robert

SprinterSB
26.06.2006, 16:15
Ich hab eigentlich all meine Applikationen mit einer Haupt-IRQ-Rate von 10ms für langsames Zeug (Taster-Abfrage, DCF-77, Jobs, etc).

Mit prellenden Taster hatte ich noch nie Probleme (Subminiatur-Taster oder wie die heissen). Teilweise ist die effektive Aufruf-Rate kleiner, weil ich in der IRQ Taster#1 dann #2 dann #3 abarbeite und dann wieder von vorne, was auf 30ms rauskommt (muss ich teilweise machen um die MCU-Last klein zu halten). Verschaltet sind die ohne äussere Hardware gegen GND und mit internem PullUp.

Razer
26.06.2006, 19:34
Ich hab mal schnell eine Funktion implementiert, die einen Taster abfragt..



char gettaster0 (void)
{
if(bit_is_clear(tasterstatus, 0) && bit_is_set(TASTERPORT, TASTER0))
{
tasterstatus |= (1 << 0);
debounce0--;
}

if(bit_is_set(tasterstatus, 0) && bit_is_set(TASTERPORT, TASTER0))
debounce0--;

if(bit_is_set(tasterstatus, 1) && bit_is_clear(TASTERPORT, TASTER0))
{
tasterstatus &= ~(1 << 0);
debounce0 = DEBOUNCEWERT;
}

if(debounce0 == 0)
return 1;

return -1;
}


TASTERPORT und TASTER0 sind in der Header Datei. DEBAUNCEWERT ist die Variable, wie oft er das ganze prüft, um dem Prellen entgegen zu gehen.

tasterstatus ist die Statusvariable für alle TAster. Bit0 ist das Statusbit für den Taster 0. Wenn das gesetzt ist, dann war der Taster bei der vorigen Prüfung gedrückt.

Kann ich das so machen?

Gruß Robert

SprinterSB
26.06.2006, 21:38
Die Frage beantwortet dir dein AVR mit nem Taster dran, ist mir jetzt zu mühsam mein Brain 1.0 anzukurbeln um das zu emulieren ;-)
Versuch's halt, du hast ja Ideen genug und weisst wie's in C auszudrücken ist. Dadurch und durch evtl. Fehlersuche/Analyse lernste allemal mehr.

Razer
27.06.2006, 17:19
Ja ich bin grad am probieren :) Leider öäuft der Timer nicht :(

Hie mal die Initialisierung



void timer2init (void)
{
TCCR0 = ((1 << CS22) | (1 << WGM21)); //Prescaler = 64; CTC Mode
TCNT2 = 0;
OCR2 = 99;
TIMSK = (1 << OCIE2); //Enable Compare Match Interrup
}


Ich finde keinen Fehler :(

Gruß Robert [/code]

0tes_Gesetz
27.06.2006, 19:32
1) ist das richtig, dass du in TCCR0 den Timer 2 initialisieren willst? -> TCCR2

2) an dem Register TIMSK? fehlt doch sicherlich noch ne 2, oder? -> TIMSK2

Grüße
0tes_Gesetz

PS: das "sei()" in main{} nicht vergessen...

PPS: mein Timer2 im m168 läuft damit:

...

// Timer2: Toggle OC2A @CompareMatch, CTC-Mode(2) & Prescaler=8
TCCR2A = (0<<COM2A1)|(1<<COM2A0)|(0<<COM2B1)|(0<<COM2B0)|(1<<WGM21)|(0<<WGM20);
TCCR2B = (0<<FOC2A)|(0<<FOC2B)|(0<<WGM22)|(0<<CS22)|(1<<CS21)|(0<<CS20);
TIMSK2 = (1<<OCIE2A)|(0<<TOIE2); // CompareInt ON, Overflow OFF

...

sei();

...

Razer
28.06.2006, 18:46
Hallo

Danke, das war der Fehler. Eigentlich wird das ganze für den Mega128 geschrieben. Da ich aber die HArdware noch nicht habe teste ich das ganze am Mega8...

Das Taster abfragen funktioniert :) :)

Nur hab ich jetzt noch eine Frage zum Berechnen der Variabeln zur Konnfigurierung des Timers.

zB Avr läuft mit 8MHz
Ich will das die Funktion xy alles 10ms = 0,01s ausgeführt werden soll.
Den Timer betreibe ich im CTC Mode.

Also Timerfrequenz = Takfrequenz / Prescaler = 8*10^6 / 64 = 125kHz
Jetzt zählt der Timer von 0 - 99. Also 100 Schritte. Also tritt alle 125kHz/100 ein Interrupt auf, oder? Also alle 1250 Timertakte = 800000 Prozessortakte.

Nur wie komm ich jetzt genau auf meine 10ms??

Gruß Robert

0tes_Gesetz
28.06.2006, 21:22
Ich rechne das immer "Anders 'rum" ;)

@ 8MHz braucht der Prozessor für einen Takt: 1/8MHz = 0,125µs

Mit einem Prescaler von 64, zählt der Timer nur jeden 64ten Takt, also 0,125µs x 64 = 8µs braucht der Timer um den Zähler um eins zu erhöhen.

Nun kannst Du deine benötigte Endzeit (10ms = 10.000µs) durch die 8µs teilen, die der Timer pro Schritt braucht, also:
10.000/8 = 1250 Timerschritte..

Um also auf 10ms zu kommen, muss dein Timer mit Prescaler 64 @8MHz bis 1250 zählen.. wenn er nur bis 255 kommt (8Bit) gibts vielleicht 2 Möglichkeiten das Problem zu lösen:

1) du zählst in der CTC-ISR eine Variable hoch (die alle CTC-Matches zählt), so dass du insgesamt 1250 Schritte zusammenbekommst. Anzuraten wäre in diesem Fall ein CTC-Wert in OCRA2 von 250, so dass du mit 5 mal hochzählen recht genau hinkommst (für die ISR und den Code da drin gehen aber nochmal ein paar Takte drauf, die man mit nem angepassten OCR2 in der Runde 4 abfangen könnte, aber das nur auf Anfrage ;)).
Also zB:



volatile uint8_t n=0;
ISR "CTC"
{
n++;
if (n==5)
{
n=0;
... was auch immer nach 10ms auch ausgeführt werden soll
}
}

2) oder du nimmst nen anderen Prescaler, so dass der Timer mit seinen maximal möglichen 255 allein hinkommt, ohne Zählvariable..

Hängt aber davon ab, was du als Prescaler noch einstellen kannst.
zB. reicht ein Prescaler von 256 noch nicht aus, wie du nachrechnen kannst, da: 10.000µs/(0,125µs x 256) = 312,5 > 256! - was das max. Mögliche im 8Bit Timer ist..

Prescaler von 512 oder mehr wäre nötig?!

3) Oder aber du findest dich damit ab und verringerst die ISR-Aufruf Zeit auf den durch die 256-OCR2-Grenze gegebenen Wert von 8,192ms...
Dann brauchst Du auch OCR2 nicht setzen, sondern kannst gleich den "Count bis 0xFF Modus" des Timers nutzen ;)

4) Noch eine weitere Möglichkeit wäre natürlich den Takt des Prozesors zu senken ;)

Grüße
0tes_Gesetz