Forum: Mikrocontroller und Digitale Elektronik Arduino: if-Abfrage beeinflußt unbeteiligte Programmsequenzen


von Alexander S. (knut740)


Lesenswert?

Hallo,
ich hatte schon mal einen Thread in dieser Sache angefangen, finde ihn 
aber nicht mehr (man sollte eine bessere Suchfunktion haben).
Also:
Ich war aufgefordert worden, das fraglich Programm so weit bis auf das 
Wesentlich zu kürzen, daß es leichter zu durchschauen ist, was ich getan 
habe.

Mein Problem: nach einer if-Abfrage hängt es von der Fragestellung ab, 
ob die Daten korrekt oder falsch in ein I2C-EEPROM geschrieben werden.
Die fragliche  Stelle befindet sich etwa in der Mitte des Programms (ich 
kann leider keine Zeilennummern einfügen).
Und anschließend habe ich ein Stück einer Ausgabe beigefügt, wo man die 
fehlerhafte Ausgabe sieht (Spalte 1 ist die Adresse, in Spalte 2 sollte 
das highByte stehen (falls gewünscht, kann ich das Ausleseprogramm noch 
posten)).
Meine Frage: weshalb beeinflußt die mehr oder weniger brauchbare 
if-Schleife die EEPROM-Schreiberei bzw. wie kann man das vermeiden?
VG
Alexander

Das abgemagerte Programm
1
// _2DS18_ganz_leer_Relais_180116                     16.1.18
2
#include <Wire.h> 
3
#include <LiquidCrystal_I2C.h>
4
LiquidCrystal_I2C lcd(0x20,16,2);      // Achtung: auf den neuen I2C-LCD gibt es Adressjumper.
5
const int I2CADRESSE = 0x51;           // A0 = high, 
6
int eepromadresse =0;
7
int adresse = 0;
8
 int a = 10;                           // zum Testen der lcd-Ausgabe
9
int relaispin = 9;                                      
10
unsigned long time;
11
12
void setup()   /****** SETUP: RUNS ONCE ******/
13
{
14
    Serial.begin(9600);                // für Ausgabe über Terminal
15
    pinMode (relaispin, INPUT);
16
    delay(4000); 
17
    lcd.init();
18
    lcd.backlight();
19
    lcd.clear();
20
    lcd.print(" _2_DS18_ins_EEPROM");
21
    lcd.clear(); 
22
  
23
  
24
  // start serial port to show results
25
  Serial.begin(9600);
26
  Serial.println("_2DS18_leer_Relais_180116");
27
  Serial.print("Initializing Temperature Control Library Version ");
28
 // Serial.println(DALLASTEMPLIBVERSION);
29
  delay(2000);
30
  
31
} //--(end setup )---
32
33
void loop()   /****** LOOP: RUNS CONSTANTLY ******/
34
{
35
36
// Abfrage des Brennerrelais, genauer gesagt, des Relais, das dem eigentlichen Brennerrelais 
37
// nachgeschaltet ist.
38
     int i;
39
     int Summelow= 0;
40
     int ersterRelaiszustand[6];
41
     for (i=0; i<7; i++)
42
     {
43
     ersterRelaiszustand[i] = digitalRead(relaispin);
44
      Summelow = Summelow + ersterRelaiszustand[i];
45
      delay(100);
46
     }
47
     
48
      int Summehigh= 0;    
49
     int zweiterRelaiszustand[6];
50
     for (i=0; i<7; i++){
51
      zweiterRelaiszustand[i] = digitalRead(relaispin);
52
      Summehigh = Summehigh + zweiterRelaiszustand[i];
53
      delay(100);
54
     } 
55
56
    if(!Summehigh > Summelow) // hier beginnt das Unerklärliche:
57
    {                         // wenn die Schleife heißt if(Summehigh > Summelow), dann wird  
58
    zeit_ins_EEPROM();        // bei zeit_ins_EEPROM() das highByte(Time) nicht geschrieben s.Anh.  
59
            // Mit der Schleife if(!(Summehigh > Summelow)) wird highByte(Time) auch nicht geschrieben
60
            // aber mit der Schleife if(!Summehigh > Summelow) wird es korrekt geschrieben.
61
62
            // wie beeinflußt die if-Schleife die EEPROM-Schreiberei ?
63
                                                
64
    
65
   int TempC = 1234;                             // irgendwelche Zahl
66
   schreibEEPROM(eepromadresse,highByte(TempC));
67
   eepromadresse++;
68
   schreibEEPROM(eepromadresse,lowByte(TempC));  
69
   eepromadresse++;  
70
71
   TempC = 2345;                                // irgendwelche Zahl
72
   schreibEEPROM(eepromadresse,highByte(TempC));
73
   eepromadresse++;
74
   schreibEEPROM(eepromadresse,lowByte(TempC));  
75
   eepromadresse++;  
76
77
//   zeit_ins_EEPROM();
78
               
79
    }          // Ende Relaispinabfrage        
80
}//--(end main loop )---
81
82
83
void   schreibEEPROM(int adresse, byte daten) 
84
  {  
85
  Wire.beginTransmission(I2CADRESSE);
86
  Wire.write ((byte) (adresse >> 8));
87
  Wire.write ( (byte) (adresse & 0xFF));
88
  Wire.write (daten);
89
  Wire.endTransmission();  
90
  delay(5);
91
  }
