HOME > > ARDUINO How To MAIN PAGE     Delicious.Com Bookmark this on Delicious    StumbleUpon.Com Recommend to StumbleUpon

Tell your Arduino the time and the date!

There are several "real time clock" (RTC) chips which can be connected to an Arduino. An RTC gives you access to the date and time of day, e.g. "noon".

This tutorial is about the BASICS. To help keep things simple, we will assume that your RTC module has a battery to keep it "ticking" even when the "main" power to it is not present. This allows us to use our "big" computer to set the date and time in the module "for all time", and not need a way to do the setting in whatever application we are using the RTC for. It has some material which will help users of any microcontroller interface to the RTC, but all of the example code is for Arduino. If anyone would like to send in links to the code for other systems, I would be glad to consider a link to their pages... especially if THEIR page has a link to THIS page.

This essay is about using a Dallas DS1302. It is a bit "old fashioned", but I like it for being cheap and simple. Of course, I don't know how GOOD it is. Judge for yourself. I picked up a couple, on PCBs, with the crystal they need, and a holder for a battery, for about $2 each. Mis-described (said to come with battery, didn't) and damaged in shipping (inadequate packing), but, at $2, how can I complain? "Good old eBay". I've often been prevented from leaving bad feedback in such circumstances. That I DO feel I can complain about!

With the DS1302, I like the fact that I can put it on the IO lines I want to use. I don't have to use the I2C port... which is fine... unless you want to put more than one thing on that. (Can be done, but there are details to get right.)

