Forum: Mikrocontroller und Digitale Elektronik Interruptprobleme beim ATMEGA32


von Sebastian (Gast)


Lesenswert?

Hallo @ all

Ich benutze den µC ATMEGA32. Ich habe ein kleines Programm geschrieben, 
das eine Interruptserviceroutine abarbeiten soll. Jedoch wird der 
Interrupt schon ausgelöst, obwohl keiner anliegt.

Problem:

Ich schalte die Powerversorgung an. Der µC initialisiert sich wartet 
anschließend 3 Sekunden und aktiviert das globale Interruptflag mit dem 
Befehl "sei". Anschließend soll mit der Abarbeitung des Hauptprogramms 
begonnen werden. Dies ist jedoch nicht der Fall. Der µC springt nach der 
Aktivierung des globalen Interruptflags sofort in die 
Interruptserviceroutine. Dies kann ich erkennen, da die 
Interruptserviceroutine "Interrupt" auf ein Zweizeihlendisplay schreibt. 
Nachdem er den Interrupt verarbeit hat springt der µC zurück ins 
Hauptprogramm. Das Hauptprogramm gibt auf dem Display "Hauptprogramm" 
aus. Der Interrupt wird nur einmalig ausgeführt.

Ich habe meine Interrupts wie folgt konfiguriert:

1. nur der externe INT0 so an sein  --> GICR |=0x40;
2. der Interrupt soll nur bei einer fallenden Flanke ausgeführt werden 
--> MCUCR=0x40;
3.MCUCSR=0x00; --> weiß nicht was MCUCSR macht
4.GIFR=0x40; --> Interruptflag vom externen INT0 setzen --> ich denke 
das hier der Fehler ist und ein Interrupt ausgelöst wird. Jedoch habe 
ich diesen Wert schon auf 0x00 gesetzt und der Interrupt wird trotzdem 
ausgelöst.

Ich habe am INT0 Port des µC nachgemessen. Dieser ist kontinuierlich 
logisch 1. Kann es vielleicht sein das beim Einschalten des System ein 
Flankenwechsel erzeugt wird, den der µC sich merkt? Anschließend beim 
aktivieren der Interrups wird dieser dann ausgelöst.

Ich hoffe jemand kann mir weiterhelfen, sitze schon 2 Tage an diesem 
Problem

Grüsse

Sebastian

von Andrew (Gast)


Lesenswert?

Ein geposteter Codeabschnitt sagt mehr als 1000 erklärende Worte!

von Sebastian (Gast)


Lesenswert?

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
   // go on the first LCD line
   lcd_gotoxy(0,0);

   // display the message
   lcd_clear();
   lcd_putsf("INTERRUPT");
   delay_ms(3000);
}


void main(void)
{
   // Declare your local variables here
   unsigned long int  status;

   status = START;

   // Input/Output Ports initialization
// Port A initialization
// Declare your local variables here
  PORTA=0x00;
  DDRA=0xFF;  // PORTA ist Ausgang

// Port B initialization
// Func7=Out Func6=In Func5=Out Func4=Out Func3=In Func2=In Func1=Out 
Func0=Out
// State7=0 State6=T State5=0 State4=0 State3=T State2=T State1=0 
State0=1
   PORTB=0x01;
   DDRB=0xB3;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In 
Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T 
State0=T
   PORTC=0x00;
   DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In 
Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T 
State0=T
   PORTD=0x00;
   DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
   TCCR0=0x00;
   TCNT0=0x00;
   OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
   TCCR1A=0x00;
   TCCR1B=0x00;
   TCNT1H=0x00;
   TCNT1L=0x00;
   ICR1H=0x00;
   ICR1L=0x00;
   OCR1AH=0x00;
   OCR1AL=0x00;
   OCR1BH=0x00;
   OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
   ASSR=0x00;
   TCCR2=0x00;
   TCNT2=0x00;
   OCR2=0x00;


// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: Off
// INT2: Off
   GICR|=0x40;
   MCUCR=0x02;
   MCUCSR=0x00;
   GIFR=0x40;


// Timer(s)/Counter(s) Interrupt(s) initialization
   TIMSK=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
   ACSR=0x80;
   SFIOR=0x00;

   PORTB.0 = 1;  //FPGA RESET aktivieren

   // LCD module initialization
  lcd_init(20);
  lcd_clear();

  delay_ms(2000);

  PORTB.0 = 0; // FPGA RESET deaktivieren




   while (1)
   {

      // globale Interrupts deaktivieren
      #asm("cli")

      if(status == START)
      {
         lcd_clear();
         lcd_putsf("Hauptprogramm");
         //delay_ms(3000);
      }


      //globale Interrupts aktivieren
      #asm("sei")
      delay_ms(1000);

   };
}

