www.mikrocontroller.net

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


Autor: r4m0n (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: r4m0n (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: r4m0n (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

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

Beitrag "Universelle Tastenabfrage"


Peter

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: r4m0n (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: r4m0n (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: r4m0n (Gast)
Datum:

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

Autor: r4m0n (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.