Tageszähler mit RTC und Display

Hi, ich wollte so etwas in der Art verwirklichen: https://vegardpaulsen.wordpress.com/valentineduino/

Und zwar soll mithilfe der RTC das aktuelle Datum ausgegeben werden in Unixtime und davon dann das Ausgangsdatum (auch in Unixtime) subtrahiert werden. Dann soll die Unixtime in Anzahl der vergangenen Tage seit dem Ausgangsdatum umgerechnet werden und auf dem Display angezeigt werden.

Ich habe: - Arduino Uno r3 - RTC Module DS1307 - Adafruit 0.56" 4-Digit 7-Segment Display - DIP Switch

Ich habe alle entsprechenden Librarys installiert, doch habe Probleme den Code zum Laufen zu bringen. Die aktuelle Zeit kann ich zwar mithilfe der RTC bereits auf dem Display anzeigen, beim anzeigen und speichern der aktuellen Unixtime stecke ich aber momentan fest.

Der Ursprungscode von dem oben geposteten Link funktioniert so leider überhaupt nicht mit meinem Equipment... Oder vielleicht bin ich auch einfach noch zu blöd um den Code umzuschreiben...

Könnte mir jemand helfen bei der Programmierung? :)

Bestimmt, kann dir jemand helfen, wenn du deinen Code postest. nutzen bitte die code-Tags (</>-Schaltfläche oben).

In wie fern sind deine Ergebnisse fehlerhaft?

Das sind die Code Snippets, die ich vergeblich zu modifizieren und zusammenzufügen versuchte: …

#include <Time.h>
#include <SPI.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include "RTClib.h"

const int  cs = 8; //chip select for the rtc
const int ledPin = 13;
const int openEventPin = 12;
//#include <NewSoftSerial.h>
//NewSoftSerial nss(4, 5);

char clientId[] = "clientId=03&"; //12 char
char dataTypeFloat[] = "dataType=float&data=" ; //20 char
char dataTypeInt[] = "dataType=int&data=" ; //18 char
char dataTypeChar[] = "dataType=char&data=" ; //19 char
char checkData[] = "&check" ;
int counter = 0 ;
unsigned long previousMillis = 0;        // will store last millis event time
unsigned long sensorpreviousMillis = 0;        // will store last millis event time
unsigned long fiveMinuteInterval = 300000;           // interval at which to use event time (milliseconds)
unsigned long postDaysInterval = 7200000 ; //seconds in a day 86400000
int openEvent = 1;
int TimeDate[7];


unsigned long theDateWeGotTogether = 1392415200   ;  //in unixtime
unsigned long days ;
int weeks ;

const int MAX_CMDLEN = 70;
char cmdBuffer[MAX_CMDLEN + 1];
int cmdLen;
int openState = 0;
unsigned long unixTime;


void setup() {
  Serial.begin(9600);
  nss.begin(9600);
  ClearLcd();
  RTC_init();
  SetTimeLibraryFromRTC();
  pinMode(ledPin, OUTPUT);
  pinMode(rfPowerPin, OUTPUT);
  pinMode(openEventPin, INPUT);
  digitalWrite(rfPowerPin, HIGH);
  delay(3000);
  LoveYouLcd() ;
  delay(100);
  sendEverything();

  // adjustTime(1392415200); //used to try the code without knowing the right time. just paste in the unixtime you know

}

void loop()
{
  days = ((now() - theDateWeGotTogether) / 86400); //magic nubmer 86400 is the number of seconds in a day
  unsigned long currentMillis = millis();
  ShowDaysReading();
  time_t t = now();


  if ( 14 == day(t)  &&  2 == month(t)  )
  {
    delay(5000);
    LoveYouLcd() ;
    AnniversaryLcd() ;


  }

  if (currentMillis - sensorpreviousMillis > fiveMinuteInterval)
  {
    // save the last time you performed event
    sensorpreviousMillis = currentMillis;
    sendEverything();
    SetTimeLibraryFromRTC();




  }

}

void ClearLcd()
{
  nss.print("v");
  nss.print("xxxx");
}

void LoveYouLcd()
{
  nss.print("v");
  nss.print("LOUE");
  delay(2500);
  nss.print("YOUx");
  delay(2500);
}

void ShowDaysReading()
{
  ClearLcd() ;
  days = ((now() - theDateWeGotTogether) / 86400); //magic nubmer 86400 is the number of seconds in a day
  weeks = ((now() - theDateWeGotTogether) / (86400 * 7) ); //magic nubmer 86400 is the number of seconds in a day
  nss.print("w");
  nss.print(B00000000, BYTE);
  nss.print("v");
  if (days <= 99999999 && days >= 10000)
  {
    if (weeks <= 9999 && weeks >= 1000)
    {
      nss.print(weeks);
      delay(5000);
      nss.print("7day");
      delay(1000);
    }
    if (weeks <= 999 && weeks >= 100)
    {
      nss.print("0");
      nss.print(weeks);
      delay(5000);
      nss.print("7day");
      delay(1000);
    }

    if (weeks <= 99 && weeks >= 10)
    {
      nss.print("00");
      nss.print(weeks);
      delay(5000);
      nss.print("7day");
      delay(1000);
    }

    if (weeks <= 9 && weeks >= 0)
    {
      nss.print("000");
      nss.print(weeks);
    }
  }

  //days
  if (days <= 9999 && days >= 1000)
  {
    nss.print(days);

  }
  if (days <= 999 && days >= 100)
  {
    nss.print("0");
    nss.print(days);

  }

  if (days <= 99 && days >= 10)
  {
    nss.print("00");
    nss.print(days);

  }

  if (days <= 9 && days >= 0)
  {
    nss.print("000");
    nss.print(days);

  }
}

void ShowTimeReading()
{
  ClearLcd() ;
  nss.print("w");
  nss.print(B00000000, BYTE);
  nss.print("v");
  if (hour() <= 24 && hour() >= 10)
  {
    nss.print(hour());
    if (minute() <= 99 && minute() >= 10)
    {
      nss.print(minute());
    }
    if (minute() <= 9 && minute() >= 0)
    {
      nss.print("0");
      nss.print(minute());
    }
    //  delay(10);
  }


  if (hour() <= 9 && hour() >= 0)
  {
    nss.print("0");
    nss.print(hour());
    if (minute() <= 99 && minute() >= 10)
    {
      nss.print(minute());
    }
    if (minute() <= 9 && minute() >= 0)
    {
      nss.print("0");
      nss.print(minute());
    }
    //  delay(10);
  }
}

void ClearLcd()
{
  nss.print("v");
  nss.print("xxxx");
}

void LoveYouLcd()
{
  nss.print("v");
  nss.print("LOUE");
  delay(2500);
  nss.print("YOUx");
  delay(2500);
}

void ShowDaysReading()
{
  ClearLcd() ;
  days = ((now() - theDateWeGotTogether) / 86400); //magic nubmer 86400 is the number of seconds in a day
  weeks = ((now() - theDateWeGotTogether) / (86400 * 7) ); //magic nubmer 86400 is the number of seconds in a day
  nss.print("w");
  nss.print(B00000000, BYTE);
  nss.print("v");
  if (days <= 99999999 && days >= 10000)
  {
    if (weeks <= 9999 && weeks >= 1000)
    {
      nss.print(weeks);
      delay(5000);
      nss.print("7day");
      delay(1000);
    }
    if (weeks <= 999 && weeks >= 100)
    {
      nss.print("0");
      nss.print(weeks);
      delay(5000);
      nss.print("7day");
      delay(1000);
    }

    if (weeks <= 99 && weeks >= 10)
    {
      nss.print("00");
      nss.print(weeks);
      delay(5000);
      nss.print("7day");
      delay(1000);
    }

    if (weeks <= 9 && weeks >= 0)
    {
      nss.print("000");
      nss.print(weeks);
    }
  }

  //days
  if (days <= 9999 && days >= 1000)
  {
    nss.print(days);

  }
  if (days <= 999 && days >= 100)
  {
    nss.print("0");
    nss.print(days);

  }

  if (days <= 99 && days >= 10)
  {
    nss.print("00");
    nss.print(days);

  }

  if (days <= 9 && days >= 0)
  {
    nss.print("000");
    nss.print(days);

  }
}

void ShowTimeReading()
{
  ClearLcd() ;
  nss.print("w");
  nss.print(B00000000, BYTE);
  nss.print("v");
  if (hour() <= 24 && hour() >= 10)
  {
    nss.print(hour());
    if (minute() <= 99 && minute() >= 10)
    {
      nss.print(minute());
    }
    if (minute() <= 9 && minute() >= 0)
    {
      nss.print("0");
      nss.print(minute());
    }
    //  delay(10);
  }


  if (hour() <= 9 && hour() >= 0)
  {
    nss.print("0");
    nss.print(hour());
    if (minute() <= 99 && minute() >= 10)
    {
      nss.print(minute());
    }
    if (minute() <= 9 && minute() >= 0)
    {
      nss.print("0");
      nss.print(minute());
    }
    //  delay(10);
  }
}

Die Inputs stimmen schonmal nicht, denn die RTC & Display sind beide an A4 & A5 angeschlossen, ich weiss jedoch nicht inwiefern ich nun die Inputs ändern müsste…

Ich versteh leider nicht, was genau du machen möchtest. Auch weiß ich nicht, was du mit "Inputs" meinst.

Evtl. solltest du dein Projekt von der Basis anfangen und einfach mal eine "normale" Uhr bauen, die eine Zeit und ein Datum auf dein Display anzeigt. Danach kannst du dich an die Dinge herantrauen, die du machen möchtest.

Dann zeig uns bitte auch einen Link deines verwendeten Displays.

nicolas_HD: Könnte mir jemand helfen bei der Programmierung? :)

Du hast noch gar nicht genau angegeben, was Du eigentlich berechnen möchtest.

Eine Unixtime enthält immer eine Datums- UND Zeitangabe.

Möchtest Du nun die Anzahl der Tage zwischen Enddatum und Anfangsdatum?

Oder vielmehr die Anzahl der vollständigen 24h-Intervalle zwischen End-Unixtime und Anfangs-Unixtime?

Das ist nicht dasselbe, wenn z.B. die Anfangs-Unixtime den 21.05.2016 23:59 Uhr repräsentiert und die End-Unixtime eine Minute später.

Dann wäre rein vom Datum her betrachtet bereits ein Tag später. Aber es liegt kein 24h-Intervall dazwischen.

Hallo, lieben Dank für eure Antworten!

@HotSystems: Ich möchte nur die aktuelle Zeit inkl. Datum von der RTC auslesen und als Unixtime in einer Variabel speichern. Dann möchte ich davon mein Ursprungsdatum (05.04.2014) abziehen und die Differenz zwischen Datum heute und Ursprungsdatum als Anzahl Tage auf dem Display anzeigen.

edit: Dieses Display: https://www.adafruit.com/products/878 Und diese RTC: https://www.sparkfun.com/products/12708 verwende ich

@jurs: Tut mir leid, vielleicht war ich zu ungenau. Wichtig ist mir nur die exakte Anzahl Tage die seit dem Ursprungsdatum verstrichen sind. Also wirklich nur die Anzahl Zage zwischen End- & Anfangsdatum. Das Ziel wäre, dass jeden Tag um 00:00 ein Tag addiert wird und das Total der dazwischenliegenden Tage auf dem Display ausgegeben wird.

Im Grunde ist es für mich auch nicht ganz einleuchtend, warum der UNIX-Timestamp verarbeitet werden soll. Doch das Thema ist hin und wieder mal vorgekommen, und daher habe ich gerade dazu etwas gesucht. Bei Wikipedia findet man ein erstes Ergebnis:

https://de.wikipedia.org/wiki/Unixzeit

Das Beispiel dort ist eine Umrechnung Tag/Datum in UNIX-Timestamp. Dieses Beispiel habe ich dann auf den Arduino gebracht… und die Ergebnisse sind exakt die selben, wenn man die Differenz UTC / MESZ ( -7200 ) berücksichtigt:

void setup()
{
  Serial.begin(9600);
}

void loop()
{

  /* Minus 7200 wegen "UTC" und "MESZ"... */
  long x = unixzeit( 2016, 5, 21, 12, 31, 58 ) - 7200;
  
  Serial.print( "Der 21.05.2016 um 12:31:58 Uhr = " );
  Serial.println( x );
  
  Serial.println( "\n=== [EOF] ===" );
  while(1);
}

long unixzeit( int jahr, int monat, int tag, int stunde, int minute, int sekunde )
{
  /* Anzahl der Tage seit Jahresanfang ohne Tage des aktuellen Monats und ohne Schalttag */
  const short tage_seit_jahresanfang[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
  
  /* Anzahl der Schaltjahre seit 1970 (ohne das evtl. laufende Schaltjahr) */
  int schaltjahre = ((jahr-1)-1968)/4 - ((jahr-1)-1900)/100 + ((jahr-1)-1600)/400;

  long tage_seit_1970 = (jahr-1970)*365 + schaltjahre + tage_seit_jahresanfang[monat-1] + tag-1;

  /* +Schalttag, wenn jahr Schaltjahr ist */
  if( ( monat>2 ) && ( jahr%4==0 && ( jahr%100!=0 || jahr%400==0 ) ) ) tage_seit_1970 += 1; 

  return sekunde + 60 * ( minute + 60 * (stunde + 24*tage_seit_1970) );
}

Eine Rückrechnung von Timestamp > Datum/Uhrzeit ist darin noch nicht enthalten. Ein Vergleich Arduino / PHP ergab identische Timestamp-Werte (nach Abzug der besagten 2 Stunden).
Vielleicht hilft das schon mal weiter?

timestamp.png

nicolas_HD: Wichtig ist mir nur die exakte Anzahl Tage die seit dem Ursprungsdatum verstrichen sind. Also wirklich nur die Anzahl Zage zwischen End- & Anfangsdatum. Das Ziel wäre, dass jeden Tag um 00:00 ein Tag addiert wird und das Total der dazwischenliegenden Tage auf dem Display ausgegeben wird.

OK. Also die Unixtime rechnet pro Tag um 86400 Sekunden weiter.

D.h. wenn Du eine Ganzzahldivision der Unixtime durch 86400 durchführst, erhältst Du die Anzahl der Tage seit Beginn der Unixtime, die zu diesem Zeitstempel gehört.

Die Tagesdifferenz zwischen End- und Anfangs-Unixtime erhältst Du also zu

  long daysBetweenDates= endUnixtime/86400- startUnixtime/86400;

Komplizierter ist das nicht.

nicolas_HD:
Die Inputs stimmen schonmal nicht, denn die RTC & Display sind beide an A4 & A5 angeschlossen, ich weiss jedoch nicht inwiefern ich nun die mmInputs ändern müsste…

Und was meinst du mit inputs?

Okay, danke für die Hilfe!
@HotSystems: Damit meinte ich die Inputdefinition im Code, den ich von einem anderen Typen übernommen hatte, der wahrscheinlich nicht dieselbe Hardware hatte wie ich und seine RTC via Digital In ausgelesen hatte.

Mein aktueller Code sieht so aus, ergibt aber noch keinen Sinn, da ich noch ziemlich am Anfang meiner Arduino Karriere stehe :wink:

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include "RTClib.h"
#include <Time.h>
#include <SPI.h>

RTC_DS1307 rtc = RTC_DS1307();
int hours = 0;
int minutes = 0;
int seconds = 0;
bool blinkColon = false;

long startUnixtime = 1392415200;
void setup()
{
  Serial.begin(9600);
  clockDisplay.begin(DISPLAY_ADDRESS);
  rtc.begin();
  bool setClockTime = !rtc.isrunning();
  if (setClockTime) {
    Serial.println("Setting DS1307 time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

}

void loop()
{
  if (minutes == 0) {
    // Get the time from the DS1307.
    DateTime now = rtc.now();
    // Set the hours and minutes.
    hours = now.hour();
    minutes = now.minute();
   }
  int displayValue = hours*100 + minutes;

clockDisplay.print(displayValue, DEC);
  if (TIME_24_HOUR && hours == 0) {
    clockDisplay.writeDigitNum(1, 0);
    if (minutes < 10) {
      clockDisplay.writeDigitNum(2, 0);
    }
  }
  blinkColon = !blinkColon;
  clockDisplay.drawColon(blinkColon);
  clockDisplay.writeDisplay();
  delay(1000);

  /* Minus 7200 wegen "UTC" und "MESZ"... */
  long x = unixzeit( 2016, 5, 21, 12, 31, 58 ) - 7200;
  
  Serial.print( "Der 21.05.2016 um 12:31:58 Uhr = " );
  Serial.println( x );
  
  Serial.println( "\n=== [EOF] ===" );
  while(1);
}

long unixzeit( int jahr, int monat, int tag, int stunde, int minute, int sekunde )
{
  /* Anzahl der Tage seit Jahresanfang ohne Tage des aktuellen Monats und ohne Schalttag */
  const short tage_seit_jahresanfang[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
  
  /* Anzahl der Schaltjahre seit 1970 (ohne das evtl. laufende Schaltjahr) */
  int schaltjahre = ((jahr-1)-1968)/4 - ((jahr-1)-1900)/100 + ((jahr-1)-1600)/400;

  long tage_seit_1970 = (jahr-1970)*365 + schaltjahre + tage_seit_jahresanfang[monat-1] + tag-1;

  /* +Schalttag, wenn jahr Schaltjahr ist */
  if( ( monat>2 ) && ( jahr%4==0 && ( jahr%100!=0 || jahr%400==0 ) ) ) tage_seit_1970 += 1; 

  return sekunde + 60 * ( minute + 60 * (stunde + 24*tage_seit_1970) );
}

long daysBetweenDates= endUnixtime/86400- startUnixtime/86400;

Auf jeden Fall müsste ich nun nur noch die aktuelle Zeit als “endUnixtime” speichern und danach “daysBetweenDates” auf dem Display ausgeben.
Doch ich scheitere schon am definieren des Ursprungsdatums…

long startUnixtime = 1392415200;

wird nicht als Variabel angesehen…

nicolas_HD: Okay, danke für die Hilfe! @HotSystems: Damit meinte ich die Inputdefinition im Code, den ich von einem anderen Typen übernommen hatte, der wahrscheinlich nicht dieselbe Hardware hatte wie ich und seine RTC via Digital In ausgelesen hatte.

Ok, was die Unix-Time betrifft, kann dir Jurs sicher mehr helfen, mir fehlt da die Erfahrung.

Aber die Pinbelegung für I2C musst du nicht extra definieren, das wird über die Library festgelegt.

Und die Libraries "Ardafruit_GFX.h" und "SPI.h" wirst du aktuell nicht brauchen, da du keine Komponenten mit SPI ansteuerst, sowie kein grafikfähiges Display nutzt.

Kannst du einfach testen, wenn du die Libs auskommentierst "//" davor. Wenn beim Kompilieren kein Fehler kommt, einfach weglassen.

Vielen Dank für eure Hilfe, mein aktueller Code sieht so aus und scheint fast zu funktionieren!

#include <Time.h>
#include <SPI.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include "RTClib.h"

RTC_DS1307 rtc = RTC_DS1307();

Adafruit_7segment clockDisplay = Adafruit_7segment();

int hours = 0;
int minutes = 0;
int seconds = 0;

unsigned long previousMillis = 0;        // will store last millis event time 
unsigned long sensorpreviousMillis = 0;        // will store last millis event time 
unsigned long fiveMinuteInterval = 300000;           // interval at which to use event time (milliseconds)
unsigned long postDaysInterval = 7200000 ; //seconds in a day 86400000

#define DISPLAY_ADDRESS   0x70

unsigned long theDateWeGotTogether = 1194242400   ;  //in unixtime
unsigned long days ; 
int weeks ; 

void setup() {                
  Serial.begin(115200); 
  clockDisplay.begin(DISPLAY_ADDRESS);
  rtc.begin();
  
 bool setClockTime = !rtc.isrunning();
 if (setClockTime) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop() {
//  DateTime now = rtc.now(); 
  days = ((now() - theDateWeGotTogether) / 86400); //86400 is the number of seconds in a day 
  unsigned long currentMillis = millis();
  ShowDaysReading();
  time_t t = now();
 
  if(currentMillis - sensorpreviousMillis > fiveMinuteInterval) 
  {
    // save the last time you performed event
    sensorpreviousMillis = currentMillis;   
    DateTime Zeit = rtc.now();
  }
}

void ShowDaysReading()
{  
  days = ((now() - theDateWeGotTogether) / 86400); //86400 number of seconds in a day
  weeks = ((now() - theDateWeGotTogether) / (86400 * 7) ); //86400 number of seconds in a day

  clockDisplay.print(days); 
}

Nun habe ich “nur” das Problem, dass absolut unverständliche Werte auf dem Display angezeigt werden, resp. nur irgendwelche zufällige beleuchtete Balken…

An was könnte das liegen, resp. wie kann das behoben werden? :o

Ich wage nochmals zu fragen, ob denn nun niemand weiss, wie man dieses Display zum korrekten Anzeigen der Zahlen bringen kann?

Da ich dieses Display nicht verwende, kommt mir nur die Idee, du hast doch sicher in der Library zum Display ein Beispiel wie die Ziffern angesprochen werden.

Und räum den Sketch auf, da sind viele Libraries drin, die du nicht brauchst.

Warum musst du mit UnixTime rechnen? Wäre es nicht einfacher, die jeweils Zahl er Tage seit einem Referenzdatum zu ermitteln und dann nur noch die Differenz zu nehmen.

Ich kann mich Theseus nur anschließen... Wenn dein Zähler die Sekunden seit dem Start des Arduinos zählt hast du doch schon alles was du brauchst. Den Zählerstand kannst du im Format "unsigned long" (= 4 Byte) speichern. Später rechnest du:

word Tage = Zaehler /86400;
byte Stunden = (Zaehler %86400) /3600;
byte Minuten = ((Zaehler %86400) %3600) /60;
byte Sekunden = ((Zaehler %86400) %3600) %60;

Dadurch bekommst du die geforderte Zeitdifferenz zwischen "Start" und "Jetzt" und rechnest evtl. nur noch das Referenzdatum hinzu.

Das ganze in Unix-Timestamp zu rechnen ist im Grunde überflüssig. Gemäß meines Links nach Wikipedia geht das zwar recht gut, ist aber für den Arduino m.E. nicht unbedingt nutzbar. Denn man findet nirgends eine allgemeine und "schnell nutzbare" Funktion, den Timestamp in reales Datum/Uhrzeit zurück zu rechnen. Ich habe zwar 'ne gewisse Vorstellung wie das gehen könnte, aber das würde den Rahmen des gewünschten hier wahrscheinlich sprengen.

Ich wollte Sekunden usw. gar nicht beachten, weil Wechselmoment für die Tageszahl 0.00Uhr ist. Ich würde ein Array Monat erstellen, wo die Tage seit Jahresbeginn jeweils für den ersten jeden Monats eingetragen ist. Mon(at), Tag und Jahr stammen von der RTC. Dann sind die Tage seit Jahresanfang Tage1=Monat[Mon-1]+Tag-1+((Jahr%4)=0 && Mon>2). *Dann nimmt man sich ein Referenzdatum und rechnet z.B. seit 1.1.2001. Dann wären die Tage seit dem Referenzdatum: * Tage2=Tage1+(Jahr-2001)*365+(Jahr-2001-1)/4.

Wie auch immer... Ich bin gespannt wie und ob der Kollege die Sache mit seinem Zeitstempel jetzt löst, da mir das Thema öfters begegnet und ich selbst gerne damit hantiere.