Krodal has written an excellent page about using the DS1302. He was using the version 1.0.1 version of the Arduino IDE. (He does, by the way, discourage us from using one of the cheap modules! Says they are unreliable, and that some are badly designed. The "bad design" seems to be a matter of adding resistors which don't help, or even should not be there. My module has the DS1302, the crystal, and the battery holder. So... maybe not enough, and maybe not hooked up right, but nothing extra, anyway. We'll see how I get on! (I write these things as I find my way into a subject. That way I don't leave out any of the newbie gotcha warnings that other tutorials leave out.) Much of what you read here came from there.

The pins on my DS1302 module were labeled...

Vcc
Gnd
CLK
DAT
RST

I haven't got going on 3v3 Arduinos yet. But Krodal (And the Dallas datasheet) says you can power the chip with 5v or 3v3, for those of you who are on a 3v3 Arduino. (There's a second Vcc on the chip, pin 8, for the positive side of the battery backup which, if you connect it, keeps the clock running when it isn't receiving a voltage via the chip's pin 1, which is what my module's Vcc pin connected to. (The battery for standby powering should be between 2 and 5.5v, with 3.3 indicated as "typical".)(You don't need to look at it, and don't worry about it, if you don't understand it, but the material in the data sheet about the programmable trickle charger is pretty cool. (Figure 5))

So... 5v (or 3v3) to the "Vcc" pin of the module.

Ground to the Gnd pin.

Krodal speaks of three data lines: CE, I/O and SCLK. He also gives the chip's pinout. A little work with a magnifying glass and the pinout diagram convinced me that....

My Module   Krodal's
Pin ID      Signal
--------    --------

CLK          SCLK
DAT          I/O
RST          CE

"RST" would usually imply "Reset", and "CE" "Chip Enable". I am just going to assume that whoever put "RST" in the silkscreen of the module was confused, or working in a (weak) second language.

In the sample code that Krodal has given us, we see....

#define DS1302_SCLK_PIN   6    // Arduino pin for the Serial Clock
#define DS1302_IO_PIN     7    // Arduino pin for the Data I/O
#define DS1302_CE_PIN     8    // Arduino pin for the Chip Enable

Every program should be written like this! Every reference to, say, the pin the SCLK signal is being sent from is made by saying "DS1302_SCLK_PIN", so if I want to hook things up for that signal to come from pin 9, as is the case, I just change the #define DS1302_SCLK_PIN... line. So I did. And I changed the next two lines, setting the program up to use line 8 for IO, and line 7 for the CE signal.

I made those changes so that I could use the DS1302 through a NoviceGuard board's twelve way connector. It need not concern you. But make sure that how you hook up your DS1302 and what you have in the three #defines match up!

I like to run the Arduino with the new code once BEFORE hooking up the hardware, to guard against unfortunate clashes between old pinMode statements and new hardware.

So... I ran the program once, then, in this order, connected...

Arduino and module grounds
Supply of 5v from Arduino to module
Pin 9 of Arduino to SCLK
Pin 8 of Arduino to IO ("DAT")
Pin 7 of Arduino to CE ("RST")

.. and I then pressed the Arduino's reset button, to give the whole thing a fair chance to work.

What was "work"?! There were no flashing LEDs to indicate "Eureka! It works!"

The "way in" to "testing" this was via the serial monitor. And excellent standard tool.

Hurrah! I was getting sensible lines, like...q

Time = 10:08:55,
Date(day of month) = 15,
Month = 4,
Day(day of week) = 2,
Year = 2013

(I've put some newlines in that, to make it fit your screen better.)

AND new lines were appearing every 5 seconds, and the time reported went up by 5 seconds every time.

The chip works! The software works! Hurrah! (It is even still working the next day!)

Setting the date and time of day

If you dig into the software, you will find the lines that sets the RTC to initial date and time values. They start...

  // Example for April 15, 2013, 10:08, Monday is 2nd day of Week.
  // Set your own time and date in these variables.
  seconds    = 40;
  minutes    = 16;
  hours      = 21;
  dayofweek  = 1;  // Day of week, any day can be first, counts 1...7
  dayofmonth = 17; // Day of month, 1...31
  month      = 8;  // month 1...12
  year       = 2015;

Revise the values on those lines to some moment in time about a minute from when you expect to run to program. Compile. Upload. Then just before the moment the settings were made for, press the Arduino's reset button, to start the program again at the programmed moment.

Once you've done that, as long as you have the battery in the module, to provide a standby voltage to get it through the times it isn't powered from the Arduino's Vcc, you don't WANT the "set starting time" part of the program to run. You arrange that by remming out the...

#define SET_DATE_TIME_JUST_ONCE

... which is just a few lines before the lines we tweaked a moment ago.

Reading date / time

Don't be intimidated by the code. To USE it, you don't need to know a lot, once you have your clock "set". (Okay, maybe that's a LITTLE tricky? Not terribly, though. How to do it described above.)

I would assume you need pretty well everything that is in the demo program. (See below. It appears in the "time has been set" version.) But you only need to UNDERSTAND the following to use the RTC...

You have a few things to do during the setup() subroutine. (See code below. Just copy it.)

The trickle charger: You don't need to worry about it, as we won't be using it. But. There is a line which is meant to disable the trickle charger. I would leave it in, just in case, even though the datasheet says....

TRICKLE-CHARGE REGISTER
This register controls the trickle-charge
characteristics of the DS1302....
To prevent accidental enabling, only a pattern
of 1010 enables the trickle charger. All other
patterns will disable the trickle charger.
   ** The DS1302 powers up with
      the trickle charger disabled.**

(You probably don't have to worry about disabling the trickle charger circuit, in other words.)


A big chunk of the "setup()" code, the stuff from...

// Remove the next define,
// after the right date and time are set.
//#define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE

... down to (and including) the #endif can be taken out, if you will always "set" the RTC module on a separate system, when necessary.

In the demo's code, have a look at the loop() subroutine, i.e....

void loop()
{
  ds1302_struct rtc;
  char buffer[80];     // the code uses 70 characters.

  // Read all clock data at once (burst mode).
  DS1302_clock_burst_read( (uint8_t *) &rtc);

  sprintf( buffer, "Time = %02d:%02d:%02d, ", \
    bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
    bcd2bin( rtc.Minutes10, rtc.Minutes), \
    bcd2bin( rtc.Seconds10, rtc.Seconds));
  Serial.print(buffer);

  sprintf(buffer, "Date(day of month) = %d, Month = %d, " \
    "Day(day of week) = %d, Year = %d", \
    bcd2bin( rtc.Date10, rtc.Date), \
    bcd2bin( rtc.Month10, rtc.Month), \
    rtc.Day, \
    2000 + bcd2bin( rtc.Year10, rtc.Year));
  Serial.println( buffer);

  delay( 5000);
}//End loop()

Just do...

  ds1302_struct rtc;
  char buffer[80];     // the code uses 70 characters.

  // Read all clock data at once (burst mode).
  DS1302_clock_burst_read( (uint8_t *) &rtc);

... just before you want to know the date or time.

When you have done that, you will find all of the elements of the date or time in the STRUCTure "rtc". It is a bit like a variable with bits...

If the time were 21:35, for instance...

In rtc.h24.Hour10, you would find a 2
In rtc.h24.Hour, you would find a 1
In rtc.Minutes10, you would find a 3
In rtc.Minutes, you would find a 5

All that...

sprintf( buffer, "Time = %02d:%02d:%02d, ", \
    bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
    ...

... stuff is just a way to get the numbers from the parts of the structure (fancy "variable", with many parts) out onto the screen via the serial monitor, nicely formatted.

The whole program (aka "sketch")...

Here, only slightly "messed with" is the magnificent gift from Krodal....

I've remmed bits out, as explained above to prevent re-setting of clock at start of execution. I also changed the I/O lines used to connect the RTC.

The program uses about 5,450 bytes. An Arduino Pro Mini gives you 30,720 to play with. I think you can spare 5k to have the date and time available so easily, don't you?

// DS1302 RTC
// ----------
//*********************************
//**SLIGHTLY Tweaked by TKB to move
//**THE PINS USED. SEE THE THREE
//**#define DS... lines
//*********************************
//
// Open Source / Public Domain
//
// Version 1
//     By arduino.cc user "Krodal".
//     June 2012
//     Using Arduino 1.0.1
// Version 2
//     By arduino.cc user "Krodal"
//     March 2013
//     Using Arduino 1.0.3, 1.5.2
//     The code is no longer compatible with older versions.
//     Added bcd2bin, bin2bcd_h, bin2bcd_l
//     A few minor changes.
//
//
// Documentation: datasheet
//
// The DS1302 uses a 3-wire interface:
//    - bidirectional data.
//    - clock
//    - chip select
// It is not I2C, not OneWire, and not SPI.
// So the standard libraries can not be used.
// Even the shiftOut() function is not used, since it
// could be too fast (it might be slow enough,
// but that's not certain).
//
// I wrote my own interface code according to the datasheet.
// Any three pins of the Arduino can be used.
//   See the first defines below this comment,
//   to set your own pins.
//
// The "Chip Enable" pin was called "/Reset" before.
//
// The chip has internal pull-down registers.
// This keeps the chip disabled, even if the pins of
// the Arduino are floating.
//
//
// Range
// -----
//      seconds : 00-59
//      minutes : 00-59
//      hour    : 1-12 or 0-23
//      date    : 1-31
//      month   : 1-12
//      day     : 1-7
//      year    : 00-99
//
//
// Burst mode
// ----------
// In burst mode, all the clock data is read at once.
// This is to prevent a rollover of a digit during reading.
// The read data is from an internal buffer.
//
// The burst registers are commands, rather than addresses.
// Clock Data Read in Burst Mode
//    Start by writing 0xBF (as the address),
//    after that: read clock data
// Clock Data Write in Burst Mode
//    Start by writing 0xBE (as the address),
//    after that: write clock data
// Ram Data Read in Burst Mode
//    Start by writing 0xFF (as the address),
//    after that: read ram data
// Ram Data Write in Burst Mode
//    Start by writing 0xFE (as the address),
//    after that: write ram data
//
//
// Ram
// ---
// The DS1302 has 31 of ram, which can be used to store data.
// The contents will be lost if the Arduino is off,
// and the backup battery gets empty.
// It is better to store data in the EEPROM of the Arduino.
// The burst read or burst write for ram is not implemented
// in this code.
//
//
// Trickle charge
// --------------
// The DS1302 has a build-in trickle charger.
// That can be used for example with a lithium battery
// or a supercap.
// Using the trickle charger has not been implemented
// in this code.
//


// Set your own pins with these defines !
#define DS1302_SCLK_PIN   9    // Arduino pin for the Serial Clock
#define DS1302_IO_PIN     8    // Arduino pin for the Data I/O
#define DS1302_CE_PIN     7    // Arduino pin for the Chip Enable


// Macros to convert the bcd values of the registers to normal
// integer variables.
// The code uses seperate variables for the high byte and the low byte
// of the bcd, so these macros handle both bytes seperately.
#define bcd2bin(h,l)    (((h)*10) + (l))
#define bin2bcd_h(x)   ((x)/10)
#define bin2bcd_l(x)    ((x)%10)


// Register names.
// Since the highest bit is always '1',
// the registers start at 0x80
// If the register is read, the lowest bit should be '1'.
#define DS1302_SECONDS           0x80
#define DS1302_MINUTES           0x82
#define DS1302_HOURS             0x84
#define DS1302_DATE              0x86
#define DS1302_MONTH             0x88
#define DS1302_DAY               0x8A
#define DS1302_YEAR              0x8C
#define DS1302_ENABLE            0x8E
#define DS1302_TRICKLE           0x90
#define DS1302_CLOCK_BURST       0xBE
#define DS1302_CLOCK_BURST_WRITE 0xBE
#define DS1302_CLOCK_BURST_READ  0xBF
#define DS1302_RAMSTART          0xC0
#define DS1302_RAMEND            0xFC
#define DS1302_RAM_BURST         0xFE
#define DS1302_RAM_BURST_WRITE   0xFE
#define DS1302_RAM_BURST_READ    0xFF



// Defines for the bits, to be able to change
// between bit number and binary definition.
// By using the bit number, using the DS1302
// is like programming an AVR microcontroller.
// But instead of using "(1<<X)", or "_BV(X)",
// the Arduino "bit(X)" is used.
#define DS1302_D0 0
#define DS1302_D1 1
#define DS1302_D2 2
#define DS1302_D3 3
#define DS1302_D4 4
#define DS1302_D5 5
#define DS1302_D6 6
#define DS1302_D7 7


// Bit for reading (bit in address)
#define DS1302_READBIT DS1302_D0 // READBIT=1: read instruction

// Bit for clock (0) or ram (1) area,
// called R/C-bit (bit in address)
#define DS1302_RC DS1302_D6

// Seconds Register
#define DS1302_CH DS1302_D7   // 1 = Clock Halt, 0 = start

// Hour Register
#define DS1302_AM_PM DS1302_D5 // 0 = AM, 1 = PM
#define DS1302_12_24 DS1302_D7 // 0 = 24 hour, 1 = 12 hour

// Enable Register
#define DS1302_WP DS1302_D7   // 1 = Write Protect, 0 = enabled

// Trickle Register
#define DS1302_ROUT0 DS1302_D0
#define DS1302_ROUT1 DS1302_D1
#define DS1302_DS0   DS1302_D2
#define DS1302_DS1   DS1302_D2
#define DS1302_TCS0  DS1302_D4
#define DS1302_TCS1  DS1302_D5
#define DS1302_TCS2  DS1302_D6
#define DS1302_TCS3  DS1302_D7


// Structure for the first 8 registers.
// These 8 bytes can be read at once with
// the 'clock burst' command.
// Note that this structure contains an anonymous union.
// It might cause a problem on other compilers.
typedef struct ds1302_struct
{
  uint8_t Seconds:4;      // low decimal digit 0-9
  uint8_t Seconds10:3;    // high decimal digit 0-5
  uint8_t CH:1;           // CH = Clock Halt
  uint8_t Minutes:4;
  uint8_t Minutes10:3;
  uint8_t reserved1:1;
  union
  {
    struct
    {
      uint8_t Hour:4;
      uint8_t Hour10:2;
      uint8_t reserved2:1;
      uint8_t hour_12_24:1; // 0 for 24 hour format
    } h24;
    struct
    {
      uint8_t Hour:4;
      uint8_t Hour10:1;
      uint8_t AM_PM:1;      // 0 for AM, 1 for PM
      uint8_t reserved2:1;
      uint8_t hour_12_24:1; // 1 for 12 hour format
    } h12;
  };
  uint8_t Date:4;           // Day of month, 1 = first day
  uint8_t Date10:2;
  uint8_t reserved3:2;
  uint8_t Month:4;          // Month, 1 = January
  uint8_t Month10:1;
  uint8_t reserved4:3;
  uint8_t Day:3;            // Day of week, 1 = first day (any day)
  uint8_t reserved5:5;
  uint8_t Year:4;           // Year, 0 = year 2000
  uint8_t Year10:4;
  uint8_t reserved6:7;
  uint8_t WP:1;             // WP = Write Protect
};


void setup()
{      
  ds1302_struct rtc;


  Serial.begin(9600);
  Serial.println(F("DS1302 Real Time Clock"));
  Serial.println(F("Version 2, March 2013"));


  // Start by clearing the Write Protect bit
  // Otherwise the clock data cannot be written
  // The whole register is written,
  // but the WP-bit is the only bit in that register.
  DS1302_write (DS1302_ENABLE, 0);

  // Disable Trickle Charger.
  DS1302_write (DS1302_TRICKLE, 0x00);

/*TKB REM OUT TEST...
// Remove the next define,
// after the right date and time are set.
//#define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE  

  // Fill these variables with the date and time.
  int seconds, minutes, hours, dayofweek, dayofmonth, month, year;

  seconds    = 35;
  minutes    = 17;
  hours      = 21;
  dayofweek  = 1;  // Day of week, any day can be first, counts 1...7
  dayofmonth = 17; // Day of month, 1...31
  month      = 8;  // month 1...12
  year       = 2015;
  // Set a time and date
  // This also clears the CH (Clock Halt) bit,
  // to start the clock.

  // Fill the structure with zeros to make
  // any unused bits zero
  memset ((char *) &rtc, 0, sizeof(rtc));

  rtc.Seconds    = bin2bcd_l( seconds);
  rtc.Seconds10  = bin2bcd_h( seconds);
  rtc.CH         = 0;      // 1 for Clock Halt, 0 to run;
  rtc.Minutes    = bin2bcd_l( minutes);
  rtc.Minutes10  = bin2bcd_h( minutes);
  // To use the 12 hour format,
  // use it like these four lines:
  //    rtc.h12.Hour   = bin2bcd_l( hours);
  //    rtc.h12.Hour10 = bin2bcd_h( hours);
  //    rtc.h12.AM_PM  = 0;     // AM = 0
  //    rtc.h12.hour_12_24 = 1; // 1 for 24 hour format
  rtc.h24.Hour   = bin2bcd_l( hours);
  rtc.h24.Hour10 = bin2bcd_h( hours);
  rtc.h24.hour_12_24 = 0; // 0 for 24 hour format
  rtc.Date       = bin2bcd_l( dayofmonth);
  rtc.Date10     = bin2bcd_h( dayofmonth);
  rtc.Month      = bin2bcd_l( month);
  rtc.Month10    = bin2bcd_h( month);
  rtc.Day        = dayofweek;
  rtc.Year       = bin2bcd_l( year - 2000);
  rtc.Year10     = bin2bcd_h( year - 2000);
  rtc.WP = 0;  

  // Write all clock data at once (burst mode).
  DS1302_clock_burst_write( (uint8_t *) &rtc);
#endif
*/ //TKB REM OUT TEST
}


void loop()
{
  ds1302_struct rtc;
  char buffer[80];     // the code uses 70 characters.

  // Read all clock data at once (burst mode).
  DS1302_clock_burst_read( (uint8_t *) &rtc);

  sprintf( buffer, "Time = %02d:%02d:%02d, ", \
    bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
    bcd2bin( rtc.Minutes10, rtc.Minutes), \
    bcd2bin( rtc.Seconds10, rtc.Seconds));
  Serial.print(buffer);

  sprintf(buffer, "Date(day of month) = %d, Month = %d, " \
    "Day(day of week) = %d, Year = %d", \
    bcd2bin( rtc.Date10, rtc.Date), \
    bcd2bin( rtc.Month10, rtc.Month), \
    rtc.Day, \
    2000 + bcd2bin( rtc.Year10, rtc.Year));
  Serial.println( buffer);

  delay( 5000);
}//end of loop()


// --------------------------------------------------------
// DS1302_clock_burst_read
//
// This function reads 8 bytes clock data in burst mode
// from the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_read( uint8_t *p)
{
  int i;

  _DS1302_start();

  // Instead of the address,
  // the CLOCK_BURST_READ command is issued
  // the I/O-line is released for the data
  _DS1302_togglewrite( DS1302_CLOCK_BURST_READ, true);

  for( i=0; i<8; i++)
  {
    *p++ = _DS1302_toggleread();
  }
  _DS1302_stop();
}


// --------------------------------------------------------
// DS1302_clock_burst_write
//
// This function writes 8 bytes clock data in burst mode
// to the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_write( uint8_t *p)
{
  int i;

  _DS1302_start();

  // Instead of the address,
  // the CLOCK_BURST_WRITE command is issued.
  // the I/O-line is not released
  _DS1302_togglewrite( DS1302_CLOCK_BURST_WRITE, false);

  for( i=0; i<8; i++)
  {
    // the I/O-line is not released
    _DS1302_togglewrite( *p++, false);
  }
  _DS1302_stop();
}


// --------------------------------------------------------
// DS1302_read
//
// This function reads a byte from the DS1302
// (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is set anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
uint8_t DS1302_read(int address)
{
  uint8_t data;

  // set lowest bit (read bit) in address
  bitSet( address, DS1302_READBIT);

  _DS1302_start();
  // the I/O-line is released for the data
  _DS1302_togglewrite( address, true);
  data = _DS1302_toggleread();
  _DS1302_stop();

  return (data);
}


// --------------------------------------------------------
// DS1302_write
//
// This function writes a byte to the DS1302 (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is cleared anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_write( int address, uint8_t data)
{
  // clear lowest bit (read bit) in address
  bitClear( address, DS1302_READBIT);

  _DS1302_start();
  // don't release the I/O-line
  _DS1302_togglewrite( address, false);
  // don't release the I/O-line
  _DS1302_togglewrite( data, false);
  _DS1302_stop();  
}


// --------------------------------------------------------
// _DS1302_start
//
// A helper function to setup the start condition.
//
// An 'init' function is not used.
// But now the pinMode is set every time.
// That's not a big deal, and it's valid.
// At startup, the pins of the Arduino are high impedance.
// Since the DS1302 has pull-down resistors,
// the signals are low (inactive) until the DS1302 is used.
void _DS1302_start( void)
{
  digitalWrite( DS1302_CE_PIN, LOW); // default, not enabled
  pinMode( DS1302_CE_PIN, OUTPUT);

  digitalWrite( DS1302_SCLK_PIN, LOW); // default, clock low
  pinMode( DS1302_SCLK_PIN, OUTPUT);

  pinMode( DS1302_IO_PIN, OUTPUT);

  digitalWrite( DS1302_CE_PIN, HIGH); // start the session
  delayMicroseconds( 4);           // tCC = 4us
}


// --------------------------------------------------------
// _DS1302_stop
//
// A helper function to finish the communication.
//
void _DS1302_stop(void)
{
  // Set CE low
  digitalWrite( DS1302_CE_PIN, LOW);

  delayMicroseconds( 4);           // tCWH = 4us
}


// --------------------------------------------------------
// _DS1302_toggleread
//
// A helper function for reading a byte with bit toggle
//
// This function assumes that the SCLK is still high.
//
uint8_t _DS1302_toggleread( void)
{
  uint8_t i, data;

  data = 0;
  for( i = 0; i <= 7; i++)
  {
    // Issue a clock pulse for the next databit.
    // If the 'togglewrite' function was used before
    // this function, the SCLK is already high.
    digitalWrite( DS1302_SCLK_PIN, HIGH);
    delayMicroseconds( 1);

    // Clock down, data is ready after some time.
    digitalWrite( DS1302_SCLK_PIN, LOW);
    delayMicroseconds( 1);        // tCL=1000ns, tCDD=800ns

    // read bit, and set it in place in 'data' variable
    bitWrite( data, i, digitalRead( DS1302_IO_PIN));
  }
  return( data);
}


// --------------------------------------------------------
// _DS1302_togglewrite
//
// A helper function for writing a byte with bit toggle
//
// The 'release' parameter is for a read after this write.
// It will release the I/O-line and will keep the SCLK high.
//
void _DS1302_togglewrite( uint8_t data, uint8_t release)
{
  int i;

  for( i = 0; i <= 7; i++)
  {
    // set a bit of the data on the I/O-line
    digitalWrite( DS1302_IO_PIN, bitRead(data, i));
    delayMicroseconds( 1);     // tDC = 200ns

    // clock up, data is read by DS1302
    digitalWrite( DS1302_SCLK_PIN, HIGH);
    delayMicroseconds( 1);     // tCH = 1000ns, tCDH = 800ns

    if( release && i == 7)
    {
      // If this write is followed by a read,
      // the I/O-line should be released after
      // the last bit, before the clock line is made low.
      // This is according the datasheet.
      // I have seen other programs that don't release
      // the I/O-line at this moment,
      // and that could cause a shortcut spike
      // on the I/O-line.
      pinMode( DS1302_IO_PIN, INPUT);

      // For Arduino 1.0.3, removing the pull-up is no longer needed.
      // Setting the pin as 'INPUT' will already remove the pull-up.
      // digitalWrite (DS1302_IO, LOW); // remove any pull-up  
    }
    else
    {
      digitalWrite( DS1302_SCLK_PIN, LOW);
      delayMicroseconds( 1);       // tCL=1000ns, tCDD=800ns
    }
  }
}



That's about it, for now. Do, please, get in touch if there were bits I should have included, drawn more attention to, etc. Help the next person!

"It isn't working...."

There's a provision in the design of the RTC which I think is rather clever, though you may curse it. What follows is what I hope the design achieves. It may only be something a bit like this, and it may be that there is a chance of the RTC running after having no power. But there is certainly at least a CHANCE of it not running if it has lost power... until you do what I explain in the next paragraph.

If it loses ALL power, (including the battery backup power), it shuts down, and a "clock halt flag" is set. It won't "work" again until you have done the "set time and date" process. If my grandfather's pocket watch runs down, needs winding. (Yes, Virginia, there were once clocks without batteries), then it will start up again. It will show the wrong time, but it will run. The DS1302 won't "run", showing a random time, or a time-since-start. It will only start running if it has had its date and time set since the last time it acquired at least the battery backup power. (The details of this are in the data sheet, under "clock halt flag". The program above, when you run it with the "set the date and time" bits enabled, takes care of clearing the flag.

For those who enjoy the details, here is an extract from the data sheet...

CLOCK HALT FLAG

Bit 7 of the seconds register is defined as the
clock halt (CH) flag. When this bit is set to logic 1,
the clock oscillator is stopped and the DS1302 is
placed into a low power standby mode with a current
drain of less than 100nA. When this bit is written
to logic 0, the clock will start.

The initial power on state is not defined.

Hmmm... maybe not quite what I said, apart from the fact that the RTC can power up in a "clock halt flag set" state? And I am confident in what I said earlier about the "set date and time" routine having "the bit" to clear the clock halt flag, so that the RTC will run.

Also, I have tested that the chip DOES continue to keep time, even if only powered by a "3 volt" (approx) "button cell". (I used a "2016" cell.)


Remember, please: This page does not claim to be "polished" yet... but you read this far... I hope it was of SOME use?



To search THIS site.... (Go to my other sites, below, and use their search buttons if you want to search them.)
Click this to search this site without using forms.

powered by FreeFind
Site search Web search

The search engine merely looks for the words you type, so....
*    Spell them properly.
*    Don't bother with "How do I get rich?" That will merely return pages with "how", "do", "I"....

Please also note that I have two other sites, and that this search will not include them. They have their own search buttons.
My site at Arunet.
My Sheepdog Software pages, another of this page's editor's sites.


Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!
Click here to visit editor's freeware, shareware page.




Here is how you can contact this page's editor. This page, and the software it references, ©TK Boyd, 8/2015.

Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org