Pages: [1]   Go Down
Author Topic: Weird issue with DS2417  (Read 1264 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, currently i'm trying to figure out, how to get right time out of DS2417 RTC chip. It's based on standart DS18B20 example from OneWire library. I have Arduino 1.0.1 IDE and Arduino UNO .
Code:
#include <OneWire.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire  ds(10);  // on pin 10

byte i;
byte present = 0;
byte type_s;
byte data[6];
byte addr[8];
byte set_time_converted[4];
long byte_dec,st_seconds;
double year_leap,day_total; //because floor(x) return double
double time[4];
int ref_time[5]={1970,1,1,0,0}; //Janury 1st 1970 Ooh OOm
int set_time[5]={2013,5,11,5,44};
char* months[]={"January","February","March","April","May","June","July","August", "September", "October","November","December"}; 
char* days_of_week[]={"Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday","Wednesday"};
//Such order is due to reference point of clock - 1970 Jan 1st is thursday
int day_count,prev_day_count, month, st_daycount_year,st_daycount;

void setup(void) {
  Serial.begin(9600);
  ds.search(addr);
  ds.reset();
  ds.select(addr);
  st_daycount_year=((set_time[0]-ref_time[0])*365)+floor(((set_time[0]-ref_time[0]-2)/4)); //+2 is correction to the first leap year since 1972
  Serial.println(st_daycount_year);
  st_daycount=0;
  for (i=1;i<set_time[2];i++) {
    if (i==2) {                          //february - leap year or not
      if (fmod(set_time[0],4)==0) st_daycount+=29;
      else st_daycount+=28;
    } 
    else {
      if (i<8) {
        if (fmod(i,2)!=0) st_daycount+=31;
        else st_daycount+=30;
      }
      else {
        if (fmod(i,2)==0) st_daycount+=31;
        else st_daycount+=30;
      }
    } 
  }
  st_daycount+=st_daycount_year;
  st_daycount+=(set_time[1]-1);
  Serial.println(st_daycount);
  st_seconds=(st_daycount*86400)+(set_time[3]*3600)+(set_time[4]*60);
  Serial.println(st_seconds);
  for (i=0;i<4;i++) {
    set_time_converted[i]=fmod(st_seconds,256);
    st_seconds=floor(st_seconds/256);
  }
  //ds.write(0x99);
  //ds.write(0x0C); //write command byte - no interruption, start oscillator (clock start counting)
  //for ( i = 0; i < 4; i++) {ds.write(set_time_converted[i]);} // setting time
  ds.reset();
}

void loop(void) {
   
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250); //this delay is reason of disappearing seconds!
    return;
  }
 
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x27:
      Serial.println("  Clock DS2417");  // or old DS1820
      type_s = 1;
      break;
    default:
      Serial.println("Device is not a DS2417 clock.");
      return;
  }
  delay(600);
  ds.reset();
  ds.select(addr);
  ds.write(0x66);         //  Read Clock command
  Serial.print("Data = ");
  for ( i = 0; i < 5; i++) {  // we need 4 bytes + 1 control byte (first) (for clock)
   data[4-i] = ds.read();      // so here we go. 5-i here is due to DS2417 blurting out bytes in backward order
  }
  byte_dec=0;
  for ( i = 0; i < 4; i++) {
    Serial.print(data[i], HEX);
   // byte_dec+=(pow(256,(3-i)))*data[i];
    byte_dec=(byte_dec*256)+data[i];
    Serial.print(" ");
  }
  Serial.print(data[4], HEX); //command byte
  Serial.print(" ");
  Serial.println();
  //Serial.println(byte_dec);

  // convert the data to actual time
 
  day_total=floor(byte_dec/86400);
  year_leap=floor(byte_dec/126230400); //amount of seconds in 3 years + leap year
  byte_dec-=(year_leap*126230400);
  time[0]=floor(byte_dec/31536000);
  byte_dec-=(time[0]*31536000);
  time[0]+=(year_leap*4);              //setting year
  time[1]=floor(byte_dec/86400);       //setting days
  byte_dec-=(time[1]*86400);           
  time[2]=floor(byte_dec/3600);        //setting hours
  byte_dec-=(time[2]*3600);
  time[3]=floor(byte_dec/60);          //setting minutes
  byte_dec-=(time[3]*60);
  time[4]=byte_dec;   //setting seconds
  for(i=0;i<5;i++){
    if (time[i]<10) Serial.print("0"); //formatting output
    Serial.print(int(time[i]));        //int here removes decimal part for printing
    if (i<4) Serial.print(":");
  }
  Serial.println();
  //determine month
  day_count=0;
  for (i=1;i<13;i++) {
    prev_day_count=day_count;
    if (i==2) {                          //february - leap year or not
      if (fmod(time[0]+ref_time[0],4)==0) day_count+=29; //calculating current year and checking if leap
      else day_count+=28;
    } 
    else {
      if (i<8) {
        if (fmod(i,2)!=0) day_count+=31;
        else day_count+=30;
      }
      else {
        if (fmod(i,2)==0) day_count+=31;
        else day_count+=30;
      }
    } 
   if (time[1]<=day_count) {
     month=i;
     Serial.print(months[i-1]);
     Serial.print(" ,");
     Serial.println(int(time[1]-prev_day_count+1));//because there is no "January, 0"
     break;
   }
  }
 Serial.println(days_of_week[int((fmod(day_total,7))+1)]);
}
Issue is - everything is working fine  while byte_dec is less then 00FFFFFF. And then printing of time[] array is all messed up - output of data[] and byte_dec shows that counter is working, but time[] is stuttering like this
Code:
ROM = 27 E6 6 29 0 0 0 B8
  Clock DS2417
Data = 1 0 9 2F C
00:194:04:59:28
July ,14
Tuesday
No more addresses.

ROM = 27 E6 6 29 0 0 0 B8
  Clock DS2417
Data = 1 0 9 30 C
00:194:04:59:28
July ,14
Tuesday
No more addresses.

ROM = 27 E6 6 29 0 0 0 B8
  Clock DS2417
Data = 1 0 9 31 C
00:194:04:59:28
July ,14
Tuesday
No more addresses.

ROM = 27 E6 6 29 0 0 0 B8
  Clock DS2417
Data = 1 0 9 32 C
00:194:04:59:30
July ,14
Tuesday
No more addresses.

ROM = 27 E6 6 29 0 0 0 B8
  Clock DS2417
Data = 1 0 9 32 C
00:194:04:59:30
July ,14
Tuesday
No more addresses.

ROM = 27 E6 6 29 0 0 0 B8
  Clock DS2417
Data = 1 0 9 33 C
00:194:04:59:32
July ,14
Tuesday
No more addresses.
As you can see, data is read correct, it converted correctly in amount of seconds (byte_dec), but issue with time[] is beyond my grasp. Everything is beginning as soon as byte_dec going over 0xFFFFFF - so i tried to set byte_dec to double, but it didn't help. Can anyone help me with that?
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 653
Posts: 50924
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

floor() may return a double, but that doesn't mean that you have to store the result in a double. Frankly, I see no reason to be using floor at all. The places where it is use are being passed an integer result, so floor() isn't doing anything.
Logged

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

floor() may return a double, but that doesn't mean that you have to store the result in a double.
I tried that, but storing results in integer variables didn't really worked out - floor() was returning some weird results unless i used a double.
Frankly, I see no reason to be using floor at all. The places where it is use are being passed an integer result, so floor() isn't doing anything.
Not really. For example
Code:
year_leap=floor(byte_dec/126230400); //amount of seconds in 3 years + leap year
byte_dec-=(year_leap*126230400);
byte_dec/126230400 here might not return integer, but i need to round results to the closer integer which is less or equal.
But anyway, first of all i messed up usage of fmod(), which caused some calculations errors. And second - calculating the date completely every cycle is waste of processing power, i should just calculate time and date once and then increment it every time second byte of output (less significant byte out of four-byte counter) changes.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 653
Posts: 50924
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
byte_dec/126230400 here might not return integer
How can it not?

Code:
long byte_dec,st_seconds;
An integer (long or int, signed or unsigned) divided by an int is an int.

So, the floor() function, given an integer, isn't doing anything to round the value down to an integer.
Logged

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

Oh well, i just tried to store real numbers in integer without giving it a second thought. That was really retarded, even for me. Thank you for pointing that out, i think i'll try to rewrite this code from scratch rather than just fix it.
Logged

Pages: [1]   Go Up
Jump to: