[gelöst] Warum bleibt mein Arduino stehen ??

Hallo allerseits,
wie einige vielleicht schon gelesen haben, versuche ich mich an einem Solar-Tracker/Sonnenfolger.
Nun habe ich festgestellt, das das Programm sich so ca. nach 2 stunden aufhängt.

Kann mal jemand auf meinen Sketch schauen, ich finde den Fehler nicht… :blush:

Ich habe die vermutung, das das mit den Millis zusammen hängt… aber das ist nur eine Vermutung…
Das Programm läuft also immer ca. 2-3 std. und dann geht nix mehr, kein Impuls wird gezählt und es wird nicht mehr geschaut welcher LDR der Hellste ist…

Hier mein Sketch:

#include <SPI.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);
byte bell[8]   = { B00100, B01110, B01110, B01110, B11111, B00000, B00100, B00000 };
byte sun[8]    = { B00100, B10101, B01110, B11111, B01110, B10101, B00100, B00000 };
byte smili[8]  = { B00000, B01010, B01010, B00000, B00100, B10001, B01110, B00000 };
byte left[8]   = { B00010, B00110, B01110, B11110, B01110, B00110, B00010, B00000 };
byte right[8]  = { B01000, B01100, B01110, B01111, B01110, B01100, B01000, B00000 };
byte ae[8]     = { B01010, B00000, B01110, B00001, B01111, B10001, B01111, B00000 };

volatile int impState = 0;
volatile int lastimpState = 0;
int bounceTime  = 100;
unsigned long act_imp;
unsigned long last_imp;
double impCounter = 0;
unsigned long millisBetween;
unsigned long lastMillis;
unsigned long watt;

double kwh = 0.000;                                   // Kilowattstunden
double Preis =  0.2622;                               // Preis einer Kilowattstunde in Euro
double euro;
char tmp1[16];
char tmp2[16];

/*--- Solar Tracker ---*/
int moveleft = 4;                                     // Motor pin left
int moveright = 5;                                    // Motor pin right
int ldrleft = 1;                                      // Name und Pin-Nr (LDR links)
int ldrcenter = 2;                                    // Name und Pin-Nr (LDR mitte)
int ldrright = 3;                                     // Name und Pin-Nr (LDR rechts)
int LDR_hell = 0;                                     // Wert von LDR_hell
unsigned long Zeit_dtime;                    // Zeit-Variable für dtime
unsigned long pauseMillis;                   // Zeit-Variable für pause
/*--- Solar Tracker ---*/

void setup () 
{
  Serial.begin(9600);
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  pinMode(7, OUTPUT);                                 // LCD Hintergrundbeleuchtung
  pinMode(moveleft, OUTPUT);                          // Motor left als Ausgang deklarieren
  pinMode(moveright, OUTPUT);                         // Motor right als Ausgang deklarieren
  digitalWrite(moveleft, HIGH);
  digitalWrite(moveright,HIGH);
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, bell);                            // Sonderzeichen Glocke
  lcd.createChar(1, sun);                             // Sonderzeichen Sonne
  lcd.createChar(2, smili);                           // Sonderzeichen Smiley
  lcd.createChar(3, left);                            // Sonderzeichen left arrow
  lcd.createChar(4, right);                           // Sonderzeichen right arrow
  lcd.createChar(5, ae);                              // Sonderzeichen right arrow
  digitalWrite(7, HIGH);                              // LCD Hintergrundbeleuchtung AN
  lcd.setCursor(0,0);
  lcd.write(1);                                       // Sonne links
  lcd.setCursor(2,0);
  lcd.print(F("Starte Solar"));
  lcd.setCursor(15,0);
  lcd.write(1);                                       // Sonne rechts
  lcd.setCursor(3,1);
  lcd.print(F("Z"));
  lcd.write(5);
  lcd.print(F("hler ..."));
  delay(5000);
  lcd.clear();
  millisBetween = 0;
  lastMillis = 0;
  lastimpState = 0;
  watt = 0;
  Zeit_dtime = 0;
  pauseMillis = 0;
}

void loop () 
{
  impState = digitalRead(2);
  act_imp = millis();
  unsigned long time = millis();
  
  if(act_imp - last_imp > bounceTime)
  {

  if (impState != lastimpState) {
    if (impState == LOW) {
      last_imp = act_imp;
      impCounter++;
      
      millisBetween = time-lastMillis;
      lastMillis = time;
    }
  }
  lastimpState = impState;
  }
  
  /*--- Solar Tracker ---*/
  int left = analogRead(ldrleft);                     // LDR links einlesen
  int right = analogRead(ldrright);                   // LDR rechts einlesen
  int center = analogRead(ldrcenter);                 // LDR mitte einlesen
  int rightN = right +20;                             // (-12 )LDR rechts an den linken angleichen, bei +47 sind L u. R vom Wert her gleich
  int dtime = 1000;                                   // Such/Beweg geschwindigkeit
  int tol = 2;                                        // (28) tolleranz zwischen LDR-links und LDR-rechts
  unsigned long pause = 120000;                       // 2 min Pause in milliSek , wenn Links und Rechts gleich sind
  int alr = (left + rightN) / 2;                      // durchschnitt LDR-links u. LDR-rechts
  int LDR_hell = center;                              // LDR-mitte auch als LDR_hell deklarieren, für Nacht/Tag modus
  int dhoriz = alr - center;                          // check the diffirence of left/rigt and center
  int LR = left - rightN;
  
  
       display_Counter();
       digitalWrite(7, HIGH);                         // LCD Hintergrundbeleuchtung AN
       
  if((millis() - pauseMillis) > pause){               // Pause wenn L&R gleich sind
    
   if((millis() - Zeit_dtime) > dtime){               // Such/Beweg geschwindigkeit
    Zeit_dtime = millis();
      
  if (center <= 50) {
    digitalWrite(moveright, HIGH);                  // einzelne schritte -
    digitalWrite(moveleft, LOW);
    //digitalWrite(7, LOW); 
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print(F("Nacht-Modus"));
    delay(120000);
  } else {
    
  if (-1*tol > dhoriz || dhoriz > tol)                // check if the diffirence is in the tolerance else change horizontal angle
  {
    
    if (left < rightN)                                // ist links kleiner als rechts, fahre nach links
    {
      //Serial.println(F("Move -->"));
      digitalWrite(moveright, HIGH);                  // einzelne schritte -
      digitalWrite(moveleft, LOW); 
      lcd.setCursor(14,1);
      lcd.write(4);
    }
    else if (left > rightN)                           // ist links größer als rechts, fahre nach rechts
    {
      //Serial.println(F("<-- Move"));      
      digitalWrite(moveleft, HIGH);                   // einzelne schritte +
      digitalWrite(moveright, LOW);
      lcd.setCursor(14,1);
      lcd.write(3);
    }
    else if (left == rightN)                          // sind links u. rechts gleich, in dieser stellung für 30 sek. bleiben
    {
      pauseMillis = millis();
      //Serial.println(F("Horizontal Optimal !"));
      digitalWrite(moveleft, HIGH);
      digitalWrite(moveright, HIGH);
      lcd.setCursor(14,1);
      lcd.write(2);
      }
     
    }

    if (left != rightN)  { /* nix */ }                 // sind links und rechts ungleich, weiter suchen...
  }
   } /* Such/Beweg geschwindigkeit ende */ 
  }    /* Pause wenn L&R gleich sind ende */
  
 }/*--- Loop Ende ---*/
 
 void display_Counter(){
   kwh = impCounter / 1000;
    dtostrf(kwh, 1, 3, tmp1);
    lcd.setCursor(0,0);
    lcd.print(tmp1);
    lcd.print(F(" KWh"));
    
    euro = kwh * Preis;
    dtostrf(euro, 1, 3, tmp2);
    lcd.setCursor(0, 1);
    lcd.print(tmp2);
    lcd.print(" EUR");
    
    watt = 3600000 / millisBetween;
    
    if (int(watt) > 500) { watt = 500; }                  // ist Watt grösser als 500 , zeige nur 500 an

    lcd.setCursor(11,0);
    if (int(watt) <= -1){ lcd.print("  "); watt = 0;}     // ist Watt kleiner oder gleich -1, setze watt auf 0
    else if (int(watt) < 100 ) { lcd.print(' '); }        //stellt ein leeres Feld voran, wenn Watt kleiner als 100
    else if(int(watt) < 10 ) { lcd.print('  '); }         //stellt zwei leere Felder voran, wenn Watt kleiner als 10
    lcd.print(int(watt));
    lcd.setCursor(15, 0);
    lcd.print("W");
 }

Wenn noch irgendwelche Info´s benötigt werden, sagt bescheid.
Achso, das ganze läuft auf einem Uno mit Ethernet-Shield…

Schau mal, was Dein Speicher noch hergibt:

//Aufruf mit Serial.println(freeRam () );
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Nein, der Code ist nicht von mir, ich glaub Serenifly hat den mal gepostet.

Ich habe den auch nur woanders geklaut :)

Ist aber recht einfach. Der Speicheraufbau ist hier beschrieben: http://www.nongnu.org/avr-libc/user-manual/malloc.html

Der Heap wächst von unten nach oben und der Stack von oben nach unten. brkval ist das Ende des Heaps. Der freie Speicher ist der freie Platz zwischen Heap und Stack. Die Variable "v" landet auf dem Stack. Wenn man die Adresse davon nimmt (&v) hat man also die oberste Adresse auf dem Stack. Wenn kein dynamischer Speicher belegt ist, ist brkval anscheinend 0. Also rechnet man "Stack - Anfang des Heaps". Wenn dynamischer Speicher belegt ist, rechnet man "Stack - Ende des Heaps".

Cetax:
Kann mal jemand auf meinen Sketch schauen, ich finde den Fehler nicht… :blush:

Achso, das ganze läuft auf einem Uno mit Ethernet-Shield…

Wie jetzt? Ethernet-Shield?
Was macht das Ethernet-Shield in dem Sketch?

Soll das nur aufgesteckt sein, um den Sketch verrecken zu lassen?

