Forum: Compiler & IDEs 2x mal Button soll interrupt auslösen hilfe :/


von r4m0n (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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)

von r4m0n (Gast)


Lesenswert?

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)

von r4m0n (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Wenn Du kurz/lang Drücken erkennen willst, da gibts schon was fertiges:

Beitrag "Universelle Tastenabfrage"


Peter

von Stefan E. (sternst)


Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von r4m0n (Gast)


Lesenswert?

Danke an alle Post-Schreiber!!!

Werd mich gleichmal mit dem Thema Volatile und dem letzten verbesserten 
source Code auseinandersetzen.

Gruß und besten Dank
R.

von r4m0n (Gast)


Lesenswert?

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.

von r4m0n (Gast)


Lesenswert?

ops ... in der Eile den Link vergessen :O)
http://www.embedded.com/story/OEG20010615S0107

von r4m0n (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.