92
93
void  zeit_ins_EEPROM()
94
    {
95
  // Zeit ins EEPROM schreiben
96
   unsigned int Time = millis()/1000;              // Zeit seit Programmstart in sec
97
   schreibEEPROM(eepromadresse,highByte(Time));
98
   eepromadresse++;
99
   schreibEEPROM(eepromadresse,lowByte(Time));  
100
   eepromadresse++;
101
    }
Und hier die mißlungene Ausgabe:
1
Ausgabe:
2
5  0  87  87  4  210  1234  9  41  2345
3
11  0  147  147  4  210  1234  9  41  2345
4
17  0  217  217  4  210  1234  9  41  2345
5
23  0  45  45  4  210  1234  9  41  2345
6
29  0  114  114  4  210  1234  9  41  2345
7
35  0  18  18  4  210  1234  9  41  2345
8
41  0  171  171  4  210  1234  9  41  2345
9
47  0  54  54  4  210  1234  9  41  2345
10
53  0  191  191  4  210  1234  9  41  2345
11
59  0  68  68  4  210  1234  9  41  2345
12
65  0  192  192  4  210  1234  9  41  2345
13
71  0  59  59  4  210  1234  9  41  2345
14
77  0  187  187  4  210  1234  9  41  2345
15
83  0  29  29  4  210  1234  9  41  2345
16
89  0  192  192  4  210  1234  9  41  2345
17
95  0  85  85  4  210  1234  9  41  2345

: Bearbeitet durch User
von Frank (Gast)


Lesenswert?

if( ! (Summehigh > Summelow))

 Oder

 if(Summelow < Summehigh )

von Kräuterli (Gast)


Lesenswert?

Frank schrieb:
> if( ! (Summehigh > Summelow))

Das hatte er schon probiert:

Alexander S. schrieb:
> Mit der Schleife if(!(Summehigh > Summelow)) wird highByte(Time) auch
> nicht geschrieben

von Edi R. (edi_r)


Lesenswert?

Ich bin mit Arduino-Code nicht so vertraut, aber in C wäre das ein 
grober Schnitzer:
1
     int ersterRelaiszustand[6];
2
     for (i=0; i<7; i++)
3
     {
4
     ersterRelaiszustand[i] = ...

von M. S. (nickfisher)


Lesenswert?

Google mal operator prezedenz.
1
if(!Summehigh > Summelow)
 Heißt so viel wie:
1
if((!Summehigh) > Summelow)

Und (!Summehigh) is genau dann 1 wenn summehigh == 0 ist, in allen 
anderen Fällen ist es 0.

von Kräuterli (Gast)


Lesenswert?

Simon S. schrieb:
> Google mal operator prezedenz.
> if(!Summehigh > Summelow) Heißt so viel wie:
> if((!Summehigh) > Summelow)
> Und (!Summehigh) is genau dann 1 wenn summehigh == 0 ist, in allen
> anderen Fällen ist es 0.

Er hatte auch das hier schon probiert:
Alexander S. schrieb:
> Mit der Schleife if(!(Summehigh > Summelow)) wird highByte(Time) auch
> nicht geschrieben

von Roland P. (pram)


Lesenswert?

Edi R. schrieb:
> Ich bin mit Arduino-Code nicht so vertraut, aber in C wäre das ein
> grober Schnitzer:
>
>
1
>      int ersterRelaiszustand[6];
2
>      for (i=0; i<7; i++)
3
>      {
4
>      ersterRelaiszustand[i] = ...
5
>

Sehe ich genauso. Damit überschreibst du dir Werte im Stack und es ist 
nicht mehr vorhersehbar, was dein Programm macht.

Mach aus der 6 mal eine 7 und teste nochmal. Kleiner Tipp noch: ändere 
deine schreibeEEPROM so ab, dass sie zuerst das byte ausliest und nur 
schreibt, wenn sich was geändert hat. (EEProms sind nur 100000 mal 
beschreibbar)

Gruß Roland

von M. S. (nickfisher)


Lesenswert?

Kräuterli schrieb:
> Er hatte auch das hier schon probiert:
> Alexander S. schrieb:
>> Mit der Schleife if(!(Summehigh > Summelow)) wird highByte(Time) auch
>> nicht geschrieben

Richtig. Er hat 3 unterschiedliche Bedingungen ausprobiert. Vielleicht 
sollte er sich mal überlegen unter welcher davon er etwas schreiben 
will.

Übrigens, Kleinigkeit, aber: ein if ist keine schleife.

von Max M. (jens2001)


Lesenswert?

Alexander S. schrieb:
> unsigned long time;

Alexander S. schrieb:
> unsigned int Time = millis()/1000;              // Zeit seit
> Programmstart in sec

von Reiner_Gast (Gast)


Lesenswert?

Alexander S. schrieb:
> for (i=0; i<7; i++)
>      {
>      ersterRelaiszustand[i] = digitalRead(relaispin);
>       Summelow = Summelow + ersterRelaiszustand[i];
>       delay(100);
>      }
>
>       int Summehigh= 0;
>      int zweiterRelaiszustand[6];
>      for (i=0; i<7; i++){
>       zweiterRelaiszustand[i] = digitalRead(relaispin);
>       Summehigh = Summehigh + zweiterRelaiszustand[i];
>       delay(100);
>      }
>
>     if(!Summehigh > Summelow) // hier beginnt das Unerklärliche:

Also... erstmal unbeachtet der fehlerhaften Array Definition (Größe 
sollte 7 sein)

Wenn sich die Variable "relaispin" in keiner der For Schleifen ändert, 
dann ist Summelow immer gleich Summehigh und beide können dann auch nur 
die Werte 0 oder 7 bekommen...

Demnach wäre die IF Abfrage eigentlich komplett unsinning, da sich nie 
etwas unterscheidet.

Dass doch (wohl eher zufällig) in die IF Abfrage reingesprungen wird, 
hängt dann vermutllich damit zusammen, dass wie bereits oben 
beschrieben, durch die FOR Schleife ausserhalb des Arrays geschrieben 
wird. Wenn der Compiler die Variablen so im Speicher anlegt, wie die im 
Code auftreten, dann liegt wohl summehigh direkt hinter dem Array 
ersterRelaiszustand und wird somit vermutlich im letzten Durchlauf der 
ersten FOR Schleife überschrieben.

Lustigerweise würde die Korrektur der Array Definition dann dazu führen, 
dass die IF Bedingung nicht mehr wahr würde ;-)

von Der kein Bock mehr A. (Gast)


Lesenswert?

Soll
1
}          // Ende Relaispinabfrage

