Hallo Community, Kann mir Jemand Bitte einen Tipp dazu geben wie ich folgendes Problem gelöst bekomme: - Ich möchte in meiner main 1 sek. lang (nur Beispiel) überprüfen wie oft mein Button gedrückt wurde. Danach startet entsprechend meinem Timer nach jeder Sekunde ein Interrupt der überprüft ob mein Zähler größer 2. Wenn ja (also Button mind. 2 mal gedrückt) zeigt er dieses durch eine LED an. Den Code unten habe ich soweit geschrieben. Nur haut es irgendwie nicht hin. Meine Button-auslöser werden irgendwie nicht registriert?! ////////////////////////////////////////////////////////////////////// #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> uint8_t x=0; int main (void) { DDRC |= (1 << 5); // Set LED as output PORTC |= (1 << 5); // Toggle the LED off DDRD |= (1 << 2); PORTD |= (0 << 2); TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode TIMSK |= (1 << OCIE1A); // Enable CTC interrupt sei(); // Enable global interrupts OCR1A = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64 TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64 for (;;) { if (!(PIND & 1<<PD2)) // if button pressed x++; } } ISR(TIMER1_COMPA_vect) { if (x >= 2) { PORTC &=~ (1 << 5); // Turn LED on _delay_ms (1000); PORTC |= (1 << 5); // Turn LED off x=0; } } ////////////////////////////////////////////////////////////////////// gruß R.
volatile Danach wirst du dann aber ein anderes Problem haben. So schnell kannst du die Taste nämlich gar nicht drücken und wieder loslassen, dass sich x dabei nur um 1 erhöht.
Klar, weil die ISR(TIMER1_COMPA_vect) die for (;;) Schleife mit ihren Anweisungen in int main (void) durch ihr _delay_ms (1000); vom laufen abhält. Die Programmlogik muss anders aussehen: ISR(TIMER1_COMPA_vect) Zählt einen Zeitvariable hoch. Hauptprogramm: Wenn der erste Tastendruck kommt, merkst du dir die aktuelle Zeitvariable als Startzeit. Dann eine Messschleife solange bis die aktuelle Zeitvariable minus die Startzeit = verstrichene Zeit größergleich deiner Messzeit ist. Innerhalb der Messschleife dann weitere Tastendrücke zählen. Anmerkungen: Die Genauigkeit für die Messzeit hängt u.a. davon ab, wie oft ISR(TIMER1_COMPA_vect) aufgerufen wird. Allerdings hängt davon auch ab, wie groß die Zeitvariable werden kann. Beim Zugriff auf die aktuelle Zeitvariable sind die Themen atomar und volatile aus dem Interrupt Artikel zu beachten. Im fertigen Programm sind keine delay Funktionen mehr nötig. Ein sauberer Tastendruck besteht aus Drücken und Loslassen. Nur die Drückphase abzufragen verfälscht das Ergebnis, wenn die Taste zwischen den Abfragen nicht losgelassen wird. Die sichere Zählung der Tastendrücke setzt voraus, dass du das Thema Entprellung im Code behandelst. Von Peter gibt es Routinen die sich in den Timer einbinden lassen und es gibt reine Softwareroutinen als Makros (anfängerfreundlich)
wow vielen Dank für Eure Denkanstöße!! werde versuchen das mal umzusetzen. das mit dem Delay stimmt natürlich. Der hält ja den ganzen Prozess an. Ich melde mich nochmal wenn ich halbwegs erfoglreich war :O)
Also ich habe mal Tesweise versucht nach 5 sek. eine LED anspringen zu lassen... leider ohne Erfolg. Ich habe einen ATMEGA8. Keine Ahnung was ich da falsch gemacht haben soll?! Rührt sich nix. //////////////////////////////////////////// #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> uint8_t t=0,t_start=0,counter=0,x=0; int main (void) { DDRC |= (1 << 5); // Set LED as output PORTC |= (1 << 5); // Toggle the LED off DDRD |= (1 << 2); PORTD |= (0 << 2); TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode TIMSK |= (1 << OCIE1A); // Enable CTC interrupt sei(); // Enable global interrupts OCR1A = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64 TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64 for(;;) { if ((t-t_start) == 5) // after 5 sec. { PORTC ^= (1 << 5); // toggle LED } } } ISR(TIMER1_COMPA_vect) { t++; // count +1 for every interrupt at 1Hz = seconds } //////////////////////////////////////////// Gruß R.
Wenn Du kurz/lang Drücken erkennen willst, da gibts schon was fertiges: Beitrag "Universelle Tastenabfrage" Peter
r4m0n schrieb:
> Keine Ahnung was ich da falsch gemacht haben soll?! Rührt sich nix.
Und nochmal: volatile!
Wenn du das nicht kennst, dann suche danach und versuche es zu
verstehen. Du wirst nicht ohne auskommen.
Wie Stefan bereits geschrieben hat: volatile Und 8-Bit Überlauf bei der Differenzbildung beachten. Und Startzeit für nächsten Durchlauf zurücksetzen, weil sonst die Aktion (fast) einmalig ist und weil während der Sekunde 5 dauernd getoggelt wird.
Danke an alle Post-Schreiber!!! Werd mich gleichmal mit dem Thema Volatile und dem letzten verbesserten source Code auseinandersetzen. Gruß und besten Dank R.
unglaublich... im Leben wär ich nicht darauf gekommen das es das Volatile ist. nu funzt auch alles. Hatte mich halt immer gewundert wieso die Dinge nicht mehr so sauber klappen sobald ich ne Interrupt im Spiel hab. Für alle die keine Probleme mit dem Englischen (und auch keine mit dem volatile) haben, poste ich hier mal sofern erlaubt einen Link der das Thema ganz gut erklärt. Gruß an Alle volatile geplagten ;O) (hab bestimmt 500mal am code geschraubt ohne das Ding =o) R.
Hallo nochmal an Alle!! Habe gestern mein Programm endlich fertiggestellt und wollte es Euch mal posten. Es funkt einwandfrei. Würd mich interessieren ob die Erfahrenen unter Euch das soweit in Ordnung finden oder ob es noch Verbesserungswürdig ist. µC = Atmega8 at 8.000.000Hz Was macht es: Alle 100ms wird geprüft ob ein Tast-Vorgang stattgefunden hat. Sprich Taste gedrückt und Taste losgelassen müssen mind. einmal in 100ms stattgefunden haben. /////////////////////////////////////////////// #include <avr/io.h> #include <avr/interrupt.h> volatile uint8_t t=0; uint8_t up=0,down=0; void check_delay() // check each 100ms { if (t == 1) { if ((down + up) != 2) // if no toggle between on off on Flowmeter turn LED on as ALARM { PORTC &=~ (1 << PC5); // turn LED on down = 0; up = 0; t=0; } else // at least one toggle in 100ms { PORTC ^= (1 << PC5); down = 0; up = 0; t=0; } } } int main (void) { DDRC |= (1 << PC5); // Set LED as output PORTC |= (1 << PC5); // Toggle the LED off DDRB |= (0 << PB1); PORTB |= (1 << PB1); TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode TIMSK |= (1 << OCIE1A); // Enable CTC interrupt TCCR1B |= (1 << CS12); // Start timer at Fcpu/256 OCR1A = 3124; // Set CTC compare value to 100ms at 8MHz AVR clock, with a prescaler of 256 (1sec. = 31250) sei(); // enable global interrupts / start timer while(1) { if (!(PINB & 1<<PB1)) //if switch down { down = 1; check_delay(); } else if ((PINB & 1<<PB1)) //if switch up { up = 1; check_delay(); } } } ISR(TIMER1_COMPA_vect) { t++; // count +1 for every interrupt at 100ms } /////////////////////////////////////////////// Gruß R.
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.