AVR GCC Timer-irqs <-> main Probleme bei Variablen

OP #2896310
Lesenswert?

Hallo,
ich verstehe die Welt nicht mehr, daher, please help.
(Ich verwende AVR Studion 4 mit GNU GCC Compiler für AVR Mega; Sprache: 
Standard "C")
Problem:

Im hauptprogramm setze ich nach der Initialisierung in der 
Hauptprogrammschleife sekündlich eine global deklarierte Steuervariable 
"OneWireFlag", die im Time-Compare-Intterrupt (Timerclock 0,5 us) 
ausgewertet wird. danach wird ein kurzes Stepping durchlaufen, wobei die 
Steuervariable das Ganze händelt.

Soweit, so gut, das geht alles. Am Ende wird die Steuervariable auif 
einen "Endcode", hier 0x88 gesetzt.

Das Hauptprogramm wartet nun in einer while-Schleife auf diesen Endcode.

Solange die Warteschleife nur aus:

while (OneWireFlag != 0x88) {
wdt_reset()
}

besteht, funktioniert es nicht. Die Schleife wird nie verlassen, bzw. 
der Wert von OneWireFlag wird nicht ausgewertet.

Das klappt dann erst, wenn ich zusätzlich eine komplexere Subroutine in 
der Schleife aufrufe. Nur das einfügen von Inline "nop" bringt nichts...

Für mich ist das ein Compilerproblem bzw. ein Optimierungsproblem???

Hat einer eine Idee? Mir fehlen dazu die Erfahrungen mit dem GNU GCC. 
Danke.

So, die Programmschipsel hänge ich mal an:

Ausschnitt aus dem Hauptprogramm:
Aufruf der Subroutine
1
    crc=OneWire_ReadRom();
Die Subroutine (Testversion)
1
U8 OneWire_ReadRom(void)
2
{
3
  U8 i, crc;
4
  OneWire_Write_Byte(0xF0);
5
  crc=0;
6
  return crc;
7
}
8
U8 OneWire_Write_Byte(U8 WriteByte)
9
{
10
  U8 i;
11
  for (i = 0;i < 8; i++){
12
    OneWireFlag = OneWire_Write_Bit(WriteByte & (1 << i));
13
  }
14
  OneWireFlag=0;
15
  return OneWireFlag;
16
}
17
U8 OneWire_Write_Bit(U8 Bitwert)
18
{
19
  if (Bitwert == 0) {
20
    OneWireFlag = 0x10;  // write 0
21
  } else {
22
    OneWireFlag = 0x20;  // write 1
23
  }
24
  while (OneWireFlag != 0x88)  //DIESE BOESE WARTSCHLEIFE
25
  {
26
//    csabs(2,1);  // mit geht, ohne nicht...
27
    wdt_reset();
28
  }
29
  return OneWireFlag;
30
}
Die Timer-Rouine (gekürzt)
1
ISR (TIMER1_COMPC_vect) //fuer 0newire bus / divers
2
{
3
  //  timer zaehlt mit 0.5 us
4
  U16 Icompvalue;
5
  Icompvalue = OCR1C;
6
  if (OneWireFlag == 1) {
7
...............................
8
...............................
9

10
  } else if (OneWireFlag == 0x10) {
11
    OneWirePortWrite &= ~(1<<OneWirePortPin);    //pin = 0
12
    OneWirePortDir |= (1<< OneWirePortPin);    // dir = output
13
    OneWireFlag = 0x11;
14
    Icompvalue += 64*2;  //64 us low
15
    OCR1C = Icompvalue;
16
  } else if (OneWireFlag == 0x11) {
17
//          PORTB ^= 0x80;  /// xtc
18
    OneWirePortDir &= ~(1<<OneWirePortPin);    // Release
19
    OneWireFlag = 0x88;
20
    Icompvalue += 50 * 2;  //50 us wait
21
    OCR1C = Icompvalue;
22

23
  // schreibe 1
24
  } else if (OneWireFlag == 0x20) {
25
    OneWirePortWrite &= ~(1<<OneWirePortPin);    //pin = 0
26
    OneWirePortDir |= (1<< OneWirePortPin);    // dir = output
27
    _noppen();
28

29

30
    OneWireFlag = 0x21;
31
    Icompvalue += 4*2;  //2 us low
32
    OCR1C = Icompvalue;
33
  } else if (OneWireFlag == 0x21) {
34

35
    OneWirePortDir &= ~(1<<OneWirePortPin);    // Releas resp hig
36
    Icompvalue += 64*2;  //64 
37
    OCR1C = Icompvalue;
38
    OneWireFlag = 0x22;
39
  } else if (OneWireFlag == 0x22) {
40
    OneWirePortDir &= ~(1<<OneWirePortPin);    // Release
41
    OneWireFlag = 0x88;
42
    Icompvalue += 50 * 2;  //50 us wait
43
    OCR1C = Icompvalue;
44

45

46
  } else if (OneWireFlag == 0x88) {
47
    Icompvalue += 50*2;  //50 us warten
48
    OCR1C = Icompvalue;
49
  } else if (OneWireFlag == 0x0) {
50
    Icompvalue += 200;  
51
    OCR1C = Icompvalue;
52
  } else  {
53
    Icompvalue += 20000;  //10 ms
54
    OCR1C = Icompvalue;
55
  }
56
}
#2896319
Lesenswert?

