Also, nachdem ja delay funktionen in ISR verpönt sind und cih im Moment nciht weiter weiß, folgede Frage: Wie (außer mit 2 delays wie im AVR GCC Tutorial beschrieben), kann ich einen Pin entprellen? In meinem jetzigen Programmcode frage ich pins(aktiv low am STK) einfach so ab: if (!(PIND & (1<<PIN0))) { } Wie "entprelle" ich eine solche Abfrage? Habe mir ebreits das beispiel angesehen, wo 8 PINS gleichzeitig entprellt werden, allerdings war mir das etwas zu hoch... Vielleciht kann mir jemand ein einfaches Beispiel zeigen?! Danke!
da gibt es mehrere Möglichkeiten... (1) Wenn du mit externer Beschaltung arbeiten willst, baust du ein R-C-Glied als Tiefpass oder mittels Flip-Flop an den Pin. (2) Softwaremäßig gibt es auch unterschiedliche Lösungen. Bei den meisten meiner "kleinen Projekte" nutze ich eh einen Timer, meist mit einem Timertick von 0,1 ... 1 ms. In den entsprechenden ISR lasse ich dann je nach Anzahl verschiedene Variablen (=> Zeitbasis) zählen. Im Hauptprogramm frage ich dann meist ganzzahlig Vielfache (modulo-Division) der Zählvariablen ab. Bei normalen Schaltern hast du meist eine Prellzeit im Bereich zwischen 5...10 ms. Also könntest Du 10 Timerticks vergehen lassen und schaust dann, ob der Signalpegel noch anliegt. Wenn nicht, ist der jeweiligen Schalter "nicht sicher" geschaltet worden. Viele Grüße müllo
Wie gesagt, das Beispiel von Peter Fleury ist mir zu hoch: Allein verstehe ich diese Aussage nicht: /* * read current state of keys (active-low), * clear corresponding bit in i when key has changed */ i = key_state ^ ~PIND; // key changed ? 1.)Warum macht man ein XOR zwishcen keystate und dem INVERTIRTEN Pin? 2.)keystate enthält zu der Zeit des codes noch gar kein Pin Abfrage 3.)warum "clear bit, when key has changed"? Soweit ich weiß ist das Ergebnis eine XOR verknüpfung "1", wenn die zwei verglichenen Bits unterschiedlich waren..?!
@müllo: Danke erstnal für die Antwort, hast du zu deiner Erklärung möglicherweise irgendein Code Schnipsel? Ich würde die Entprellung schon gerne softwaremäßig(und ressourcenschonend) machen, wenn irgendwie möglich..
Ich würde die Sache auf die Schnelle so machen: if (!(PIND & (1<<PIN0))) key = 1; else key = 0; if ((timerticks % 10 == 1) & (!(PIND & (1<<PIN0))) & (key ==1)) { //mach etwas... } else { //mach etwas nicht... } Ohne Gewähr - habe ich gerade zwischen Aufräumen und Heimgehen gemacht... mfg müllo
@Max, mach mal nen Link auf den ganzen Code, damit man mitreden kann. So mit 3 Zeilen ausm Zusammenhang raus geht das nicht. Peter
@Peter: Hier ist de komplette Code(zum entprellen von 8 PINS) /*********************************************************************** ***** Title: Debouncing 8 Keys Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury, based on algorithm of Peter Dannegger <danni@specs.de> Date: December 2003 Software: AVR-GCC 3.3 Hardware: AT90S8515 at 4 Mhz, STK200 compatible starter kit Description: Demonstrates debouncing 8 keys. The state of the eight keys is sampled four times using a timer interrupt. If a key is pressed longer than four seconds, the corresponding bit in the key_press global variable is set. The main loop checks if a bit is set in this global variable and resets the bit. Pressing the key connected to PIND2 increments a counter, while pressing the key connected to PIND3 decrements the counter. The value of this counter is displayed using LEDs on PORTB. ************************************************************************ *****/ #include <inttypes.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #ifndef CTC1 #define CTC1 WGM12 // for compatibility with ATmega #endif #define XTAL 4000000L // Crystal frequency in Hz #define DEBOUNCE 200L // debounce clock 200Hz = 5msec /* * Module global variable, informs the main programm when a key is pressed. * This variable must be declared 'volatile, since it is accessed from * both interrupt und main loop. */ static volatile uint8_t key_press; SIGNAL (SIG_OUTPUT_COMPARE1A) { static uint8_t key_state; // debounced and inverted key state: static uint8_t ct0, ct1; // holds two bit counter for each key uint8_t i; /* * read current state of keys (active-low), * clear corresponding bit in i when key has changed */ i = key_state ^ ~PIND; // key changed ? /* * ct0 and ct1 form a two bit counter for each key, * where ct0 holds LSB and ct1 holds MSB * After a key is pressed longer than four times the * sampling period, the corresponding bit in key_state is set */ ct0 = ~( ct0 & i ); // reset or count ct0 ct1 = (ct0 ^ ct1) & i; // reset or count ct1 i &= ct0 & ct1; // count until roll over ? key_state ^= i; // then toggle debounced state /* * To notify main program of pressed key, the correspondig bit * in global variable key_press is set. * The main loop needs to clear this bit */ key_press |= key_state & i; // 0->1: key press detect } int debounce( void) { uint8_t count = 0; TCCR1B = _BV(CTC1) + _BV(CS10); // clear timer on compare match, no prescaler OCR1A = XTAL/DEBOUNCE; // timer = 5 msec TIMSK = _BV(OCIE1A); // enable Output Compare 1 overflow interrupt DDRB = 0x00; // use all pins on PortD for input PORTD = 0xff; // with pull-up enabled DDRB = 0xff; // use all pins on PortB for output PORTB = 0xff; // turn all LED off sei(); // enable interrupt for(;;) { if (key_press & _BV(2) ) { // key 2 pressed, increment counter count++; PORTB = ~count; key_press = 0; } else if ( key_press & _BV(3) ) { // key 3 pressed, decrement counter count--; PORTB = ~count; key_press = 0; } } }
@müllo: if (!(PIND & (1<<PIN0))) key = 1; else key = 0; Ist mir klar; einfache (invertierte) Abfrage, ob Switch gedrückt if ((timerticks % 10 == 1) & (!(PIND & (1<<PIN0))) & (key ==1)) Diese Ziele kapier ich net ganz: -->if ((timerticks % 10 == 1) Du meinst, wenn der zustand nach 10 timertikt nach wie vor der selbe geblieben ist?
Hmm, irgendwie schnall cih das ganze net so ganz.... Das kann doch nicht so kompliziert sein?! Im Prinzip suche ich en verenifachte Version von dem oben geposteten Code von Peter Fleury... Statt 8 Pins reicht mir einer
3-4 mal mit etwas abstand in einer timer isr einlsen und nach einem wechesl bzw. einer flanke 001 oder so ausschauen
8 Taster in C: http://www.mikrocontroller.net/forum/read-4-20549.html#20758 1 Taster in ASM: http://www.mikrocontroller.net/forum/read-4-20549.html#35911 ...
- Ich lassen einen Timer mit T=1ms laufen - in der Interrupt-Service-Routine (ISR) für den Timerüberlauf lasse ich die Variable timertick hochzählen (evtl. bei bestimmten Zählerstand rücksetzen) => timerticks wird alle 1ms um 1 erhöht und meinetwegen beim Typ char bei einem Zählerstand von 219 auf 0 zurückgesetzt if (!(PIND & (1<<PIN0))) key = 1; else key = 0; //key ist eine Hilfsvariable, mit der ich sehe, ob die Taste am PortD gedrückt wurde if ((timerticks % 10 == 1) & (!(PIND & (1<<PIN0))) & (key ==1)) //Wenn der Rest der Division durch 10 = 1 ist (Zählerstand 1,11,21,31...) und die Taste an PortD dauerhaft gedrückt ist, ist die Tasteneingabe gültig (ansonsten wäre key auf 0 zurückgegangen) { //mach etwas bei gültiger Tastenabfrage } else { //mach etwas bei ungültiger Tastenabfrage } Mfg müllo
Moinsen! Manche machen sich das Leben echt schwer... Wenn ich den Tastenzustand ohnehin in einem Timerinterrupt abfrage, dann muss ich einfach nur das Abfrageintervall länger als die maximale Prelldauer machen und fertig ist die Laube.
@Max "* clear corresponding bit in i when key has changed" Ich würd mal sagen, da hat sich Peter Fleury verschrieben. Wie Du ja richtig erkannt hast, wird das Bit gesetzt. Ansonsten hat Dir ja ...HanneS... Lux den original Link gegeben und da sind auch ne Menge Erklärungen dabei. Es dauert nur etwas, diesen langen Thread zu lesen (aber es lohnt sich). Diese 8-Tasten-Routine hat nämlich den Vorteil, daß sie kürzer und schneller als die meisten 1-Tasten Routinen ist. Sie lohnt sich also schon bei nur einer Taste. Und oftmals bleibt es ja nicht bei einer Taste. Man hat also das schöne Gefühl, für die Zukunft vorgesorgt zu haben. Peter
@Baku: Klar kannst du es so einfach machen. Wenn man aber mehrere unterschiedlichen Zeitbasen benötigt und keine freien Timer hat, hilft die Sache mit den timerticks...ansonsten hast du natürlich Recht. mfg müllo
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.