Drehgeber gibt bei längerem Code falsche Werte aus

Hallo, ich nutze einen Arduino Mega mit zwei Drehgebern (KY-040), einem 4-Zeilendisplay und einem Temp-Sensor DS18B20 um eine Heizung anzusteuern. Die einzelnen Komponenten habe ich erfolgreich angesteuert. Auch die Drehgeber erzeugen im separaten Programm korrekte Werte, nur in meinem zusammengefügten Code kommt nichts vernünftiges bei rum. Liegt es am längeren Durchlaufzyklus? Würde mich über Hilfe freuen.
Gruß

Bin selbst Anfänger, aber die erste Frage, die dir gestellt wird, ist die nach dem Code. Sonst kann dir auch von den Profis leider keiner helfen.

Sorry, wusste nicht dass man nach jedem Post 5 Min warten muss, also hier noch der Code:

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

// Display 

int CLK1 = 3;  // Connected to CLK on KY-040
int DT1 = 4;  // Connected to DT on KY-040
int CLK2 = 5;  // Connected to CLK on KY-040
int DT2 = 6;  // Connected to DT on KY-040
int SollTemp = 0; 
int Timer = 0; 
int CLK1Last;  
int aVal;
boolean bCW1;
int CLK2Last;  
int bVal;
boolean bCW2;
int Heizung = 9;
OneWire  ds(10);
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
void setup()   
{
Serial.begin(9600);  
lcd.begin(20,4);   
 pinMode (CLK1,INPUT);
 pinMode (DT1,INPUT);
 pinMode(Heizung,OUTPUT);
  CLK1Last = digitalRead(CLK1); 
}
void loop()   
{
//Temperatur
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;
{
  // when characters arrive over the serial port...
  if (Serial.available()) {
    // wait a bit for the entire message to arrive

    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());
    }
  }
}
if ( !ds.search(addr)) {

  Serial.println();
  ds.reset_search();
  return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
  Serial.write(' ');
  Serial.print(addr[i], HEX);
}

if (OneWire::crc8(addr, 7) != addr[7]) {
    Serial.println("CRC is not valid!");
    return;
}
Serial.println();
// the first ROM byte indicates which chip
switch (addr[0]) {
    Serial.println("  Chip = DS18B20");
    type_s = 0;
} 
ds.reset();
ds.select(addr);
ds.write(0x44, 1);        // start conversion, with parasite power on at the end
present = ds.reset();
ds.select(addr);    
ds.write(0xBE);         // Read Scratchpad
Serial.print("  Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) {           // we need 9 bytes
  data[i] = ds.read();
  Serial.print(data[i], HEX);
  Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
  raw = raw << 3; // 9 bit resolution default
  if (data[7] == 0x10) {
    // "count remain" gives full 12 bit resolution
    raw = (raw & 0xFFF0) + 12 - data[6];
  }
} else {
  byte cfg = (data[4] & 0x60);
  // at lower res, the low bits are undefined, so let's zero them
  if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
  else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
  else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  //// default is 12 bit resolution, 750 ms conversion time
}
aVal = digitalRead(CLK1);
 if (aVal != CLK1Last){ // Means the knob is rotating
   // if the knob is rotating, we need to determine direction
   // We do that by reading pin B.
   if (digitalRead(DT1) != aVal) {  // Means pin A Changed first - We're Rotating Clockwise
     SollTemp ++;
     bCW1 = true;
   } else {// Otherwise B changed first and we're moving CCW
     bCW1 = false;
     SollTemp--;
   }
   Serial.print ("Rotated: ");
   if (bCW1){
     Serial.println ("clockwise");
   }else{
     Serial.println("counterclockwise");
   }
   Serial.print("SollTemp: ");
   Serial.println(SollTemp);
 } 
 CLK1Last = aVal;

 bVal = digitalRead(CLK2);
 if (bVal != CLK2Last){ // Means the knob is rotating
   // if the knob is rotating, we need to determine direction
   // We do that by reading pin B.
   if (digitalRead(DT2) != bVal) {  // Means pin A Changed first - We're Rotating Clockwise
     Timer ++;
     bCW2 = true;
   } else {// Otherwise B changed first and we're moving CCW
     bCW2 = false;
     Timer--;
   }
   Serial.print ("Rotated: ");
   if (bCW2){
     Serial.println ("clockwise");
   }else{
     Serial.println("counterclockwise");
   }
   Serial.print("Timer: ");
   Serial.println(Timer);
  } 
 CLK2Last = bVal;
{
if (celsius < SollTemp) {digitalWrite(Heizung, HIGH);
} else {
  digitalWrite(Heizung, LOW);
  }
}
celsius = (float)raw / 16.0;
lcd.setCursor(0,0);
lcd.print("Soll Temp:");
lcd.setCursor(11,0);
lcd.print(SollTemp);
lcd.setCursor(16,0);
lcd.print("Grad");
lcd.setCursor(0,1);
lcd.print("Ist  Temp: "); 
lcd.setCursor(11,1);
lcd.print(celsius); 
lcd.setCursor(16,1);
lcd.print("Grad"); 
lcd.setCursor(0,2);
lcd.print("Timer:");
lcd.setCursor(11,2);
lcd.print(Timer); 
lcd.setCursor(16,2);
lcd.print("Min"); 
}

