Forum: Mikrocontroller und Digitale Elektronik seltsamer Zuweisungsfehler [Arduino-C]


von leer (Gast)


Lesenswert?

Was läuft hier falsch:

1
uint16_t messe() {
2
const uint16_t SCHWELLWERT=8;   
3
uint16_t wert;
4
uint16_t rueck=9999;  //nur damit es nicht 0 ist., s.u.
5
6
//...unwichtig, Messung vom ADC dreimal mit Mittelwertbildung
7
8
// wert wird direkt nach einer Zuweisung ausgegeben und hat irgendeinen Wert
9
Serial.print("ADC-Ergebniss:");  Serial.println(wert);   // z.B. 981  ok
10
11
Serial.print("Schwellwert:"); Serial.println(SCHWELLWERT);  //8  ok
12
if(wert >= SCHWELLWERT) {
13
   rueck=wert;
14
   Serial.print("rueck in true:");   Serial.println(rueck);  //1021  ok
15
}
16
else {
17
   rueck=0;
18
   Serial.print("rueck in false:");   Serial.println(rueck);
19
}
20
Serial.print("rueck Ende:"); Serial.println(rueck);   // liefert 0 ! ???
21
22
return rueck;  // liefert auch 0
23
}

Nehm ich den Code in ein separates Programm wo nur das drinnsteht läuft 
alles korrekt, ich weiss nicht wo oben der Wurm drinn ist, weil 
dazwischen keine Werte verändert werden. Wieso ist rueck am Ende 0, wo 
es doch in den if block reinläuft, es ausserhalb des Blocks deklariert, 
wieso ist der Wert nach der Zuweisung wieder weg?

Ich hatte das bisher verkürzt als Einzeiler in der return-Anweisung mit 
ternärem Operator, da kam auch schon immer dieser Müll bei raus, dachte 
erst da sind die Klammern falsch, passiert ja bei der ternären Variante 
mal aber das war es nicht, bis das mal aufgeprielet habe mit if else den 
Ausgaben dazwischen.

Erst hatte ich den const Schwellwert als uint8_t und dachte wegen den 
unterschiedlichen Grössen gibt es vielleicht diesen Fehler aber das 
sollte trotzdem funktionieren, jetzt alles auf uint16_t umgestellt immer 
noch der Fehler.

von Klaus W. (mfgkw)


Lesenswert?

Verstehe nicht, was da passiert.

Wenn wert erst 981 sein soll und dann angeblich ein rueck=wert gemacht 
wird, wieso soll rueck dann 1021 sein? Und das findest du ok?

Irgendwie habe ich den Eindruck, daß hier nur die halbe Wahrheit steht.

