Forum: Compiler & IDEs Compiler fehlerhaft oder uC ?


von tronic (Gast)


Lesenswert?

Hallo,

wenn ich am Atmega8, die zwei Interrupts eingeschaltet habe,
INT0, INT1 ... scheint es schwierigkeiten zu geben.
Auf dem INT1 hab ich den Clock von der Tastatur, wo
bei jeder fallenden Flanke einen Output-Zustand wechselt.

solange ich folgenden befehl:

GIFR|=(1<<INTF0);

nicht aktiviere, funktioniert es tadellos,
sobald dieser jedoch eingeschaltet ist - entspricht der Output-Zustand
nicht mehr dem des Clocks (nur annähernd).

am INT0 ist die Datenleitung der Tastatur angeschlossen (so
programmiert das auch auf negative Flanke reagiert)

die funktion ISR(INT1_vect)
{} ist aber nicht vorhanden...

interessanterweise, kann ich bei Outputs die immer auf High sind, mit
dem Oszilloskop ein kurzzeitiges low (paar ns) fesstellen. Diese
stimmen genau mit der Datenleitung enthaltende neg. Flanken überrein,
also:

obwohl der externe Interrupt wo die Datenleitung angehängt ist,
aktiviert ist, jedoch keine Funktion hierfür vorgesehen ist. setzt der
Mikrocontroller alle Outputs bei einer negativen Flanke, alle Outputs
kurzfristig auf 0 (paar ns).

wieso das? ist das Hardwarebedingt? wenn ja, ziemlich blöd!

danke für Hilfe
tronic

von Michael U. (Gast)


Lesenswert?

Hallo,

hmmm, ich weiß nicht, ob ich Dich jetzt richtig verstanden habe:

Du gibst die externen Interrupts frei, hast keine ISR im Programm und
wunderst Dich, daß der AVR abstürzt?
Der ATmega erkennt den IRQ, holt die Adresse aus dem Interruptvektor
und springt dahin. Da Du ja keine ISR definiert hast, weiß nur der
Compiler, was da nun drinsteht, mit Sicherheit nichts, was den IRQ
sinnvoll bearbeitet und beendet...

Ich verstehe also den Sinn Deiner Frage nicht so ganz.

Gruß aus Berlin
Michael

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> mit Sicherheit nichts, was den IRQ
> sinnvoll bearbeitet

Doch, der default interrupt vector, und der besteht aus einem
Sprung nach Adresse 0.

von Rolf Magnus (Gast)


Lesenswert?

> obwohl der externe Interrupt wo die Datenleitung angehängt ist,
> aktiviert ist, jedoch keine Funktion hierfür vorgesehen ist.

Wozu aktivierst du ihn, wenn du keine Interrupt-Funktion hast?

von tronic (Gast)


Lesenswert?

"Doch, der default interrupt vector, und der besteht aus einem
Sprung nach Adresse 0."

ok. aber wieso setzt der Mikrocontroller bei diesem Sprung, bzw.
Interrupt, für paar ns die Ausgänge auf 0 - der dürfte laut Code gar
nichts auf null setzen, bzw. da ja keine Funktion für den INterrupt
vorhanden ist, die so irgendwas integriert hätte?

"Wozu aktivierst du ihn, wenn du keine Interrupt-Funktion hast?"

wozu, einfach so ;) ... ich meine ich könnte ja den zweiten externen
Interrupt vielleicht brauchen, wenn aber dadurch nur schon der erste
interrupt nicht ganz korrekt funktioniert, bzw. dadurch irgendwie
unterbrochen wird... ist mir das ein rätsel.

so sieht mein Code aus:

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

void ini();

ISR(INT1_vect) //Clock
{
clk=!clk;
      if(clk)
      {
        PORTB&=~(1<<PB1);
      }
      else
      {
        PORTB|=(1<<PB1);
      }
}

void ini() //Initialisierung
{
DDRD = 0x00; // PortD als Eingang
DDRC = 0xFF; // PortC als Ausgang
DDRB = 0xFF; // PortB als Ausgang

PORTD=0xff; //Pullup aktivieren

MCUCR|=(1<<ISC11); //Fallende Flanke für Data
MCUCR&=~(1<<ISC10);

MCUCR|=(1<<ISC01); //Fallende Flanke für Clock
MCUCR&=~(1<<ISC00);

GIMSK|=(1<<INT1); //Externe Interrupts einschalten

//GIMSK|=(1<<INT0); =>>> sobald dieser aktiviert wird, funktioniert
es nicht mehr korrekt!! bei jeder neg. Flanke am INT0, wird an jedem
Ausgang für paar ns. der Pegel auf 0 gesetzt. komisch?

GIFR|=(1<<INTF1); //Interruptsroutine anspringen ON
GIFR|=(1<<INTF0);
}

int main()
{

ini();
sei();

PORTC=0xFF;
PORTB=0xFF;

  while(1)
  {}


return 0;
}

von tronic (Gast)


Lesenswert?

die variable clk. ist natürlich noch definiert

von johnny.m (Gast)


Lesenswert?

Wie andere oben schon gesagt haben: Du darfst keinen Interrupt
aktivieren, für den Du keinen Handler schreibst! Der Compiler erzeugt
für alle Interrupts, für die kein Handler vorliegt, einen default
Handler, der, wie Jörg schon sagte, aus einem Sprungbefehl zur Adresse
0 besteht. An der Adresse 0 steht der RESET-Vektor. Das heißt, dass
beim Auftreten eines solchen Interrupts der µC geresettet wird. Es ist
völliger Unsinn, einen Interrupt freizugeben, bei dessen Auftreten
nichts definiertes passiert.

von inoffizieller WM-Rahul (Gast)


Lesenswert?

spendiere deinem Programm noch eine INT0-ISR.

von Karl heinz B. (kbucheg)


Lesenswert?

> wenn aber dadurch nur schon der erste interrupt nicht ganz korrekt
> funktioniert

Der funktioniert völlig korrekt.
Das einzige was hier nicht richtig ist, ist dein Program.

Ein freigegebener Interrupt für den es keinen Handler gibt,
ist ein logischer Fehler.

Du gehst von der Annahme aus, dass ein freigegebener Interrupt
für den es keinen Handler gibt, auch nichts bewirkt. Diese
Annahme ist aber falsch. Die Macher von avr-gcc haben sich
entschieden, dass in so einem Fall nicht einfach nur nichts
geschehen soll (wäre auch möglich gewesen), sondern dass
in diesem Fall das Programm (inklusive Initialisierung der
C-Laufzeitumgebung) wieder von vorne anfangen soll.

von johnny.m (Gast)


Lesenswert?

BTW: Was soll das da...
> GIFR|=(1<<INTF1); //Interruptsroutine anspringen ON
...bewirken? Diese Anweisung löscht im Prinzip nur das Interrupt-Flag
INTF1. Wenn Du das Flag löschen willst, um sicherzugehen, dass ein
bereits gesetztes Flag keinen Interrupt auslöst, dann musst Du das Flag
vor der Freigabe des Interrupts löschen. Danach geschieht das
automatisch, wenn die ISR ausgeführt wird.

Abgesehen davon löscht die Anweisung "GIFR|=(1<<INTF1);" nicht nur
INTF1, sondern alle Interrupt-Flags in GIFR! Löschen von
Interrupt-Flags sollte man immer ohne "|" machen, um sicherzugehen,
dass nur die gewünschten Flags gelöscht werden. Also wenn überhaupt,
dann "GIFR = (1<<INTF1);". Der "|="-Operator führt eine
Read-Modify-Write-Operation durch, wobei erst das GIFR in ein
Rechenregister eingelesen, anschließend die ODER-Operation mit der
konstanten Maske "(1<<INTF1)" durchgeführt und zum Schluss das ganze
wieder ins GIFR zurückgeschrieben wird. Dabei werden alle Bits, die
vorher (beim Lesen) "1" waren, mit einer 1 beschrieben, wodurch sie,
da es sich um Interrupt-Flags handelt, gelöscht werden. Da das u.U.
nicht erwünscht ist, sollte man das grundsätzlich ohne "|" schreiben.

von tronic (Gast)


Lesenswert?

uiii hab ich da doch einiges falsch angenommen... dann
also vielen Dank um die Korrekturen.

die Korrektur von jonny, betreff "GIFR|=(1<<INTF1);" habe ich aber
nicht ganz getscheggt...

>>abei werden alle Bits, die
>>vorher (beim Lesen) "1" waren, mit einer 1 beschrieben, wodurch
sie,
>>da es sich um Interrupt-Flags handelt, gelöscht werden.

mit GIFR=(1<<INTF1); ... werden aber doch auch alle Bits gelöscht, und
nur das INTF1 bit gesetzt ... bisher habe ich das so gelernt: mit dem |
Operator kann bitweise gesetzt werden, ohne die anderen Bits zu
verändern..... hm

mit freundlichen Grüssen
tronic

von Karl heinz B. (kbucheg)


Lesenswert?

> mit GIFR=(1<<INTF1); ... werden aber doch auch alle Bits gelöscht,
> und nur das INTF1 bit gesetzt

Ja. Genau das willst du aber auch.

Das erklärt sich dadurch, dass ein Interrupt Flag dadurch gelöscht
wird, dass man eine 1 an die entsprechende Stelle schreibt.

Du möchtest daher nur eine einzige 1 in das GIFR Register schreiben,
nämlich an die INTF1 Position. Alle anderen Bits sollen beim
Schreibzugriff 0 sein, damit sich das Interrupt Flag Bit nicht
verändert.

von Karl heinz B. (kbucheg)


Lesenswert?

Die Interrupt Flag Register verhalten sich in dieser Hinsicht
anders als die normalen Register:

Eine 1 bedeutet: Bit löschen
Eine 0 bedeutet: Bit nicht verändern

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.