Wenn man den Sensor blockierend ausliest, dauert eine Wandlung je nach Auflösung 93-750ms. Während dessen kann nichts gemacht werden. Je nach Anwendung reicht es aber völlig wenn man Temperatur-Sensoren nur alle 30-60s Sekunden ausliest. Dann aber ohne delay()!

Schon mal vielen Dank für die Antwort, wie setzt man so eine punktuelle Auswertung ohne delay denn um?

Indem du millis() verwendest.

Dank Dir!

buffalo64:
Indem du millis() verwendest.

Hier solltest du noch das Beispiel "BlinkWithoutDelay" erwähnen, da kann man die Funktion von millis gut entnehmen.

Sch...., ich vergaß.

Hallo,

und der übliche Hinweis. :slight_smile: Code bitte in Code Tags setzen. Ersten Button links </>.
Geht auch nachträglich.

Doc_Arduino:
Hallo,

und der übliche Hinweis. :slight_smile: Code bitte in Code Tags setzen. Ersten Button links </>.
Geht auch nachträglich.

Hab's schon gemacht.
Uwe

Vielen Dank für die Antworten. Ich habe die Millis nun eingefügt, aber das Ergebnis stimmt noch nicht, habe ich einen Fehler gemacht?

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

// Display 

 int CLK1 = 3;  // Connected to CLK on KY-040
 int DT1 = 4;  // Connected to DT on KY-040
 int CLK2 = 5;  // Connected to CLK on KY-040
 int DT2 = 6;  // Connected to DT on KY-040
 int SollTemp = 0; 
 int Timer = 0; 
 int CLK1Last;  
 int aVal;
 boolean bCW1;
 int CLK2Last;  
 int bVal;
 boolean bCW2;
 int Heizung = 9;
OneWire  ds(10);
unsigned long previousMillis = 0;
const long interval = 1000;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
void setup()   
{
  Serial.begin(9600);  
  lcd.begin(20,4);   
   pinMode (CLK1,INPUT);
   pinMode (DT1,INPUT);
   pinMode(Heizung,OUTPUT);
    CLK1Last = digitalRead(CLK1); 
}
void loop()   
{
//Temperatur
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;

  unsigned long currentMillis = millis();
 if (currentMillis - previousMillis >= interval) {
    
    previousMillis = currentMillis;}
  
  {
    // when characters arrive over the serial port...
    if (Serial.available()) {
      // wait a bit for the entire message to arrive

      // clear the screen
      lcd.clear();
      // read all the available characters
      while (Serial.available() > 0) {
        // display each character to the LCD
        lcd.write(Serial.read());
      }
    }
  }
 if ( !ds.search(addr)) {

    Serial.println();
    ds.reset_search();
    return;
  }
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();
  // the first ROM byte indicates which chip
  switch (addr[0]) {
      Serial.println("  Chip = DS18B20");
      type_s = 0;
  } 
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad
  Serial.print("  Data = ");
  Serial.print(present, HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print(OneWire::crc8(data, 8), HEX);
  Serial.println();
  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
aVal = digitalRead(CLK1);
   if (aVal != CLK1Last){ // Means the knob is rotating
     // if the knob is rotating, we need to determine direction
     // We do that by reading pin B.
     if (digitalRead(DT1) != aVal) {  // Means pin A Changed first - We're Rotating Clockwise
       SollTemp ++;
       bCW1 = true;
     } else {// Otherwise B changed first and we're moving CCW
       bCW1 = false;
       SollTemp--;
     }
     Serial.print ("Rotated: ");
     if (bCW1){
       Serial.println ("clockwise");
     }else{
       Serial.println("counterclockwise");
     }
     Serial.print("SollTemp: ");
     Serial.println(SollTemp);
   } 
   CLK1Last = aVal;

   bVal = digitalRead(CLK2);
   if (bVal != CLK2Last){ // Means the knob is rotating
     // if the knob is rotating, we need to determine direction
     // We do that by reading pin B.
     if (digitalRead(DT2) != bVal) {  // Means pin A Changed first - We're Rotating Clockwise
       Timer ++;
       bCW2 = true;
     } else {// Otherwise B changed first and we're moving CCW
       bCW2 = false;
       Timer--;
     }
     Serial.print ("Rotated: ");
     if (bCW2){
       Serial.println ("clockwise");
     }else{
       Serial.println("counterclockwise");
     }
     Serial.print("Timer: ");
     Serial.println(Timer);
    } 
   CLK2Last = bVal;
{
  if (celsius < SollTemp) {digitalWrite(Heizung, HIGH);
  } else {
    digitalWrite(Heizung, LOW);
    }
  }
  celsius = (float)raw / 16.0;
  lcd.setCursor(0,0);
  lcd.print("Soll Temp:");
  lcd.setCursor(11,0);
  lcd.print(SollTemp);
  lcd.setCursor(16,0);
  lcd.print("Grad");
  lcd.setCursor(0,1);
  lcd.print("Ist  Temp: "); 
  lcd.setCursor(11,1);
  lcd.print(celsius); 
  lcd.setCursor(16,1);
  lcd.print("Grad"); 
  lcd.setCursor(0,2);
  lcd.print("Timer:");
  lcd.setCursor(11,2);
  lcd.print(Timer); 
  lcd.setCursor(16,2);
  lcd.print("Min"); 
 }

Ein Vorschlag zu deinem Sketch, hat nicht direkt etwas mit deinem Fehler zu tun:

Setze die einzelnen Programmteile (Temperatur, Anzeige) in Funktionen, dadurch wird der Sketch übersichtlicher und ein Programmfehler lässt sich so schneller finden.

Verfolgst du einen bestimmten Zweck mit deiner eigenartigen Klammersetzung?

Ich mach sowas nur in bestimmten Fällen, um lokale Variablen im loop mehrfach zu verwenden.

Der Aufbau ist vll noch nicht ganz optimal. Bin noch blutiger Anfänger.

Matthias321:
Der Aufbau ist vll noch nicht ganz optimal. Bin noch blutiger Anfänger.

Das ist doch kein Problem, wir sind alle mal angefangen.

Wenn du aber die gemachten Ratschläge befolgst, wird es einfacher und der Sketch übersichtlicher.

Hallo,

das mit der Klammersetzung haste sicherlich nirgendswo so gesehen.
Hab den Code mal formatiert. Jetzt siehst du auch was deine obige millis Funktion macht.
Sie macht nämlich nichts, außer eine Variable zu aktualisieren.
Und ob deine Temperaturvariablen am Anfang der loop als lokale richtig sind, waage ich anzuweifeln.
Denn diese werden mit jeder neuen loop Runde neu erstellt.
Und nicht initialisierte lokale Variablen haben keinen definierten Inhalt/Wert.
Praktisch alles außer present.
Dann haste 2x Serial.available hintereinander mit if und while. Bestimmt auch nicht so wie gedacht.
Wild zusammen kopiert nehme ich an. Das klappt leider fast nie.

  #include <Wire.h>
  #include <OneWire.h>
  #include <LiquidCrystal_I2C.h>
  
  // Display
  
   int CLK1 = 3;  // Connected to CLK on KY-040
   int DT1 = 4;  // Connected to DT on KY-040
   int CLK2 = 5;  // Connected to CLK on KY-040
   int DT2 = 6;  // Connected to DT on KY-040
   int SollTemp = 0;
   int Timer = 0;
   int CLK1Last; 
   int aVal;
   boolean bCW1;
   int CLK2Last; 
   int bVal;
   boolean bCW2;
   int Heizung = 9;
   OneWire  ds(10);
   unsigned long previousMillis = 0;
   const long interval = 1000;
   LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
  
void setup()   
{
    Serial.begin(9600); 
    lcd.begin(20,4);   
    pinMode (CLK1,INPUT);
    pinMode (DT1,INPUT);
    pinMode(Heizung,OUTPUT);
    CLK1Last = digitalRead(CLK1);
}

  
void loop()   
{
    
    //Temperatur
    byte i;
    byte present = 0;
    byte type_s;
    byte data[12];
    byte addr[8];
    float celsius;
  
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
    }
       
    // when characters arrive over the serial port...
    if (Serial.available() > 0) {
      // wait a bit for the entire message to arrive
      // clear the screen
      lcd.clear();
      // read all the available characters
      while (Serial.available() > 0) {
        // display each character to the LCD
        lcd.write(Serial.read());
      }
    }
    
    if ( !ds.search(addr)) {
      Serial.println();
      ds.reset_search();
    }
    
    Serial.print("ROM =");
    for( i = 0; i < 8; i++) {
      Serial.write(' ');
      Serial.print(addr[i], HEX);
    }
  
    if (OneWire::crc8(addr, 7) != addr[7]) {
        Serial.println("CRC is not valid!");
    }
    
    Serial.println();
    // the first ROM byte indicates which chip
    switch (addr[0]) {
      Serial.println("  Chip = DS18B20");
      type_s = 0;
    }
    
    ds.reset();
    ds.select(addr);
    ds.write(0x44, 1);        // start conversion, with parasite power on at the end
    present = ds.reset();
    ds.select(addr);   
    ds.write(0xBE);         // Read Scratchpad
    Serial.print("  Data = ");
    Serial.print(present, HEX);
    Serial.print(" ");
    for ( i = 0; i < 9; i++) {           // we need 9 bytes
      data[i] = ds.read();
      Serial.print(data[i], HEX);
      Serial.print(" ");
    }
    
    Serial.print(" CRC=");
    Serial.print(OneWire::crc8(data, 8), HEX);
    Serial.println();
    // Convert the data to actual temperature
    // because the result is a 16 bit signed integer, it should
    // be stored to an "int16_t" type, which is always 16 bits
    // even when compiled on a 32 bit processor.
    int16_t raw = (data[1] << 8) | data[0];
    if (type_s) {
      raw = raw << 3; // 9 bit resolution default
      if (data[7] == 0x10) {
        // "count remain" gives full 12 bit resolution
        raw = (raw & 0xFFF0) + 12 - data[6];
      }
    } 
    else {
      byte cfg = (data[4] & 0x60);
      // at lower res, the low bits are undefined, so let's zero them
      if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
      else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
      else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
      //// default is 12 bit resolution, 750 ms conversion time
    }
    
    aVal = digitalRead(CLK1);
    if (aVal != CLK1Last){ // Means the knob is rotating
      // if the knob is rotating, we need to determine direction
      // We do that by reading pin B.
      if (digitalRead(DT1) != aVal) {  // Means pin A Changed first - We're Rotating Clockwise
        SollTemp ++;
        bCW1 = true;
      } 
      else {  // Otherwise B changed first and we're moving CCW
          bCW1 = false;
          SollTemp--;
      }
      
       Serial.print ("Rotated: ");
       if (bCW1){
         Serial.println ("clockwise");
       }else{
         Serial.println("counterclockwise");
       }
       Serial.print("SollTemp: ");
       Serial.println(SollTemp);
     }
     CLK1Last = aVal;
  
     bVal = digitalRead(CLK2);
     
     if (bVal != CLK2Last){ // Means the knob is rotating
       // if the knob is rotating, we need to determine direction
       // We do that by reading pin B.
       if (digitalRead(DT2) != bVal) {  // Means pin A Changed first - We're Rotating Clockwise
         Timer ++;
         bCW2 = true;
       } else {// Otherwise B changed first and we're moving CCW
         bCW2 = false;
         Timer--;
       }
       Serial.print ("Rotated: ");
       if (bCW2){
         Serial.println ("clockwise");
       }
       else{
         Serial.println("counterclockwise");
       }
       
       Serial.print("Timer: ");
       Serial.println(Timer);
     }
     CLK2Last = bVal;
 
    if (celsius < SollTemp) {
      digitalWrite(Heizung, HIGH);
    } 
    else {
      digitalWrite(Heizung, LOW);
    }
   
    celsius = (float)raw / 16.0;
    lcd.setCursor(0,0);
    lcd.print("Soll Temp:");
    lcd.setCursor(11,0);
    lcd.print(SollTemp);
    lcd.setCursor(16,0);
    lcd.print("Grad");
    lcd.setCursor(0,1);
    lcd.print("Ist  Temp: ");
    lcd.setCursor(11,1);
    lcd.print(celsius);
    lcd.setCursor(16,1);
    lcd.print("Grad");
    lcd.setCursor(0,2);
    lcd.print("Timer:");
    lcd.setCursor(11,2);
    lcd.print(Timer);
    lcd.setCursor(16,2);
    lcd.print("Min");

}  // loop Ende

Danke für Eure Hilfe! Muss ich dann die Variable meiner Temperatur mit Hilfe von Millis für die gewisse Zeit festsetzen?

Hallo,

ich weis nicht wo du den Code her hast, dass einfachste wäre jedoch für dich du nimmst die Lib für den Sensor.

Hier sind gute Bsp. dabei die man sich anschauen sollte.
Conversion 2 blockiert zum Bsp. nicht.
Im Grunde läuft das immer gleich ab. Ob blockierend oder nicht.
Der Sensor bekommt ein Request Befehlt geschickt das er messen soll. Das dauert eben bis zu 750ms lang.
Nach der Wartezeit kann man den Messwert abholen.
Ob man während der Wartezeit nochwas macht oder nicht ist erstmal egal.
Macht aber keinen Sinn dabei nichts zu tun. Deswegen nimmt man millis um während der Wartezeit andere sinnvolle Dinge dem µC aufzuhalsen.

Die Lib wollte ich auch schon empfehlen.

Den Sensor nicht-blockierend auszulesen muss man erst mal nicht unbedingt machen. Gerade bei den geringen Kenntnissen. Aber es sollte schon mal eine Verbesserung darstellen wenn man den Sensor nicht dauernd ausliest. Dann sollte genug Zeit bleiben den Drehgeber abzuarbeiten.