von leer (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Verstehe nicht, was da passiert.
>
> Wenn wert erst 981 sein soll und dann angeblich ein rueck=wert gemacht
> wird, wieso soll rueck dann 1021 sein? Und das findest du ok?
>
> Irgendwie habe ich den Eindruck, daß hier nur die halbe Wahrheit steht.
Das ist noch ein alter Wert, von einer Ausgabe. wert ist 981 in dem 
Beispiel.

Else-Teil wird nie durchlaufen, es erfolgt keine ausgabe, am Ende hat 
rueck aber den Wert 0. Ändere ich die 0 in der Zuweisung hat rueck am 
Ende den eben diesen Wert.

Als Standaloneprogramm läuft es wie es soll.

von leer (Gast)


Lesenswert?

Jetzt habe ichs:
habe die Variable explizit vor der Messung auf 0 gesetzt.

Macht man das nicht, ist sie zwar auch Null wenn man ihren Wert gleich 
danach ausgibt. Die erste explizite Zuweisung erfolgt aber innerhalb 
einer for-schleife also eines Blocks, das scheint der Compiler anders 
handzuhaben
wenn die später nicht bis zum Ende einen Wert zugewiesen bekommt setzt 
der sie wieder so wie es aussieht wieder null, deshalb dieser Effekt.

Weist man ihr am Anfang (oder auch woanders, habe es an mehreren Stellen 
getestet) explzit einen Wert zu verhält sich das Programm wie es soll.

Ich dachte immer lokale Variablen werden automatisch mit 0 
initialisiert.

Hier nochmal der ganze Code:
1
uint16_t messe() {
2
  /* macht eine Messung mit dem ADC
3
     Rückgabewert: den Wert des ADC wenn >= Threshhold sonst 0  */
4
5
  const uint16_t SCHWELLWERT=8;   
6
  uint16_t wert=0 ;                           
7
  uint16_t rueck=9999;   //wert egal bei initialisierung
8
     
9
10
  Serial.println("Messe...");   
11
12
  //setup_ADC();  //wird schon vorher aufgerufen todo: später hier reinbauen
13
14
  ADCSRA |= (1<<ADEN) | (1<<ADSC)| (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);   // Arduino Teiler 128 bei 16Mhz = 160kHz
15
  while ( ADCSRA & (1<<ADSC) ) ;   // dummymessung
16
17
  // jetzt lesen wir xmal und bilden den mittelwert
18
  const uint8_t anz=3;
19
  uint8_t i;
20
  for (i = 0; i<anz; i++) {
21
        ADCSRA |=(1<<ADSC);
22
        while ( ADCSRA & (1<<ADSC) )  ; //warten bis messung vorbei
23
        wert +=ADCW;                    // HIER ERSTE ZUWEISUNG AN wert
24
  }
25
26
 ADCSRA &= ~(1<<ADEN); //ADC aus, spart Strom
27
28
 Serial.print("ADC-Ergebniss ohne Mittelwert:");  Serial.println(wert);
29
 wert /= anz; //... bilden Mittelwert 
30
 Serial.print("ADC-Ergebniss:");  Serial.println(wert);
31
32
 Serial.print("schwellwert:"); Serial.println(SCHWELLWERT);
33
 if(wert >= SCHWELLWERT) {
34
   rueck=wert;
35
   Serial.print("rueck in true:");   Serial.println(rueck);
36
 }
37
 else {
38
   rueck=0;   
39
   Serial.print("rueck in false:");   Serial.println(rueck); 
40
 }
41
 
42
 Serial.print("rueck Ende:"); Serial.println(rueck);
43
 
44
 return rueck;
45
46
}

von leer (Gast)


Lesenswert?

Habe jetzt nochmal mit der fehlerhaften Version rumgespielt.

Der else-Teil unten wird scheibar nicht durchlaufen, weil die Ausgabe 
nie erscheint weist man dort aber rueck einen anderen wert als 0 zu hat 
es am Ende diesen Wert, besonders seltsam da rueck bei der Deklaration 
schon initialisiert wurde.

Lektion gelernt: IMMER nach/mit der Deklaration Variablen initialisieren 
und nicht erst in Blöcken.

von er bei sich selbst suchen (Gast)


Lesenswert?

Da du nur die Hälfte gezeigt hast, kann dir Keiner deinen 
Programmierfehler auslösen. Der Compiler und der uC arbeiten bei 
10tausenden problemlos, nur bei dir nicht?

Es wird der else Zweig durchlaufen. Du Schreiber es ja selber!

von er bei sich selbst suchen (Gast)


Lesenswert?

leer schrieb:
> Habe jetzt nochmal mit der fehlerhaften Version rumgespielt.
>
> Der else-Teil unten wird scheibar nicht durchlaufen, weil die Ausgabe
> nie erscheint weist man dort aber rueck einen anderen wert als 0 zu hat
> es am Ende diesen Wert, besonders seltsam da rueck bei der Deklaration
> schon initialisiert wurde.
> Lektion gelernt: IMMER nach/mit der Deklaration Variablen initialisieren
> und nicht erst in Blöcken.

Nein, nix gelernt: Bei einer Deklaration kann man nix zuweisen, das geht 
nur bei einer Definition! Und zuweisen kannst du wo du willst.

von leer (Gast)


Lesenswert?

er bei sich selbst suchen schrieb:
> Da du nur die Hälfte gezeigt hast, kann dir Keiner deinen
Weiter unten steht die Komplettversion.

> Programmierfehler auslösen.
Ja weil die Initialisierung der Variable fehlte.

> Der Compiler und der uC arbeiten bei
> 10tausenden problemlos, nur bei dir nicht?
Schon mal was von Compilerfehlern gehört, undefniertem Verhalten, nicht 
standardkonform,... Kann ja sein dass dieses Verhalten irgendwo 
dokumentiert ist oder die Compilerswitches der Arduino-IDE da lockerer 
gesetzt sind, wat weiss ich, die Ursache wurde identifiziert, was willst 
du mir mitteilen?

> Es wird der else Zweig durchlaufen. Du Schreiber es ja selber!
Jein, lies mal genauer was ich geschrieben habe.

von leer (Gast)


Lesenswert?

er bei sich selbst suchen schrieb:
> Und zuweisen kannst du wo du willst.
Eben nicht wie man an meinem Beispiel sieht.

von Alexander I. (Gast)


Lesenswert?

Du hast im ersten Beispiel auf eine nicht initialisierte Variable 
addiert. Der Compiler macht hier alles richtig, denn es gibt keine 
Garantie, dass die Variable automatisch = 0 ist.

Der C Standard sagt sogar explizit, dass diese Variablen nicht vorbelegt 
werden: http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf 
(6.7.8, §10).

Eine ganz nette Lektüre, die nicht ganz so trocken wie der C Standard 
ist, ist: http://www.slideshare.net/olvemaudal/deep-c (Hier wird das 
übrigens ab Slide 55ff auch nochmal erwähnt.

Fazit: Der Compiler ist nicht Schuld. Es gibt einfach immer viel dazu zu 
lernen :)

von Kaj (Gast)


Lesenswert?

leer schrieb:
>> Der Compiler und der uC arbeiten bei
>> 10tausenden problemlos, nur bei dir nicht?
> Schon mal was von Compilerfehlern gehört, undefniertem Verhalten, nicht
> standardkonform,... Kann ja sein dass dieses Verhalten irgendwo
> dokumentiert ist oder die Compilerswitches der Arduino-IDE da lockerer
> gesetzt sind, wat weiss ich, die Ursache wurde identifiziert, was willst
> du mir mitteilen?

Schraub dich erstmal n Gang zurück und häng den Beutel in Eiswasser... 
Du bist hier der, der Hilfe möchte, also halt mal die Luft an!

Compilerfehler: Natürlich... Such mal hier im Forum. Bei jedem zweiten 
Problem wird erstmal in den Raumgeworfen "das muss ein Compilerfehler 
sein.", bis sich dann herausstellt das da nur jemand die Sprache nicht 
beherrscht und auch nicht lernen will. Diese Leute kommen ganz besonders 
gerne aus der Arduino-Dummbeutel-Fraktion.

Und wenn du hier schon anfängst was von undefiniertem Verhalten und co 
zu blubbern, dann hättest du ja auch mal einfach in die Dokumentation 
vom Compiler gucken können.

von Erneut Zittermann (Gast)


Lesenswert?

Nimm einen Kompiler, der Variablen standardmäßig mit Null belegt, wenn
sie nicht vom Programmierer mit einem Wert beschickt werden.
Bascom ist so einer.

Du mußt Dich dann hier nicht von "Experten" wie "Kaj" belehren lassen.

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.