mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interruptprobleme beim ATMEGA32


Autor: Sebastian (Gast)
Datum:

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

Autor: Andrew (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein geposteter Codeabschnitt sagt mehr als 1000 erklärende Worte!

Autor: Sebastian (Gast)
Datum:

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

   };
}

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was macht GIFR=0x40;

Löse ich damit einen Interrupt aus?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Sebastian (Gast)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Sebastian (Gast)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Sebastian (Gast)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Danke hat mir sehr geholfen

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.