Huge Sketch, huge Problem (TimeLib, NTP-Time)

Hi

I used this Original-Sketch to get the NTP-Time:

/*
 * Time_NTP.pde
 * Example showing time sync to NTP time source
 *
 * Also shows how to handle DST automatically.
 *
 * This sketch uses the EtherCard library:
 * http://jeelabs.org/pub/docs/ethercard/
 */
 
#include <TimeLib.h>
#include <EtherCard.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 

// NTP Server
const char timeServer[] PROGMEM = "pool.ntp.org";

const int utcOffset = 1;     // Central European Time
//const int utcOffset = -5;  // Eastern Standard Time (USA)
//const int utcOffset = -4;  // Eastern Daylight Time (USA)
//const int utcOffset = -8;  // Pacific Standard Time (USA)
//const int utcOffset = -7;  // Pacific Daylight Time (USA)

// Packet buffer, must be big enough to packet and payload
#define BUFFER_SIZE 550
byte Ethernet::buffer[BUFFER_SIZE];

const unsigned int remotePort = 123;

void setup() 
{
  Serial.begin(9600);
  
  while (!Serial)    // Needed for Leonardo only
    ;
  delay(250);
  
  Serial.println("TimeNTP_ENC28J60 Example");
  
  if (ether.begin(BUFFER_SIZE, mac) == 0) {
     // no point in carrying on, so do nothing forevermore:
    while (1) {
      Serial.println("Failed to access Ethernet controller");
      delay(10000);
    }
  }
  
  if (!ether.dhcpSetup()) {
    // no point in carrying on, so do nothing forevermore:
    while (1) {
      Serial.println("Failed to configure Ethernet using DHCP");
      delay(10000);
    }
  }

  ether.printIp("IP number assigned by DHCP is ", ether.myip);

  Serial.println("waiting for sync");
  //setSyncProvider(getNtpTime);            // Use this for GMT time
  setSyncProvider(getDstCorrectedTime);     // Use this for local, DST-corrected time
}

time_t prevDisplay = 0; // when the digital clock was displayed

void loop()
{
  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      digitalClockDisplay();  
    }
  }
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*-------- NTP code ----------*/

// SyncProvider that returns UTC time
time_t getNtpTime()
{
  // Send request
  Serial.println("Transmit NTP Request");
  if (!ether.dnsLookup(timeServer)) {
    Serial.println("DNS failed");
    return 0; // return 0 if unable to get the time
  } else {
    //ether.printIp("SRV: ", ether.hisip);
    ether.ntpRequest(ether.hisip, remotePort);
  
    // Wait for reply
    uint32_t beginWait = millis();
    while (millis() - beginWait < 1500) {
      word len = ether.packetReceive();
      ether.packetLoop(len);

      unsigned long secsSince1900 = 0L;
      if (len > 0 && ether.ntpProcessAnswer(&secsSince1900, remotePort)) {
        Serial.println("Receive NTP Response");
        return secsSince1900 - 2208988800UL;
      }
    }
    
    Serial.println("No NTP Response :-(");
    return 0;
  }
}

/* Alternative SyncProvider that automatically handles Daylight Saving Time (DST) periods,
 * at least in Europe, see below.
 */
time_t getDstCorrectedTime (void) {
  time_t t = getNtpTime ();

  if (t > 0) {
    TimeElements tm;
    breakTime (t, tm);
    t += (utcOffset + dstOffset (tm.Day, tm.Month, tm.Year + 1970, tm.Hour)) * SECS_PER_HOUR;
  }

  return t;
}

/* This function returns the DST offset for the current UTC time.
 * This is valid for the EU, for other places see
 * http://www.webexhibits.org/daylightsaving/i.html
 * 
 * Results have been checked for 2012-2030 (but should work since
 * 1996 to 2099) against the following references:
 * - http://www.uniquevisitor.it/magazine/ora-legale-italia.php
 * - http://www.calendario-365.it/ora-legale-orario-invernale.html
 */
byte dstOffset (byte d, byte m, unsigned int y, byte h) {
  // Day in March that DST starts on, at 1 am
  byte dstOn = (31 - (5 * y / 4 + 4) % 7);

  // Day in October that DST ends  on, at 2 am
  byte dstOff = (31 - (5 * y / 4 + 1) % 7);

  if ((m > 3 && m < 10) ||
      (m == 3 && (d > dstOn || (d == dstOn && h >= 1))) ||
      (m == 10 && (d < dstOff || (d == dstOff && h <= 1))))
    return 1;
  else
    return 0;
}


This Sketch works perfectly and I put it into my Sketch:

//#include <Wire.h>
//#include <SPI.h>
#include <DS3231.h>
DS3231 clock;
RTCDateTime dt;
//String outdate = "";
const unsigned int DISPLAY_TIMEOUT = 8000;
bool displayIsOn;
unsigned long displayTimeout;

#include <SoftwareSerial.h>
SoftwareSerial BTserial(2, 3);
// BTconnected will = false when not connected and true when connected
boolean BTconnected = false;
// connect the STATE pin to Arduino pin D4
const byte BTpin = 4;

#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// BLK an 3,3V VCC
#define TFT_CLK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_DC 5
#define TFT_CS -1  //erforderlich!
#define TFT_RST 8
#define TFT_BLK 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

#include <TimeLib.h>
#include <EtherCard.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// NTP Server
const char timeServer[] PROGMEM = "pool.ntp.org";
const int utcOffset = 1;  // Central European Time
//const int utcOffset = -5;  // Eastern Standard Time (USA)
//const int utcOffset = -4;  // Eastern Daylight Time (USA)
//const int utcOffset = -8;  // Pacific Standard Time (USA)
//const int utcOffset = -7;  // Pacific Daylight Time (USA)
// Packet buffer, must be big enough to packet and payload
#define BUFFER_SIZE 550
byte Ethernet::buffer[BUFFER_SIZE];
const unsigned int remotePort = 123;
boolean IPconnected = true;
time_t prevDisplay = 0;  // when the digital clock was displayed


//unsigned long currentMillis = 0;
//unsigned long previousMillis = 0;
const long interval = 3000;
//int Blight = 0;

byte trigger = 7;     //Trigger-Pin des Ultraschallsensors an Pin7 des Arduino-Boards
byte echo = 6;        // Echo-Pim des Ultraschallsensors an Pin6 des Arduino-Boards
long dauer = 0;       // Das Wort dauer ist jetzt eine Variable, unter der die Zeit gespeichert wird, die eine Schallwelle bis zur Reflektion und zurück benötigt. Startwert ist hier 0.
long entfernung = 0;  // Das Wort „entfernung“ ist jetzt die variable, unter der die berechnete Entfernung gespeichert wird. Info: Anstelle von „int“ steht hier vor den beiden Variablen „long“. Das hat den Vorteil, dass eine größere Zahl gespeichert werden kann. Nachteil: Die Variable benötigt mehr Platz im Speicher.
byte zl1 = 0;
byte zl2 = 31;
byte zl3 = 62;
byte zl4 = 93;
byte zl5 = 124;
byte zl6 = 155;
byte zl7 = 186;
byte zl8 = 217;

void setup() {


  clock.begin();
  // Nur zum Setzen der Zeit einmal freisetzen
  // Manual (YYYY, MM, DD, HH, II, SS
  //clock.setDateTime(2024, 1, 20, 13, 23, 00);
  //Serial.begin(9600);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextSize(3);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setCursor(0, zl3);
  tft.print(F("Balkon:"));
  tft.setCursor(0, zl5);
  tft.print(F("Innen:"));
  if (digitalRead(BTpin) == HIGH) {
    analogWrite(TFT_BLK, 0);
    displayIsOn = false;
  } else {
    analogWrite(TFT_BLK, 200);
    displayIsOn = true;
  }
  tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
  tft.setCursor(0, zl8);
  tft.print(F("Warte auf IP"));
  if (ether.begin(BUFFER_SIZE, mac) == 0) {
    // no point in carrying on, so do nothing forevermore:
    IPconnected = false;
  }
  if (!ether.dhcpSetup()) {
    // no point in carrying on, so do nothing forevermore:
    IPconnected = false;
  }
  if (IPconnected = true) {
    char* myTemplate = "";
    char resultip[64] = {};
    myTemplate = "%d:%d:%d:%d";
    sprintf(resultip, myTemplate, ether.myip[0], ether.myip[1], ether.myip[2], ether.myip[3]);
    //ether.printIp("IP number assigned by DHCP is ", ether.myip);
    tft.setCursor(0, zl6);
    tft.print(resultip);

    setSyncProvider(getDstCorrectedTime);  // Use this for local, DST-corrected time
    //setSyncProvider(getNtpTime);  
    //digitalClockDisplay();
    
    if (timeStatus() != timeNotSet) {
      if (now() != prevDisplay) {  //update the display only if time has changed
        prevDisplay = now();
        digitalClockDisplay();
      }
    }
   
  } else {
    tft.setCursor(0, zl8);
    tft.print("No IP           ");
  }

  BTserial.begin(38400);
  pinMode(trigger, OUTPUT);  // Trigger-Pin ist ein Ausgang
  pinMode(echo, INPUT);      // Echo-Pin ist ein Eingang
}


void loop() {
  digitalWrite(trigger, LOW);
  delay(5);
  digitalWrite(trigger, HIGH);         //Jetzt sendet man eine Ultraschallwelle los.
  delay(10);                           //Dieser „Ton“ erklingt für 10 Millisekunden.
  digitalWrite(trigger, LOW);          //Dann wird der „Ton“ abgeschaltet.
  dauer = pulseIn(echo, HIGH);         //Mit dem Befehl „pulseIn“ zählt der Mikrokontroller die Zeit in Mikrosekunden, bis der Schall zum Ultraschallsensor zurückkehrt.
  entfernung = (dauer / 2) * 0.03432;  //Nun berechnet man die Entfernung in Zentimetern. Man teilt zunächst die Zeit durch zwei (Weil man ja nur eine Strecke berechnen möchte und nicht die Strecke hin- und zurück). Den Wert multipliziert man mit der Schallgeschwindigkeit in der Einheit Zentimeter/Mikrosekunde und erhält dann den Wert in Zentimetern.

  //if (digitalRead(BTpin) == HIGH) { displayBacklight(); }
  displayBacklight();

  dt = clock.getDateTime();
  char timebuffer[8];
  char datebuffer[5];
  sprintf(datebuffer, "%02u.%02u", dt.day, dt.month);
  tft.setTextColor(ILI9341_PINK, ILI9341_BLACK);
  tft.setCursor(0, zl1);
  tft.print(datebuffer);
  tft.print(".");
  tft.print(String(dt.year).substring(2, 4));
  sprintf(timebuffer, "%02u:%02u:%02u", dt.hour, dt.minute, dt.second);
  tft.print(" " + String(timebuffer));
  tft.setCursor(0, zl2);
  switch (dt.dayOfWeek) {
    case 1: tft.print(F("Montag     ")); break;
    case 2: tft.print(F("Dienstag   ")); break;
    case 3: tft.print(F("Mittwoch   ")); break;
    case 4: tft.print(F("Donnerstag ")); break;
    case 5: tft.print(F("Freitag    ")); break;
    case 6: tft.print(F("Samstag    ")); break;
    case 7: tft.print(F("Sonntag    ")); break;
    default: tft.print(F("Wochentag ?"));
  }
  tft.setTextColor(ILI9341_CYAN, ILI9341_BLACK);
  tft.setCursor(126, zl5);
  tft.print(clock.readTemperature());
  tft.print("C  ");

  if (digitalRead(BTpin) == HIGH) {
    if (BTserial.available() > 0) {
      delay(100);
      String readString = BTserial.readString();
      int firstClosingBracket = readString.indexOf('<');
      int secondClosingBracket = readString.indexOf('>', firstClosingBracket + 1);
      String readString1 = readString.substring(firstClosingBracket + 1, secondClosingBracket);
      if (readString1.length() > 17) { readString1.remove(17); }
      tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
      tft.setCursor(0, zl4);
      tft.print(readString1);
      readString = "";
      readString1 = "";
    }
  } else {
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(0, zl4);
    tft.print("Kein Signal      ");
    tft.setCursor(120, zl7);
    //tft.print("        ");
  }
}
void displayBacklight() {
  if (displayIsOn && (millis() - displayTimeout <= DISPLAY_TIMEOUT)) {
    tft.setTextColor(ILI9341_ORANGE, ILI9341_BLACK);
    tft.setCursor(120, zl7);
    unsigned long count1 = ((millis() - displayTimeout) / 1000) + 1;
    unsigned long count2 = (DISPLAY_TIMEOUT / 1000) + 1;
    tft.print(String(abs(int(count1) - int(count2))) + " Sek.");
    //tft.print(String(((millis() - displayTimeout) / 1000) + 1) + " Sek.");
  }
  if (entfernung > 0 && entfernung <= 10) {
    displayTimeout = millis();
    if (!displayIsOn) {
      displayIsOn = true;
      analogWrite(TFT_BLK, 200);
    }
    return;
  }
  if (displayIsOn && (millis() - displayTimeout > DISPLAY_TIMEOUT)) {
    displayIsOn = false;
    tft.setCursor(120, zl7);
    tft.print("       ");
    analogWrite(TFT_BLK, 0);
  }
}
void digitalClockDisplay() {
  // digital clock display of the time
  tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
  tft.setCursor(0, zl8);
  tft.print(day());
  tft.print(".");
  tft.print(month());
  tft.print(".");
  
  /*tft.print(String(year()).substring(2, 4));
  tft.print(" ");
  printDigits(hour());
  tft.print(":");
  printDigits(minute());
  tft.print(":");
  printDigits(second());
  */
}

void printDigits(int digits) {
  // utility for digital clock display: prints preceding colon and leading 0
  if (digits < 10)
    tft.print('0');
  tft.print(digits);
}

/*-------- NTP code ----------*/

// SyncProvider that returns UTC time
time_t getNtpTime() {
  // Send request
  tft.setCursor(0, zl8);
  tft.print("NTP Request");
  if (!ether.dnsLookup(timeServer)) {
    tft.print(" failed");
    return 0;  // return 0 if unable to get the time
  } else {
    //ether.printIp("SRV: ", ether.hisip);
    ether.ntpRequest(ether.hisip, remotePort);

    // Wait for reply
    uint32_t beginWait = millis();
    while (millis() - beginWait < 1500) {
      word len = ether.packetReceive();
      ether.packetLoop(len);

      unsigned long secsSince1900 = 0L;
      if (len > 0 && ether.ntpProcessAnswer(&secsSince1900, remotePort)) {
        tft.setCursor(0, zl8);
        tft.print("Receive NTP");
        return secsSince1900 - 2208988800UL;
      }
    }
    tft.setCursor(0, zl8);
    tft.print("No NTP Response");
    return 0;
  }
}

/* Alternative SyncProvider that automatically handles Daylight Saving Time (DST) periods,
 * at least in Europe, see below.
 */
time_t getDstCorrectedTime(void) {
  time_t t = getNtpTime();
  if (t > 0) {
    TimeElements tm;
    breakTime(t, tm);
    t += (utcOffset + dstOffset(tm.Day, tm.Month, tm.Year + 1970, tm.Hour)) * SECS_PER_HOUR;
  }
  return t;
}

/* This function returns the DST offset for the current UTC time.
 * This is valid for the EU, for other places see
 * http://www.webexhibits.org/daylightsaving/i.html
 * 
 * Results have been checked for 2012-2030 (but should work since
 * 1996 to 2099) against the following references:
 * - http://www.uniquevisitor.it/magazine/ora-legale-italia.php
 * - http://www.calendario-365.it/ora-legale-orario-invernale.html
 */
byte dstOffset(byte d, byte m, unsigned int y, byte h) {
  // Day in March that DST starts on, at 1 am
  byte dstOn = (31 - (5 * y / 4 + 4) % 7);

  // Day in October that DST ends  on, at 2 am
  byte dstOff = (31 - (5 * y / 4 + 1) % 7);

  if ((m > 3 && m < 10) || (m == 3 && (d > dstOn || (d == dstOn && h >= 1))) || (m == 10 && (d < dstOff || (d == dstOff && h <= 1))))
    return 1;
  else
    return 0;
}

And it works ... except for the Day and Month at digitalClockDisplay().
I get something like 35 for the Day and 13 for the Month.

I compared and checked both Sketches over and over but I can't figure out what's wrong.
I get a correct Unix-Time back from the Functions.

I know this is a big Request but I don't know what to do next. So I would really appreciate it if someone could have a Look at the Sketches and can maybe find out what's the Problem.

I have not seen anyone on the forum able to reliably get those speeds from software serial. Also, software serial uses interrupts that may be interfering with other parts of your program. Try an Arduino with more than one real UART.

Hm, but it works. And I checked the Documentation about this:

speed: the desired baud rate (long). Supported baud rates are: 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400, 57600, and 115200 bauds.

I only have a Nano and I don't wanna buy another Arduino if it's not really necessary. But I will check the other Hardware again regarding to the Interrupts.

Oops! Shouldn't that be

  char timebuffer[9];
  char datebuffer[6];

?

That is ALL correct. However, you are wanting time to run other parts of your program. Documentation saying something is supported does not imply other things can interfere and all will be well.

I don't think so because I get the correct Date and Time. And this is not the Date/Time-Function with the mentioned Problem.

    char datebuffer[5];     //room for 5 characters
    sprintf(datebuffer, "%02u.%02u", dt.day, dt.month); //5 characters PLUS the terminating zero

Can you see the problem ?

There a so many boards in the Arduino ecosystem that would give you an available hardware UART port and they are so cheap that there's really no excuse to stick with one that forces you to use SoftwareSerial. If you want to stick with the AVR architecture, look for a 32u4-based board like: This One.

You are right. I tried slower Baudrates but it makes no difference.

Yes, yes, you are right. I changed it.
But it has no impact on the Date/Time-Problem.

Software serial uses one of the internal timers to generate the interrupts at the baud rate you are using. Is any other part of your code using the internal timers?

Did you fix the similar problem with the size of timebuffer ?

True. But I will try it with the Nano. Maybe it's only a very small Problem.

Yes, I did.

Did you intend to set IPconnected to "true", or were you wanting to do a comparison? (this is line 102 of your code)
Why the contortions of declaring a pointer to an empty string, then setting the pointer to the template for sprintf(), instead of directly putting the template in the call to sprintf()?
The size of result is overly generous for a string that is not going to exceed 16 characters (ether.myip[x] is a uint8_t).

  if (IPconnected = true) {
    char* myTemplate = "";
    char resultip[64] = {};
    myTemplate = "%d:%d:%d:%d";
    sprintf(resultip, myTemplate, ether.myip[0], ether.myip[1], ether.myip[2], ether.myip[3]);
    //ether.printIp("IP number assigned by DHCP is ", ether.myip);
    tft.setCursor(0, zl6);
    tft.print(resultip);

With the amount of ram this sketch uses (1536 bytes compiled for an UNO), I would store the pattern for sprintf() in PROGMEM:

    sprintf_P(resultip, PSTR("%d:%d:%d:%d"), ether.myip[0], ether.myip[1], ether.myip[2], ether.myip[3]);

I've changed it. Thank you.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.