Hi,
I have a RTC in my project and I am trying to update it via NTP. It updates fine but it stops providing data to my program once I perform the update. Has anyone ever experienced anything like this? Code is as follows. It is a simple temperature sensor that also serves up a web page.
// Import needed libraries
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <DHT.h>
#include <RTClib.h>
#include <Time.h>
#include <LiquidCrystal_I2C.h>
#include <EthernetUdp.h>
// Set the MAC address for the network shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
unsigned int localPort = 8888; // local port to listen for UDP packets
byte timeServer[] = {128, 101, 101, 101}; //ns.nts.umn.edu
const int NTP_PACKET_SIZE = 48; // NTP Time stamp is in the first 48 bytes of the message
byte pb[NTP_PACKET_SIZE]; // Buffer to hold incoming & outgoing packets
EthernetUDP udp;
// Set the pins used for the LCD
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
// Instantiate our EthernetServer
EthernetServer server(80);
// Instantiate our global variables
RTC_DS1307 rtc;
float humidity = 0.0;
float temperature = 0.0;
// Define our constants
#define DHTTYPE DHT22
#define DHTPIN 14
// Instantiate DHT
DHT dht(DHTPIN, DHTTYPE);
void setup()
{
// Startup serial communications
Serial.begin(9600);
// Startup the LCD
lcd.begin(20,4);
// Startup the Ethernet
Ethernet.begin(mac);
// Startup the server
server.begin();
// Startup the DHT sensor
dht.begin();
Wire.begin();
rtc.begin();
humidity = dht.readHumidity();
temperature = dht.readTemperature(true);
//adjust the date & time to the compile date & time
//rtc.adjust(DateTime(__DATE__, __TIME__));
}
void loop()
{
// Print the server information to the serial port
Serial.print("Server is at ");
Serial.println(Ethernet.localIP());
DateTime now = rtc.now();
Serial.println(GetDateTime(now));
if (now.unixtime() % 10 == 0)
{
humidity = dht.readHumidity();
temperature = dht.readTemperature(true);
}
if (now.unixtime() % 3600 == 0)
{
sendNTPpacket(timeServer);
delay (1000);
if (udp.available())
{
udp.read(pb, NTP_PACKET_SIZE);
// NTP contains four timestamps with an integer part and a fraction part
// we only use the integer part here
unsigned long t1, t2, t3, t4;
t1 = t2 = t3 = t4 = 0;
for (int i=0; i< 4; i++)
{
t1 = t1 << 8 | pb[16+i];
t2 = t2 << 8 | pb[24+i];
t3 = t3 << 8 | pb[32+i];
t4 = t4 << 8 | pb[40+i];
}
// part of the fractional part
// could be 4 bytes but this is more precise than the 1307 RTC
// which has a precision of ONE second
// in fact one byte is sufficient for 1307
float f1,f2,f3,f4;
f1 = ((long)pb[20] * 256 + pb[21]) / 65536.0;
f2 = ((long)pb[28] * 256 + pb[29]) / 65536.0;
f3 = ((long)pb[36] * 256 + pb[37]) / 65536.0;
f4 = ((long)pb[44] * 256 + pb[45]) / 65536.0;
// NOTE:
// one could use the fractional part to set the RTC more precise
// 1) at the right (calculated) moment to the NEXT second!
// t4++;
// delay(1000 - f4*1000);
// RTC.adjust(DateTime(t4));
// keep in mind that the time in the packet was the time at
// the NTP server at sending time so one should take into account
// the network latency (try ping!) and the processing of the data
// ==> delay (850 - f4*1000);
// 2) simply use it to round up the second
// f > 0.5 => add 1 to the second before adjusting the RTC
// (or lower threshold eg 0.4 if one keeps network latency etc in mind)
// 3) a SW RTC might be more precise, => ardomic clock :)
// convert NTP to UNIX time, differs seventy years = 2208988800 seconds
// NTP starts Jan 1, 1900
// Unix time starts on Jan 1 1970.
const unsigned long seventyYears = 2208988800UL;
t1 -= seventyYears;
t2 -= seventyYears;
t3 -= seventyYears;
t4 -= seventyYears;
// Adjust timezone and DST... in my case substract 4 hours for Chile Time
// or work in UTC?
if (IsDST(now.day(), now.month(), now.dayOfWeek()))
t4 -= (-5 * 3600L);
else
t4 -= (-6 * 3600L); // Notice the L for long calculations!!
t4 += 1; // adjust the delay(1000) at begin of loop!
if (f4 > 0.4) t4++; // adjust fractional part, see above
rtc.adjust(DateTime(t4));
rtc.begin();
}
}
String IP = "";
for (byte thisByte = 0; thisByte < 4; thisByte++)
{
IP += String(Ethernet.localIP()[thisByte], DEC);
if (thisByte < 3) IP += '.';
}
UpdateLCD(IP, temperature, humidity, now);
// Instante a new client
EthernetClient client = server.available();
// If the client has connected start sending it info
if (client)
{
// Write out that a new client has connected via serial
Serial.println("New client connected");
boolean currentLineIsBlank = true;
// Loop while a client is connected
while (client.connected())
{
// Only continue if a client is available
if (client.available())
{
// Read a character
char c = client.read();
// Write the character out via Serial
Serial.write(c);
// If the character is a new line & the current line is blank, continue
if (c == '\n' && currentLineIsBlank)
{
// Write a HTTP response
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println("Refresh: 5");
client.println();
// Start writing the HTML page
client.println("<!DOCTYPE HTML>");
client.println("<html>");
// Write information from the sensor if it is good
client.print("Humidity: ");
client.print(humidity, 2);
client.print("%\n
\nTemperature: ");
client.print(temperature, 2);
client.print("F\n
");
// Write the current time
client.print("\nTime: ");
client.print(GetDateTime(now));
// Close the HTML page
client.print("\n</html>");
// Break out
break;
}
if (c == '\n')
{
currentLineIsBlank = true;
}
else if (c != '\r')
{
currentLineIsBlank = false;
}
}
}
delay(1);
client.stop();
Serial.println("client disonnected");
}
// Wait ~1 seconds before looping
delay(1000);
}
String GetDateTime(DateTime now)
{
String retVal = "";
if (now.month() < 10) retVal += '0';
retVal += String(now.month()) + '/';
if (now.day() < 10) retVal += '0';
retVal += String(now.day()) + '/';
retVal += String(now.year()) + ' ';
if (now.hour() < 10) retVal +='0';
retVal += String(now.hour()) + ':';
if (now.minute() < 10) retVal +='0';
retVal += String(now.minute()) + ':';
if (now.second() < 10) retVal +='0';
retVal +=String(now.second());
return retVal;
}
void UpdateLCD(String IP, float temp, float humidity, DateTime now)
{
lcd.setCursor(0, 0);
lcd.print(IP);
lcd.setCursor(0, 1);
lcd.print(temp, 2);
lcd.print('F');
lcd.setCursor(0, 2);
lcd.print(humidity, 2);
lcd.print('%');
lcd.setCursor(0,3);
lcd.print(GetDateTime(now));
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(byte *address)
{
// set all bytes in the buffer to 0
memset(pb, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
pb[0] = 0b11100011; // LI, Version, Mode
pb[1] = 0; // Stratum, or type of clock
pb[2] = 6; // Polling Interval
pb[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
pb[12] = 49;
pb[13] = 0x4E;
pb[14] = 49;
pb[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
// IDE 1.0 compatible:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(pb,NTP_PACKET_SIZE);
udp.endPacket();
}
bool IsDST(int dayVal, int monthVal, int dow)
{
//January, february, and december are out.
if (monthVal < 3 || monthVal > 11) { return false; }
//April to October are in
if (monthVal > 3 && monthVal < 11) { return true; }
int previousSunday = dayVal - dow;
//In march, we are DST if our previous sunday was on or after the 8th.
if (monthVal == 3) { return previousSunday >= 8; }
//In november we must be before the first sunday to be dst.
//That means the previous sunday must be before the 1st.
return previousSunday <= 0;
}