Temperatursteuerung bremst Arduino uno aus - Warum?

Hallo alle zusammen,
ich habe einen Arduino Uno und wollte mit einem DHT 11 (Temperatursensor) und LCD Display mit sechs Tasten eine Art Temperatursteuerung basteln. Das Auslesen des DHT11 funktioniert sehr gut und mein selbst gebasteltes Menü zur Auswahl der Temperaturminimum- und maximumwerte funktioniert einzeln auch. Wenn ich aber beide sketches zusammenlege, reagiert der Arduino nur sehr langsam auf meine Eingaben.
Das ist mein erstes Projekt mit dem Arduino und der Code ist bestimmt nicht der schönste. Statt den ganzen “if” Abfragen habe ich auch mit “switch” und “case” probiert, was aber von der Performance sehr langsam war?!
Hier der Code für den Temperatursensor DHT11 mit Anzeige auf LCD:

//Sample using LiquidCrystal library
#include <LiquidCrystal.h>

#include "DHT.h"

#define DHTPIN 2     // what pin we're connected to

// Uncomment whatever type you're using!
#define DHTTYPE DHT11   // DHT 11

/*******************************************************
 * 
 * This program will test the LCD panel and the buttons
 * Mark Bramwell, July 2010
 * 
 ********************************************************/

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor 
  // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result

    // For V1.0 comment the other threshold and use the one below:

  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 195)  return btnUP; 
  if (adc_key_in < 380)  return btnDOWN; 
  if (adc_key_in < 555)  return btnLEFT; 
  if (adc_key_in < 790)  return btnSELECT;   



  return btnNONE;  // when all others fail, return this...
}
DHT dht(DHTPIN, DHTTYPE);
int SupplyDHT = 13; // Volts for DHT, cant use 5V Pin, already used by LCD


void setup()
{
  lcd.begin(16, 2);              // start the library
  //lcd.begin(0, 2);
  lcd.setCursor(0,0);
  lcd.print("Temp:");
  lcd.setCursor(12,0);
  lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("Humid:");
  lcd.setCursor(12,1);
  lcd.print("%Rel");
  Serial.begin(9600); 
  Serial.println("DHTxx test!");
  // initialize the digital pin as an output.
  pinMode(SupplyDHT, OUTPUT);
  dht.begin();
}

void loop()
{
  digitalWrite(SupplyDHT, HIGH);   // turn the DHT on (HIGH is the voltage level)
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  lcd.setCursor(6,0);            // move cursor to second line "1" and 9 spaces over
  lcd.print(t);
  lcd.setCursor(6,1);            // move cursor to second line "1" and 9 spaces over
  lcd.print(h);

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } 
  else {
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" *C");
  }


  lcd.setCursor(14,0);            // move to the begining of the second line
  lcd_key = read_LCD_buttons();  // read the buttons

    switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
  case btnRIGHT:
    {
      lcd.print("RIGHT ");
      break;
    }
  case btnLEFT:
    {
      lcd.print("LEFT   ");
      break;
    }
  case btnUP:
    {
      lcd.print("UP    ");
      break;
    }
  case btnDOWN:
    {
      lcd.print("DOWN  ");
      break;
    }
  case btnSELECT:
    {
      lcd.print("SELECT");
      break;
    }
  case btnNONE:
    {
      lcd.print("NONE  ");
      break;
    }
  }

}

Der Code für das Menü mit Temperatur Min- und Max-Auswahl, sowie Anzeige von Temperatur und Luftfeuchte (noch nicht hinzugefügt, erst im nächsten Sketch).

//Sample using LiquidCrystal library
#include <LiquidCrystal.h>

/*******************************************************
 * 
 * This program will test the LCD panel and the buttons
 * Mark Bramwell, July 2010
 * 
 ********************************************************/

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some tMs used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

int tMax = 0;    //Temperatur Maximum
int tMin = 0;    //Temperature Minimum
int Select = 0;  //State of the menu: 0 = nothin (later shows Temps), 1 select Temp Max, 2 select Temp Min
int Range = 1;   //Value to increase or decrease Temps
int SupplyDHT =  13;  //Power supply for DHT11, not installed 

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the tM from the sensor 

  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result

  // For V1.0 comment the other threshold and use the one below:

  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 195)  return btnUP; 
  if (adc_key_in < 380)  return btnDOWN; 
  if (adc_key_in < 555)  return btnLEFT; 
  if (adc_key_in < 790)  return btnSELECT;   



  return btnNONE;  // when all others fail, return this...
}

void setup()
{
  lcd.begin(16, 2);              // start the library
  pinMode(SupplyDHT, OUTPUT);       
  Serial.begin(9600);

}

void loop()
{
  //Range to change Values
  lcd.setCursor(14,0);            // move cursor to second line "1" and 9 spaces over
  lcd.print("~");
  lcd.setCursor(15,0);            // move cursor to second line "1" and 9 spaces over
  lcd.print(Range);               // shows Value of Range on LCD

  //Display
  
  //Menu
  if (Select == 1) {            //select Max Temp border
    lcd.setCursor(0,0);
    lcd.print("Temp Max ");
    lcd.setCursor(9,0);
    lcd.print(tMax);
  }
  if (Select == 2){            //select Min Temp border
    lcd.setCursor(0,0);
    lcd.print("Temp Min ");
    lcd.setCursor(9,0);
    lcd.print(tMin);
  }
  if (Select == 0){            //go back to Main manu
    lcd.setCursor(0,0);
    lcd.print("Push Setup ");
  }
  lcd.setCursor(13,1);            // move to the end of the second line
  //BUTTONS
  lcd_key = read_LCD_buttons();  // read the buttons

    Serial.println(tMax);
  delay(1);                      // delay in between reads for stability
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
  case btnRIGHT:
    {
      lcd.print("RIGHT ");
      break;
    }
  case btnLEFT:
    {
      lcd.print("LEFT   ");
      break;
    }
  case btnUP:
    {
      lcd.print("UP    ");
      if (Select == 1){        //Increase tMax or tMin when pushing the button and Select is on (Value 1 or 2)
        tMax ++;
        delay(300);
      }
      if (Select == 2){
        tMin ++;
        delay(300);
      }
      break;
    }
  case btnDOWN:
    {
      lcd.print("DOWN  ");
      if (Select == 1){      //decrease tMax or tMin when pushing the button and Select is on (Value 1 or 2)
        tMax --;
        delay(300);
      }
      if (Select == 2){
        tMin --;
        delay(300);
      }
      break;
    }

  case btnSELECT:          //open Select menu; choose the option, like Max Temp...
    {
      Select ++;
      lcd.print("SE");
      delay(300);
      if (Select == 3){     //go back to main manu
        Select = 0;
      }
      break;
    }
  case btnNONE:
    {
      lcd.print("..");
      break;
    }
  }
}

Fortsetzung im nächsten Beitrag…

Hier die Fortsetzung:

Code für Sensor DHT11 und Menü zusammen. Der Arduino reagiert nur noch auf lang gedrückte Tasten und oder mehrfache Eingaben?! Ich habe auch schon Teile des Codes deaktiviert und getestet. Leider konnte ich nichts finden. Was bremst den Guten nun aus?

//Sample using LiquidCrystal library
#include <LiquidCrystal.h>
#include "DHT.h"
#define DHTPIN 2     // what pin we're connected to
// Uncomment whatever type you're using!
#define DHTTYPE DHT11   // DHT 11
/*******************************************************
 * 
 * This program will test the LCD panel and the buttons
 * Mark Bramwell, July 2010
 * 
 ********************************************************/

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some tMs used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
//Sensor data

int tMax = 30;      //Temperatur Maximum
int tMin = 19;      //Temperature Minimum
int Select = 0;     //State to select Temps
int SupplyDHT = 13; // Power supply for DHT

DHT dht(DHTPIN, DHTTYPE);

//Variabels
int ledMax = 12;    //LED to show that Temp is higher than selected Temp Max
int ledMin = 11;    //same as above for Temp Min
int Range = 1;      //Value to change Temp borders

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the tM from the sensor 

  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  // For V1.0 comment the other threshold and use the one below:

  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 195)  return btnUP; 
  if (adc_key_in < 380)  return btnDOWN; 
  if (adc_key_in < 555)  return btnLEFT; 
  if (adc_key_in < 790)  return btnSELECT;   
  return btnNONE;  // when all others fail, return this...
}
void setup()
{
  lcd.begin(16, 2);              // start the library
  pinMode(ledMax, OUTPUT);
  pinMode(ledMin, OUTPUT);
  pinMode(SupplyDHT, OUTPUT);
  Serial.begin(9600);
  digitalWrite(SupplyDHT, HIGH);   // turn the DHT on (HIGH is the voltage level - pin13 for power supply)
}

void loop()
{
    // read sensors
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  //Display

  //Menu
  if (Select == 0){            //go back to Main manu and show all Values od Temp and Humidity
    lcd.setCursor(0,0);
    lcd.print("Temp:");
    lcd.setCursor(12,0);
    lcd.print("C");
    lcd.setCursor(0,1);
    lcd.print("Humid:");
    lcd.setCursor(12,1);
    lcd.print("%Rel");
    Serial.begin(9600); 
    Serial.println("DHTxx test!");
    dht.begin();
    lcd.setCursor(5,0);            //print Temp on LCD
    lcd.print(t);
    lcd.setCursor(6,1);            // print Humidity in LCD
    lcd.print(h);
  }
  if (Select == 1) {            //select Max Temp border
    lcd.setCursor(0,0);
    lcd.print("Temp Max ");
    lcd.setCursor(9,0);
    lcd.print(tMax);
    lcd.setCursor(0,1);
    lcd.print("use up or down to select Max");
  }
  if (Select == 2){            //select Min Temp border
    lcd.setCursor(0,0);
    lcd.print("Temp Min ");
    lcd.setCursor(9,0);
    lcd.print(tMin);
  }

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  //for debug reason
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } 
  else {
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" *C");
  }

  lcd.setCursor(16,1);            // move to the end of the second line (hide button output)
  //BUTTONS
  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
  case btnRIGHT:
    {
      lcd.print("RIGHT ");
      break;
    }
  case btnLEFT:
    {
      lcd.print("LEFT   ");
      break;
    }
  case btnUP:
    {
      lcd.print("UP    ");
      if (Select == 1){        //Increase tMax or tMin when pushing the button and Select is on (Value 1 or 2)
        tMax ++;
        delay(300);
      }
      if (Select == 2){
        tMin ++;
        delay(300);
      }
      break;
    }
  case btnDOWN:
    {
      lcd.print("DOWN  ");
      if (Select == 1){      //decrease tMax or tMin when pushing the button and Select is on (Value 1 or 2)
        tMax --;
        delay(300);
      }
      if (Select == 2){
        tMin --;
        delay(300);
      }
      break;
    }

  case btnSELECT:          //open Select menu; chose the option, like Max Temp...
    {
      Select ++;
      lcd.print("SE");
      delay(50);
      if (Select == 3){     //go back to main manu
        Select = 0;
      }
      break;
    }
  case btnNONE:
    {
      break;
    }
  }
  //next code switches on LEDs to show when the Temp is lower or higher as the preselection of Temp  Min and Max
  if (Select == 0){      //do this just if your not in the selection menu
    if (t >= tMax){      //If Temp is too high or minimal switch on LED13
      digitalWrite(ledMax, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(50);
    }
    else {
      digitalWrite(ledMax, LOW);   // turn the LED off (LOW is the voltage level)
      delay(50);  
    }
    if (t <= tMin){      //If Temp is too high or minimal switch on LED13
      digitalWrite(ledMin, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(50);
    }
    else {
      digitalWrite(ledMin, LOW);   // turn the LED off (LOW is the voltage level)
      delay(50);  
    }
  }
}

Ich würde mich riesig über einen Tipp freuen warum der Arduino Uno so langsam reagiert und wäre sehr dankbar. Zum besseren Verständnis mache ich gerne ein Abbild mit fritzing, falls gewünscht.
Beste Grüße und Dank im Vorraus
Herr Schmidt

schmidt100:
Das ist mein erstes Projekt mit dem Arduino und der Code ist bestimmt nicht der schönste.

Der Code ist ja hübsch häßlich!

Leider etwas unübersichtlich.

Außerdem steckt ein Teil des Codes in einer Library, die Du nicht benennst, wo Du sie her hast.
Es gibt bestimmt ein Dutzend verschiedene DHT-Libraries, bei denen die Include-Dateien teils dieselben Namen haben.

Um auszuschließen, dass es die Temperaturmessung im Library-Code ist, die Deinen Sketch ausbremst, kannst Du ja mal statt:

 float h = dht.readHumidity();
  float t = dht.readTemperature();

den Code testweise ändern auf:

 float h = 66.0;
  float t = 22.5;

Macht das einen Unterschied? Oder ergibt sich damit keine Änderung?

Hallo!
Die Button Abfrage sollte ja im Loop sein.
mfg Martin

Besten Dank für die Antworten!
@jurs: Ich habs ausprobiert und die DHT Library scheint das Problem zu sein. Ich habe die Library von: Downloads | DHT11, DHT22 and AM2302 Sensors | Adafruit Learning System benutzt.
Andere Libraries habe zu Problemen geführt, aber ich werds nochmal ausprobieren.
Besten Dank!

@Wasjetzt: Die abfrage der Buttons ist doch im Loop mit Switch und Case?!

schmidt100:
@jurs: Ich habs ausprobiert und die DHT Library scheint das Problem zu sein. Ich habe die Library von:

Guckst Du Quellcode, weißt Du Bescheid:

boolean DHT::read(void) {
...
  // pull the pin high and wait 250 milliseconds
  digitalWrite(_pin, HIGH);
  delay(250);

Das ist Code, den Du für nicht-interaktive Programme gebrauchen kannst. Sagen wir mal ein batteriebetriebener Temperatursensor ohne jegliche Bedienelemente hängt im Garten und funkt alle drei Minuten seine Temperatur an eine Wetter-Basisstation im Haus. Dem Sensor im Garten ist es völlig egal, ob Du in den drei Minuten zwischen zwei Messungen das Programm für eine Viertelsekunde blockierst oder nicht. Da ist so etwas brauchbar.

Bei interaktiven Programmen, die blitzschnell auf Benutzereingaben reagieren sollen, ist das Programm mit einem "delay(250)" von einer Viertelsekunde in jeder loop schon total verkackt.

Solche digitalen Temperatursensoren benötigen alle eine bestimmte Auslesezeit zwischen "Anforderung einer Messung" und "Auslesen der Daten". Und im Endeffekt muß die Library genau das auch widerspiegeln, d.h. es muss eine Funktion zum Anfordern einer Messung geben und eine andere Funktion zum Abholen der Messdaten, die man dann erst nach einer bestimmten Zeit aufruft. Und zwischendrin kann das Programm eine Viertelsekunde lang beliebige andere Dinge tun, z.B. auf Tastendrücke reagieren.

Deine Library ist wegen der Verwendung von "delay(250)" für interaktive Programme unbrauchbar.

Du kannst bei einem interaktiven Programm allenfalls die negativen Auswirkungen verringern, wenn Du die Temperatur seltener ausliest. Mal angenommen,, Du liest die Temperatur statt "ständig in der loop" nur noch "einmal pro Minute" aus, dann würde auch nur einmal pro Minute das delay auftreten und damit das Programm viel seltener für Eingaben blockiert sein.

Aber im Endeffekt wäre das nur ein Herumstümpern an Symptomen. Für ein interaktives Programm muss viel eher das Auslesen des Sensors optimiert werden.

Besten Dank für die schnelle und ausführliche Antwort!!! Ich werde nochmal andere Libraries ausprobieren und hoffe weiter zu kommen. Ansonsten werde ich noch mal anfragen…
Besten Dank
Schmidt