Träge Zykluszeit mit TemperaturSensor

Ich habe gerade ein paar Probleme, die nach dem einbinden eines Temperatursensors DS18B20 aufgetreten sind.

Ich habe einmal den Sketch so laufen lassen. Die Zykluszeit beträgt ~26ms.

void loop() {
  unsigned long aktuelleZeit = millis();
  Serial.print(aktuelleZeit);
  Serial.println(" : Arduino im loop()");
}

Nun lasse ich den Sketch wie folgt laufen. Die Zykluszeit beträgt nun ~800ms.

void loop() {
  unsigned long aktuelleZeit = millis();
  Serial.print(aktuelleZeit);
  Serial.println(" : Arduino im loop()");
  ausgabe();
}

void ausgabe() {
  sensoren.requestTemperatures(); 
  float temp1 = sensoren.getTempCByIndex(0);
  lcd.setCursor(9,1);
  lcd.print(temp1);
  lcd.print((char)223);
  lcd.print('C'); 
}

Das 2. Probleme kommt, sobald ich ShiftRegister aus der setup auskommentiere. Nun ist das Display leer, die Serielle Verbindung verbindet, gibt aber keine Werte zurück.

Zur Vollständigkeit hier noch einmal das komplette Sketch

// LCD I2C Display
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

// RTC
#include <DS3232RTC.h>
#include <Time.h>

// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 10 // One Wire an Pin 10
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensoren(&oneWire);

// RGB Shift Register
#include <ShiftPWM.h>
//const int ShiftPWM_dataPin = 11;
//const int ShiftPWM_clockPin = 13;
const int ShiftPWM_latchPin = 8;
const bool ShiftPWM_invertOutputs = false;
const bool ShiftPWM_balanceLoad = false;
unsigned char maxHelligkeit = 255;
unsigned char pwmFrequenz = 75;
unsigned int numRegister = 3;
unsigned int numAusgaenge = numRegister * 8;
unsigned int numRgbLeds = numRegister * 8 / 3;


void setup() {
  // LCD I2C Diplay
  lcd.init(); 
  lcd.backlight();

  /*
  // RGB Shift Register
   ShiftPWM.SetAmountOfRegisters(numRegister);
   ShiftPWM.SetPinGrouping(4);
   ShiftPWM.Start(pwmFrequenz, maxHelligkeit);
   ShiftPWM.SetAll(0);
   */

  // DS18B20
  sensoren.begin();

  // Serielle Schnittstelle
  Serial.begin(9600);
}


void loop() {
  unsigned long aktuelleZeit = millis();
  Serial.print(aktuelleZeit);
  Serial.println(" : Arduino im loop()");
  ausgabe();
}


void ausgabe() {
  sensoren.requestTemperatures(); 
  float temp1 = sensoren.getTempCByIndex(0);
  /*
  lcd.setCursor(0,0);
   uhrzeitLcd();
   lcd.setCursor(0,1);  
   if(temp1 > 40.0) lcd.print("AUS");
   else lcd.print("AN ");
   */
  lcd.setCursor(9,1);
  lcd.print(temp1);
  lcd.print((char)223);
  lcd.print('C'); 
}

void uhrzeitLcd() {
  tmElements_t tm;
  RTC.read(tm);
  if(tm.Day >= 0 && tm.Day < 10) lcd.print('0');
  lcd.print(tm.Day);
  lcd.print('.');
  if(tm.Month >= 0 && tm.Month < 10) lcd.print('0');
  lcd.print(tm.Month);
  lcd.print(".  ");
  if(tm.Hour >= 0 && tm.Hour < 10) lcd.print('0');
  lcd.print(tm.Hour);
  lcd.print(':');
  if(tm.Minute >= 0 && tm.Minute < 10) lcd.print('0');
  lcd.print(tm.Minute);
  lcd.print(':');
  if(tm.Second >= 0 && tm.Second < 10) lcd.print('0');
  lcd.print(tm.Second);
}

Zur genauen Herkunft der DallasTemperature Libary kann ich gerade nichts näheres sagen, hatte die über Umwege gefunden.
Gibt es evtl. eine alternative Libary mit einer einfachen Einbindung eines DS18B20?