die schliessende Klammer der If-Abfrage sein ? oder schon vorher ?

Wenn ja, rück die Anweisung nochmal bitte einen Tab ein, dann sieht mans 
besser.
LG

von Peter D. (peda)


Lesenswert?

Alexander S. schrieb:
> Die fragliche  Stelle befindet sich etwa in der Mitte des Programms (ich
> kann leider keine Zeilennummern einfügen).

Genau deshalb postet man ja solchen langen Code als Anhang.

von Stefan F. (Gast)


Lesenswert?

Ich empfehle, mit 4 Leerzeichen einzurücken, dann hat man keinen Stress 
mit unterschiedlicher Darstellung der Tabs in diversen Programmen.

von HerrGlax (Gast)


Lesenswert?

Bezüglich if Schleifen kann ich diese Website empfehlen: 
http://www.if-schleife.de

von Kräuterli (Gast)


Lesenswert?

HerrGlax schrieb:
> Bezüglich if Schleifen kann ich diese Website empfehlen:
> http://www.if-schleife.de

Hörst du die Bart-Wickelmaschine laufen? ;-)

von Agetu G. (herrglax)


Lesenswert?

Kräuterli schrieb:
> Hörst du die Bart-Wickelmaschine laufen? ;-)

Ja ist echt unerträglich laut :(
Sollte sie vielleicht mal wieder schmieren ...

Trotzdem sollte man es richtig benennen :D

von Programmiersprachentheaterintendant (Gast)


Lesenswert?

Jörch B. schrieb:
> Soll
>
1
}          // Ende Relaispinabfrage
>
> die schliessende Klammer der If-Abfrage sein ? oder schon vorher ?
>
> Wenn ja, rück die Anweisung nochmal bitte einen Tab ein, dann sieht mans
> besser.
> LG

Du meinst, einrücken ist nicht bloss kosmetisch nützlich sondern sollte 
fast obligatorisch sein?
Meine Güte: am Schluss wird noch in Python programmiert...

von Klaus (Gast)


Lesenswert?

Programmiersprachentheaterintendant schrieb:
> Du meinst, einrücken ist nicht bloss kosmetisch nützlich sondern sollte
> fast obligatorisch sein?

Eigentlich schon. Ich rücke selber ein und lass dann die IDE das nochmal 
machen. Wenn sich dann etwas stark verändert schau ich mir den Code 
nochmal genau an.

MfG Klaus

von Alexander S. (knut740)


Lesenswert?

Stimmt!

Kräuterli schrieb:
> Simon S. schrieb:
>> Google mal operator prezedenz.
>> if(!Summehigh > Summelow) Heißt so viel wie:
>> if((!Summehigh) > Summelow)
>> Und (!Summehigh) is genau dann 1 wenn summehigh == 0 ist, in allen
>> anderen Fällen ist es 0.
>
> Er hatte auch das hier schon probiert:
> Alexander S. schrieb:
>> Mit der Schleife if(!(Summehigh > Summelow)) wird highByte(Time) auch
>> nicht geschrieben

Es geht mir durchaus nicht um die Logik der if-Schleife. Es gibt eine 
einzige brauchbare Version, die anderen habe ich nur probiert, als ich 
gesehen hatte, daß die EEPROM-Schreiberei  von  der if-Schleife abhängt 
(mit while geht es besser).
Diese Abhängigkeit verstehe ich nicht! Ich kann das später im richtigen 
Programm sicher umschiffen, aber neugierdehalber würde ich gern wissen, 
woran es liegt.
Gruß
Alexander

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Alexander S. schrieb:
> Es geht mir durchaus nicht um die Logik der if-Schleife.

