mikrocontroller.net

Forum: Compiler & IDEs Delay in Interrupt - routine


Autor: Fabian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
HI

Mein Interrupt 0 ist durch ein Taster gesteuert.

Ich möchte die variable "press" inkrementieren, wenn der Taster nur
kurz gedrückt ist.

Wenn der Taster jedoch 2sec  lang gedrückt wurde, soll auf dem Port C
(LED's) 0xAA ausgegeben werden!

Nun mein Problem:
Ich simuliere das Programm im AVR Studio und die while Schlaufe
funktioniert nur, wenn ich darin kein Delay aufrufe!
Wieso ist das so?

THANKS




SIGNAL(SIG_INTERRUPT0)
{
  unsigned char s;

  _delay_loop_2(60000);                   //entprellen
  _delay_loop_2(60000);
  _delay_loop_2(20000);

  TIMSK = (0<<TOIE0);                     //Timer0 abschalten
  do
  {
    _delay_loop_2(10000);           // 10ms Delay
    int_flag = bit_is_set(PIND,3);
    PORTC = int_flag;
    s++;
  }
  while ( (int_flag >= 1) && (s <= 200) );

  if (s >= 200)
  {
    PORTC = 0xAA;
  }
  else
  {
    press++;
    address = press * 1000;
    if (press >= 15) press = 0;
    PORTC = ~press;
    TIMSK = (0<<TOIE0);
  }
  GIFR = (1<<INTF0);
}

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interruptroutinen macht man so kurz wie möglich.  Delays verbieten
sich damit automatisch.

Benutze einen Timer dafür, den Du aus dem Interrupt nur anschiebst
bzw. Software-Timer.

Autor: Fabian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also die ersten Delay's (140ms) sind Warteroutinen, damit der Taster
entprellt ist...

Danach wird im "normal" - Betrieb des Tasters nur noch ein 10ms Delay
dazu addiert! also 150ms! (ansonsten prellt mein Taster)

Wenn dann aber der Taster 2sec lange gedrückt wird, soll mein uC in den
Sleep Modus (OFF) versetzt werden!

Sollte man das wirklich nicht mit Delays machen?


(Ich glaube es liegt daran, dass ich eine Variable (s) in der ISR
definiert habe!

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, man sollte das wirklich nicht mit delays machen.

Laß einen Timer z. B. alle 10 ms ticken, dort kannst Du das
dranhängen.  Damit lassen sich dann beliebige Vielfache von 10 ms als
Verzögerungen realisieren, auch die Entprellung selbst.

Ich habe sowas auch schon gemacht, allerdings ist das Projekt nie
wirklich fertig geworden (daher mag ich es nicht veröffentlichen).
Aber genau diese Aufgabe, unterschiedliche Funktionalität je nachdem,
ob Taster kurz oder lange gedrückt, habe ich damit realisiert.

Autor: Fabian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also sollte ich in der INT0 Routine nur ein Flag setzen und alles andere
im Hauptprogramm machen???

Hmm... werde es mal versuchen!

Vielen Dank noch...

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genau so.
Also Timer-IRQ kurz genug. Dann Taste bei jedem IRQ prüfen, bei
gedrückter Taste Flag setzen. Bei jedem folgenden IRQ Zähler
hochzählen.
Falls Taste nicht mehr gedrückt, wenn der Zähler kleiner als die
Prellzeit ist, Flag löschen.
Ansonsten weiterzählen und weiterprüfen. Wenn dann die Taste wieder
losgelassen wird, Zähler überprüfen und wenn kleiner 2s dann Flag für
einfachen Tastendruck setzen oder aber für 2s-Tastendruck.

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eins nur noch: es empfiehlt sich, einen externen Interrupt innerhalb
der Interruptroutine als allererstes mal abzuschalten, ansonsten
bekommst Du aufgrund des Tastenprellens X Stück davon ausgeliefert.
Erst nach Ablauf der Entprellzeit schaltest Du ihn dann wieder zu.

Ggf. kann man ihn dann auch ,negiert' zuschalten und das Ganze
herumdrehen, dann bekommst Du ein Ereignis geliefert, wenn der Nutzer
die Taste wieder losläßt (und mußt danach natürlich die Negation
wieder negieren ;-).

Aber das Prinzip ist richtig, in der Interruptroutine macht man nur
das, was wirklich zeitkritisch ist, für den Rest setzt man ein Flag
und macht es später in der Hauptschleife (`volatile' nicht
vergessen!).

Autor: Fabian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal vielen vielen Dank für die vielen Ideen.

So wie ich das jetzt verstehe, muss ich in der Interruptroutine
folgendes machen:


1. Interrupt ausschalten
2. Taster_flag = 1
3. entprellzeit abwarten (delay) -> wie lange ist das üblicherweise?
4. Interrupt wieder einschalten


In der Timer routine mache ich folgendes:


1. zähler inkrementieren
2. Taster - Pin einlesen
3. Timer zurückstellen


Im Hauptprogramm

Endlosschlaufe, die verlassen wird, wenn der Taster losgelassen wird,
oder der Zähler auf dem Endwert ist...


Funktioniert das so? -> Vorallem das Entprellen würde mich wunder
nehmen, denn jetzt habe ich ja wieder ein Delay in der ISR.

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde den externen IRQ gar nicht nutzen. Port einfach per IO
abfragen. In der Timer-IRQ, und dann jeden Durchlauf abfragen.
Und in der Hauptschleife den MC in den idle-Mode schicken, wird durch
die timer-IRQs jeweils aufgeweckt und falls dann ein Flag gesetzt
wurde, dann wird die entsprechende Routine aufgerufen.

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Externen Interrupt kann man schon nehmen, aber eben nicht dort warten.

Ungefähr so:

Timer-Interrupt tickt alle 10 ms und sieht nach, was alles an
Aufträgen da ist.  Diese werden abgearbeitet.  (Bei mir in einer
verketteten Liste, aber das ist ziemlich aufwendig und braucht
außerdem malloc().)

Externer Interrupt läuft ein, klemmt sich erstmal ab, und gibt einen
Auftrag für den Timerinterrupt nach 20 ms (was effektiv heißt,
irgendwas zwischen 10 und 20 ms) auf.

Der Timer-Auftrag prüft, ob die Taste wirklich noch gedrückt ist.
Wenn nicht -> alles Spaß, zurück über "Los!".  Wenn ja: registrieren
des negierten Interrupts (Loslassen der Taste), neuer Zeitgeberauftrag
um festzustellen, ob die Taste lange gedrückt worden ist.

Je nachdem, ob nun zuerst das Ereignis "Taste losgelassen" oder
"langer Zeitgeber" eintrifft, werden die weiteren Aktionen ausgelöst.

Autor: F___ (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also das mit dem negierten Interrupt pack ich nicht ganz?

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> also das mit dem negierten Interrupt pack ich nicht ganz?

Wie ich oben schon mal schrob: Du registrierst den Interrupt auf der
jeweils entgegengesetzten Flanke.  Wenn also anfangs die H->L Flanke
den Interrupt ausgelöst hat (Taster gegen Masse), dann regisrierst Du
danach (nach Ablauf der Entprellzeit) einen, der auf die L->H Flanke
reagiert, damit bekommst Du ein Ereignis gemeldet, wenn der Taster
wieder losgelassen wird.

Autor: Tipper (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg Wunsch:

Ich verfolge diesen Thread sehr aufmerksam, da es für mich einiges zu
lernen gibt. In einen obigen Beitrag hast Du geschrieben: 'volatile
nicht vergessen'. Kannst Du das bitte genauer erklären?

Besten Dank  Tipper

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
FAQ #1 lesen.

Kurz:

volatile struct {
  intbit_0: 1;
  intbit_1: 1;
  /* ... */
} intbits;

SIGNAL(SIG_FOO)
{
  /* ... */
  intbits.intbit_0 = 1;
}

...
int
main(void)
{
  ...
  for (;;) {
    if (intbits.intbit_0) {
      intbits.intbit_0 = 0;
      /* handle interrupt here */
    }
  }
}

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich staune immer wieder, wie aufwendig und fehleranfällig Leute eine
Tastenentprellung und Abfrage hinkriegen, nur weil sie unbedingt den
völlig ungeeigneten externen Interrupt verwenden wollen.

Am sichersten und einfachsten ist und bleibt doch der Timerinterrupt:

http://www.mikrocontroller.net/forum/read-4-20549.html


Peter

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sehe ich genauso wie Peter.

Wer seine Tasten im Timer-IR abfragt (alle 10 - 20ms), wird die
Probleme  mit Tastenprellen bald nicht mehr verstehen können.

Tasten an IR-Eingängen machen für mich dann Sinn, wenn mit diesen
Tasten die CPU aus dem Sleep geweckt werden soll.

Stefan

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sag ich doch ;)

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, wollte natürlcih schreiben:

"Sehe ich genauso wie Peter und Michael" :-)))

Stefan

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.