www.mikrocontroller.net

Forum: Compiler & IDEs Interruptroutine funktioniert nicht richtig


Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir jemand sagen warum dieser Code nicht funktioniert ?
Auf die Zeile -> while (bit_is_clear(PIND,PD2)); reagiert der Mega8 
nicht.
Es kommt jedesmal zum Überlauf in der Pausenroutine -> zähler ist dann 
10008

Die Routine soll 8 Bits an INT0 auswerten.
1 = 100us/300us Puls/Pause
0 = 300us/300us Puls/Pause
void Empfang_Bit(void)
{
  zaehler=0;
  status=1;
  do
    {
    zaehler++;
    if (zaehler > 10005) 
      {
        status=0;
        break;
      }
    }
  while (bit_is_set(PIND,PD2));
  if (zaehler<3000) 
   {
     rxbyte=rxbyte*2;
    rxbyte=rxbyte+1;
   }
   else
   {
     rxbyte=rxbyte*2;
   }
}

void Empfang_Pause(void)
{
  zaehler=0;
  status=1;
  do
    {
    zaehler++;
    if (zaehler > 10007) 
      {
        status=0;
        break;
      }
    }
  while (bit_is_clear(PIND,PD2));
}

ISR(INT0_vect) //Interruptroutine steigende Flanke an INT0
{
  uint8_t bitcnt;
  rxbyte = 0;
  Empfang_Bit();
  if (status==0) {rxbyte=0;return;}
  for (bitcnt=1;bitcnt<7;bitcnt++)
    {
    Empfang_Pause();
    if (status==0) {rxbyte=0;return;}
    Empfang_Bit();
    if (status==0) {rxbyte=0;return;}
    }

}

Gruß

Günter

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenter B. schrieb:

> Es kommt jedesmal zum Überlauf in der Pausenroutine -> zähler ist dann
> 10008

Wie stellst du das fest? Oder besser: wo? Ich vermute, dass du eine 
entsprechende Abfrage im main-Code hast.
Es gibt dann zwei Dinge:
1) Sind die beteiligten Variablen volatile deklariert?
2) Ist dir bewusst, dass nach dem Empfang der 8 Bits die ISR sofort 
wieder ausgeführt wird, und versucht weitere 8 Bits zu empfangen?

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:

> Wie stellst du das fest? Oder besser: wo? Ich vermute, dass du eine
> entsprechende Abfrage im main-Code hast.
Ja ich habe dort eine LCD-Ausgabe.

> Es gibt dann zwei Dinge:
> 1) Sind die beteiligten Variablen volatile deklariert?
Die Variablen habe ich gleich zu Beginn noch vor der Main-Routine als 
volatile deklariert.

> 2) Ist dir bewusst, dass nach dem Empfang der 8 Bits die ISR sofort
> wieder ausgeführt wird, und versucht weitere 8 Bits zu empfangen?
Ich habe mal drüber nachgedacht und zu Beginn der ISR CLI() und am Ende 
SEI()
gestzt, aber das mach der AVR ja eigentlich eh automatisch. Wie kann ich 
es sonst verhindern ?

Zumindest müste ja ein Byte ordentlich eingelesen werden.
Mit DDRD=0x00 habe ich PortD als Eingang deklariert.
Oder kann man den Pin nicht als INT0 deklarieren und gleichzeitig in der 
Routine seinen Status überprüfen ?

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenter B. schrieb:

>> Es gibt dann zwei Dinge:
>> 1) Sind die beteiligten Variablen volatile deklariert?
> Die Variablen habe ich gleich zu Beginn noch vor der Main-Routine als
> volatile deklariert.

mur einzelne Code-Fragmente posten ist zu 99% eine schlechte Idee...

>> 2) Ist dir bewusst, dass nach dem Empfang der 8 Bits die ISR sofort
>> wieder ausgeführt wird, und versucht weitere 8 Bits zu empfangen?
> Ich habe mal drüber nachgedacht und zu Beginn der ISR CLI() und am Ende
> SEI()
> gestzt, aber das mach der AVR ja eigentlich eh automatisch. Wie kann ich
> es sonst verhindern ?

