Pages: 1 [2] 3 4   Go Down
Author Topic: Keeping accurate time  (Read 18388 times)
0 Members and 1 Guest are viewing this topic.
Georgina Ontario
Offline Offline
Sr. Member
****
Karma: 5
Posts: 437
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Easiest way is the external clock.

Check here:
http://arduino.cc/forum/index.php/topic,51802.0.html

I reworked the time and DS1307 libraries to add some functions which should help. Using the internet or your PC as a time reference is the best solution -- not the cheapest. The only other solution is a radio chip for WWV/CHU or equivalent.
Logged

Just another Hacker

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well here's the latest. I purchased the Sparkfun DS3234 breakout board to keep accurate time. I have it wired as follows:

Pin 13 to CLK on the RTC
Pin 12 to MISO
Pin 11 to MOSI
pin 8 to SS.

Using the example code below, I tried MODE1 and MODE3 and both result in the following being displayed in the Serial output display:

45/25/165 18:85:85

or

0/0/0 0:0:0

The example code is from the Sparkfun web site for the RTC. Any ideas?

Thanks.
--------------------------

#include <SPI.h>
const int  cs=8; //chip select

void setup() {
  Serial.begin(9600);
  RTC_init();
  //day(1-31), month(1-12), year(0-99), hour(0-23), minute(0-59), second(0-59)
  SetTimeDate(11,12,13,14,15,16);
}

void loop() {
  Serial.println(ReadTimeDate());
  delay(1000);
}
//=====================================
int RTC_init(){
     pinMode(cs,OUTPUT); // chip select
     // start the SPI library:
     SPI.begin();
     SPI.setBitOrder(MSBFIRST);
     SPI.setDataMode(SPI_MODE1); // both mode 1 & 3 should work
     //set control register
     digitalWrite(cs, LOW); 
     SPI.transfer(0x8E);
     SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
     digitalWrite(cs, HIGH);
     delay(10);
}
//=====================================
int SetTimeDate(int d, int mo, int y, int h, int mi, int s){
   int TimeDate [7]={s,mi,h,0,d,mo,y};
   for(int i=0; i<=6;i++){
      if(i==3)
         i++;
      int b= TimeDate/10;
      int a= TimeDate-b*10;
      if(i==2){
         if (b==2)
            b=B00000010;
         else if (b==1)
            b=B00000001;
      }   
      TimeDate= a+(b<<4);
       
      digitalWrite(cs, LOW);
      SPI.transfer(i+0x80);
      SPI.transfer(TimeDate);       
      digitalWrite(cs, HIGH);
  }
}
//=====================================
String ReadTimeDate(){
   String temp;
   int TimeDate [7]; //second,minute,hour,null,day,month,year      
   for(int i=0; i<=6;i++){
      if(i==3)
         i++;
      digitalWrite(cs, LOW);
      SPI.transfer(i+0x00);
      unsigned int n = SPI.transfer(0x00);       
      digitalWrite(cs, HIGH);
      int a=n & B00001111;   
      if(i==2){   
         int b=(n & B00110000)>>4; //24 hour mode
         if(b==B00000010)
            b=20;       
         else if(b==B00000001)
            b=10;
         TimeDate=a+b;
      }
      else if(i==4){
         int b=(n & B00110000)>>4;
         TimeDate=a+b*10;
      }
      else if(i==5){
         int b=(n & B00010000)>>4;
         TimeDate=a+b*10;
      }
      else if(i==6){
         int b=(n & B11110000)>>4;
         TimeDate=a+b*10;
      }
      else{   
         int b=(n & B01110000)>>4;
         TimeDate=a+b*10;   
         }
   }
   temp.concat(TimeDate[4]);
   temp.concat("/") ;
   temp.concat(TimeDate[5]);
   temp.concat("/") ;
   temp.concat(TimeDate[6]);
   temp.concat("     ") ;
   temp.concat(TimeDate[2]);
   temp.concat(":") ;
   temp.concat(TimeDate[1]);
   temp.concat(":") ;
   temp.concat(TimeDate[0]);
  return(temp);
}
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8856
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You have to mark code as code (put 'code' in square brackets before it and '/code' in square brackets after it) otherwise all the square brackets get stripped.

Look like you got your date and time register addresses reversed:

00 = Seconds
01 = Minutes
02 = Hours
03 = Day of the week
04 = Day
05 = Month
06 = Year

Well here's the latest. I purchased the Sparkfun DS3234 breakout board to keep accurate time. I have it wired as follows:

Pin 13 to CLK on the RTC
Pin 12 to MISO
Pin 11 to MOSI
pin 8 to SS.

Using the example code below, I tried MODE1 and MODE3 and both result in the following being displayed in the Serial output display:

45/25/165 18:85:85

or

0/0/0 0:0:0

The example code is from the Sparkfun web site for the RTC. Any ideas?

Thanks.
--------------------------
Code:
#include <SPI.h>
const int  cs=8; //chip select

void setup() {
  Serial.begin(9600);
  RTC_init();
  //day(1-31), month(1-12), year(0-99), hour(0-23), minute(0-59), second(0-59)
  SetTimeDate(11,12,13,14,15,16);
}

void loop() {
  Serial.println(ReadTimeDate());
  delay(1000);
}
//=====================================
int RTC_init(){
  pinMode(cs,OUTPUT); // chip select
  // start the SPI library:
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1); // both mode 1 & 3 should work
  //set control register
  digitalWrite(cs, LOW); 
  SPI.transfer(0x8E);
  SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
  digitalWrite(cs, HIGH);
  delay(10);
}
//=====================================
int SetTimeDate(int d, int mo, int y, int h, int mi, int s){
int TimeDate [7]={s,mi,h,0,d,mo,y};
for(int i=0; i<=6;i++){
if(i==3)
i++;
int b= TimeDate[i]/10;
int a= TimeDate[i]-b*10;
if(i==2){
if (b==2)
b=B00000010;
else if (b==1)
b=B00000001;
}
TimeDate[i]= a+(b<<4);
 
digitalWrite(cs, LOW);
SPI.transfer(i+0x80);
SPI.transfer(TimeDate[i]);       
digitalWrite(cs, HIGH);
  }
}
//=====================================
String ReadTimeDate(){
String temp;
int TimeDate [7]; //second,minute,hour,null,day,month,year
for(int i=0; i<=6;i++){
if(i==3)
i++;
digitalWrite(cs, LOW);
SPI.transfer(i+0x00);
unsigned int n = SPI.transfer(0x00);       
digitalWrite(cs, HIGH);
int a=n & B00001111;   
if(i==2){
int b=(n & B00110000)>>4; //24 hour mode
if(b==B00000010)
b=20;       
else if(b==B00000001)
b=10;
TimeDate[i]=a+b;
}
else if(i==4){
int b=(n & B00110000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==5){
int b=(n & B00010000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==6){
int b=(n & B11110000)>>4;
TimeDate[i]=a+b*10;
}
else{
int b=(n & B01110000)>>4;
TimeDate[i]=a+b*10;
}
}
temp.concat(TimeDate[4]);
temp.concat("/") ;
temp.concat(TimeDate[5]);
temp.concat("/") ;
temp.concat(TimeDate[6]);
temp.concat("     ") ;
temp.concat(TimeDate[2]);
temp.concat(":") ;
temp.concat(TimeDate[1]);
temp.concat(":") ;
temp.concat(TimeDate[0]);
  return(temp);
}
[/code
[/quote]
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh thanks John. Didn't know I could do that with the code snippet. I'll do that next time and thanks for the response on the registers. I'll take a look at that.

Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8856
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh thanks John. Didn't know I could do that with the code snippet. I'll do that next time and thanks for the response on the registers. I'll take a look at that.

My mistake.  I didn't notice that you re-ordered the values between the function arguments and the array.

I have read in various places that when you use the SPI library you are supposed to set the hardware Slave Select line (D10) to an output.  It sounds like a strange requirement but couldn't hurt to try.  Just put it in setup().
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have read in various places that when you use the SPI library you are supposed to set the hardware Slave Select line (D10) to an output.  It sounds like a strange requirement but couldn't hurt to try.  Just put it in setup().

Actually the other way around. If pin 10 (SS) is set to be an input then the SPI hardware will setup to be as a SPI slave device. Defining it (SS pin 10) as a output is required for the master device so that it's SPI hardware will setup to be a master. This is true even if the master is using other pin(s) as slave select outputs, pin 10 must be setup as an output pin in the master device even if it's not being used by the master. The slave must only use it's pin 10 as the slave select line.

Lefty

« Last Edit: April 08, 2011, 09:42:19 am by retrolefty » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I changed SS to pin 10 and changed the code accordingly as:
Code:
const int  cs=10; //chip select
.
.
.
int RTC_init(){
 pinMode(cs,OUTPUT); // chip select
.
.
.
Same result. Still only returns zeros.
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I changed SS to pin 10 and changed the code accordingly as:
Code:
const int  cs=10; //chip select
.
.
.
int RTC_init(){
 pinMode(cs,OUTPUT); // chip select
.
.
.
Same result. Still only returns zeros.

The pinMode should probably happen before the call to RTC_init as that then initilizes the SPI which looks at pinmode for pin 10 to decide to be master or slave.

Lefty

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The pinMode() statement is the first thing that happens in the init so that should make sure it is set before the rest of the SPI initialization. Here's the whole thing as it looks right now. My apologies for not understanding all the detail around this code. It's the sample code from the Sparkfun web site for the RTC. I've left a request for info on that site as well. Thanks everyone for all your help.

Code:
#include <SPI.h>
const int  cs=10; //chip select

void setup() {
  Serial.begin(9600);
 
  RTC_init();
  //day(1-31), month(1-12), year(0-99), hour(0-23), minute(0-59), second(0-59)
  SetTimeDate(05,04,11,18,21,16);
}

void loop() {
  Serial.println(ReadTimeDate());
  delay(1000);
}
//=====================================
int RTC_init(){
          pinMode(cs,OUTPUT); // chip select
          // start the SPI library:
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3); // both mode 1 & 3 should work
  //set control register
  digitalWrite(cs, LOW); 
          SPI.transfer(0x8E);
  SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
  digitalWrite(cs, HIGH);
  delay(10);
}
//=====================================
int SetTimeDate(int d, int mo, int y, int h, int mi, int s){
int TimeDate [7]={s,mi,h,0,d,mo,y};
for(int i=0; i<=6;i++){
if(i==3)
i++;
int b= TimeDate[i]/10;
int a= TimeDate[i]-b*10;
if(i==2){
if (b==2)
b=B00000010;
else if (b==1)
b=B00000001;
}
TimeDate[i]= a+(b<<4);
 
digitalWrite(cs, LOW);
SPI.transfer(i+0x80);
SPI.transfer(TimeDate[i]);
digitalWrite(cs, HIGH);
  }
}
//=====================================
String ReadTimeDate(){
String temp;
int TimeDate [7]; //second,minute,hour,null,day,month,year
for(int i=0; i<=6;i++){
if(i==3)
i++;
      digitalWrite(cs, LOW);
                SPI.transfer(i+0x00);
unsigned int n = SPI.transfer(0x00);       
digitalWrite(cs, HIGH);
int a=n & B00001111;   
if(i==2){
int b=(n & B00110000)>>4; //24 hour mode
if(b==B00000010)
b=20;       
else if(b==B00000001)
b=10;
TimeDate[i]=a+b;
}
else if(i==4){
int b=(n & B00110000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==5){
int b=(n & B00010000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==6){
int b=(n & B11110000)>>4;
TimeDate[i]=a+b*10;
}
else{
int b=(n & B01110000)>>4;
TimeDate[i]=a+b*10;
}
}
temp.concat(TimeDate[4]);
temp.concat("/") ;
temp.concat(TimeDate[5]);
temp.concat("/") ;
temp.concat(TimeDate[6]);
temp.concat("     ") ;
temp.concat(TimeDate[2]);
temp.concat(":") ;
temp.concat(TimeDate[1]);
temp.concat(":") ;
temp.concat(TimeDate[0]);
  return(temp);
}
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8856
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Try the slowest clock speed:  SPI.setClockDivider(SPI_CLOCK_DIV128);

If that helps you can reduce the divider to see how fast you can go before it fails.  smiley
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

No joy. I put SPI.setClockDivider(SPI_CLOCK_DIV128); in the init routine but it didn't change anything. I'm starting to wonder if the RTC itself is defective.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Finally determined that the RTC was bad. Got a new one, wired it up, and it is working fine.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In fact I got motivated enough to replace the resonator on my Uno board, partly to see how tricky it was to do.

By any chance to you have a part # for the crystal?

Thanks,
William
Logged

0
Offline Offline
God Member
*****
Karma: 1
Posts: 513
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

sorry to hear the uno went ceramic.

Yah, unless you have a software glitch, the basic processor can keep perfect time with the crystal, the same way the rtc module keeps time with ITS OWN crystal.    As long as the period is consistent, you can make any necessary adjustments to convert to wall time.  If it is off by a fixed amount, that is trivial to fix in software (in fact I think the timer library already has an adjustment for it http://www.arduino.cc/playground/Code/Time )

I cannot think of any application where I would bother with an rtc instead of putting the crystal directly on the cpu and calibrating/validating it to real time.   There might be one but it has never been on my todo.

here is a 10ppm 16mhz crystal http://www.mouser.com/ProductDetail/TXC-Corporation/9C-16000MEEJ-T/?qs=sGAEpiMZZMsBj6bBr9Q9aWUu9Vmt5DeoFlToalzCQFw%3d , if you want more precision.  I've only messed with the 50ppm fox crystals.

« Last Edit: June 09, 2011, 10:59:20 pm by dcb » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13739
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

5) to generate logfiles that need to be processed later ...
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: 1 [2] 3 4   Go Up
Jump to: