how to protect against bad DS1302 data read?

I’m new to arduino, and programming, so please bear with me.

I have a DS1302 that I am playing with. Basically, everything in my circuit works.
Most of the time.
But sometimes, when i read the ds1302, I get back garbage.
Not always, just every so often.

So, when i do get back garbage…how can i protect myself?

I basically feel that I need to keep trying to read the ds1302, and only proceed if I get 2 reads that result in matching values.
Else, keep trying to read it till at least 2 reads values match up.
(or until i exceed some number of attempts, at which time I would give up and stop trying to read it.)

I know that other people have dealt with this in some form or another…
And would appreciate some feedback on what is considered good design.

The problem I have is that I don’t want to take any action on what I get from the DS1302 unless I have a good time value

A sample of my code that I’ve rigged up is as follows:

void lights()
{
  int currentJulian;
  int anotherCurrentJulian;
  int loopCounter;
  loopCounter = 0;
  
  //trying to prevent bad data from triggering a ramp up or down...
  //read the sensor twice and keep trying till they match up...
  //need to add in a loop counter to get out if somethign fails...
  do
  {
  currentJulian = rtc.getJulian();
  delay(100);
  anotherCurrentJulian = rtc.getJulian();
  loopCounter++; 
  } while ((currentJulian != anotherCurrentJulian) && loopCounter < 10);
  
  if (loopCounter == 10)
  {
    //something is wrong...get out without doing annything
    Serial.print("?y3x00?lrtc lights error");
    return;
  }
  
  //other code that uses the currentJulian value is located here...

My rtc.getJulian code is as follows:

int DS1302::getJulian()
{
	//returns an int between 0 - 1439
	int output;
	Time t;
	t = getTime();
	output = (t.hour*60) + t.min;
	return output; 
}

I bought an rtc on ebay that doesn't use the standard resistor values, to use it successfully the programming approach needs to be changed from reading all 7 or 8 bytes at a time to only reading 1. If I don't do this, I get garbage every so often as you mentioned. Try this:

  // for DS1307 RTC

  struct DateType
  {
   int yr;
   uint8_t mo;
   uint8_t dy;
   uint8_t hr;
   uint8_t mn;
   uint8_t sc;
  };

  DateType CustomDate;
  boolean RTC_State_ON;
  int RTCBaseYear = 2000; // adjust as needed

  const uint8_t RTC_YEAR                     =  6;
  const uint8_t RTC_MONTH                  =  5;
  const uint8_t RTC_DAY                       =  4;
  const uint8_t RTC_HOUR                    =  2;
  const uint8_t RTC_MINUTE                  =  1;
  const uint8_t RTC_SECOND                  =  0;

uint8_t ReadRTCByte(uint8_t adr)
{
 uint8_t data;

  Wire.beginTransmission(0x68);
  Wire.write(adr);
  Wire.endTransmission();

  Wire.requestFrom(0x68,1);
  while (Wire.available()) data=Wire.read();

  return data;
}

void WriteRTCByte(uint8_t adr, uint8_t data)
{
  Wire.beginTransmission(0x68);
  Wire.write(adr);
  Wire.write(decToBcd(data));
  Wire.endTransmission();
} 

uint8_t GetRTCData(uint8_t adr, uint8_t validbits)
{
uint8_t data;

  // read using wire library
  data = ReadRTCByte(adr);

  // adjust the return value depending
  // on the number of valid bits    
  data=data & 0xff >> (8-validbits);
  return(bcdToDec(data));
}

// convert normal decimal numbers to binary coded decimal
uint8_t decToBcd(uint8_t val)
{
  return ((val/10*16) + (val%10));
}

// convert binary coded decimal to normal decimal numbers
uint8_t bcdToDec(uint8_t val)
{
  return ((val/16*10) + (val%16));
}

uint8_t GetSecondsFromRTC()
{
int a;  

  if (RTC_State_ON == false)
    StartRTC();
    
  a = (int)GetRTCData(RTC_SECOND,7);

  return(a);
}

void GetDateAndTimeFromRTC()
{ 
  if (RTC_State_ON == false)
    StartRTC();
  
  // date
  CustomDate.yr  = (int) GetRTCData(RTC_YEAR,8) + RTCBaseYear;
  CustomDate.mo  = GetRTCData(RTC_MONTH,5);
  CustomDate.dy  = GetRTCData(RTC_DAY,6);
  
  // time    
  CustomDate.hr  = GetRTCData(RTC_HOUR,6);
  CustomDate.mn  = GetRTCData(RTC_MINUTE,7);
  CustomDate.sc  = GetRTCData(RTC_SECOND,7);    
}

void SetRTCTime(uint8_t h, uint8_t m, uint8_t s)
{
  if (RTC_State_ON == false)
    StartRTC();
  
  WriteRTCByte(RTC_SECOND,s);
  WriteRTCByte(RTC_MINUTE,m);
  WriteRTCByte(RTC_HOUR,h);
}

void SetRTCDate(uint8_t mo, uint8_t d, int y)
{
  if (RTC_State_ON == false)
    StartRTC();

  WriteRTCByte(RTC_YEAR,(uint8_t) y-RTCBaseYear);
  WriteRTCByte(RTC_MONTH,mo);
  WriteRTCByte(RTC_DAY,d);
}

void StartRTC()
{
  Wire.begin();
  RTC_State_ON = true;
}

Hope that helps.

Hi!

I have the same problem with Mega1280 and DS1302.

The time is read this way:

Thursday 02.03.2005 – 01:00:85
Friday 06.08.2010 – 12:00:01
Thursday 02.03.2005 – 01:02:85
Friday 06.08.2010 – 12:00:03
Thursday 02.03.2005 – 01:04:85
Friday 06.08.2010 – 12:00:05
Thursday 02.03.2005 – 01:06:85
Friday 06.08.2010 – 12:00:07
Thursday 02.03.2005 – 01:08:85

Friday 06.08.2010 – 12:00:07 is the correct, but Thursday 02.03.2005 – 01:08:85 is wrong.

One of two reads are incorrect!

Any suggestions?

Thanks!

If you're getting bad readings with any consistency, doesn't that imply either the device in question is bad or that the circuit requires some help to clean up noise?

doesn't that imply either the device in question is bad or that the circuit requires some help to clean up noise?

Or that there is a problem with the code that manipulates the data read.

Agreed.

I have the same problem with Mega1280 and DS1302.

It could be the resistor values.

See Nick Gammon's comments on "Pull-up resistors" at: http://www.gammon.com.au/forum/?id=10896

Or that there is a problem with the code that manipulates the data read.

Look at the pattern that is evident in your results.

Thursday 02.03.2005 -- 01:[color=red]00[/color]:85
Friday 06.08.2010 -- 12:00:01
Thursday 02.03.2005 -- 01:[color=red]02[/color]:85
Friday 06.08.2010 -- 12:00:03
Thursday 02.03.2005 -- 01:[color=red]04[/color]:85
Friday 06.08.2010 -- 12:00:05
Thursday 02.03.2005 -- 01:[color=red]06[/color]:85
Friday 06.08.2010 -- 12:00:07
Thursday 02.03.2005 -- 01:[color=red]08[/color]:85

The data that is read during the odd numbered seconds is correct.

The data that is read during the even numbered seconds is wrong, and none of the data changes except for the minutes. That changing minutes information is actually the the correct value for the seconds.

Don

It could be the resistor values.

It could also be the phase of the moon....

Don

It could also be the phase of the moon....

C'mon now, your just guessing. :)

PaulS:

It could also be the phase of the moon…

C’mon now, your just guessing. :slight_smile:

No - I’m sure it is true, I read it on the Internet.

Don

People keep mentioning resistors - the DS1302 doesn’t use any resistors, its not an I2C device!!

People keep mentioning resistors ...

Only one person, the same one who posted DS1307 code. It's easy to get confused, the two devices are somewhat similar.

Don

I've a similar issue, when the reading is odd is correct. I think I solved this twisting all the connection cables to the ds1302 module, to reduce the noise in the lines. I'm not fully convinced about this, could anybody test and check if the twisted cables solve the problem?

Readings without twisted cables (fails on even values):

Saturday 2011-25-45 27:31:23 Saturday 2011-25-45 27:31:85 Saturday 2011-25-45 27:31:25 Saturday 2011-25-45 27:31:85 Saturday 2011-25-45 27:31:27 Saturday 2011-25-45 27:31:85 Saturday 2011-25-45 27:31:29 Saturday 2011-25-45 27:31:85

Readings with twisted cables:

Wednesday 2011-08-06 14:38:46 Wednesday 2011-08-06 14:38:47 Wednesday 2011-08-06 14:38:48 Wednesday 2011-08-06 14:38:49 Wednesday 2011-08-06 14:38:50 Wednesday 2011-08-06 14:38:51 Wednesday 2011-08-06 14:38:52 Wednesday 2011-08-06 14:38:53 Wednesday 2011-08-06 14:38:54 Wednesday 2011-08-06 14:38:55

I know this is an old topic but since it solved my problem I’ll post a confirmation.

Just like jp42k said, the problem can be noise in the lines. So if you’re using separate wires that have a lot of space in between them.
Twisting them together, binding them together or using a ribbon cable should solve the problem of inaccurate reads from the DS1302.

In my case every other time that was read from the RTC was 0x00 in all bytes. I’m using the DS1302 library by Henning Karlsen.

Confirm. In my case every other time the read result from the RTC was 2000-00-00 00:00:00. Even moving the DS1302 around and touching wires helped to fix the issue.

I've had exactly this problem, and I just perform a sanity check on the values.

Are all of the numbers valid binary-coded decimal? Are the seconds less than 60? Are the minutes less than 60? Are the hours less than 24? Is the year reasonable? (since we're in 2015, anything less than 15 is not reasonable) Is the month between 1 and 12? Is the day of the month within the range of acceptable dates for that month? (1 through 30 or whatever) Is the day of the week between 1 and 7? Is it consistent with the year, month, and day of the month? (example: '15-5-14 should be a Thursday; '15-5-15 should be a Friday).