Laut Arduino Shield List: Arduino Ethernet Shield v5.0 verwendet das Ethernet-Shield A0 und A1.

Und Du machst im Sketch:

int ldrleft = 1;   
...
int left = analogRead(ldrleft);                     // LDR links einlesen

Je nach verwendetem Board und Arduino-Softwareversion wird die unsaubere Deklaration “1” in der Funktion “analogRead” als “A1” interpretiert und A1 angesprochen. Wenn der Sketch wenigstens anfänglich funktioniert, dürfte das bei Dir der Fall sein. Und dann beißt es sich mit der Verwendung von A1 durch das Ethernet-Shield.

Hallo jurs,

jurs:

Cetax: Kann mal jemand auf meinen Sketch schauen, ich finde den Fehler nicht... :blush: ... Achso, das ganze läuft auf einem Uno mit Ethernet-Shield...

Wie jetzt? Ethernet-Shield? Was macht das Ethernet-Shield in dem Sketch?

Soll das nur aufgesteckt sein, um den Sketch verrecken zu lassen?

Laut http://shieldlist.org/arduino/ethernet-v5 verwendet das Ethernet-Shield A0 und A1.

Und Du machst im Sketch:

int ldrleft = 1;   
...
int left = analogRead(ldrleft);                     // LDR links einlesen

Je nach verwendetem Board und Arduino-Softwareversion wird die unsaubere Deklaration "1" in der Funktion "analogRead" als "A1" interpretiert und A1 angesprochen. Wenn der Sketch wenigstens anfänglich funktioniert, dürfte das bei Dir der Fall sein. Und dann beißt es sich mit der Verwendung von A1 durch das Ethernet-Shield.

Also das Ethernetshield ist drauf, weil er auch noch Server ist um die Werte an zu zeigen. Aber warum beist sich das ? ich dachte das Ethernetshield benutzt pin 10, 11, 12, und 13

Hallo Klaus,

Klaus_ww: Schau mal, was Dein Speicher noch hergibt:

//Aufruf mit Serial.println(freeRam () );
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Nein, der Code ist nicht von mir, ich glaub Serenifly hat den mal gepostet.

Kann ich erst morgen sehen, wenn die Sonne wieder da ist und dasganze arbeitet. Ich hoffe nicht das es am Speicher liegt. Aber mal sehen..

Cetax: Also das Ethernetshield ist drauf, weil er auch noch Server ist um die Werte an zu zeigen. Aber warum beist sich das ? ich dachte das Ethernetshield benutzt pin 10, 11, 12, und 13

An A0 und A1 sind zwei Signale des SD-Kartenschachtes angeschlossen, und zwar Signale für - SD Karte vorhanden / nicht vorhanden - SD Karte schreibgeschützt / nicht schreibgeschützt

Wenn Du zwar den Ethernet-Teil benötigst, aber diese beiden SD-Kartensignale nicht, dann kannst Du die beiden Pins A0 und A1 am Ethernet-Shield gerne um 90° krummbiegen oder abknipsen bevor Du das Shield aufsteckst, so dass diese beiden Pins keine Verbindung zwischen Arduino-Board und Ethernet-Shield mehr haben. Dann kannst Du auch A0 und A1 bei aufgestecktem Ethernet-Shield für analogRead verwenden. Allerdings kannst Du an diesen beiden Pins danach nicht mehr auslesen, ob eine SD Karte eingesteckt ist oder nicht und ob sie ggf. den Schreibschutz eingelegt hat oder nicht.

Ist das wirklich der Sketch bei dem sich Arduin blockiert oder nur eine Auswahl?

Millis würd ich ausschließen da der Überlauf nach 49,5 Tagen passiert und nicht nach 2-3 Stunden. Pin 4 wird für die SD Karte auf dem Ethernetshied verwendet.

Zum Kontrollieren wirf mal alle Ausgaben fürs Display raus; Steck das Ethernetshield ab; Wie schaut die Spannungsversorgung aus?

Grüße Uwe

Hallo Uwe, Hallo Jurs,
erstmal Danke für Eure unterstützung :smiley:

Das habe ich so nicht bedacht, also welche Pins vom Ethernetshield benutzt werden.
Ich werde das ganze mal umbauen, erstmal testen ohne Ethernetshield und dann mit anderer Pin belegung.

Die Stomversorgung kommt von einer Autobatterie mit einem Step-down-Wandler auf ca. 9V.

Erstmal vielen Dank, ich werde das dann mal umsetzten und testen.
Ich melde dann noch mal, ob Erfolgreich oder nicht.

DANKE !

Hallo allerseits, so kleines Feedback... Es läuft, ich habe das EtheretShield weggelassen und siehe da... Löppt... :D

Also, werde ich das ganz umbauen, Arduino Mini Pro und WIZnet WIZ812MJ Ethernet Modul. Damit habe ich schon mal sehr gute Erfahrung gemacht (Washduino gebaut).

Also Uwe und Jurs, vielen Dank für die Hilfe, Ohne Euch hätte ich mich tot gesucht... Big Thx !!