Bitte:

Es gibt keine "if-schleife".

Gewöhn' Dir das einfach sofort und jetzt gleich ab.

von Programmiersprachenteaterintendant (Gast)


Lesenswert?

Damit ich die Absicht des Codes auch durchschaue: bei  jedem  Durchlauf 
von loop() wird der Zustand von D9 (da ist ein Relais dran) alle 100ms 
6* Mal erstmalig erfasst, anschl. zweitmalig wieder D9 alle 100ms 6* 
erfasst. Danach soll entschieden werden ob ins EEPROM zu schreiben ist.
Korrekt?

In beiden Schleifen werden die Rückgabewerte von digitalRead() -also 
HIGH / LOW- gespeichert und aufsummiert als int gespeichert.
@TO: was bedeutet Dir eine 6er* Summe von HIGH / LOW?

(* 6 oder 7 Mal hängt davon ab ob die Grösse der 2 Arrays oder die 
Anzahl For-Durchläufe korrigiert wird)

Der Vergleich (int Summehigh > int Summelow) lässt sich Boolesch 
negieren und bewerten.
Aber was soll (! (int Summehigh)) für eine Bedeutung haben?

Ja, in C kann man viel so Mann weiss was man tut.
@TO: was weisst DU, was DU da tust? WILLST DU das so?

von Stefan F. (Gast)


Lesenswert?

Ist es eigentlich eine gute Idee, immer wieder die selben Zellen im 
EEPROM zu überschreiben?

von Alexander S. (knut740)


Lesenswert?

Programmiersprachent h eaterintendant schrieb:
> Damit ich die Absicht des Codes auch durchschaue: bei  jedem  Durchlauf
> von loop() wird der Zustand von D9 (da ist ein Relais dran) alle 100ms
> 6* Mal erstmalig erfasst, anschl. zweitmalig wieder D9 alle 100ms 6*
> erfasst. Danach soll entschieden werden ob ins EEPROM zu schreiben ist.
> Korrekt?

Korrekt! Allerdings geht es mir derzeit nicht um die Logik hinter der 
if-Abfrage, die Variationen dienen nur dazu, daß ich herausfinden 
wollte, weshalb highByte(Time) manchmal und manchmal nicht ins EEPROM 
geschrieben wird. Was hat das if mit der nachfolgenden Anweisung 
zeit_ins_EEPROM() zu tun?


> In beiden Schleifen werden die Rückgabewerte von digitalRead() -also
> HIGH / LOW- gespeichert und aufsummiert als int gespeichert.
> @TO: was bedeutet Dir eine 6er* Summe von HIGH / LOW?
>
> (* 6 oder 7 Mal hängt davon ab ob die Grösse der 2 Arrays oder die
> Anzahl For-Durchläufe korrigiert wird)

Ich weiß, in den for-Anweisungen sind die Arrays falsch, sollte hier 
aber nicht überbewertet werden. da sich wahrscheinlich die Hardware 
ändern wird und die Passagen dann verschwinden werden.

>
> Der Vergleich (int Summehigh > int Summelow) lässt sich Boolesch
> negieren und bewerten.
> Aber was soll (! (int Summehigh)) für eine Bedeutung haben?
>

Gar keine!
Wie oben erwähnt, ging es mir  n u r  um den Einfluß der if-Abfrage auf 
die EEPROM-Schreiberei

von M. S. (nickfisher)


Lesenswert?

Alexander S. schrieb:
> Es geht mir durchaus nicht um die Logik der if-Schleife. Es gibt eine
> einzige brauchbare Version, die anderen habe ich nur probiert, als ich
> gesehen hatte, daß die EEPROM-Schreiberei  von  der if-Schleife abhängt
> (mit while geht es besser).
> Diese Abhängigkeit verstehe ich nicht! Ich kann das später im richtigen
> Programm sicher umschiffen, aber neugierdehalber würde ich gern wissen,
> woran es liegt.
> Gruß
> Alexander

