www.mikrocontroller.net

Forum: Compiler & IDEs Atmega16 Interrupt kruzzeitig deaktiveren


Autor: Benedikt Dietrich (metalhead)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich habe folgendes Problem: ich möchte den externen Interrupt kurzzeitig 
nach dessen Auslösen deaktivieren und nach einer bestimmten Zeit mittels 
eines Compare-Interrupts wieder deaktivieren. Sitzt schon ewig dran und 
versteh einfach nicht was da falsch läuft. Hier mal der Quellcode kurz 
und knapp:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>
#include "lcd.h"

unsigned char counter;


ISR(INT0_vect)
{
  cli();
  TCNT1H = 0x00;      //Timer zurücksetzen
  TCNT1L = 0x00;


  OCR1AH = 0x05;  //Compare nach ca 50ms
  OCR1AL = 0xDC;


  GICR &= ~(0x40); //INT0 deaktivieren

  sei();

  char buffer[10];
  counter++;
  itoa(counter, buffer, 10 );
  set_cursor(0,1);
  lcd_string(buffer);

}

ISR(TIMER1_COMPA_vect)
{
  if(!(GICR | 0x40))
  {
    cli();
    GIFR = 0x40;
    GICR |= 0x40; //INT0 aktivieren
    sei();
  }
}

ISR(TIMER1_OVF_vect)
{
  //auf Overflow reagieren
}

int main(void)
{
  cli();

  GIFR = 0x40;
  GICR |= 0x40;  //INT0 aktivieren
  MCUCR = 0x0f;  //auf steigende Flanken reagieren

  OCR1AH = 0x05;  //Compare nach ca 50ms
  OCR1AL = 0xDC;  //bei Taktung von 1MHz/64
  TIMSK |= 0x04;  //Overflow-Int aktivieren
  TCCR1A = 0x00;  //Steigende Flanken, kein clear bei Compare-Match
  TCCR1B = 0x03;  //Prescaler mit 64; Timer starten



  sei();

    lcd_init();

    set_cursor(0,2);

    lcd_string("Hello World!");

    while(1)
    {

    }

    return 0;
}

Der Controller reagiert brav auf den ersten Interrupt, wird aber nach 
einer gewissen Zeit noch einer angelegt, passiert gar nichts mehr ...
Jemand eine Idee, was da schief läuft ?

Grüße Beni

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Benedikt Dietrich (metalhead)

>ISR(INT0_vect)
>{
>  cli();

Ist Unsinn, in einer ISR sind die Interrupts automatisch ausgeschaltet.

>  sei();

Hat in einer ISR nix zu suchen (jaja, es gint Ausnahmen, aber nicht in 
diesem Fall)

>ISR(TIMER1_COMPA_vect)
>{
>  if(!(GICR | 0x40))
>  {
>    cli();
>    GIFR = 0x40;
>    GICR |= 0x40; //INT0 aktivieren
>    sei();

Das selbe hier, kein cli() und sei(), ist sinnlos und gefährlich.


>int main(void)
>{
>  cli();

Hat du Paranoia? Beim Start von main() sind die Interrupts inaktiv.

>Der Controller reagiert brav auf den ersten Interrupt, wird aber nach
>einer gewissen Zeit noch einer angelegt, passiert gar nichts mehr ...
>Jemand eine Idee, was da schief läuft ?

>ISR(TIMER1_COMPA_vect)
>{
>  if(!(GICR | 0x40))

Das muss so heissen

>  if(!(GICR & 0x40))

Siehe Bitmanipulation.

MFG
Falk

Autor: Benedikt Dietrich (metalhead)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antwort. Die Paranoia haben mich überfallen nachdem es 
nach ewigem Suchen nicht ging.

Der Fehler bei der Bitmanipulation ist peinlich, aber ändert nichts in 
diesem Fall. Das Ganze funktioniert nach wie vor nicht :-( Der Interrupt 
wird nur einmal ausgelöst

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Benedikt Dietrich wrote:
> Der Interrupt
> wird nur einmal ausgelöst

Kein Wunder, wenn du diese Zeile in der Interruptroutine (in beiden) 
hast:

 GICR &= ~(0x40); //INT0 deaktivieren

Anmerkung:

Diesen aufwändigen Kram

  char buffer[10];
  counter++;
  itoa(counter, buffer, 10 );
  set_cursor(0,1);
  lcd_string(buffer);

macht man nicht im Interrupthandler sondern im Hauptprogramm. Im 
Interrupthandler schafft man nru die Daten zur Seite auf die das 
Hauptprogramm (oder eine vom Hauotprogramm aufgerufene Funktion) 
auswertet und weiterverarbeitet.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Benedikt Dietrich (metalhead)

>Der Fehler bei der Bitmanipulation ist peinlich, aber ändert nichts in
>iesem Fall. Das Ganze funktioniert nach wie vor nicht :-( Der Interrupt
>wird nur einmal ausgelöst

Nimm mla die Deaktivierung aus der ISR und prüfe, ob dann die ISR 
mehrfach ausgelöst wird.

MfG
Falk

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Stefan "stefb" B. (stefan) Benutzerseite

>Kein Wunder, wenn du diese Zeile in der Interruptroutine (in beiden)
>hast:

> GICR &= ~(0x40); //INT0 deaktivieren

Augen auf beim Eierkauf. Er hat das schon richtig.

>ISR(TIMER1_COMPA_vect)
>{
>  if(!(GICR | 0x40))
>  {
>    cli();
>    GIFR = 0x40;
>    GICR |= 0x40; //INT0 aktivieren

ODER, nicht UND.

>    sei();
>  }
>}

MfG
Falk

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich seh's, sorry!

INT0 kommt => INT0 deaktivieren + Timer Countdown auf 50ms => Timer 
kommt => INT0 scharf machen (# s.u.) => INT0 kommt => ...

#)

  if(!(GICR | 0x40))

ist falsch

  if(!(GICR & 0x40))

ist richtig

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dumme Frage. Wie Erzeugst du denn deinen exteren Interrupt? Mit einem 
taster nach Masse? Hast du da auch einen Pull-Up am Pin?

MFg
Falk

Autor: Benedikt Dietrich (metalhead)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ohne die Deaktivierung wird der Interrupt ohne Probleme öfters 
aufgerufen.
Der INT0 wird mit nem 10k Widerstand nach GND gezogen. Den Interrupt 
erzeuge ich mit nem Reed-Kontakt, der dann INT0 auf 5V zieht, wenn er 
durchschaltet

Grüße Beni

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lass mal in

ISR(TIMER1_OVF_vect)

Eine LED togglen. Dann sieht man, ob der Timer evt. nicht läuft.

Mal dein code aufgeräumt

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>
#include "lcd.h"

unsigned char counter;


ISR(INT0_vect)
{
  TCNT1 = 0x00;      //Timer zurücksetzen
  OCR1A = 0x05DC;  //Compare nach ca 50ms
  GICR &= ~(0x40); //INT0 deaktivieren

  char buffer[10];
  counter++;
  itoa(counter, buffer, 10 );
  set_cursor(0,1);
  lcd_string(buffer);
}

ISR(TIMER1_COMPA_vect)
{
  if(!(GICR & 0x40))
  {
    GICR |= 0x40;  // INT0 aktivieren
    GIFR = 0x40;   // INT0 löschen
  }
}

ISR(TIMER1_OVF_vect)
{
  //auf Overflow reagieren
  // LED hier togglen!
}

int main(void)
{
  MCUCR = 0x0f;  //auf steigende Flanken reagieren
  GICR  |= 0x40;  //INT0 aktivieren
  GIFR   = 0x40;
  OCR1A  = 0x05DC;  //Compare nach ca 50ms
  TIMSK |= 0x04;  //Overflow-Int aktivieren
  TCCR1A = 0x00;  //Steigende Flanken, kein clear bei Compare-Match
  TCCR1B = 0x03;  //Prescaler mit 64; Timer starten

  sei();

  lcd_init();
  set_cursor(0,2);
  lcd_string("Hello World!");
  while(1) {
  }
}

Mfg
Falk

Autor: Benedikt Dietrich (metalhead)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gute Idee Falko!

Jetzt weiss ich dass der Timer läuft (hab mit nem Overflow das Lämpchen 
erlöschen lassen), aber die Compare-Match ISR wird nicht angesprungen. 
Mal schaun was das Datenblatt sagt...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein 'O' zuviel. Naja ;-)

Autor: Benedikt Dietrich (metalhead)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ich hab des Rätsels Lösung: habe vergessen im TIMSK das Bit 4 – 
OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable - zu 
setzen ... doofer Fehler :-)

Danke für die Hilfe Falko - o und 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.