Go Down

Topic: Stalker V2 Help!! Set the time? RFID Logger (Read 3259 times) previous topic - next topic

Godslust

Hi Guys,

Got a little issue, & feel a little silly!

I have been lurking here for a while, I am also new to arduino, so sorry for the silly questions etc..(case of little knowlage == Dangerous)

I am working on a little battery/solar powerd rfid logging project for orienteering etc. This consists of an Seeeduino Stalker V2, RFID Reader, Battery and Solar Panel in a Waterproof encloser.

I have wrote (well cobbled together using bits and bobs of code from around the net) a sketch that would read an rfid tag, validate the cheksum if valid then write the tags serial number and the time it is swiped to the sd card. I plan in the future adding the temp also as the temp sensor is built in to the stalker.

I uploaded the sketch to my Stalker V2, then I had the shock of my life! It worked!!!

After about half an hour of jumping up and down and also a beer to celebrate, I realised that I needed to set the time!!! Talk about pride before a fall!!

How do you set the RX8025 RTC on the Stalker V2?

I have the code in my sketch I enter the value in this code for the time I want to set, I upload that to the stalker, then comment out the two lines that were used to set the time and then re-upload my code as I do not want it reseting the time everytime the stalker powers up, as is my understanding.  

I just can't set the dam time, Can any one help?

I have the code in my sketch to set the time but can't get the little fella to work.

Code Below => Due to post limit
This cannot be as hard as I am making it?

Godslust

Code: [Select]
/*
SD card datalogger (RFID swipe-time logger)

Log data from UART RFID reader to an SD card using the SD library.

*/

#include <RX8025.h>
#include <Wire.h> 
#include <SD.h>
#include <NewSoftSerial.h>

//Define the value of rfid start bit
#define stx 2

//Define the value of rfid end bit
#define etx 3

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 10;

//Dont forget to change the values in 'NewSoftSerial' below if you move the rfid rx and tx pins somewhere else
NewSoftSerial mySerial(2, 3);
int counter;
byte data[14];
byte hexBlock1,hexBlock2,hexBlock3,hexBlock4,hexBlock5;
byte hexCalculatedChecksum,hexChecksum;

