Few, yes very few things that I have encountered from playing with Arduino has given me as much grief as the DS1307 modules.  On the surface, these clock-calendar chips and associated break-out boards seem to be a great idea if you are dealing with sketches that must output reasonably accurate time/date over some long periods.  Most breakout boards even come with a backup battery to keep the DS1307 happy when the external power source is off.

But these little marvels come completely brain-dead!  Ignorant... like a battery powered watch, they are useless until set.  But Arduino users generally must load a sketch into their boards, connect the DS1307, and then run the sketch to program the time and date registers.  Which is OK except a month later when you go to check and find that the DS1307 has drifted a couple of minutes.  Well, maybe that is not a big deal for some, but I'm anal and I want my data loggers to have time more accurate than the inexpensive DS1307 modules will support.

I tried buying some quality crystals and replacing the stock crystal.  That actually worked and this is where the 20 seconds every 24 hours shifted to 4 seconds every 24 hours.  Not bad.  But sometimes I do not use the data logger for a few months.  Now, I have to load the Arduino sketch, set the time and date, and then reload my data logger sketch.  Pretty annoying and even though it was just a little thing, it really grated on my psyche.

So, I decided to write my own set routine where I could set the date once and set the time anytime or just "hack" the seconds if that was all that was necessary.  I did not want to deal with keyboards or terminals, so I rewrote a sketch I found for the ATtiny85 which can host an Infrared detector.  With this less-than-$2 circuit, I can now use a $1 universal controller from the "dollar store" and my UNO and Mega sketches do not have to poll for IR since the IR activity is handled separately and the normally unused hardware serial input is used to identify that the remote control has activated the Power Button and IR commands are awaiting.  If the user presses Power on the remote again, the UNO sketch simply returns to doing what it was doing.  The ONLY wasted instruction in the main sketch is just to check the serial buffer:

if (Serial.available() > 0)    // Something from IR is in the serial buffer
Most sketches can live with that!  The test sketch that follows compiles to 13,664 Bytes on an UNO with 32,256 Bytes of flash, or about 42%.  However, much of the code is "library" code and not specific to the DS1307, or to put it into prospective, 23% of the 42% is library code for serial and I2C.


Step 1: ATtiny85 Code

