Arduino: if-Abfrage beeinflußt unbeteiligte Programmsequenzen

OP #5282264
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
Gast #5282308
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
#5282319
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
#5282322
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.
Gast #5282352
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 ;-)
Gast #5282504
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
Gast #5282690
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...
OP #5282705
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
Gast #5282724
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?
OP #5283162
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
#5283163
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.
Gast #5283204
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...
OP #5283370
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
Gast #5283474
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.

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