Bei der DallasTemperature gab es mehrere Beispiele, ua. diese, wovon ich meine Funktion abgeleitet hab

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");

  // Start up the library
  sensors.begin();
}

void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  
  Serial.print("Temperature for the device 1 (index 0) is: ");
  Serial.println(sensors.getTempCByIndex(0));  
}

sschultewolter:
Nun lasse ich den Sketch wie folgt laufen. Die Zykluszeit beträgt nun ~800ms.

Wenn zwischen den beiden Zeilen
sensoren.requestTemperatures();
und
float temp1 = sensoren.getTempCByIndex(0);
nicht mindestens 750 ms (bei 12-Bit Auflösung) Zeit vergangen ist, dann knallt Dir Deine Library da gnadenlos ein delay() für die fehlende Zeit rein. Die Temperaturmessung erfordert Zeit für die Messung, je höher die Messauflösung, desto länger dauert eine Temperaturmessung.

Wie wäre es damit:
Du kannst z.B. in allen geraden Sekunden einer Minute "sensoren.requestTemperatures();" machen und in allen ungeraden Sekunden holst Du die Messwerte mit "sensoren.getTempCByIndex(0);" ab. Natürlich ohne delay() Aufrufe zwischendrin. Zeitlich gesteuert über den Stand des millis()-Zeitzählers. Dann bleibt die loop auf Drehzahl, weil Deine Libraries keine delay() Aufrufe mehr einfügt.

Hab mir die Libary gerade angeschaut. Da ist ernsthaft ein delay eingebaut. Werde somit mal auf die Standard Libary OneWire zurückgreifen. Der Wert ist für die Schaltungen eher von kleinerer Wichtigkeit. Er soll nur bei erreichen einer Temperatur ein Relais anschalten. Temperatur erhöht sich alle paar Minuten nur um wenige 0,x °C.

Danke jurs für den Tipp. Habe nun entsprechend eine Zeitverzögerung basierten auf millis für dieses Problem genutzt. Nun startet er jede Sekunde eine Anfrage und wertet alle 2 Sekunden aus. Irgendwelche Einwände?

void ausgabe() {
  unsigned long aktuelleZeit = millis();
  static unsigned long vorherigeZeit;
  static unsigned long vorherigeZeit2;
  static float temp1;

  if(aktuelleZeit - vorherigeZeit > 1000) {
    sensoren.requestTemperatures();
    Serial.print(aktuelleZeit);
    Serial.print(" | Anfrage |");
    Serial.println(aktuelleZeit - vorherigeZeit);
    vorherigeZeit = aktuelleZeit;
  }
  else if(aktuelleZeit - vorherigeZeit2 > 2000) {
    Serial.print(aktuelleZeit);
    Serial.print(" | Wert | ");
    Serial.println(aktuelleZeit - vorherigeZeit2);
    temp1 = sensoren.getTempCByIndex(0);
    vorherigeZeit2 = aktuelleZeit;
  }
  lcd.setCursor(9,1);
  if(temp1 < 0.0) lcd.print(" Fehler");
  else if(temp1 < 10.0) {
    lcd.print(' '); 
    lcd.print(temp1); 
    lcd.print((char)223);
    lcd.print('C'); 
  }
  else {
    lcd.print(temp1);  
    lcd.print((char)223);
    lcd.print('C'); 
  }

  lcd.setCursor(0,0);
  uhrzeitLcd();
  lcd.setCursor(0,1);  
  if(temp1 > 40.0) lcd.print("AUS");
  else lcd.print("AN ");
}

Oder macht es so mehr Sinn?

void ausgabe() {
  unsigned long aktuelleZeit = millis();
  static unsigned long vorherigeZeit;
  static unsigned long vorherigeZeit2;
  static float temp1;
   sensoren.requestTemperatures();
 /*if(aktuelleZeit - vorherigeZeit > 1000) {
    sensoren.requestTemperatures();
    Serial.print(aktuelleZeit);
    Serial.print(" | Anfrage |");
    Serial.println(aktuelleZeit - vorherigeZeit);
    vorherigeZeit = aktuelleZeit;
  }*/
  if(aktuelleZeit - vorherigeZeit2 > 2000) {
    Serial.print(aktuelleZeit);
    Serial.print(" | Wert | ");
    Serial.println(aktuelleZeit - vorherigeZeit2);
    temp1 = sensoren.getTempCByIndex(0);
    vorherigeZeit2 = aktuelleZeit;
  }

Beide funktionieren auf jedenfall ohne Zeitverzögerung. Die PWM Shift Sache kann vorerst auch verschoben werden. An Pin 10 und 12 will das nicht funktionieren. Habe Kontakte schon durchgemessen, keine Bebindung.

Mit Pin 2 geht es wunderbar.

sschultewolter:
Irgendwelche Einwände?

So rein vom Gefühl her würde ich sagen, brauchst Du nur die Reihenfolge umdrehen

  • erst Temperatur auslesen
  • unmittelbar danach eine neue Messung anfordern
    und dann darauf achten, dass dieser Zyklus nicht häufiger als einmal pro Sekunde abläuft
void ausgabe() {
  static unsigned long letzteAnforderung;
  static float temp1;
  if (millis()-letzteAnforderung>1000)  // mindestens eine sec nach letzter Anforderung
  {
    temp1 = sensoren.getTempCByIndex(0); // Auslesen
    sensoren.requestTemperatures();      // Anfordern
    letzteAnforderung=millis();
    // lcd.print...                     // Auf LCD ausgeben
  }  
}

Die allererste Auslesung erfolgt dann zwar aus dem luftleeren Raum heraus und führt zu einem abgelesenen Fehlerwert, aber danach (also mindestens 2 Sekunden nach Programmstart) sollte es dann passen.

Problem ist noch nicht ganz gelöst, habe getTemp und request wieder getrennt.
Hab den Fade versucht aus meiner ShiftPWM Libary. Das Problem ist, er zählt nicht mehr einzelne Werte hoch. Ohne den Tempsensor werden die Werte in Einzelschritten hochgezählt. Wenn jedoch der Tempsensor ausgewertet wird, springen die Zahlen deutlich schneller hoch und dabei überspringt er Werte, das Fade ist dann nicht mehr smooth!

void rgbFadeAlle(unsigned long zyklusZeit) { 
  unsigned long aktuelleZeit = millis();
  unsigned long hue = (360 * aktuelleZeit / zyklusZeit) % 360;
  ShiftPWM.SetAllHSV(hue, 255, 255); 
  Serial.print(millis());
  Serial.print(";");
  Serial.println(hue);  
}
void ausgabe() {
  unsigned long aktuelleZeit = millis();
  static unsigned long vorherigeZeit;
  static unsigned long vorherigeZeit2;
  static float temp1;
  
  if(aktuelleZeit - vorherigeZeit > 1000) {
    sensoren.requestTemperatures();
    vorherigeZeit = aktuelleZeit;
  }
    if(aktuelleZeit - vorherigeZeit2 > 2000) {
    temp1 = sensoren.getTempCByIndex(0);
    vorherigeZeit2 = aktuelleZeit;
  }
  
  lcd.setCursor(9,1);
  if(temp1 <= -127.0) lcd.print(" Fehler");
  else if(temp1 < 10.0) {
    lcd.print(' '); 
    lcd.print(temp1); 
    lcd.print((char)223);
    lcd.print('C'); 
  }
  else {
    lcd.print(temp1);  
    lcd.print((char)223);
    lcd.print('C'); 
  }

  lcd.setCursor(0,0);
  uhrzeitLcd();
  lcd.setCursor(0,1);  
  if(temp1 > 40.0) lcd.print("AUS");
  else lcd.print("AN ");
}

wie wärs wenn du versuchts die Libs zu verstehen, die du da benutzt, dann würdest du nämlich auf folgende memberfunktion stoßen:

  // sets/gets the waitForConversion flag
  void setWaitForConversion(bool);

Wenn das falsch ist, dann werden die Werte immer nach jedem Poll gelesen, egal ob sie aktualisiert wurden.