void setup() {
  pinMode(8,OUTPUT);//LED pin set to OUTPUT
  Serial.begin(9600);
  mySerial.begin(9600);

  //To set the clock - uncomment two lines below
  unsigned char RX8025_time[7]={0x00,0x35,0x00,0x00,0x11,0x05,0x11};//second, minute, hour, week, date, month, year, BCD format
  RX8025.setRtcTime(RX8025_time);

  //RTC
  RX8025.init();

  //Announce the script
  Serial.println("RFID Logger V1.02");

  //initializ sd card
  Serial.println("Initializing SD Card...");

  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("SD Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("SD Card initialized.");
}

void loop() {
  digitalWrite(8,LOW);//LED pin set to OUTPUT
  //read the rfid tag if present
  if (mySerial.available() > 0) {
    data[counter] = mySerial.read();
    counter++;
    if(counter > 13) {
      //we read the whole message, so reset counter
      counter = 0;
      //check if start of text and end of text is correct
      if(data[0] == stx && data[13] == etx) {
        digitalWrite(8,HIGH);//LED pin set to OUTPUT
        Serial.println("Start of text and end of Tag St correctly received.");
        Serial.print("ID: ");
        //show ID
        for(int x = 1; x < 11; x++) {
          Serial.print(data[x], BYTE);
        }

        Serial.println("");
        Serial.print("Checksum: ");
        //show checksum
        Serial.print(data[11], BYTE);
        Serial.println(data[12], BYTE);

        //Hex ID blocks. Two transmitted Bytes form one Hex ID block.
        //Hex ID blocks:      6   2  |  E   3  |  0   8  |  6   C  |  E   D
        //Transmitted Bytes: 36H 32H | 45H 33H | 30H 38H | 36H 43H | 45H 44H

        hexBlock1 = AsciiCharToNum(data[1])*16 + AsciiCharToNum(data[2]);
        hexBlock2 = AsciiCharToNum(data[3])*16 + AsciiCharToNum(data[4]);
        hexBlock3 = AsciiCharToNum(data[5])*16 + AsciiCharToNum(data[6]);
        hexBlock4 = AsciiCharToNum(data[7])*16 + AsciiCharToNum(data[8]);
        hexBlock5 = AsciiCharToNum(data[9])*16 + AsciiCharToNum(data[10]);

        //Transmitted checksum.
        hexChecksum = AsciiCharToNum(data[11])*16 + AsciiCharToNum(data[12]);

        //XOR algorithm to calculate checksum of ID blocks.
        hexCalculatedChecksum = hexBlock1 ^ hexBlock2 ^ hexBlock3 ^ hexBlock4 ^ hexBlock5;
        if ( hexCalculatedChecksum == hexChecksum )
        {
          Serial.println("Calculated checksum matched transmitted checksum.");



          //going to write it all to sd now
          Serial.println("Will try to write ID and checksum to datalog.txt on SD now.");

          // open datalog.txt. note that only one file can be open at a time,
          // so you have to close this one before opening another.
          File dataFile = SD.open("datalog.txt", FILE_WRITE);

          // if the file is available, write to it:
          if (dataFile) {
            //Write the RFID Card ID
            //***************I am sure I need to convert to ascii befor printing? is the byte already ascii?
            //***************but will see if this works for now think will print hex?, same with the output to the serial monitor
            dataFile.print("Card ID: ");
            dataFile.print(data[1], BYTE);
            dataFile.print(data[2], BYTE);
            dataFile.print(data[3], BYTE);
            dataFile.print(data[4], BYTE);
            dataFile.print(data[5], BYTE);
            dataFile.print(data[6], BYTE);
            dataFile.print(data[7], BYTE);
            dataFile.print(data[8], BYTE);
            dataFile.print(data[9], BYTE);
            dataFile.print(data[10], BYTE);
            dataFile.print(", ");

            //write RFID cards checksum
            dataFile.print("Checksum: ");
            dataFile.print(data[11], BYTE);
            dataFile.print(data[12], BYTE);
            dataFile.print(", ");

            //Log the time from the rtc
            int rtc_sec, rtc_min, rtc_hou, rtc_wee, rtc_dat, rtc_mon, rtc_yea;
            delay(300); // There will be new values every 100ms

            RX8025.getRtcTime(&rtc_sec, &rtc_min, &rtc_hou, &rtc_wee, &rtc_dat, &rtc_mon, &rtc_yea);

            dataFile.print(rtc_dat,DEC);
            dataFile.print("/");
            dataFile.print(rtc_mon,DEC);
            dataFile.print("/");
            dataFile.print(rtc_yea,DEC);
            dataFile.print(" ");
            dataFile.print(rtc_wee,DEC);
            dataFile.print(" ");
            dataFile.print(rtc_hou,DEC);
            dataFile.print(":");
            dataFile.print(rtc_min,DEC);
            dataFile.print(":");
            dataFile.println(rtc_sec,DEC);


            //close the sd file?
            dataFile.close();

            // print to the serial port for monitoring
            monitorout();

           
            //turn led off
            digitalWrite(8,HIGH);//LED pin set to OUTPUT

            mySerial.flush();

            delay(1000);
          } 

          // if the file isn't open, pop up an error:
          else {
            Serial.println("Error opening data file - datalog.txt");

            return;
          }
        }

        else {
          Serial.println("Calculated checksum didn't match transmitted checksum. Corrupt data!");
          Serial.println("Please scan again");
          // don't do anything more:
          return;
        }



      }
    }
  }
}

uint8_t AsciiCharToNum(byte data) {

  //First substract 48 to convert the char representation
  //of a number to an actual number.
  data -= '0';

  //If it is greater than 9, we have a Hex character A-F.
  //Substract 7 to get the numeral representation.
  if (data > 9)
    data -= 7;
  return data;
}
void rfiddata() {

}

void monitorout(){
  Serial.print("Card Sc ");
  Serial.print("Card ID: ");
  Serial.print(data[1], BYTE);
  Serial.print(data[2], BYTE);
  Serial.print(data[3], BYTE);
  Serial.print(data[4], BYTE);
  Serial.print(data[5], BYTE);
  Serial.print(data[6], BYTE);
  Serial.print(data[7], BYTE);
  Serial.print(data[8], BYTE);
  Serial.print(data[9], BYTE);
  Serial.print(data[10], BYTE);
  Serial.print(", ");

  //print cards checksum
  Serial.print("Checksum: ");
  Serial.print(data[11], BYTE);
  Serial.print(data[12], BYTE);   
  Serial.print(", ");
  // print time 

  int rtc_sec, rtc_min, rtc_hou, rtc_wee, rtc_dat, rtc_mon, rtc_yea;
  delay(1000); // There will be new values every 100ms

  RX8025.getRtcTime(&rtc_sec, &rtc_min, &rtc_hou, &rtc_wee, &rtc_dat, &rtc_mon, &rtc_yea);

  Serial.print("Time:");
  Serial.print(rtc_dat,DEC);
  Serial.print("/");
  Serial.print(rtc_mon,DEC);
  Serial.print("/");
  Serial.print(rtc_yea,DEC);
  Serial.print(" ");
  Serial.print(rtc_wee,DEC);
  Serial.print(" ");
  Serial.print(rtc_hou,DEC);
  Serial.print(":");
  Serial.print(rtc_min,DEC);
  Serial.print(":");
  Serial.println(rtc_sec,DEC);
  Serial.println("Done!");
  Serial.println(" ");
 
}
This cannot be as hard as I am making it?

wildbill

Guessing, but shouldn't the RX8025.init() come before you try to set the time?

Godslust

Doh!

That's exactly it silly me thank you.  :)
This cannot be as hard as I am making it?

ardudillo

I have a problem with figuring out the RTC of a newly acquired stalker v2.0.

I have played around with code such as found on this site or in this thread (nasukaren's post of 06.08.2010 at 12:55:33) or as in the TimeRTCSet example in the Time library.

The problem is, I can set the RTC to a specified time but this time resets when I reset the board. In the case of the Time library example, I can send an ASCII time string over Serial (character 'T' followed by ten digits) to set time to whatever I want but it still resets when I reset the board (to midnight December 31st 1999).

All of these examples use Time.h and DS1307RTC.h (and of course, Wire.h). Could it be that DS1307RTC.h cannot set the Stalker's RTC and I have to use RX8025.h instead? If I understand things correctly, RX8025.h does not use time_t which can be used by Time.h. If I got this right, I find it awkward (the Time library offers functionality I 'd rather not have to do without).

Am I making some stupid mistake?

PaulS

Quote
Am I making some stupid mistake?

I don't know that I would consider it "stupid", but, you didn't post any code.

ardudillo

I don't want to clutter the thread with duplicate code since the two links in my original post both lead to code and the TimeRTCSet example is part of the Time library. Here it is:

Quote

/*
 * TimeRTCSet.pde
 * example code illustrating Time library with Real Time Clock.
 *
 * RTC clock is set in response to serial port time message 
 * A Processing example sketch to set the time is inclided in the download
 */

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


void setup()  {
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet)
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");     
}

