Forum: Compiler & IDEs Interruptroutine funktioniert nicht richtig


von Guenter B. (gbl)


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
1
void Empfang_Bit(void)
2
{
3
  zaehler=0;
4
  status=1;
5
  do
6
    {
7
    zaehler++;
8
    if (zaehler > 10005) 
9
      {
10
        status=0;
11
        break;
12
      }
13
    }
14
  while (bit_is_set(PIND,PD2));
15
  if (zaehler<3000) 
16
   {
17
     rxbyte=rxbyte*2;
18
    rxbyte=rxbyte+1;
19
   }
20
   else
21
   {
22
     rxbyte=rxbyte*2;
23
   }
24
}
25
26
void Empfang_Pause(void)
27
{
28
  zaehler=0;
29
  status=1;
30
  do
31
    {
32
    zaehler++;
33
    if (zaehler > 10007) 
34
      {
35
        status=0;
36
        break;
37
      }
38
    }
39
  while (bit_is_clear(PIND,PD2));
40
}
41
42
ISR(INT0_vect) //Interruptroutine steigende Flanke an INT0
43
{
44
  uint8_t bitcnt;
45
  rxbyte = 0;
46
  Empfang_Bit();
47
  if (status==0) {rxbyte=0;return;}
48
  for (bitcnt=1;bitcnt<7;bitcnt++)
49
    {
50
    Empfang_Pause();
51
    if (status==0) {rxbyte=0;return;}
52
    Empfang_Bit();
53
    if (status==0) {rxbyte=0;return;}
54
    }
55
56
}

Gruß

Günter

von Stefan E. (sternst)


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?

von Guenter B. (gbl)


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 ?

von Justus S. (jussa)


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...

von Guenter B. (gbl)


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

von Stefan E. (sternst)


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.

von STK500-Besitzer (Gast)


Lesenswert?

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

von Guenter B. (gbl)


Lesenswert?

Es funktioniert durch Löschung des Interruptflags.

Vielen Dank

von STK500-Besitzer (Gast)


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.

von Guenter B. (gbl)


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.

von Oliver (Gast)


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

von Guenter B. (gbl)


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.

von Oliver (Gast)


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

von Guenter B. (gbl)


Lesenswert?

Dann greift ein Timeout namens zaehler.
Sobald zaehler 10007 überschreiten bricht die ISR ab :
1
zaehler=0;
2
  status=1;
3
  do
4
    {
5
    zaehler++;
6
    if (zaehler > 10007) 
7
      {
8
        status=0;
9
        break;
10
      }
11
    }
12
  while (bit_is_clear(PIND,PD2));

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.