Uhr Läuft nur sehr Langsam mit DS18B20

Ich habe versucht eine Uhr und ein DS18B20
(Programmable Resolution 1-Wire Digital Thermometer) auf einem 16x2 LCD zu schreiben. Wenn ich das Programm starte erschient die Temperatur sofort und die Uhr erst nach sehr langem Laden und nachdem sie geladen ist läuft sie sehr sehr langsam 1 sek dauert über 1 Minute, woran könnte das liegen?

// LCD Library
#include <LiquidCrystal.h>

// RS, E, D4, D5, D6, D7
LiquidCrystal lcd(11, 10, 2, 3, 4, 5);
#define Backlight   9

#include <OneWire.h> 
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 7 
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);
int cnt, Sekunde, Minute, Stunde=0;
int LED=13;

void setup()
{
       
      pinMode(LED, OUTPUT);
      analogWrite(Backlight, 200);
      lcd.begin(16, 2);
      // Celcius
      byte Celsius[8] = {B11100,B10100,B11100,B0000,B00000,B00000,B00000,B00000}; lcd.createChar(0, Celsius);
      // Zeitvorgabe
      Sekunde = 50;
      Minute = 59;
      Stunde = 23;
      lcd.setCursor (0, 0);
      lcd.print("Time:");
      lcd.setCursor (0, 1);
      lcd.print("Temp:");
      lcd.setCursor (11, 1);
      lcd.write((uint8_t)0);
      lcd.setCursor (12, 1);
      lcd.print("C");
      //Sensor
      sensors.begin();
}

void loop() 
{
  //Uhr
  cnt++;

  
  if(cnt == 100)
  {
      

      lcd.setCursor(6, 0);
 
    if(Stunde < 10) lcd.print("0");
    lcd.print(Stunde);
    lcd.print(":");

    if(Minute < 10) lcd.print("0");
    lcd.print(Minute);
    lcd.print(":");

    if(Sekunde < 10) lcd.print("0");
    lcd.print(Sekunde);
    
    Sekunde++; 
    if(Sekunde == 60)
    {
        Sekunde = 0;
        Minute++;     
        if(Minute == 60)
        {
            Minute = 0;
            Stunde++;        
            if(Stunde == 24)
            {
                Stunde = 0;
            }
        }
    }    
    cnt = 0;
  } 
  //Thermometer
  lcd.setCursor(6, 1);
  sensors.requestTemperatures();
  lcd.print(sensors.getTempCByIndex(0));
  //delay
  delay(10);
  
}

ThermoClock.ino (1.99 KB)

Welche Uhr verwendest du ?
Ich sehe keine RTC.

Der Arduino (welcher ?) hat keine Uhr eingebaut. Wenn du das per millis machst, ist das nicht sehr genau und damit dein DS18B20 richtig arbeitet, brauch der eine längere Zeit um die Temperaur auch richtig zu messen.
In dieser Zeit wird vermutlich deine Ausgabe verzögert.

Unsichtbar04:

...    Sekunde++; 

if(Sekunde == 60)
    {
        Sekunde = 0;
        Minute++;   
        if(Minute == 60)
        {
            Minute = 0;
            Stunde++;       
            if(Stunde == 24)
            {
                Stunde = 0;
            }
        }
    }   
...
}

Eine Uhr auf diese Weise „zu Fuß“ zu programmieren ist zwar naheliegend, wenn man annimmt, dass ein Arduino über längere Zeit gleich schnell läuft. Das tut er aber nicht und verschiedene Arduinos sind unterschiedlich schnell - selbst, wenn sie aus der selben Charge stammen. Ich würde Dir empfehlen, Dir eine RTC zuzulegen.

Gruß

Gregor

Danke für die Antworten
Ich verwende keie RTC mir ist bewusst dass die Uhr abweichen kann. Es ist ein UNO, die Sache ist das sich die Temperatur direktverändert, aber die Zeit nur sehr sehr langsam.

Gruß U04

Hallo U04,

du frägst in der Loop den Sensor ab und hast ein Delay von 10 ms drin. Nun gehst du davon aus, dass ein Schleifendurchlauf 10 ms braucht.
Hab mal kurz gegoogelt und “Messgeschwindigkeit: <750ms” gefunden. Das heißt deine Schleife dauert im schlimmsten Fall 760 ms.
Bei 100 Durchläufen in einer “angezeigten Sekunde” vergehen tatsächlich bis zu 76 Sekunden.

Du könntest nun einmal pro Sekunde die Temp auslesen und den Schleifenzähler auf 75 setzen. Durch Vergleichsmessungen kannst du den Wert anpassen und genauer werden.

Kleiner Schönheitsfehler:
Zuerst die Zeit (Sek, Min, Std) berechnen und dann ausgeben, nicht die alten Werte ausgeben und dann die aktuellen berechnen (EVA). Na ja, macht hier nicht viel aus.
Bei der Variablendeklaration “int cnt, Sekunde, Minute, Stunde=0;” würde ich alle Werte auf 0 setzen. Macht global vermutlich nichts aus, aber als lokale Variablen würde ich mich nicht drauf verlassen.

Zumindest solltest Du millis() verwenden um die Zeit zu ermitteln, und nicht die Anzahl der Schleifendurchläufe als Zeit benutzen. Die Schleifendurchläufe ändern sich je nachdem was in der Schleife gerade zu tun ist.

Unsichtbar04:
Ich verwende keie RTC mir ist bewusst dass die Uhr abweichen kann. Es ist ein UNO, die Sache ist das sich die Temperatur direktverändert, aber die Zeit nur sehr sehr langsam.

Dann schau Dir mal Dein if()-Konstrukt mit der Variable cnt an: Du aktualisierst die Temperatur in jedem loop()-Durchlauf, die Zeit aber nur in jedem hundertsten.

NB: Du hast zwar hübsche Einzüge (Einrückungen), aber viele Leerzeilen im Code. Außerdem muss man wegen lediglich einer Zeile horizontal scrollen. Beides macht den Code schlecht(er) lesbar. Bei der Fehlersuche/Analyse des Codes ist gute Lesbarkeit Gold wert.

Gruß

Gregor

Die Aktualisierungsrate ist im Prinzip 1Hz, also durchaus akzeptabel - aber nur wenn die Messung das Timing nicht ausbremst.

Gibt es denn eine Möglichleit zu schauen wenn die millis sich um 1000 erhöhen? Wie z.b.

If(millis + 1000){ sekunde ++1}

Vielen Dank für die Antworten
Gruß U04

Unsichtbar04:
Ich verwende keie RTC mir ist bewusst dass die Uhr abweichen kann.

Und warum nicht.
Der Uno ist keine Uhr und "kann" nicht nur abweichen, sondern ist immer sehr ungenau.
Das geht bis zu einigen Minuten am Tag. Damit hast du also nie eine vernünftige Uhr.

Du solltest dich tatsächlich mit dem Gedanken befassen, eine RTC (DS3231) einzusetzen. Diese ist dank einer internen Temperaturkompensation sehr genau und kostet nicht mal viel. Obiger Link ist nur als ein Beispiel zu sehen.

HotSystems:
Und warum nicht.

Weil ich das Projekt kurzfristig mache und keine Lust habe lange auf die Lieferung aus China zu warten, da der Händler bei mir leider zu gemacht hat.

LG U04

Unsichtbar04:
Weil ich das Projekt kurzfristig mache und keine Lust habe lange auf die Lieferung aus China zu warten, da der Händler bei mir leider zu gemacht hat.

Warum bestellst Du sie Dir dann nicht in UK, oder Spanien. Die liefern vielleicht schneller.
Oder...warte, ich habe noch eine wahnwitzige Idee:
Bestell sie Dir bei einem Händler in Deutschland, dann hast Du sie mit A***z Prime schon morgen.

Unsichtbar04:
Weil ich das Projekt kurzfristig mache und keine Lust habe lange auf die Lieferung aus China zu warten, da der Händler bei mir leider zu gemacht hat.

Ok…verstehe ich :disappointed_relieved: :disappointed_relieved:

Und dafür nimmst du eine nicht funktionierende Uhr in Kauf. Alles klar.

Zum Glück gibt es auch viele Händler hier bei uns, die so etwas anbieten und schnell liefern.

Unsichtbar04:
Gibt es denn eine Möglichleit zu schauen wenn die millis sich um 1000 erhöhen? Wie z.b.

If(millis + 1000){ sekunde ++1}

Vielen Dank für die Antworten
Gruß U04

Ja, gibt es!

combie:
Ja, gibt es!

Wie denn?

Wenn man eine "Uhr" mit millis() baut sollte man auch den Sensor nicht-blockierend auslesen. So ist da ein verstecktes Delay drin. Dadurch wird es passieren dass die Sekunden nicht gleichmäßig laufen. Dazu gibt es in der Bibliothek ein Beispiel.

Das Zeit-Management ist aber sehr kurzsichtig. Die Zeit die jetzt da rein steckst verlierst du später weil es nicht zuverlässig funktionieren kann.

Und eine DS3231 gibt es wie gesagt auch von deutschen Versendern billig

Unsichtbar04:
Wie denn?

Schau mal in BlinkWithoutDelay, wie man mit millis() umgeht.

DrDiettrich:
Schau mal in BlinkWithoutDelay, wie man mit millis() umgeht.

Als Grundlagenwissen ja.
Da er regelmässig den DS ausliest, und der bei 12bit bis zu 750ms für eine Antwort braucht (ja, es gibt auch das nicht blockierende auslesen) kann ihm passieren, das er mit jedem Umlauf altmillis=millis() sich eine erhebliche Abweichung reinholt.

Combie hat das mal so genial erklärt, wie es besser geht:

Die Arduino Uhr läuft ständig weiter, da braucht man kein altmillis für die Zeit selbst, nur für die Wiedergaberate.

Die Arduino Uhr läuft ständig weiter, ....

Das wäre schön.....

Eine Situation, wo millis() und auch micros() gnadenlos versagen:
Die Timing sensible Ausgabe auf WS2812 Stripes.

Denn dafür werden die ISR abgeschaltet und die Ausgabe dauert so lange (natürlich nur bei langen Stripes), dass Interrupts verloren gehen.

OK, ok, das ist auch logisch, wenn man drüber nachdenkt.
Aber ohne "nachdenken" kann man damit derbe auf die Nase fallen.