void loop()
{
  if(Serial.available())
  {
     time_t t = processSyncMessage();
     if(t >0)
     {
        RTC.set(t);   // set the RTC and the system time to the received value
        setTime(t);          
     }
  }
   digitalClockDisplay();  
   delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  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);
}

/*  code to process time sync messages from the serial port   */
#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

time_t processSyncMessage() {
  // return the time if a valid sync message is received on the serial port.
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ;
    Serial.print(c); 
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();         
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number   
        }
      }   
      return pctime;
    }  
  }
  return 0;
}



I can send an ASCII string to set the time to whatever I want over the serial terminal but resetting the board resets the RTC.

Example output:

RTC has set the system time
0:00:00 31 12 1999
0:00:01 31 12 1999
0:00:02 31 12 1999
0:00:03 31 12 1999
0:00:04 31 12 1999
T23:31:31 13 2 2009  <--- Sent string T1234567890
23:31:32 13 2 2009
23:31:33 13 2 2009
23:31:34 13 2 2009
23:31:35 13 2 2009
RTC has set the system time  <--- Reset button pressed
0:00:00 31 12 1999
0:00:01 31 12 1999
0:00:02 31 12 1999

PaulS

It looks to me like your RTC's battery is dead. Is it replaceable?

ardudillo

The Stalker v2.0 doesn't have a battery but a super capacitor for RTC backup (see here and here).

