Forum: Compiler & IDEs probleme mit globaler variable / interrupt


von tubbu (Gast)


Lesenswert?

Hi, ich habe eine Variable, die ich in einem Interrupt verwenden will,
die aber auch global verfügbar sein soll.

Ich deklariere die variable mit volatile in einem File data.c  und mit
extern in einem file data.h, das ich dann include.

Dennoch wird die variable bei jedem aufruf der Interruptroutine
resettet.

Was mache ich falsch?

Danke

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


Lesenswert?

> Ich deklariere die variable mit volatile in einem File data.c und
> mit extern in einem file data.h, das ich dann include.

Lass mich raten: bei "extern" hast du kein "volatile" davor, ja?

> Was mache ich falsch?

Genau das.  Überleg' doch mal, wie ein Compiler arbeitet.
"volatile"
ist ein sogenannter type qualifier, er bestimmt also einen bestimmten
Typ näher.  In diesem Falle werden durch diese Bestimmung bestimmte
Zugriffe auf diese Variable nicht mehr optimiert.  Nun spiel' mal
Compiler:

data.h:
1
extern uint8_t x;

data.c:
1
#include "data.h"
2
3
volatile uint8_t x;

main.c:
1
#include "data.h"
2
3
int
4
main(void)
5
{
6
  /* ... */
7
  while (x == 0) {
8
  }
9
  /* ... */
10
  return 42;
11
}

Was sieht der Compiler nach dem Präprozessor?

data.i:
1
extern uint8_t x;
2
3
volatile uint8_t x;

Das erste ist eine Deklaration, das zweite eine Definition.
Eigentlich solltest du eine Compilerwarnung bekommen, da die
qualifiers zwischen beiden verschieden sind.

main.i:
1
extern uint8_t x;
2
3
int
4
main(void)
5
{
6
  /* ... */
7
  while (x == 0) {
8
  }
9
  /* ... */
10
  return 42;
11
}

main.i ist nun aber die Stelle, an der der Compiler tatsächlich auf x
zugreift und wissen muss, dass sie `volatile' ist.  Nur: er weiß es
nicht.  Woher auch?  Das Einzige, was er an dieser Stelle weiß ist,
dass sie vom Type uint8_t ist und dass es sie ,,irgendwo'' (wo
genau,
weiß erst der Linker) außerhalb des aktuellen Übersetzungsmoduls
(compilation unit) gibt.  Da er nicht weiß, dass sie eigentlich
volatile ist, wird er deren Wert aber am Beginn der while-Schleife
genau einmal einlesen und danach nie wieder.

von tubbu (Gast)


Lesenswert?

Danke für die ausführliche Antwort.

Ich habe scjon bevor ich gepostet habe alle möglichen kombinationen
durchprobiert.

Ursprünglich hatte ich

data.c:

volatile unsigned char a;

data.h

extern volatile unsigned char a;

ich habe mit dieser kombination gerade ein wenig rumprobiert

in der main.c:

a=1;
DisplayOutput(1);

while(1)
{
    if(a > 100)
        DisplayOutput(5)
}
.....
SIGNAL (SIG_OVERFLOW0){
a=200;
}

Das Ergebniss ist, dass sehr schnell nacheinander immer 5 und 1
ausgegeben werden, so als ob der Controller ständig resetten würde.

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


Lesenswert?

> so als ob der Controller ständig resetten würde.

Dann tut er das wohl.  Denk dran, dass ein Interrupt, der
keinen Vektor hat (oder einen, dessen Namen falsch geschrieben
ist), einen Software-Reset auslöst.

von tubbu_der (Gast)


Lesenswert?

>> so als ob der Controller ständig resetten würde.

>Dann tut er das wohl.  Denk dran, dass ein Interrupt, der
>keinen Vektor hat (oder einen, dessen Namen falsch geschrieben
>ist), einen Software-Reset auslöst.

Ja das war es, hab ich dann auch rausgefunden..

das waren jetzt ein paar stunden rumprobiere..wegen sowas


jedenfalls vielen dank

von Karl H. (kbuchegg)


Lesenswert?

Dafuer vergisst Du das aber auch nie wieder :-)

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.