probleme mit schleife

Liebes Forum,

ich bin neu in der Arduino-Welt und aergere mich seit vorgestern mit einem Programmfehler rum den ich nicht gelöst bekomme. Mein Sketch haengt in einer do… while schleife fest obwohl die stopp-bedingung (gemessene temperatur < vorgebene temp.) bereits erreicht wurde. wenn ich eine andere bedingung eintrage (variable hochzaehlen und mit fixwert vergleichen) funktioniert es so wie es sollte. unten der code, ich weiss nicht ob damit ohne die Hardware jemand etwas anfangen kann? vielleicht ists aber auch ein ganz bloeder fehler der euch sofort auffaellt!

Danke fuer eure Hilfe!!

christoph

#include <OneWireTempSensor.h>

#include <OneWire.h>
#include <LiquidCrystal.h>

const int HeizPin = 13; //nachher das Steuerrelais fuer Brenner hier dranhaengen
const int startPin = 10; // Pin fuer taster fuer Programmstart
boolean startknopf; //wird nachher bei einmaligem betaetigen auf 1 gesetzt
boolean heizphase; //heizphase == 1: heizen auf naechste Stufe. wenn 0: wartezeit
int phase; // durchlaufender Phasenzaehler, pro Rast und heizstufe eine phase

int TempEinmaisch = 30;
int TempRast_01 = 62;
int TempRast_02 = 68;
int TempRast_03 = 73;
int TempRast_04 = 76;
int TempAbmaisch = 78;

int DauerRast_01 = 10;
int DauerRast_02 = 30;
int DauerRast_03 = 30;
int DauerRast_04 = 30;

int ZielTemp; //wird jeweils gleich mit aktueller rast gesetzt
int Dauer; //wird jeweils gleich mit aktueller rast gesetzt
long Restdauer; //Restdauer einer Raststufe
long abgelaufeneZeit; //stoppt die bis dahin im Arduino abgelaufene Zeit
//fuer die Restdauerberechnung

int DS18S20_Pin = 7; //DS18S20 Signal pin on digital 7 by rahulmitra
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

//Temperature chip i/o
OneWire ds(DS18S20_Pin); // on digital pin 7 by rahulmitra

void setup(void) {
lcd.begin(20, 4);

pinMode(HeizPin, OUTPUT);
pinMode(startPin, INPUT);

phase = 0;
heizphase = 0;
startknopf = 0;
ZielTemp = TempEinmaisch;
Dauer = DauerRast_01;

}

void loop(void) {

if (digitalRead(startPin) == HIGH){ //einmaliges betaetigen des Starters
startknopf = 1; // setzt variable dauerhaft auf 1
}

float temperature = getTemp();

if (startknopf == 0){

lcd.setCursor(0, 0);
lcd.print("Akt: ");
lcd.print(temperature);
lcd.print(“C”);

lcd.setCursor(2, 2);
lcd.print(“WARTEN AUF START”);

lcd.setCursor(0, 3);
lcd.print("Phase: ");
lcd.print(phase);
}

if (startknopf == 1 && phase == 0){

lcd.setCursor(0, 0);
lcd.print("Akt: ");
lcd.print(temperature);
lcd.print(“C”);

lcd.setCursor(2, 2);
lcd.print(" GESTARTET ");

lcd.setCursor(0, 3);
lcd.print("Phase: ");
lcd.print(phase);

delay(500);
heizphase = 1;
phase = 1;
}

// hier spaeter mal eine funktion einbauen, was passiert wenn
//die akt. Kesseltemp. hoeher ist als die naechste Zieltemp.

if (startknopf == 1 && heizphase == 1) {

do {

digitalWrite(HeizPin, HIGH);

float temperature = getTemp();

lcd.setCursor(0, 0);
lcd.print("Akt: ");
lcd.print(temperature);
lcd.print(“C; Heizen”);

lcd.setCursor(0, 1);
lcd.print("bis ");
lcd.print(ZielTemp);
lcd.print(“C fuer “);
lcd.print(phase);
lcd.print(”. Rast”);

lcd.setCursor(0, 2);
lcd.print(" ");

lcd.setCursor(0, 3);
lcd.print("Phase: ");
lcd.print(phase);

}

** while (temperature < ZielTemp); //DAS HIER IST DIE BEDINGUNG DIE NICHT FUNKTIONIERT**

digitalWrite(HeizPin, LOW);
phase = 2;
heizphase = 0;

lcd.setCursor(0, 3);
lcd.print("Phase ");
lcd.print(phase);

}

}

float getTemp()
{
//returns the temperature from one DS18S20 in DEG Celsius

byte data[12];
byte addr[8];

if ( !ds.search(addr)) {
//no more sensors on chain, reset search
ds.reset_search();
return -1000;
}

if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.println(“CRC is not valid!”);
return -1000;
}

if ( addr[0] != 0x10 && addr[0] != 0x28) {
Serial.print(“Device is not recognized”);
return -1000;
}

ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end

byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad

for (int i = 0; i < 9; i++) { // we need 9 bytes
data = ds.read();

  • }*
  • ds.reset_search();*
  • byte MSB = data[1];*
  • byte LSB = data[0];*
  • float tempRead = ((MSB << 8) | LSB); //using two’s compliment*
  • float TemperatureSum = tempRead / 16;*
  • return TemperatureSum;*
    }
    [/quote]
while (temperature < ZielTemp);

Wo werden die Werte denn verändert?
Du bist in der schleife und die Werte bleiben immmer dieselben weil Du sie nie liest.
Ist so wie wenn Du auf schönes Wetter wartest aber immer den gleichen alten Wetterbericht seit Ewigkeiten liest.

while (temperature < ZielTemp)
{
temperature lesen!!!;
}

Die ist auch bewußt das das While den Sketch blockiert und du nichts anderes machen kannst?

[EDIT]
Hatte übersehen daß das eine DO while Schleife ist und keine While. Entschuldige facetto meinen Fehler

Grüße Uwe

Bitte mit # posten und nicht diese gequirlte :zipper_mouth_face: aus der IDE heraus.

    while (temperature < ZielTemp);  //DAS HIER IST DIE BEDINGUNG DIE NICHT FUNKTIONIERT


    digitalWrite(HeizPin, LOW);
    phase = 2;
    heizphase = 0;

    lcd.setCursor(0, 3);
    lcd.print("Phase ");
    lcd.print(phase);

  }

Das ist nicht gut gelöst! Zum einen dürfte es auf dem LCD zum Flackern kommen. Es reicht alle x Sekunden das LCD neuzubeschreiben. Schau dir mal BlinkWithousDelay an.

Die while-Funktioniert so wunderbar. Nur wird dein Code nicht ausgeführt der darunter steht. Hinter while (temperature < ZielTemp); kommt kein “;”. Alles was dauerhaft ausgeführt wird muss somit

while(bedingung) {
// ..
}
gemacht werden.
do {
      digitalWrite(HeizPin, HIGH);
      float temperature = getTemp();

      lcd.setCursor(0, 0);
      lcd.print("Akt: ");
      lcd.print(temperature);
      lcd.print("C; Heizen");

      lcd.setCursor(0, 1);
      lcd.print("bis ");
      lcd.print(ZielTemp);
      lcd.print("C fuer ");
      lcd.print(phase);
      lcd.print(". Rast");

      lcd.setCursor(0, 2);
      lcd.print("                   ");

      lcd.setCursor(0, 3);
      lcd.print("Phase: ");
      lcd.print(phase);
    }

    while (temperature < ZielTemp);

Was wird auf dem Display ausgegeben?

Grüße Uwe

danke fuer eure antworten!

@sschultewolter: es handelt sich nicht um eine while schleife sondern um eine do… while schleife. Da sollte das mit dem semikolon am ende funktionieren, siehe hier:
http://arduino.cc/en/pmwiki.php?n=Reference/DoWhile

@uwefed: auf dem display wird konstant der text usw. ausgegeben der waehrend der “do” phase ausgegeben werden soll. wenn ich die bedingung fuer “while” vereinfache ((variable hochzaehlen und mit fixwert vergleichen) komme ich aus der schleife raus und der inhalt des displays aendert sich so wie ich es erwarte. nur irgendwie scheint meine bedingung (temperature < ZielTemp), das vergleichen der “ist”- mit einer “solltemperatur” nicht zu funktionieren. Habe auch schon die art der variable von float in integer verwandelt weil ich dachte man kann kein float mit integer vergleichen, hat auch nix gebracht…

gruss, facetto

Am besten du verzichtest auf die Schleife und strukturierst statt dessen dein Programm vernünftig.

Was du da hast ist eine Prozessablaufsteuerung. Die stellt man durch eine Finite State Machine dar. Oder auf deutsch einen endlichen Zustandsautomaten: http://de.wikipedia.org/wiki/Endlicher_Automat

Einfache FSMs lassen sich ganz bequem mit enums und switch/case realisieren.

Vereinfachter Code für das Prinzip:

enum states { PHASE1, PHASE2 };
states currentState = PHASE1;

void loop()
{   
        switch(currentState)
    {
        case PHASE1:
            Serial.println("Phase 1");

                        if(...) currentState = PHASE2;
            break;

        case PHASE2:
            Serial.println("Phase 2");

                        if(...) currentState = PHASE1;
            break;
    }
}

Und dann je nach Bedarf mit weiteren Zuständen und Übergängen erweitern. Dieses Schema wird zwar schnell unübersichtlich, aber für dich reicht das vollkommen.

Hier bietet sich noch an Code in Funktionen auszulagern, weil du dann den switch/case Code kürzer und übersichtlicher hast:

void loop()
{   
        switch(currentState)
    {
        case PHASE1:
            phase1();

                        if(...) currentState = PHASE2;
            break;
         }
}

void phase1()
{
}

Die nächste Stufe wäre dann ein Funktionszeiger auf die aktuelle Funktion und die Funktionen jeweils einen Zeiger auf die nächste Funktion zurückgeben lassen. Dann muss man nur noch den Funktions-Zeiger in loop() aufrufen, aber der Rest ist vollständig gekapselt. Darüber hinaus gibt es noch diverse Varianten mit Tabellen (d.h. Arrays) aus Funktionszeigern. Das wäre für dich als Anfänger aber zu kompliziert und ist hier auch gar nicht nötig.

facetto:
@uwefed: auf dem display wird konstant der text usw. ausgegeben der waehrend der “do” phase ausgegeben werden soll. wenn ich die bedingung fuer “while” vereinfache ((variable hochzaehlen und mit fixwert vergleichen) komme ich aus der schleife raus und der inhalt des displays aendert sich so wie ich es erwarte. nur irgendwie scheint meine bedingung (temperature < ZielTemp), das vergleichen der “ist”- mit einer “solltemperatur” nicht zu funktionieren. Habe auch schon die art der variable von float in integer verwandelt weil ich dachte man kann kein float mit integer vergleichen, hat auch nix gebracht…

gruss, facetto

welche Zahlen für Die gemessene Temperatur werden ausgegeben?

Grüße Uwe

Hallo,

Du solltest Dein Code in code Tags und nicht in quote Tags “einrahmen” Funktioniert erstmal auch, aber ganz unten sehe ich ein Smilie im Code, was bestimmt ein Operationszeichen sein soll. Das darf nicht sein.

Zum Problem. Wenn ich den Sketch nachbaue, funktioniert er. Egal ob ich Zieltemp als float 0.0 oder int 0 definiere. Manchmal gibts ein Problem beim rechnen mit float wenn man statt 0.0 nur 0 nimmt. Trifft aber hier demnach nicht zu.

Mich macht aber folgender Satz stutzig.

Mein Sketch haengt in einer do… while schleife fest obwohl die stopp-bedingung (gemessene temperatur < vorgebene temp.) bereits erreicht wurde.

Du läßt beim testen eine Variable hochzählen, wie ich hier auch und das funktioniert. Weil die do-while Schleife so lange durchlaufen wird, solange bei Dir “temperature” kleiner ist wie die “ZielTemp”.
Das heißt, die Stoppbedingung ist nicht das die temperatur kleiner ist, sondern sobald diese größer wird wie die Zieltemp. ist die Bedingung erfüllt. Das ist in dem Sinne keine Stop-Bedingung, sondern eine Gültigkeitsbedingung für die do-while Schleife. Wenn die Bedingung nicht mehr gültig ist, wird sie abgebrochen.

Falls Du Dich nur falsch ausgedrückt hast, oder ich falsch verstanden, würde ich die Funktion getTemp kontrollieren ob das mit dem float Rückgabewert auch wirklich so funktioniert. In dem Du alles auskommenstiert und darin nur eine float Variable um 0.5 hochzählen läßt. Mal sehen was dann passiert.

#define LED1 34

int ZielTemp = 20;
float Temp = 0;

void setup()  {
  
  Serial.begin(57600);  
  
  pinMode(LED1, OUTPUT);     // 1.LED
  digitalWrite(LED1, LOW);   // 
 
    
}   // Ende setup


void loop(void) {
 
// LoopTiming();  // Loop Time Messung Start

  do {

      digitalWrite(LED1, HIGH);
      Serial.print("LED 1: ");
      Serial.println("EIN");
      Temp = Temp + 0.5;
      Serial.println(Temp,2);
      delay(500);
    }
    while (Temp < ZielTemp);  
  
   digitalWrite(LED1, LOW);
   Serial.print("LED 1: ");
   Serial.println("AUS");
   delay(500);
   
}   // Ende loop

Mein Sketch haengt in einer do… while schleife fest obwohl die stopp-bedingung (gemessene temperatur < vorgebene temp.) bereits erreicht wurde.

Hi, geil, habs gefunden!! War ein blöder anfaengerfehler!! Ich hatte die variable float temperature nicht EINMAL global definiert sondern zweimal in void loop (einmal am anfang und dann nochmal in der do… while schleife). Anscheinend wurde aufs display dann die version aus der schleife gedruckt, aber die while() hat sich die uebergeornete version rangezogen. Und die wurde natuerlich nicht aktualisiert weil nicht in der schleife…

Danke fuer eure antworten!

Achso, eins faellt mir grad noch ein: was bedeutet es, dass in meinem grundsketch bei void loop() in den klammern nochmal „void“ steht?? Also void loop(void)

Gruß, facetto (der nun an seiner automatische bierbrausteuerung weiterarbeiten kann)

void hinten in den Klammern heißt dass keine Parameter übergeben werden. Das ist aber anders als der Rückgabe-Wert optional.

Was du gemacht hast nennt sich Variablen-Überdeckung oder - Verdeckung: http://de.wikibooks.org/wiki/C-Programmierung:_Funktionen#Verdeckung Jetzt wo des sagst ist es sehr offensichtlich. Auf die globale Variable hättest du mit dem Scope-Resolution Operator :: zugreifen können.

Der Vollständigkeit halber übrigens die FSM mit Funktionszeigern als Rückgabewert:

struct nextFunc {
  nextFunc (*next)();         //Zeiger auf eine Funktion "next" die ein nextFunc struct zurückgibt und keine Parameter hat
};

inline nextFunc ret(nextFunc(*func)())       //Hilfs-Funktion um ein struct zu erstellen
{
  nextFunc ret = { func };
  return ret;
}

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  static nextFunc next = { func1 };            //Ausgangs-Situation
  static unsigned long previousMillis;

  if (millis() - previousMillis > 1000)          //nur um die die Ausgabe zu verlangsamen!
  {
    previousMillis = millis();

    next = next.next();               //Funktion aufrufen und nächste Funktion abspeichern
  }
}


struct nextFunc func1()
{
  Serial.println("Func 1");

  return ret(func2);                 //nächste Funktion die aufgerufen werden soll zurückgeben.
                                                  //hier kann man mit Bedingungen verzweigen
}

struct nextFunc func2()
{
  Serial.println("Func 2");

  return ret(func1);
}

Das struct ist nötig weil man sonst in eine Rekursion bei der Definition des Funktionszeigers gerät. Man müsste einen Zeiger auf eine Funktion definieren die den Zeiger den man gerade definieren will zurückgibt. Das kann man zwar einfach umgehen in dem man void* zurückgibt und dann den Zeiger für dem Aufruf auf den eigentlichen Typ castet, aber untypisierte Zeiger sind etwas unschön. Ist aber Geschmackssache. Den Zeiger aber einfach in ein struct zu packen wird oft vorgeschlagen. Dann gibt man statt dem Zeiger ein struct zurück.

Die ret() Funktion ist nur eine Hilfs-Funktion damit man das struct leichter erstellen kann und weniger schreiben muss.

Den Vorteil hier sollte man gleich sehen. Man muss in loop() nichts mehr machen. :) Dort wird einfach immer die nächste Funktion aufgrufen und deren Rückgabe-Wert (der wiederum die nächste Funktion ist) abgespeichert.

Um neue Zustände hinzuzufügen reicht es lediglich neue Funktionen zu erstellen und diese über die Rückgabe-Werte miteinander zu verbinden. Man kann dann auf irgendein Ereignis (z.B. Taster gedrückt, Temperatur überschritten) abfragen und je nachdem eine andere Funktion zurückgeben die als nächsten aufgerufen werden soll.