afaik:
cli() wird schon gemacht, allerdings wird die nächste Flanke am INT 
trotzdem das entsprechende Bit INTF0 in GIFR setzen (es wird nur nicht 
zum Anfang der ISR gesprungen, weil eben cli() ), welches dann nach dem 
automatischen sei() am Ende der ISR den nächsten Interrupt auslöst. 
Versuch mal, das entsprechende Bit am Ende der ISR zu löschen...

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Justus Skorps schrieb:

> mur einzelne Code-Fragmente posten ist zu 99% eine schlechte Idee...

Hast recht.

Bin allerdings gerade unterwegs und habe den Code nicht vorliegen.

Der Rest des Programmes besteht momentan nur aus der Deklaration:

INT0 bei steigender Flanke
DDRD=0*00

und der Main-Routine:

Ausgabe von zaehler auf LCD zur Kontrolle

Günter

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenter B. schrieb:

> Zumindest müste ja ein Byte ordentlich eingelesen werden.

Aber selbst wenn ein Byte ordentlich eingelesen wird, siehst du das im 
main-Code nicht, weil sofort nach dem Ende der ISR der Interrupt wieder 
auslöst (*), und die Werte des erfolgreichen Einlesens überschreibt.

(*) Das Warum und die Beseitigung hat Justus schon gepostet.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso diesen Umweg über den INT0?
Für solche Sachen dürfte InputCapture einfacher zu nutzen sein.

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es funktioniert durch Löschung des Interruptflags.

Vielen Dank

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Es funktioniert durch Löschung des Interruptflags.

Um welchen Controller handelt es sich denn eigentlich?
Das Interrupt-Flag braucht man eigentlich nicht anfassen, wenn eine ISR 
vorhanden ist. Dann kümmert sich der Controller (meist) ganz alleine um 
die Flags.
Deine Lösung fällt aus meiner Sicht unter "fieses Gebastel"; das ist 
aber meine völlig unbedeutende Meinung, die ich einfach nur aus 
Geltungssucht loswerden musste.

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es handelt sich um einen Mega8.
Das Problem war ja, dass der Controller beim 2 Bit des auszuwertenden 
Bytes schon wieder eine Interruptanforderung bekam.
Wenn die ISR 8 Bits oder eventuell auch die Störung auf der Leitung (das 
Signal wird per 8xxMHz-Funkmodul übertragen)abgearbeitet hat, setzte ich 
am Ende der ISR durch setzen des Interruptsflag das Interruptflag 
zurück.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wenn die ISR 8 Bits oder eventuell auch die Störung auf der Leitung (das
>Signal wird per 8xxMHz-Funkmodul übertragen)abgearbeitet hat, setzte ich
>am Ende der ISR durch setzen des Interruptsflag das Interruptflag
>zurück.

Und was machst du, wenn Störungen auftreten? Dann kommen deine Bits doch 
völlig durcheinander.

Oliver

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:

>
> Und was machst du, wenn Störungen auftreten? Dann kommen deine Bits doch
> völlig durcheinander.
>

Ich lebe damit :-)

Es kommen nur 3 von 256 Bitkombinationen in Betracht.
Wenn eine Störung zufällig mal eines dieser Bitmuster produziert, kann 
ich damit leben, da es sich nur um eine Anzeige handelt: Leer - Voll - 
Übervoll

Der Sender sendet alle 15 Minuten ein Lebenszeichen. Ausserdem sendet er 
bei Statusänderung den aktuellen Zustand.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Und was machst du, wenn Störungen auftreten? Dann kommen deine Bits doch
>> völlig durcheinander.

>Ich lebe damit :-)

Nun ja, nach meinem Verständnis deines Codeschnippels kommt das Programm 
nur alle 8 Impulse aus der ISR. Ein falsches Bit stört da vielleicht 
nicht, soweit hast du Recht, ein zusätzliches dagegen schon. Und bei 
externen Interrupts und/oder Funkstrecken soll das schon mal vorkommen.
Sobald sich da einmal eine Störung dazwischen gemogelt hat, geht nix 
mehr.

Oliver

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann greift ein Timeout namens zaehler.
Sobald zaehler 10007 überschreiten bricht die ISR ab :
zaehler=0;
  status=1;
  do
    {
    zaehler++;
    if (zaehler > 10007) 
      {
        status=0;
        break;
      }
    }
  while (bit_is_clear(PIND,PD2));


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.