2x mal Button soll interrupt auslösen hilfe :/

Gast #1652645
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.
Persönliche Seite #1652662
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)
Gast #1652705
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)
Gast #1652879
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.
Gast #1653354
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.
Gast #1656560
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren