Keeping accurate time

kdecker:
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().

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

I changed SS to pin 10 and changed the code accordingly as:

const int  cs=10; //chip select 
.
.
.
int RTC_init(){ 
	  pinMode(cs,OUTPUT); // chip select
.
.
.

Same result. Still only returns zeros.

kdecker:
I changed SS to pin 10 and changed the code accordingly as:

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

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.

#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);
}

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. :slight_smile:

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.

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

MarkT:
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

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 Arduino Playground - 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.

  1. to generate logfiles that need to be processed later ...

KE7GKP:

  1. Keeping accurate date/time without main power supply.
  2. The Arduino is NOT a "real-time" system. There are things you can program that could keep the internal millis() or micros() from keeping accurate time.
  3. You want to run something for more than 50 days (for millis) or 70 minutes (for micros)
  4. You want to actually know what time and/or date it is in the real world.

If we maintain a count of seconds, we can easily keep track of time for more than 100 years irrespective of millis/micros overflow. Tracking real-time is also no show stopper as it is just a matter of setting initial time as will be required for a RTC as well. Real-time accuracy is a property of the oscillator and not unique to RTC. It is also possible to operate a timer (timer2 on AtMega328) independent of the main clock from a separate external crystal.

The main benefit of using a RTC chip as I see it is low power battery operation. A dime-size coin cell battery will keep a DS1307 ticking for 10 years. You can even use the RTC without a crystal as a low cost I2C NVRAM chip to preserve accumulators/state/preferences across microcontroller power cycles or add the crystal to get both time keeping and data retention.

The better RTC chips have built-in temperature compensation, making them more accurate than a normal (microprocessor) crystal oscillator.

Yes but the point is that an rtc is essentially a processor too. Insisting that a cpu cannot keep accurate time is 100% false/incorrect, it is merely a function of the quality of the oscillator, and there are processing strategies that can assist too if it is really important (i.e. read a thermistor).

And it is far simpler to read a variable from memory and format it, than to figure out how to communicate with a time processor, i.e. DS1306 (and format the results).

They work the same way, oh look, a crystal is also needed for the rtc (duh):

Responses 1-5 are a matter of implementation. I could see a couple situations why a developer might like an RTC if they are plugging and unplugging things a lot, and reprogramming the cpu, but for a clock with set buttons on it (and most clocks reset on unplugging anyway, so this is feature creep), no need.

EDIT: The frustrating thing though is the abundance of ceramic resonators. Arduino was crystal driven when I got involved, and the ceramic resonators and onboard oscillator designs really murdered the idea of onboard timekeeping for the masses, and everybody and their brother wants to build a clock. So buy an arduino with a crystal if you care about having a semblance of accuracy, or mod it like MarkT, thumbs up there! http://arduino.cc/forum/index.php/topic,54621.msg391290.html#msg391290 , but if you have a crystal, and are building a clock, the time library was meant just for you, no extra hardware required.

re: uno, they put a crystal on the bleeding com chip, but not the main chip?!? Sorry guys, but wtf? You could have even shared the com chip crystal with the main chip if you just wanted to save a few cents:

KE7GKP:
...OTOH, the main Arduino controller chip was never intended for precision timekeeping

You joined last february, you are talking out your ass, "never intended", stfu. The main chip is at the heart of may a precision timepiece.

people who make up bullcrap statements will be called on it, it isn't personal. Please try to stick to facts and not dabble in fantasy.

more bullcrap from a newbie who claims to know what the original intent of the atmega was in regards to timekeeping. I cannot help that you are full of crap, that is your problem, deal with it.

your post count and registration date must have gotten hosed then (speaking of bad timekeeping). Still it is microcontrollers and logic what make possible small and accurate clocks that can make adjustments, combined with decent oscillators. But to be in the ballpark you do not need to pimp rtc modules. Use the library, tell vendors to not cut corners on oscillators so you can have a decent timepiece in your arduino by itself.

wbphelps:

MarkT:
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

Just a standard 16MHz crystal I think - there are different suppliers and different grades but most are 50ppm or better.

You have to have proper load capacitance otherwise you may be off >100ppm. The datasheets contain the formula for proper matching of crystal load capacitance and the caps.