I presume that the capacitor should charge immediately as soon as the board is powered up and keep the RTC ticking between resets.

ardudillo

#9
Jul 28, 2011, 12:09 am Last Edit: Jul 28, 2011, 12:16 am by ardudillo Reason: 1
The plot thickens. The RTC behaves itself when using the RX8025 library. Here is a very stripped down version of the example source code linked in the Stalker wiki page.

Quote

#include "RX8025.h"
#include <Wire.h>

unsigned char hour=0;
unsigned char minute=0;
unsigned char second=0;
unsigned char week=0;
unsigned char year=0;
unsigned char month=0;
unsigned char date=0;

unsigned char RX8025_time[7]=
{
 0x00,0x54,0x09,0x03,0x10,0x11,0x10 //second, minute, hour, week, date, month, year, BCD format
};


//======================================
void setup(void)
{
 Serial.begin(9600);
 RX8025_init();
}
//======================================
void loop(void)
{
 getRtcTime();
 print_RX8025_time();
 Serial.println("--------------next--data---------------");
 delay(2000);
}


//==============================================
void print_RX8025_time(void)
{
 Serial.print(year,DEC);
 Serial.print("/");
 Serial.print(month,DEC);
 Serial.print("/");
 Serial.print(date,DEC);
 switch(week)
 {
 case 0x00:
   {
     Serial.print("/Sunday  ");  
     break;
   }
 case 0x01:
   {
     Serial.print("/Monday  ");
     break;
   }
 case 0x02:
   {
     Serial.print("/Tuesday  ");
     break;
   }
 case 0x03:
   {
     Serial.print("/Wednesday  ");
     break;
   }
 case 0x04:
   {
     Serial.print("/Thursday  ");
     break;
   }
 case 0x05:
   {
     Serial.print("/Friday  ");
     break;
   }
 case 0x06:
   {
     Serial.print("/Saturday  ");
     break;
   }
 }
 Serial.print(hour,DEC);
 Serial.print(":");
 Serial.print(minute,DEC);
 Serial.print(":");
 Serial.println(second,DEC);
}



Pressing the reset button with this code loaded does not reset the RTC, unlike in the case of the DS1307RTC and Time libs, used in the "TimeRTCSet" example. Reading through the code of the RX8025 and DS1307RTC libs, I cannot for the life of me figure out what the offending difference might be. Even worse, I 'd have thought DS1307RTC shouldn't work at all since it seems to think the address of the RTC is 0x68 (#define DS1307_CTRL_ID 0x68 in DS1307RTC.cpp below) whereas the RX8025 suggests the RTC lives at number 0x32 (#define  RX8025_address  0x32 RX8025.cpp below).

DS1307RTC has what looks like a constructor whose only statement is to fire up the Wire comms:
Code: [Select]

DS1307RTC::DS1307RTC()
{
 Wire.begin();
}


whereas RX8025 has function RX8025_init() which both fires up Wire comms as well as sending 0xe0 to the RTC, followed by 0x20 and 0x00. I don't know what these characters are actually doing but, for some reason, DS1307RTC seems to be communicating OK with something, even if it's at another address than whatever RX8025 is talking to and without having sent these characters.

When it comes to reading time, both seem to be doing similar things. They send 0x00 and ask for some chars. However, notice a difference, in function void DS1307RTC::read( tmElements_t &tm), DS1307RTC seemingly asks for 7 values (assuming tmNbrFields == 7 as the comment suggests) whereas in function void getRtcTime(void) RX8025 asks for 8 values and discards the first one! WTF? Full code of RX8025.cpp and DS1307RTC follow.

RX8025.cpp:

Quote

#include <Wire.h>
#include "RX8025.h"
//********************************************************************

//===============================================
#define  RX8025_address  0x32

unsigned char RX8025_Control[2]=
{
 0x20,0x00
};

//===============================================
void setRtcTime(void)
{
 Wire.beginTransmission(RX8025_address);
 Wire.send(0x00);
 for(unsigned char i=0; i<7; i++)
 {
   Wire.send(RX8025_time);
 }
 Wire.endTransmission();
}

//===============================================
uint8_t bcd2bin (uint8_t val)
{
 return val - 6 * (val >> 4);
}

uint8_t bin2bcd (uint8_t val)
{
 return val + 6 * (val / 10);
}

//===============================================
void getRtcTime(void)
{
 unsigned char i=0;
 Wire.beginTransmission(RX8025_address);
 Wire.send(0x00);
 Wire.endTransmission();//
 Wire.requestFrom(RX8025_address,8);
 RX8025_time= Wire.receive();//not use
 while(Wire.available())
 {
   RX8025_time= Wire.receive();
   i++;
 }
 Wire.endTransmission();//

 year   = bcd2bin(RX8025_time[6]&0xff);
 month  = bcd2bin(RX8025_time[5]&0x1f);
 date   = bcd2bin(RX8025_time[4]&0x3f);
 week   = bcd2bin(RX8025_time[3]&0x07);
 hour   = bcd2bin(RX8025_time[2]&0x3f);
 minute = bcd2bin(RX8025_time[1]&0x7f);
 second = bcd2bin(RX8025_time[0]&0x7f);
}

//===============================================
void RX8025_init(void)
{
 Wire.begin();
 Wire.beginTransmission(RX8025_address);//clear power on reset flag, set to 24hr format
 Wire.send(0xe0);
 for(unsigned char i=0; i<2; i++)
 {
   Wire.send(RX8025_Control);
 }
 Wire.endTransmission();
 //setRtcTime();
}


ardudillo

#10
Jul 28, 2011, 12:10 am Last Edit: Jul 28, 2011, 12:15 am by ardudillo Reason: 1
DS1307RTC.cpp:

Quote

/*
 * DS1307RTC.h - library for DS1307 RTC
  
  Copyright (c) Michael Margolis 2009
  This library is intended to be uses with Arduino Time.h library functions

  The library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  
  30 Dec 2009 - Initial release
 */

#include <Wire.h>
#include "DS1307RTC.h"

#define DS1307_CTRL_ID 0x68 

DS1307RTC::DS1307RTC()
{
  Wire.begin();
}
  
// PUBLIC FUNCTIONS
time_t DS1307RTC::get()   // Aquire data from buffer and convert to time_t
{
  tmElements_t tm;
  read(tm);
  return(makeTime(tm));
}

void  DS1307RTC::set(time_t t)
{
  tmElements_t tm;
  breakTime(t, tm);
  tm.Second |= 0x80;  // stop the clock
  write(tm);
  tm.Second &= 0x7f;  // start the clock
  write(tm);
}

// Aquire data from the RTC chip in BCD format
void DS1307RTC::read( tmElements_t &tm)
{
  Wire.beginTransmission(DS1307_CTRL_ID);
  Wire.send(0x00);
  Wire.endTransmission();

  // request the 7 data fields   (secs, min, hr, dow, date, mth, yr)
  Wire.requestFrom(DS1307_CTRL_ID, tmNbrFields);
  
  tm.Second = bcd2dec(Wire.receive() & 0x7f);   
  tm.Minute = bcd2dec(Wire.receive() );
  tm.Hour =   bcd2dec(Wire.receive() & 0x3f);  // mask assumes 24hr clock
  tm.Wday = bcd2dec(Wire.receive() );
  tm.Day = bcd2dec(Wire.receive() );
  tm.Month = bcd2dec(Wire.receive() );
  tm.Year = y2kYearToTm((bcd2dec(Wire.receive())));
}

void DS1307RTC::write(tmElements_t &tm)
{
  Wire.beginTransmission(DS1307_CTRL_ID);
  Wire.send(0x00); // reset register pointer
  
  Wire.send(dec2bcd(tm.Second)) ;   
  Wire.send(dec2bcd(tm.Minute));
  Wire.send(dec2bcd(tm.Hour));      // sets 24 hour format
  Wire.send(dec2bcd(tm.Wday));   
  Wire.send(dec2bcd(tm.Day));
  Wire.send(dec2bcd(tm.Month));
  Wire.send(dec2bcd(tmYearToY2k(tm.Year)));   

  Wire.endTransmission(); 
}
// PRIVATE FUNCTIONS

// Convert Decimal to Binary Coded Decimal (BCD)
uint8_t DS1307RTC::dec2bcd(uint8_t num)
{
  return ((num/10 * 16) + (num % 10));
}

// Convert Binary Coded Decimal (BCD) to Decimal
uint8_t DS1307RTC::bcd2dec(uint8_t num)
{
  return ((num/16 * 10) + (num % 16));
}

DS1307RTC RTC = DS1307RTC(); // create an instance for the user



pathub

Greetings,
I just have the same problems, but i have some "stupid" work-around :D

This is what I do,

set the time in the array RX8025_time[7]
i set it beyond 2 minute from the PC realtime clock.

and place this in void setup()
  RX8025.setRtcTime(RX8025_time);

After the sketch upload done, check the date/time
And test is again with reset.
YES the clock is ticking, but setting back to RX8025_time[7] array again.

When the date/time is correct, then comment the line   
//RX8025.setRtcTime(RX8025_time);
in the void setup()

and upload the sketch again

When it done, check again with reset. The clock will keep ticking and give the correct date/time after reset :)

I hope it helped.
Sorry for the Inglish :D

mem

The Stalker 2 RTC is not compatible with the DS1307 so the RTC1307 code in the Time download wont work.

Here is an updated version that autodetects the RTC type.
Save the files as RTC.cpp and RTC.h. Its used in the sketch like the old library but the name is now RTC

Code: [Select]
/*
* RTC.cpp - library for DS1307 and RX8025 RTC chips
 
  Copyright (c) Michael Margolis 2009, 2010
  This library is intended to be used with Arduino Time.h library functions

  The library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
   30 Dec 2009 - Initial release for DS1307
   20 Nov 2010 - renamed to RTC and Added support for DX8025
*/

#include <WProgram.h>
#include <Wire.h>
#include "RTC.h"

//#include <HardwareSerial.h>  //only needed for diagnostics

const uint8_t DS1307_ADDRESS = 0x68; 
const uint8_t RX8025_ADDRESS = 0x32;

const uint8_t RX8025_CTL1   = 0xE0;
const uint8_t RX8025_CTL2   = 0xf0;

const uint8_t RX8025_24HR_MODE    = 0x20;      // set bit 5 for 24 hr mode

const uint8_t RX8025_NO_INTR      = 0x0;       // interupts off, INTA hi-Z
const uint8_t RX8025_INTR_PER_SEC = 0x4;       // INTA occurs once per second
const uint8_t RX8025_INTR_PER_MIN = 0x5;       // INTA occurs once per minute
const uint8_t RX8025_INTR_PER_HR  = 0x6;       // INTA occurs once per hour
const uint8_t RX8025_INTR_PER_MON = 0x7;       // INTA occurs once per month

// PUBLIC FUNCTIONS   

time_t RTCget()  // static function that can be used as a callback
{
  RTC.get();
}

rtcClass::rtcClass()
{

}

// returns true if selection is valid or autodetect succeeds in finding a device
bool rtcClass::begin(RTCDevice_t selection)
{
   device =  rtcUnknown; // default to indicate that no device is selected
   Wire.begin();
   if( selection == rtcUnknown)
   {
      // discover RTC device
      if(isAddressValid( RX8025_ADDRESS))
        selection = rtcRX8025;   
      else if(isAddressValid( DS1307_ADDRESS))
        selection = rtcDS1307;             
   }
   
   if(selection == rtcDS1307)
   {
       address = DS1307_ADDRESS;
       device = rtcDS1307;
   }
   else if(selection == rtcRX8025)
   {
     address = RX8025_ADDRESS;       
     device = rtcRX8025;
     writeRegister(RX8025_CTL1,RX8025_24HR_MODE); // RX8025 defaults to 12 hr mode so change to 24hrs   
     writeRegister(RX8025_CTL2,0);                // reset power on reset flag in control register 2     
   }
   //Serial.print("device = "); Serial.println(device, DEC);
   //Serial.print("address = 0x"); Serial.println(address, HEX);
   return (device != rtcUnknown); // returns true if a valid device selected
   
}   

time_t rtcClass::get()   // Aquire data from RTC and convert to time_t
{
  tmElements_t tm;
  read(tm);
  return(makeTime(tm));
}

void  rtcClass::set(time_t t)  // set RTC to given time
{
  tmElements_t tm;
  breakTime(t, tm);
  tm.Second |= 0x80;  // stop the clock
  write(tm);
  tm.Second &= 0x7f;  // start the clock
  write(tm);
}

// Aquire data from the RTC chip in BCD format
void rtcClass::read( tmElements_t &tm)
{
  Wire.beginTransmission(address);
  Wire.send(0x00);
  Wire.endTransmission();

  // request the data fields   (secs, min, hr, dow, date, mth, yr)
  if( device == rtcRX8025)
  {
     Wire.requestFrom((int)address, 8);
     Wire.receive();  // RX8025 gets an extra byte that is ignored
  }
  else     
    Wire.requestFrom((int)address, tmNbrFields);
 
  tm.Second = bcd2dec(Wire.receive() & 0x7f);   
  tm.Minute = bcd2dec(Wire.receive() & 0x7f);  // mask added for RX8025
  tm.Hour   = bcd2dec(Wire.receive() & 0x3f);  // mask assumes 24hr clock
  tm.Wday   = bcd2dec(Wire.receive() & 0x07);  // mask added for RX8025
  tm.Day    = bcd2dec(Wire.receive() & 0x3f);  // mask added for RX8025
  tm.Month  = bcd2dec(Wire.receive() & 0x1f);  // mask added for RX8025
  tm.Year = y2kYearToTm((bcd2dec(Wire.receive())));
}

void rtcClass::write(tmElements_t &tm)
{
  Wire.beginTransmission((int)address);
  Wire.send(0x00); // reset register pointer
 
  Wire.send(dec2bcd(tm.Second)) ;   
  Wire.send(dec2bcd(tm.Minute));
  Wire.send(dec2bcd(tm.Hour));      // sets 24 hour format
  Wire.send(dec2bcd(tm.Wday));   
  Wire.send(dec2bcd(tm.Day));
  Wire.send(dec2bcd(tm.Month));
  Wire.send(dec2bcd(tmYearToY2k(tm.Year)));   

  Wire.endTransmission(); 
}

// this method sets the RX8025 periodic interrupt to the given period
// the INTA pin is set low at the selected interval if the interrupt is enabled
void rtcClass::setPeriodicInterrupt( RTCIntrInterval_t interval)
{
  if( device != rtcRX8025)
     return; // only allow this method if using RX8025
  switch(interval) {
     case rtcIntrDisable    : writeRegister(RX8025_CTL1, RX8025_24HR_MODE | RX8025_NO_INTR); break;
     case rtcIntrEachSecond : writeRegister(RX8025_CTL1, RX8025_24HR_MODE | RX8025_INTR_PER_SEC ); break;
     case rtcIntrEachMinute : writeRegister(RX8025_CTL1, RX8025_24HR_MODE | RX8025_INTR_PER_MIN ); break;
     case rtcIntrEachHour   : writeRegister(RX8025_CTL1, RX8025_24HR_MODE | RX8025_INTR_PER_HR ); break;
     case rtcIntrEachMonth  : writeRegister(RX8025_CTL1, RX8025_24HR_MODE | RX8025_INTR_PER_MON ); break;
   }
}

// this method sets the INTA pin high impedence ready for next interrupt
// call this after every interrupt
void rtcClass::resetPeriodicInterrupt( )
{
  if( device == rtcRX8025)
     writeRegister(RX8025_CTL2, 0); // clear the control2 register
}

// PRIVATE FUNCTIONS

/// returns true if there is an i2c device at the given address
bool rtcClass::isAddressValid(uint8_t address)
{
   Wire.beginTransmission(address);
   Wire.send(0x00);
   Wire.endTransmission();
   Wire.requestFrom((int)address,1);
   delay(10);
   if (Wire.available() > 0 )
   {
      Wire.receive();
      //Serial.print("check for addr "); Serial.print(address,HEX), Serial.println(" returned true");
      return true;
   }
   //Serial.print("check for addr "); Serial.print(address,HEX), Serial.println(" returned false");   
   return false;       
}       

