Time Library added to Playground

Lets see if we can find out why you had problems running the example GPS code, perhaps that may be related to the problem you are having in your current sketch.

Was the example code that locked up modified, and if so, can you post the code you ran.

OK, I went back to the original GPS code and put it into my code. It does not lock up everything, but it's stuck in 1970. It does seem to be counting in the loops though.

The code is too long to post, it is viewable at www.schnellnetworks.com/code.html

Thanks,
Eddie

Had a breakthrough. When I pressed some of the buttons on the door, it magically got the correct time on the screen. I changed the startup code to wait for serial data to be available by using the feedgps function, then called the gps.encode line for the Time library to read, and now it seems to be getting the correct time at startup.

Serial.println("Waiting for GPS Time...");                          // debug
  setSyncProvider(gpsTimeSync);
  while(feedgps() != true) {                                          // if feedgps is false
    delay(50);                                                        // take a breath
  }
  gps.encode(Serial3.read()); // process gps messages

Thanks,
Eddie Schnell

Eddie, good to hear you have it working, it looks like an interesting project. Perhaps you could post some more details in the exhibition forum when you are ready.

For the benefit of others that may want to test using the GPS example code in the download, did that work as expected with your GPS after you changed the serial port for the Mega, but before you added any logic for your application?

In reply #4 Veronica pointed out:

#include <time.h>

in Time.cpp should have a capital T.

This is the case ( ;)) in the DS1307RTC.h file also.

It took me way too long to figure out this was the problem.

Otherwise, great library. I've been using the old one since last June, and it's nice to have RTC support integrated.
Also I was really glad to see the default TIME_HEADER changed to 'T' instead of 255.

-transfinite

Hi,
I'm having a problem with your leap year calculation.
For some reason, the function setTime() always adds one more day when you use the year 2000.
I did change this:
#define LEAP_YEAR(_year) ( ( (((1970+_year)%4)==0) && ((1970+year)%100!=0) ) || ((1970+_year)%400==0) )
to this:
#define LEAP_YEAR(_year) ( ( (((1970+_year)%4)==0) && ((1970+_year)%100!=0) ) || ((1970+_year)%400==0) )
but still have problems.
Would you be able to check on that?

Thanks

good catch on the missing underscore.

That calculation is used internally using Unix time where 1970 is year 0
so year 2000 would be given to that expression as year 30.

I'm sorry for not being so clear.
Here is an example of faulty unix time calculation:
setTime(8,29,40,1,1,0); // set time to 8:29:40am Jan 1 2000
Serial.print(month());
Serial.print("/");
Serial.print(day());
Serial.print("/");
Serial.println(year());
And this is what you get from serial output:
1/2/2000
Do you see where I'm trying to get?
It increments by 1 day because of leap year calculation. I just can't find out where and I just didn't have time to look further and test it if it is every 4 years or just on centuries or just on milleniums.
If you can look into it, I would appreciate your effort.
Great library btw. I'm using a modified version for my own purposes.

Thanks.

@newhobby, I have uploaded an update to the Time library that fixes an error in the leap calculation. This should resolve the problem you found.

have fun!

Hi,
I'm new using this library. The example works fine but the events like Alarm.alarmRepeat() won't trigger when I take delay(1000) out of the loop(). Is there a way around this?

I need event to occur without the delay.

thanks.

Pretty sure you can do delay(0)

thanks. that did it. It didn't work without a Alarm.delay() or some sort.

Yes, you need to do alarm.delay when using the alarm library.

as it says in the documentation for the timeAlarm library:

Note that the loop code calls Alarm.delay(1000) - Alarm.delay must be used
instead of the usual arduino delay function because the alarms are serviced in the Alarm.delay method.
Failing to regularly call Alarm.delay will result in the alarms not being triggered
so always use Alarm.delay instead of delay in sketches that use the Alarms library.

I had some problems to get "Time_SNP.pde" up and running. Main reason was wrong buffer length in UdpEtherne.h. So i introduced some changes to "Time_NTP.pde" code to ease beginners to bring it to operation.

  1. Added some comments how to change UdpEthernet.h buffer size
  2. removed gateway adress, this would normaly not be neccesary.
  3. renamed Server-IP Variable to "SNTP_server_IP[]" for better international reading.
  4. introduced some more time servers as a comment to easy try some other servers.
  5. added a const unsigned long for time zone correction, which ist used in unsigned long getNtpTime() function. This could also be done by definig 24 different like e.g.
       const unsigned long seventy_years_CET = 22089XXXXUL;
//     const unsigned long seventy_years_UTC = 2208988800UL;
//     const unsigned long seventy_years_    ____ and so on ____

Which version would you or a beginner prefer for time zone correction ? i can provide the changes if someone wants me to do :slight_smile:

Hi mem,
please review my changes and introduce them to your library.

Here is my code :

/*
 * Time_NTP.pde
 * Example showing time sync to NTP time source
 *
 * This sketch uses the Ethenet library with the user contributed UdpBytewise extension
 */

#include <Time.h> 
#include <Ethernet.h>
// the follwing library should be copied to the Ethernet directory
#include <UdpBytewise.h>  // UDP library from: bjoern@cs.stanford.edu 12/30/2008 
//  You will also need to modify the UdpBytewise.h library to allow enough space in the buffers for the NTP packets. 
//  Open up UdpBytewse.h and change these lines:
//
//  #define UDP_TX_PACKET_MAX_SIZE 32
//  #define UDP_RX_PACKET_MAX_SIZE 32
//
//  to this:
//
//  #define UDP_TX_PACKET_MAX_SIZE 64
//  #define UDP_RX_PACKET_MAX_SIZE 64
//

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
byte ip[] = { 
  192, 168, 178, 100 };   // fill in your local Arduino ip adress
  
// byte SNTP_server_IP[] = { 192, 43, 244, 18}; // time.nist.gov
// byte SNTP_server_IP[] = { 130,149,17,21}; // ntps1-0.cs.tu-berlin.de
byte SNTP_server_IP[] = { 
  192,53,103,108}; // ptbtime1.ptb.de

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

// time zone correction [sec]. e.g. CET = -3600 sec
const unsigned long add_time_zone=-3600UL; 

void setup() 
{
  Ethernet.begin(mac,ip);  
  Serial.begin(19200);
  Serial.println ("waiting for NTP server ...");
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet)   
    ; // wait until the time is set by the sync provider
}

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

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

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

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

unsigned long getNtpTime()
{
  sendNTPpacket(SNTP_server_IP);
  delay(200); // for roundtriptiime in slow environtment
  if ( UdpBytewise.available() ) {
    for(int i=0; i < 40; i++){
      UdpBytewise.read(); // ignore every field except the time
    }    
    const unsigned long seventy_years = 2208988800UL+add_time_zone;        
    return getUlong() -  seventy_years;      
  }
  return 0; // return 0 if unable to get the time
}

unsigned long sendNTPpacket(byte *address)
{
  UdpBytewise.begin(123);
  UdpBytewise.beginPacket(address, 123);
  UdpBytewise.write(B11100011);   // LI, Version, Mode
  UdpBytewise.write(0);    // Stratum
  UdpBytewise.write(6);  // Polling Interval
  UdpBytewise.write(0xEC); // Peer Clock Precision
  write_n(0, 8);    // Root Delay & Root Dispersion
  UdpBytewise.write(49); 
  UdpBytewise.write(0x4E);
  UdpBytewise.write(49);
  UdpBytewise.write(52);
  write_n(0, 32); //Reference and time stamps  
  UdpBytewise.endPacket();   
}

unsigned long getUlong()
{
  unsigned long ulong = (unsigned long)UdpBytewise.read() << 24;
  ulong |= (unsigned long)UdpBytewise.read() << 16;
  ulong |= (unsigned long)UdpBytewise.read() << 8;
  ulong |= (unsigned long)UdpBytewise.read();
  return ulong;
}

void write_n(byte what, int how_many)
{
  for( int i = 0; i < how_many; i++ )
    UdpBytewise.write(what);
}

Happy playing with Arduino !
Ditmar

Hi folks,
i did a mash up because i am so lazy ....

I dont want to enter 11 characters to the terminal. I have an DS1307 and an Ethernet shield, so why not synchronising or initialising the DS1307 RTC with a NTP server delivered time ....

Hi mem,
may be you like it. You can include the code in your time library examples.

... and her is the code.

/*
 * TimeSetRTCByNTP.pde
 * Example showing time sync of RTC DS1307 with NTP time source
 * it is a mash up out of "TimeRTCSet.pde" and "TimeNTP.pde"
 *
 * This sketch uses the Ethenet library with the user contributed UdpBytewise extension
 */

#include <Time.h> 
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

#include <Ethernet.h>
// the follwing library "UdpBytewise.h" and "UdpBytewise.cpp" should be copied to the Ethernet directory
#include <UdpBytewise.h>  // UDP library from: bjoern@cs.stanford.edu 12/30/2008 
//  You will also need to modify the UdpBytewise.h library to allow enough space in the buffers for the NTP packets. 
//  Open up UdpBytewse.h and change these lines:
//
//  #define UDP_TX_PACKET_MAX_SIZE 32
//  #define UDP_RX_PACKET_MAX_SIZE 32
//
//  to this:
//
//  #define UDP_TX_PACKET_MAX_SIZE 64
//  #define UDP_RX_PACKET_MAX_SIZE 64
//

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
byte ip[] = { 
  192, 168, 178, 100};   // fill in your local Arduino ip adress

// byte SNTP_server_IP[] = { 192, 43, 244, 18}; // time.nist.gov
// byte SNTP_server_IP[] = { 130,149,17,21}; // ntps1-0.cs.tu-berlin.de
byte SNTP_server_IP[] = { 
  192,53,103,108}; // ptbtime1.ptb.de

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

// time zone correction [sec]. e.g. CET = -3600 sec
const unsigned long add_time_zone=-3600UL; 

void setup() 
{
  Ethernet.begin(mac,ip);  
  Serial.begin(9600);
  Serial.println ("waiting for NTP server ...");
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet)   
    ; // wait until the time is set by the sync provider

  RTC.set(now());   // set the RTC time to the received value
  Serial.print ("got NTP server time to RTC ...  ");
  digitalClockDisplay();
  setSyncProvider(RTC.get);   // set time source to get the time from the RTC for verification
  if(timeStatus()!= timeSet) 
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time"); 
}

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

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

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

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

unsigned long getNtpTime()
{
  sendNTPpacket(SNTP_server_IP);
  delay(200); // for roundtriptiime in slow environtment
  if ( UdpBytewise.available() ) {
    for(int i=0; i < 40; i++){
      UdpBytewise.read(); // ignore every field except the time
    }    
    const unsigned long seventy_years = 2208988800UL+add_time_zone;        
    return getUlong() -  seventy_years;      
  }
  return 0; // return 0 if unable to get the time
}

unsigned long sendNTPpacket(byte *address)
{
  UdpBytewise.begin(123);
  UdpBytewise.beginPacket(address, 123);
  UdpBytewise.write(B11100011);   // LI, Version, Mode
  UdpBytewise.write(0);    // Stratum
  UdpBytewise.write(6);  // Polling Interval
  UdpBytewise.write(0xEC); // Peer Clock Precision
  write_n(0, 8);    // Root Delay & Root Dispersion
  UdpBytewise.write(49); 
  UdpBytewise.write(0x4E);
  UdpBytewise.write(49);
  UdpBytewise.write(52);
  write_n(0, 32); //Reference and time stamps  
  UdpBytewise.endPacket();   
}

unsigned long getUlong()
{
  unsigned long ulong = (unsigned long)UdpBytewise.read() << 24;
  ulong |= (unsigned long)UdpBytewise.read() << 16;
  ulong |= (unsigned long)UdpBytewise.read() << 8;
  ulong |= (unsigned long)UdpBytewise.read();
  return ulong;
}

void write_n(byte what, int how_many)
{
  for( int i = 0; i < how_many; i++ )
    UdpBytewise.write(what);
}

happy Ardunio computing ...
Ditmar

Ditmar, thanks for your comments.

I had made the change to UdpBytewise.h buffer but forgot to add the comment to the sketch.
I have fixed this and included your other suggestions in the latest version that I will upload soon.

A useful enhancement that I have also added is to include the following after the UdpBytewise.h include:

#if  UDP_TX_PACKET_MAX_SIZE <64 ||  UDP_RX_PACKET_MAX_SIZE < 64
#error : UDP packet size to small - modify UdpBytewise.h to set buffers to 64 bytes
#endif

This checks the buffer sizes and reports an error if too small

edit: updated sketch uploaded to playground

Hi,
I need to add IR detection in one of my projects that is using TimeAlarms. The IR detection example is using

attachInterrupt(0, interrupt_func, FALLING);

Here is the IR detection example:

void loop()
 {
  // read the state of the IRDetector value:
  objectPresent = digitalRead(IRDetectorPin2);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (objectPresent == HIGH) 
  {       
    digitalWrite(LEDPin12, HIGH);
  }
  else
  {
    digitalWrite(LEDPin12, LOW);
  }
  attachInterrupt(0, interrupt_func, FALLING);
 }

Does attachInterrupt mess up the timer alarms? What should I use to replace attachInterrupt?

TIA
-ioan

attachInterrupt should be done once only in setup, not in loop.
See: http://www.arduino.cc/en/Reference/AttachInterrupt

You should be fine using alarms and attachInterrupt together in a sketch.

Hi,
Is there a limit to how many Alarm.alarmRepeat I can use?
I have 9 alarmRepeat defined and only first 6 out of the 9 triggers. When I comment out a few at the beginning, they all work.

thanks.

Is there a limit to how many Alarm.alarmRepeat I can use?

The answer is in the FAQ included in readme.txt file in the download:

Q: How many alarms can be created?
**A: Up to six alarms can be scheduled. **
The number of alarms can be changed in the TimeAlarms header file (set by the constant dtNBR_ALARMS,
note that the RAM used equals dtNBR_ALARMS * 12)

for nine alarms, use:
#define dtNBR_ALARMS 9