Hanns-Jürgen "Yogy" Mostert schrieb:
> Solange die Warteschleife nur aus:
>
> while (OneWireFlag != 0x88) {
> wdt_reset()
> }
>
> besteht, funktioniert es nicht. Die Schleife wird nie verlassen, bzw.
> der Wert von OneWireFlag wird nicht ausgewertet.
>
> Das klappt dann erst, wenn ich zusätzlich eine komplexere Subroutine in
> der Schleife aufrufe. Nur das einfügen von Inline "nop" bringt nichts...

Da fehlt dann wohl ein "volatile".
OP #2896372
Lesenswert?

Stefan Ernst schrieb:
> Hanns-Jürgen "Yogy" Mostert schrieb:
>> Solange die Warteschleife nur aus:
>>
>> while (OneWireFlag != 0x88) {
>> wdt_reset()
>> }
>>
>> besteht, funktioniert es nicht. Die Schleife wird nie verlassen, bzw.
>> der Wert von OneWireFlag wird nicht ausgewertet.
>>
>> Das klappt dann erst, wenn ich zusätzlich eine komplexere Subroutine in
>> der Schleife aufrufe. Nur das einfügen von Inline "nop" bringt nichts...
>
> Da fehlt dann wohl ein "volatile".

hmm, wo soll das denn bitte hin?
OP #2896442
Lesenswert?

volatile wirkt hier zwar überraschednerweise, aber, wie gesagt , 
überaschenderweise.

Laut dem Schirmer-Buch über "C"

"Mit dem Attribut 'volotile' sagen sie über eine Variable aus, daß ihr 
Typ implementierungsabhängige Eigenschaften besitzen kann.Genaueres legt 
der ANSI-Standard hier nicht fest. Insbesondere werden volotile-Objekte 
von der Optimierung beim Compilieren ausgeschlossen"

So, was sagt das jetzt?!

a) Der Compiler verschluckt Variablen, obwohl sie benutzt werden? So was 
hätte mir früher einer implementieren sollen, Au Backe

b) unbekanntes Verhalten im ANSI Dschungel? In der GNU Compiler Doku 
steht nix zu volotile

Aber egal, danke für die Hilfe, es funzt mit volotile. Problem für mich 
hier gelöst.  Happy Halloween :-)

Yogy
#2896445
Lesenswert?

Hanns-Jürgen "Yogy" Mostert schrieb:
> volatile wirkt hier zwar überraschednerweise, aber, wie gesagt ,
> überaschenderweise.

Nein,  nicht überraschend.

FAQ: Was hat es mit volatile auf sich


> So, was sagt das jetzt?!
>
> a) Der Compiler verschluckt Variablen, obwohl sie benutzt werden?

Das sagt es nicht aus

> Aber egal, danke für die Hilfe, es funzt mit volotile.
Es heißt volAtile.
UNd lies die FAQ. Dann verstehst du auch wo das Problem liegt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren