Atmega16 Interrupt kruzzeitig deaktiveren

#763599
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
#763621
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
Persönliche Seite #763706
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.
#763707
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
#763709
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
#763798
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

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
#include <util/delay.h>
5
#include "lcd.h"
6

7
unsigned char counter;
8

9

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

16
  char buffer[10];
17
  counter++;
18
  itoa(counter, buffer, 10 );
19
  set_cursor(0,1);
20
  lcd_string(buffer);
21
}
22

23
ISR(TIMER1_COMPA_vect)
24
{
25
  if(!(GICR & 0x40))
26
  {
27
    GICR |= 0x40;  // INT0 aktivieren
28
    GIFR = 0x40;   // INT0 löschen
29
  }
30
}
31

32
ISR(TIMER1_OVF_vect)
33
{
34
  //auf Overflow reagieren
35
  // LED hier togglen!
36
}
37

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

48
  sei();
49

50
  lcd_init();
51
  set_cursor(0,2);
52
  lcd_string("Hello World!");
53
  while(1) {
54
  }
55
}

Mfg
Falk

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