von Sebastian (Gast)


Lesenswert?

Was macht GIFR=0x40;

Löse ich damit einen Interrupt aus?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian wrote:
> Was macht GIFR=0x40;
>
> Löse ich damit einen Interrupt aus?

Nein. Das löscht das Flag, das anzeigt, dass ein
Interrupt auf seine Abarbeitung wartet.

Mach vor dem sei() noch mal ein

  GIFR = 0x40;


Das ist das Problem mit diesen Wizards. Kein Mensch liest
mehr Datenblätter und sieht nach, was die vom Wizard
vorgeschlagenen Einstellungen eigentlich bewirken.

Hol dir von Atmel das Datenblatt zum Prozessor und lies
nach was die einzelnen Flags tatsächlich bewirken anstatt
2 Tage mit einem Code der nicht so funktioniert wie du dir
das vorstellst zu verplempern.

von Johannes M. (johnny-m)


Lesenswert?

Sebastian wrote:
> Was macht GIFR=0x40;
>
> Löse ich damit einen Interrupt aus?
Nein, Interrupts kann man nicht per Software auslösen. Damit wird nur 
das Flag vom INT0 gelöscht. Da Du ziemlich viele und lange Delays drin 
hast, ist die Wahrscheinlichkeit recht groß, dass nach dem Löschen des 
Flags dieses wieder gesetzt wird. Und das wiederum führt dann zu einem 
Aufruf des Handlers, sobald das I-Bit gesetzt wird.

von Sebastian (Gast)


Lesenswert?

Für mich heist GIFR=0x40; schreibe in Register GIFR den Wert 0x40. 
Demnach sollte nur das 7.Bit gesetzt sein.

Ich habe das Datenblatt durchgelesen dort steht folgendes:

When an edge or logic change on the INT0 pin triggers an interrupt 
regquest, INTF0 becomes set (one). If the I-bit in SREG and the INT0 bit 
in GICR are set(one), the MCU will jump to the corresponding interrupt 
vector. The flag is cleared when the interrupt routine is executed. 
Alternatively, the flag can be cleared by writing a logical one to it. 
This flag is always cleared when INT0 is configured as a level 
interrupt.

Das verstehe ich nicht ganz. In der ersten Zeile wird geschriben, das 
der Zustand des Flags 1 ist, wenn ein Interrupt ausgelöst wurde. Unten 
steht wenn ich das Flag löschen will muss ich eine 1 ins Register 
schreiben. Kann mir das vielleicht einer genauer erklären

von Johannes M. (johnny-m)


Lesenswert?

Das ist genau so wie es da steht: Wenn das Flag gesetzt ist, ist es "1", 
d.h., wenn Du das Flagregister liest, bekommst Du jedes gesetzte Flag 
als "1" ausgegeben, während nicht gesetzte Flags "0" sind. Um ein Flag 
zu löschen, muss man eine "1" hineinschreiben, was mit der internen 
Logik dazu führt, dass das Flag gelöscht wird. Das Schreiben einer "0" 
hat bei Interrupt-Flags keinen Effekt. Wie oben schon gesagt: Ein 
Interrupt-Flag kann nur von der dazugehörigen Hardware gesetzt werden. 
Softwaremäßig kann man es nur löschen.

EDIT:
...Und das ganze hat zur Folge, dass man Register, die nur 
Interrupt-Flags enthalten (wie z.B. GIFR) nicht mit 
Read-Modify-Write-Operationen beschreibt (z.B. "|="), sondern direkt mit 
einer Zuweisung. Ein Read-Modify-Write-Zugriff hätte zur Folge, dass 
alle gesetzten Flags gelöscht werden, da sie ja beim Einlesen "1" sind 
und ebenso als "1" zurückgeschrieben werden. Da das Schreiben einer "0" 
aber eh keinen Effekt hat, kann man auch direkt "=" schreiben.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Johannes M. wrote:
> Nein, Interrupts kann man nicht per Software auslösen. Damit wird nur

Man kann (wenn ich mich recht erinnere) einen PINCHANGE Interupt beim 
AVR per Software auslösen...

von Johannes M. (johnny-m)


Lesenswert?

Läubi Mail@laeubi.de wrote:
> Johannes M. wrote:
>> Nein, Interrupts kann man nicht per Software auslösen. Damit wird nur
>
> Man kann (wenn ich mich recht erinnere) einen PINCHANGE Interupt beim
> AVR per Software auslösen...
Man kann auch einen "normalen" externen Interrupt aus dem Programm 
heraus auslösen, wenn man den betreffenden Portpin als Ausgang 
konfiguriert und über das PORTx-Register eine entsprechende Flanke 
erzeugt. Allerdings wird auch dabei das Flag von der Hardware gesetzt 
und nicht direkt durch das Programm! Und meine Aussage oben bezog sich 
auf die Frage, ob durch "setzen" des Bits im GIFR ein Interrupt 
ausgelöst wird. Und das ist nicht der Fall.

von Sebastian (Gast)


Lesenswert?

Komisch ist es aber trotzdem. Wenn ein Interrupt ausgelöst wird, dann 
wird das Flag gesetzt. Wenn ich jedoch eine 1 zuweise wird das Flag 
gelöscht.

Dann werde ich mir einfach merken, dass ich das Interruptflag per 
GIFR=0x40; lösche.

Noch mal vielen Dank an alle

von Johannes M. (johnny-m)


Lesenswert?

Das ist eben durch die interne Logik (oder Unlogik?) bei den 
AVR-Controllern so geregelt und gilt eben nur für Interrupt-Flags.

von Sebastian (Gast)


Lesenswert?

Kann das sein, wenn der INT0 aktiviert ist, jedoch das global 
Interruptflag deaktiviert ist, das trotzdem Interrupts erkannt, jedoch 
nicht sofort ausgeführt werden. Erst wenn das global Interruptflag 
gesetzt wird, wird der gespeichert Interrupt ausgeführt.

von Johannes M. (johnny-m)


Lesenswert?

Alle Freigaben von Interrupts beziehen sich NUR auf die BEARBEITUNG 
der Ereignisse. Die Flags werden IMMER gesetzt, wenn das betreffende 
Hardware-Ereignis eintritt, auch dann, wenn die Bearbeitung des 
Interrupts (global durch das I-Bit im SREG und/oder lokal durch das 
entsprechende Interrupt-Enable-Bit) nicht freigegeben ist. Deshalb ist 
es auch in vielen Fällen sinnvoll (besonders bei externen Interrupts), 
vor der Freigabe das betreffende Flag zu löschen, was der schlaue Wizard 
von CodeVision durch eben das "GIFR = 0x40;" macht. Ist das Flag bei der 
Freigabe bereits gesetzt, wird es natürlich sofort bearbeitet 
(vorausgesetzt, es stehen keine weiteren Interrupts mit niedrigeren 
Vektoradressen und dementsprechend höherer Verarbeitungs-"Priorität" 
an).

Du solltest Dir aber wirklich mal die entsprechenden Abschnitte im 
Tutorial durchlesen. Es macht keinen Sinn, alles, was irgendwo schon 
steht, hundertmal neu zu schreiben...

von Sebastian (Gast)


Lesenswert?

Vielen Danke hat mir sehr geholfen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.