das war mir schon klar.  die frage ist: warum schreibst du ein programm, 
das nicht tut was du willst? schreib doch einfach mal eine if-bedingung 
die das überprüft was du wissen willst. Dann korrigierst du die array 
grenzen und wenn es immernoch komische sachen macht kannst du noch mal 
wieder kommen.

Und dann könntest du uns noch erklären wie deine ausgabe zustande kommt. 
im moment sehe ich da nämlich einfach nur irgendwelche zahlen.

von Reiner_Gast (Gast)


Lesenswert?

Alexander S. schrieb:
> Ich weiß, in den for-Anweisungen sind die Arrays falsch, sollte hier
> aber nicht überbewertet werden. da sich wahrscheinlich die Hardware
> ändern wird und die Passagen dann verschwinden werden.
>
>>
>> Der Vergleich (int Summehigh > int Summelow) lässt sich Boolesch
>> negieren und bewerten.
>> Aber was soll (! (int Summehigh)) für eine Bedeutung haben?
>>
>
> Gar keine!
> Wie oben erwähnt, ging es mir  n u r  um den Einfluß der if-Abfrage auf
> die EEPROM-Schreiberei

Das eine hängt in einer Kausalkette mit dem anderen Zusammen...

von M. S. (nickfisher)


Lesenswert?

Alexander S. schrieb:
> Wie oben erwähnt, ging es mir  n u r  um den Einfluß der if-Abfrage auf
> die EEPROM-Schreiberei

vermutlich: die compileroptimierungen verschieben die befehle so, dass 
dein kaputtes array geschreibe manchmal was kaputt macht und manchmal 
nicht, je nachdem wo der copiler die zugriffe hin optimiert.

von Alexander S. (knut740)


Lesenswert?

Stefan U. schrieb:
> Ist es eigentlich eine gute Idee, immer wieder die selben Zellen im
> EEPROM zu überschreiben?

Natürlich nicht, aber für die Probephase sind 10000x mehr als 
ausreichend, danach werden die 32k einmal pro Woche beschrieben.

von Nop (Gast)


Lesenswert?

HerrGlax schrieb:
> Bezüglich if Schleifen kann ich diese Website empfehlen:
> http://www.if-schleife.de

Hier eine if-Schleife:
1
if_loop:
2
    do_stuff();
3
    if (condition) goto if_loop;

von Alexander S. (knut740)


Lesenswert?

Simon S. schrieb:
> vermutlich: die compileroptimierungen verschieben die befehle so, dass
> dein kaputtes array geschreibe manchmal was kaputt macht und manchmal
> nicht, je nachdem wo der copiler die zugriffe hin optimiert.

Ok, ich werde die array-Größen in Ordnung bringen und mich dann wieder 
melden (bis dahin muß ich erst mal den ewig benutzten USB-Anschluß, der 
plötzlich nicht mehr funktioniert, gangbar machen).

VG
Alexander

von Stefan F. (Gast)


Lesenswert?

> Ich weiß, in den for-Anweisungen sind die Arrays falsch, sollte hier
> aber nicht überbewertet werden.

Du korrumpierst damit den Stack. Das sollte man sehr hoch bewerten, denn 
ohne intakten Stack verhalten sich Computer praktisch nur noch zufällig. 
Sie tun nicht mehr das, was du ihnen befohlen hast.

Array/Buffer Überläufe sind seit ich denken kann die häufigste 
Fehlerursache für schwerwiegende Computerprobleme! Auch für Viren sind 
sie in den allermeisten Fällen der Angriffspunkt.

Deswegen haben sich die Designer einiger Programmiersprachen darum 
bemüht, sie von vorne herein auszuschließen. Das selbe Programm in Java 
wäre zum Beispiel prompt abgebrochen worden.

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.