There are two (2) sets of code: one for the ATtiny85 and one for the ATmega328P (UNO).  I have also tested the code with minor modifications on the ATMega2560, the Mini, and the Nano.  Please use the PDF versions to copy code since I have found a few source code characters "eaten alive" by the Instructables editor (that is, <PRE> and </PRE> codes not completely respected... especially in the #include <library> statements.

This code can be compiled and loaded into the "tiny85" chip using ISP.  Check Instructables as there are several articles on how to do this easily, or see: http://hlt.media.mit.edu/?p=1695

  IR remote control (Sony) detection for Arduino, M. Burnette
  Binary sketch size: 2,794 bytes (of a 8,192 byte maximum)
  :  20130103 MRB Modified for interface to Mega2560
      Europa codebase for menu system
  :  20121230 MRB Modified for Tiny85 Google Tiny library
      Tiny85 Internal RC 16MHz
  :  20121230 MRB modifications to adapt to numeric input, avoid dupes,
      and to generally "behave" consistently
  :  Used with Electronic Goldmine IR detector MIM 5383H4
  :  IR detector:
      Pin 1: To pin D4 on Arduino ATtiny85
      Pin 2: GND
      Pin 3: 5V through 33 Ohm resistor
:  This is based on pmalmsten's code found on the Arduino forum from 2007:
// Pins 2/3 used for Software serial
int irPin     = 4;       //Sensor pin 1 wired to Arduino's pin D4
int statLED   = 0;       //Toggle the status LED every time Power is pressed
int start_bit = 2200;    //Start bit threshold (Microseconds)
int bin_1     = 1000;    //Binary 1 threshold (Microseconds)
int bin_0     = 400;     //Binary 0 threshold (Microseconds)
void setup() {
  pinMode(statLED, OUTPUT);
  digitalWrite(statLED, LOW);
  pinMode(irPin, INPUT);
  Serial.println("IR/Serial Initialized: ");
void loop() {
  int key = getIRKey();   //Fetch the key
  if(key != 0)            //Ignore keys that are zero
      case 128: Serial.print("1"); break;
      case 129: Serial.print("2"); break;
      case 130: Serial.print("3"); break;
      case 131: Serial.print("4"); break;
      case 132: Serial.print("5"); break;
      case 133: Serial.print("6"); break;
      case 134: Serial.print("7"); break;
      case 135: Serial.print("8"); break;
      case 136: Serial.print("9"); break;
      case 137: Serial.print("0"); break;
            case 144: Serial.print("A"); break;  // CH Up
      case 145: Serial.print("B"); break;  // CH Down
      case 146: Serial.print("C"); break;  // VOL Right
      case 147: Serial.print("D"); break;  // VOL Left
      case 148: Serial.print("E"); break;  // Mute
      case 165: Serial.print("F"); break;  // AV/TV
      case 149: Serial.print("P");         // Power == MENU ACTIVE
        //This toggles the statLED every time power button is hit
        if(digitalRead(statLED) != 1)
          digitalWrite(statLED, HIGH);
          digitalWrite(statLED, LOW);
      //default: Serial.println(key); // for inspection of keycode
    delay(400);    // avoid double key logging (adjustable)
int getIRKey() {
  int data[12];
  int i;
  while(pulseIn(irPin, LOW) < start_bit); //Wait for a start bit
  for(i = 0 ; i < 11 ; i++)
    data[i] = pulseIn(irPin, LOW);      //Start measuring bits, I only want low pulses
  for(i = 0 ; i < 11 ; i++)             //Parse them
    if(data[i] > bin_1)                 //is it a 1?
      data[i] = 1;
    else if(data[i] > bin_0)            //is it a 0?
      data[i] = 0;
      return -1;                        //Flag the data as invalid; I don't know what it is! Return -1 on invalid data
  int result = 0;
  for(i = 0 ; i < 11 ; i++)             //Convert data bits to integer
    if(data[i] == 1) result |= (1<<i);
  return result;                        //Return key number

I have shown in the graphic that a AX-1838HS was used for the IR detector.  I have also used MIM-5383H4 which is also 38KHz.  But please note that the MIM device is a different pinout!

The circuit for the ATtiny85 is very simple:
ATtiny PIN #1     Reset (this should be connected to the main Arduino RESET)
ATtiny PIN #2     Not used
ATtiny PIN #3     Leg #1 of the AX-1838 IR detector
ATtiny PIN #4     Connect to Arduino Gnd (ground)
ATtiny PIN #5     anode of optional LED
ATtiny PIN #6     Not used
ATtiny PIN #7     9600 BAUD serial output TO Arduino D0 (Rx0) *
ATtiny PIN #8     Connect to Arduino +5V

* Note: You MUST disconnect this line (suggest a simple switch or jumper) to program the Arduino UNO.  This is because the onboard USB-serial converter also drives the Rx0 line through a 1K resistor.

ATtiny85 Board and Core Selection:
From this link: http://code.google.com/p/arduino-tiny/downloads/detail?name=arduino-tiny-0100-0015.zip
Most Excellent Instructable Ray !! <br>A truly Awesome insight into the lazy operation of these DS1307 RTC Modules !! <br> <br>Im really annoyed at their ability to lose so much time per 24 hours too and am now collecting the parts needed for your great instructable !!! <br> <br>May i kindly ask you what the frequency crystal is that you used to replace the stock crystal on these modules that eliminated the time-wastage from 20 seconds every 24 hours to about 4 seconds as i would also like to replace the crystal too but clueless as to what frequency crystal should be used ! <br> <br>The DS1307 datasheet says to use a specific 32.768 Khz Quartz Crystal - is this the one you used by any chance ?!? <br> <br>many thanks in advance for this help ! <br> <br>kindest regards !
I had a few of these from another project in my parts bin:<br>http://www.newark.com/ael-crystals/x32k768l104/watch-crystal-32-768khz-12-5pf/dp/96K4261<br><br>These are 20 ppm and seem to be a a great replacement. I'm sure competitive devices can be sourced from numerous vendors.<br><br>Ray
Absolutely AWESOME Info - thanks so much ! <br> <br> so sorry about the delay in reply, 20 ppm is the info i never knew about to look for in the crystal specs, are there more accurate than that easily available if you know ?!?
NP... generally I have found that the &quot;ppm&quot; will have some impact on pricing... the lower the ppm the higher the quality and the higher the price. This is just a rule-of-thumb and does not always apply since volume manufacturing also plays a part. We hobbyists enjoy lower prices on parts that are used in general high volume electronics.
Neat set up and I like your approach. I am anal about accurate time also (why bother keeping track otherwise?). I ended up building one without a clock module using only a network shield attached to a small wireless access point that routinely checks the timeservers every 6 hours... I will post it soon once I feel it is ready, still testing it and it seems pretty stable so far...

About This Instructable


10 favorites


Bio: Ray Burne is my pseudonym, I sometimes write on various Blogs and Sites. Effective 12 June 2013, Ray has decided to no longer participate as ... More »
More by RayBurne: Minty Magic Morse - Arduino Style PICAXE Pitcher Perfect Thermometer A PICAXE Infrared "logging" Thermometer
Add instructable to: