Sekundentaktanzeige - Schönheitsfehler

Hallo,

bin mit meinem Projekt ein ganzes Stück weiter gekommen. Nur habe ich heute zufällig festgestellt, dass der Doppelpunkt als Sekundentaktanzeige aller 5x, sprich aller 10 Sekunden kurz verzögert. Manchmal bleibt der : etwas länger stehen und mancmal das Leerzeichen. Aller 4 bis 5 Anzeigen, nie richtig konstant.

Das ist die Funktion wo die : Sekundenanzeige drin steckt. Im Anhang der komplette Sketch. Wenn die Auswertung in der Funktion es verzögern würde, wäre es doch nur einmal aller 60sec. Laut meiner Meinung. Also muß etwas anderes in der loop ca. aller 10sec. mehr Rechenzeit benötigen. Wieder die Dallas Funktion? Die hatte schon einmal meinen Sketch ausgebremst. Jetzt nutze ich sie allerdings asynchron. Sollte passen.

Ansonsten macht der Sketch ohne Tastendruck immer die gleichen Aufgaben.
Dallas Sensoren Wandelbefehl geben,
Taster abfragen, nur wenn Taster gedrückt wurde, aktuelle Daten auf SD schreiben und File auslesen,
abgelaufene Zeit seit µC Reset auf Display anzeigen,
Dallas Temperaturen einlesen,
Dallas Temperaturen auf Display ausgeben,
jede Sekunde RTC Zeit auslesen,
RTC Zeit auf Display ausgeben,

Die Sekunden der laufenden Zeit seit µC Reset laufen jedoch ohne stocken auf dem Display durch.

Ideen was hier aller 10sec. mehr Rechenzeit beansprucht?

// gibt das Datum und Zeit von DS3231RTC auf das Display aus
void RtcWriteToDOGM(int SpalteY, int ZeileX)
{
  lcd.setCursor(SpalteY,ZeileX);
  if (tage < 10) lcd.print(0);
  lcd.print(tage);
  lcd.print(".");
  if (monate < 10) lcd.print(0);
  lcd.print(monate);
  lcd.print(".");
  int Jahr = jahre-2000;    		// kürzt die Jahreszahl auf 2 Stellen
  if (Jahr < 10) lcd.print(0);
  lcd.print(Jahr);
  lcd.print("   ");                     // Leerzeichen Abstand zwischen Datum und Uhrzeit
  if (stunden < 10) lcd.print(0);
  lcd.print(stunden);
  Modulo = sekunden % 2;                // : blinkt im Sekundentakt
  if (Modulo == 0) 
    { lcd.write(0x3A); }                // gib : Zeichen aus, interner DOGM Zeichensatz
      else
        { lcd.print(" "); }        
  if (minuten < 10) lcd.print(0);
  lcd.print(minuten); 
}

SDcard_Write_Taster_LcdSPI_DS1820_005.ino (17.3 KB)

Besteht das Problem auch, wenn du auf den Dallas verzichtest im loop?

Versuche mal die Zeit eines Loop Durchlaufs zu messen.
Zusätzlich fällt mir auf:

    static unsigned long prevMillis=-2000;
  char linebuf[30];
  if (millis()-prevMillis<1000) return; // Zeit noch nicht erreicht, Funktion abbrechen
  prevMillis=millis();

Eine unsigned long kann nicht negativ sein und dadurch, dass die Variable bei jedem Aufruf neu gesetzt wird, macht die nachfolgende Belegung von "prevMillis" keinen Sinn.

Hallo,

wenn ich das Dallas Zeugs auskommentiere, dann sehe ich keine Verzögerungen in der Anzeige.
Loop Durchlaufzeit ohne Dallas liegt bei 1 bis 2 ms.

Loop Durchlaufzeit mit Dallas, alles komplett, liegt zwischen 27 und 31ms. Die 4ms sehe ich bestimmt nicht mit dem Auge.

Das hier, ist eine übernommene Funktion für meine DS3231. Hatte jurs mal ins Forum gestellt.
static unsigned long prevMillis=-2000;
Gefiel mir, weil man das so schön einfach ohne zusätzliche RTC Library verwenden kann.
Vielleicht ist das eine Art Überlaufschutz der Variable?
So richtig erklären kann ich mir die Zeile auch nicht. Vielleicht liest jurs selbst hier mit und kann das erklären.

Ich werde diesen 1 Sekundenintervall mal umbauen auf gewöhnlichen Codebau ... :slight_smile:
Ich denke jedoch eher, der Schönheitsfehler hängt mit dem Dallaskonstrukt zusammen.

Probier vielleicht mal den Sensor asychron auszulesen (mit waitForConversion(false)) sowie ich es mal vorgeschlagen hatte.

Du scheinst auch in jedem Durchlauf die Temperatur auszulesen. So oft braucht man das nicht. Alle halbe Sekunde ergibt immer noch eine flüssige und schnelle Anzeige.

Ich habe auch gleich an den Dallas gedacht. Der braucht mindestens 750 ms um sich mit Strom "vollzusaugen". Guck mal, es gibt ne neue Lib für den Dallas, da haben sie das irgendwie anders gelöst, das der nix anderes mehr ausbremst :wink:

Gruß Gerald

Den Code dafür habe ich ihm schon gegeben, aber er hat es dann anders gemacht :slight_smile:

Wobei bei mir das Delay nur 100ms ist, da der DS18B20 9 Bit in 93ms schafft, aber das kann man anpassen.

Gerald, welche Quelle hast du für die neue Libary? Würde gerne mal testen, ob diese wirklich so rund läuft, wie du vermutest. Habe in meinen Projekten nirgends einen DS18B20 im Einsatz, aber habe hier welche liegen.

Doc_Arduino:
Das hier, ist eine übernommene Funktion für meine DS3231. Hatte jurs mal ins Forum gestellt.
static unsigned long prevMillis=-2000;
Gefiel mir, weil man das so schön einfach ohne zusätzliche RTC Library verwenden kann.
Vielleicht ist das eine Art Überlaufschutz der Variable?
So richtig erklären kann ich mir die Zeile auch nicht. Vielleicht liest jurs selbst hier mit und kann das erklären.

Da stelle ich die Variable einfach auf "2000 vor dem Überlauf auf null".
Den exakten Wert, wann das bei einem unsigned 32-Bit Integerwert der Fall ist, habe ich nicht im Kopf.
Soll der Compiler sich ausrechnen.

Doc_Arduino:
Ich werde diesen 1 Sekundenintervall mal umbauen auf gewöhnlichen Codebau ... :slight_smile:
Ich denke jedoch eher, der Schönheitsfehler hängt mit dem Dallaskonstrukt zusammen.

Wenn ich hier lese, dass Deine loop-Funktion auch schon für sich an die 30 ms läuft und alle paar Sekunden vertaktet sich das Programm, dann würde ich mal wenigstens das probieren, statt:

void RtcTimeEverySecond(){
...
  prevMillis=millis();
...

Setze:

void RtcTimeEverySecond(){
...
  prevMillis+=1000;
...

So dass an der Stelle auch bei einer lahmenden loop immer entweder gar nicht, oder um 1000ms weitergezählt wird.

Das mit dem "prevMillis=millis();" läuft nämlich nur dann sauber, wenn die loop-Funktion WENIGER als 1 ms lang läuft.

sschultewolter:
Gerald, welche Quelle hast du für die neue Libary? Würde gerne mal testen, ob diese wirklich so rund läuft, wie du vermutest. Habe in meinen Projekten nirgends einen DS18B20 im Einsatz, aber habe hier welche liegen.

http://www.milesburton.com/?title=Dallas_Temperature_Control_Library

Wie gesagt kann man jetzt setWaitForConversion(false) machen. Dann ist man selbst für das Delay verantwortlich. Das geht dann einfach mit millis(). Ich habe da zwei Abfragen. Einmal für die Zeit wie oft der Sensor gelesen werden und dann für das Delay zwischen Anforderung und Auslesen.

Hallo,

ähm Moment, ich mach das doch schon asynchron.
Es gibt DS18B20 und DS18S20. Meiner braucht 750ms für 9Bit, der kann auch nur 9bit. Das sollte aber keine Rolle spielen, dann wird er eben nur fast jede Sekunden neu ausgelesen.

Das von jurs werde ich gleich ausprobieren.

Doc_Arduino:
ähm Moment, ich mach das doch schon asynchron.

Nein, machst du nicht.

Ich sehe auch nicht wo du da eine Sekunde wartest. Du machst sensors.requestTemperatures(). Dann kommt der Kram mit den Tastern, aber danach kommt gleich TempSensor1 = getDallasTempC(sensor1). Wo ist da eine Zeitsteuerung für das Auslesen?

Oder übersehe ich da etwas?

EDIT:
Dazu kommt, dass wie ich in dem anderen Thread gesagt habe, die Lib nicht ganz kompatibel zum deinem DS18S20 ist! (auf der Webseite ist das kurz angegeben, aber nicht erläutert). Wenn man das nämlich nicht so macht und statt dessen das Delay von der Lib bekommt ist das bei 9 Bit nur 94ms. Das passt für den neueren Sensor, aber nicht für deinen.

void DallasTemperature::requestTemperatures()
{
  _wire->reset();
  _wire->skip();
  _wire->write(STARTCONVO, parasite);

  // ASYNC mode?
  if (false == waitForConversion) return; 
  
  switch (bitResolution)
  {
    case 9:
      delay(94);
      break;
    case 10:
      delay(188);
      break;
    case 11:
      delay(375);
      break;
    case 12:
    default:
      delay(750);
      break;
  }
  return;
}

Statt dessen per millis() ein Delay zwischen Anforderung und Auslesen machen, dann passt die Länge und es blockiert nichts :slight_smile:

Hallo,

hatte wir nicht hier festgestellt das in der Library die 750ms oder andere Wartezeiten überwacht werden? Oder hab ich doch noch Mist gemacht?
http://forum.arduino.cc/index.php?topic=224167.new;topicseen#new

Mit der Änderung von jurs taktet es richtig ohne Verzögerung. Nur bedarf ich dessen genauere Erklärung.
Du ziehst am Anfang von prevMillis die 2000 ab. Negativer Überlauf.
Dann prüftst Du ob die Differenz der aktuellen Zeit abzüglich prevMillis kleiner 1000 ist.
Danach addierst Du zu prevMillis die 1000 dazu
Beim erneuten Funktionsaufruf, ziehst Du 2000 wieder ab.
Ähm ??? Hier bin ich raus... :roll_eyes: Warum so kompliziert?

void RtcTimeEverySecond(){
  static unsigned long prevMillis=-2000;
  char linebuf[30];
  if (millis()-prevMillis<1000) return; // Zeit noch nicht erreicht, Funktion abbrechen
  prevMillis+=1000;
  // RTC Uhr auslesen
  rtcReadTime(jahre,monate,tage,stunden,minuten,sekunden);
  // Zeit für Ausgabe formatieren
  snprintf(RtcDateTimeBuf,sizeof(linebuf),"%02d.%02d.%04d ; %02d:%02d:%02d",tage,monate,jahre,stunden,minuten,sekunden);
  
}  // Ende "RtcTimeEverySecond"

Doc_Arduino:
static unsigned long prevMillis=-2000;

Eine "static" deklarierte statische Variable wird exakt einmal initialisiert, beim ersten Aufruf der Funktion.
Und NICHT bei jedem Funktionsaufruf.
Zwischen den Funktionsaufrufen behalten "static" Variablen ihre Gültigkeit und ihren letzten zugewiesenen Wert.

Diese Variable ist von mir (übrigens in einem anderen Test-Sketch) nur deshalb nicht auf 0 initialisiert worden, damit schon beim allerersten Aufruf der Funktion eine neue Sekunde erkannt und gezählt wird und nicht erst ab der zweiten Sekunde. Wenn Du jetzt den Code auf "prevMillis+=1000" änderst, solltest Du den Initialwert eher auf "-1000" setzen. Oder auf "0", wenn es innerhalb der ersten Sekunde nach einem Reset keine Anzeige zu geben braucht.

Hallo,

wegen dem Dallas Code. Ich hab nochmal verglichen. Ich habe das Dallas Bsp. "Multiple" genommen und für mich dann angepaßt. In dem Bsp. Code ist keine zusätzliche Wartezeit in loop drin. Zur Zeit ist das ja so, dass ich scheinbar so oft wie möglich aktuelle Temperaturwerte verarbeite. Nur real bekomme ich nur aller 750ms wirklich einen neuen Wert vom Sensor ausgelesen. Das macht auch keinen richtigen Sinn. Sodass ich wohl eh wieder umbauen werde und den Sensor in der loop nur jede Sekunde abfrage. Dann nützt mir zwar die neue Dallas Library wenig, aber ich bekomme Rechenzeit frei und dann eben für jede Sensorabfrage wirklich einen frischen Wert.

Soll die kleine prevMillis Änderung wirklich für den Takt-Schönheitsfehler verantwortlich gewesen sein? Kann es noch gar nicht glauben.

Wegen der static Variable. Warum deklariert man dann die Variable nicht gleich vor setup? Wenn sie beibehalten wird.

Wegen den 30ms Durchlaufzeit und der Randbemerkung. Muß ich mir Sorgen machen das es zu lange dauert?
Ich bin nämlich noch nicht fertig mit dem Gesamtprojekt. Eine Spannung muß auch noch eingelesen werden und gespeichert. Das würde aber auch nur auf Tastendruck passieren derzeit. Später aller paar Minuten oder Stunden oder zu bestimmten Uhrzeiten. Deshalb die Uhr.

Wünsche erstmal gute Nacht ... :smiley:

Doc_Arduino:
Wegen der static Variable. Warum deklariert man dann die Variable nicht gleich vor setup? Wenn sie beibehalten wird.

Weil man Variablen so lokal wie möglich deklarieren sollte. Wenn du die global machst, dann können alle anderen Funktionen darauf zugreifen. Wo ist der Sinn darin?
Das hat auch den Vorteil dass du in einer anderen Funktion eine Variable des gleichen Namens deklarieren kannst. Man sieht auch gleich welche Variablen von der Funktion verwendet werden ohne durch den halben Code zu scrollen.

Man kann es natürlich global machen. Das ist aber kein guter Stil wenn es sich vermeiden lässt.

Hallo,
"Nur real bekomme ich nur aller 750ms wirklich einen neuen Wert vom Sensor ausgelesen"
Wenn dem so ist?
Wenn mich nicht alles täuscht, braucht der Sensor diese Zeit zum messen der
Temperatur. Lesen und schreiben kommt noch hinzu.
Bei 12 bit Auflösung braucht der Sensor 750ms
Bei 11 bit Auflösung braucht der Sensor 375ms
Bei 10 bit Auflösung braucht der Sensor 187ms
Bei 9 bit Auflösung braucht der Sensor 93ms

Nun mußt Du einmal die schwere Entscheidung treffen, was für Dich genau ist.
Ich nehme an Du mist Temperatur in Grad Celsius.
Da reicht es doch, wenn Dir 1/10 Grad angezeigt werden. 1/100 Grad macht bei dem
"Schätzeisen" ja kein Sinn.
Gruß und Spaß dabei
Andreas

^^
Das gilt für den DS18B20. Der DS18S20 macht nur 9 Bit (0,5°) und braucht dafür 750ms

http://datasheets.maximintegrated.com/en/ds/DS18S20.pdf

Hallo,
Ups! Dann vergesse das mal wieder.
Gruß und Glück
Andreas

Hallo,

muß doch nochmal antworten, lässt mir keine Ruhe. Nur wie am Besten mein neues Problem beschreiben.

void RtcTimeEverySecond()
{
  static unsigned long prevMillis=-1000;
  char linebuf[30];
  if (millis()-prevMillis<1000) return; // Zeit noch nicht erreicht, Funktion abbrechen
  //prevMillis=millis();
  prevMillis+=1000;            // addiere 1000 
  // RTC Uhr auslesen
  rtcReadTime(jahre,monate,tage,stunden,minuten,sekunden);
  // Zeit für Ausgabe formatieren
  snprintf(RtcDateTimeBuf,sizeof(linebuf),"%02d.%02d.%04d ; %02d:%02d:%02d",tage,monate,jahre,stunden,minuten,sekunden);
} // Ende "RtcTimeEverySecond"

Wenn ich hier die static prevMillis auf 0 setze, dann verschiebt sich meine Anzeige auf dem Display. Normalerweise steht oben links wie eingemeißelt "MEGA". Und in der letzten Zeile steht das Datum und Uhrzeit ohne Sekunde. Dafür mit blinkenden Doppelpunkt.
Setzte ich die static prevMillis auf 0, dann wird MEGA it 0:00 überschrieben. Aus unbekannten Gründen, so scheint es, schreibt die letzte Funktion noch eine 0:00 hinten ran. Da das Display zu Ende ist, fängt es oben links wieder an. Nur warum? Steht überhaupt nicht da das nach Minuten noch was zur Anzeige gebracht werden soll.
Wird aufgerufen mit: RtcWriteToDOGM(0,2); // setzt Cursor auf Spalte 0, Zeile 2
Die Ausgabe sind genau 16 Stellen. Nehme ich die Lehrzeichen zwischen Datum und Zeit weg, rutscht die falsche Anzeige von 0:00 mit runter und GA von MEGA kommt zum Vorschein. :cold_sweat:

// gibt das Datum und Zeit von DS3231RTC auf das Display aus
void RtcWriteToDOGM(int SpalteY, int ZeileX)
{
  lcd.setCursor(SpalteY,ZeileX);
  if (tage < 10) lcd.print(0);
  lcd.print(tage);
  lcd.print(".");
  if (monate < 10) lcd.print(0);
  lcd.print(monate);
  lcd.print(".");
  int Jahr = jahre-2000;    		// kürzt die Jahreszahl auf 2 Stellen
  if (Jahr < 10) lcd.print(0);
  lcd.print(Jahr);
  lcd.print("   ");                     // Leerzeichen Abstand zwischen Datum und Uhrzeit
  if (stunden < 10) lcd.print(0);
  lcd.print(stunden);
  Modulo = sekunden % 2;                // : blinkt im Sekundentakt
  if (Modulo == 0) 
    { lcd.write(0x3A); }                // gib : Zeichen aus, interner DOGM Zeichensatz
      else
        { lcd.print(" "); }        
  if (minuten < 10) lcd.print(0);
  lcd.print(minuten); 
}

Bitte nicht unnötig die Dallas Geschichte durcheinander bringen. Sonst werde ich blöde in der Birne. Ich habe einen billigeren DS18S20. Der hat nur 9Bit und benötigt 750ms. http://www.maximintegrated.com/app-notes/index.mvp/id/4377
Vielleicht darf man wie schon erwähnt wurde die neue Dallas Library mit dem S nicht verwenden. Nur Anzeigen tut er richtig. Kümmer ich mich später drum.

Ich habe jetzt plötzlich wie aus heiteren Himmel tausende Baustellen. Mir platzt der Schädel. :cold_sweat:

Okay, static Variable habe ich nun verstanden. Danke.