// sets the given register to the given value
void rtcClass::writeRegister( uint8_t reg, uint8_t value)
{
  Wire.beginTransmission((int)address);
  Wire.send(reg);
  Wire.send(value);
  Wire.endTransmission(); 
}

// Convert Decimal to Binary Coded Decimal (BCD)
uint8_t rtcClass::dec2bcd(uint8_t num)
{
  return ((num/10 * 16) + (num % 10));
}

// Convert Binary Coded Decimal (BCD) to Decimal
uint8_t rtcClass::bcd2dec(uint8_t num)
{
  return ((num/16 * 10) + (num % 16));
}

rtcClass RTC = rtcClass(); // create an instance for the user


Code: [Select]
/*
* RTC.h - library for DS1307 RTC
* This library is intended to be uses with Arduino Time.h library functions
*/

#ifndef rtcClass_h
#define rtcClass_h
#include <Time.h>    // download from http://www.arduino.cc/playground/Code/Time

// the list of supported RTC devices
enum RTCDevice_t {rtcUnknown, rtcDS1307, rtcRX8025};

// the list of interrupt intervals supported by the RX8025
enum RTCIntrInterval_t {rtcIntrDisable, rtcIntrEachSecond, rtcIntrEachMinute,rtcIntrEachHour,rtcIntrEachMonth} ; 

extern time_t RTCget(); //  function that can be used as a sync provider callback 

// library interface description

class rtcClass
{
  // user-accessible "public" interface
  public:
    rtcClass();
bool begin(RTCDevice_t device = rtcUnknown);
     //getExternalTime get;   // pointer to the get time method
time_t get();
void set(time_t t);
void read(tmElements_t &tm);
void write(tmElements_t &tm);
void setPeriodicInterrupt( RTCIntrInterval_t interval); // RX8025 only, set the periodic interrupt
void resetPeriodicInterrupt();                         // call after each interrupt to reset the pin.       
     RTCDevice_t device;  // the active device
  private:
     uint8_t address;     
bool isAddressValid(uint8_t address);
uint8_t dec2bcd(uint8_t num);
     uint8_t bcd2dec(uint8_t num);
void writeRegister( uint8_t register, uint8_t value);
};

extern rtcClass RTC;

#endif




ardudillo

Thank you very much mem, I was about to try adding some function to the RX8025 library that returns time_t so I could feed it to the Time library's setSyncProvider() but thankfully your library will save me from getting mauled by the compiler.

I just tried your code and it initialises the RX8025 fine, as well as reading from it. However, the Time library doesn't seem to like its get() for some bizarre reason. Here is my code:

Quote

#include <RTC.h>
#include <Time.h>
#include <Wire.h>
 
void setup() {
  
  Serial.begin(9600);
  if (RTC.begin()) Serial.println("Valid RTC device initialised");
  else Serial.println("Problem initialising RTC");
  
  Serial.println("Testing the two flavours of the RTC.get() function (should return time_t):");
  Serial.print(RTC.get());
  Serial.print(" : ");
  Serial.println(RTCget());
  
  //setSyncProvider(RTCget());
  //setSyncProvider(RTC.get());
  
}
 
void loop() {
}


If I uncomment either line:

setSyncProvider(RTCget());
or
setSyncProvider(RTC.get());


I get the following error:

error: invalid conversion from 'time_t' to 'time_t (*)()'

which seems strange as, if you look at the DS1307RTC library (which works fine with the Time library) the get() is declared in the DS1307RTC.h (line 17) as follows:

static time_t get();


So, the expected return type is time_t. No idea, how the static is breaking things. Could you please post some sample code of registering your lib's get() function as a sync provider?

mem

sure, try this:
Code: [Select]
#include <RTC.h>
#include <Time.h>
#include <Wire.h>

void setup() {
 
  Serial.begin(9600);
  if (RTC.begin()) {
     Serial.println("Valid RTC device initialised");
     setSyncProvider(RTCget);  // register the get function
  }
  else {
    Serial.println("Problem initialising RTC"); 
  }


 
}

void loop() {
}

Go Up