Sunday, January 8, 2012

DS1307 RTC with LED

A DSR1307RTC IC is a pretty cheap and accurate Real Time Clock that only needs a few components to work.

The 3 volt battery is necessary for time keeping when the 5V power supply is off. A CR battery will be sufficient to keep time for many many years.

The PWM pin is not really necessary, but it can be used to output a pulse of e.g. 1Hz that can be used to drive a LED that will be pulsing 1x per second. For this one must write a 0x10 (10 in HEX format, 16 in digital format, 00010000 in binary format) to register 07 (HEX).
//-----------
/*
 reading and writing to the Maxim DS1307 real time clock IC
 based on code by Maurice Ribble
 17-4-2008 - http://www.glacialwanderer.com/hobbyrobotics
 ---------------------------------------
 CONTROL REGISTER
 The DS1307 control register is used to control
 the operation of the SQW/OUT pin.

 BIT 7  BIT 6  BIT 5  BIT 4  BIT 3  BIT 2  BIT 1  BIT 0
 OUT     0      0     SQWE     0     0     RS1    RS0

 Bit 4: Square-Wave Enable (SQWE): This bit, when set to logic 1,
       enables the oscillator output. 
 ---------------------------------------
 Pin 5 (SDA) naar analoog4
 Pin 6 (SCL) naar analoog5
 */

#include "Wire.h"   // available in the Arduino files
#define DS1307_I2C_ADDRESS 0x68

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

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

// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock

// Assumes you're passing in valid numbers

void setDateDs1307(byte second,        // 0-59
byte minute,        // 0-59
byte hour,          // 1-23
byte dayOfWeek,     // 1-7
byte dayOfMonth,    // 1-28/29/30/31
byte month,         // 1-12
byte year)          // 0-99
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.send(decToBcd(second));    // 0 to bit 7 starts the clock
  Wire.send(decToBcd(minute));
  Wire.send(decToBcd(hour));     
  Wire.send(decToBcd(dayOfWeek));
  Wire.send(decToBcd(dayOfMonth));
  Wire.send(decToBcd(month));
  Wire.send(decToBcd(year)); 
  Wire.endTransmission();
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  *second     = bcdToDec(Wire.receive() & 0x7f);
  *minute     = bcdToDec(Wire.receive());
  *hour       = bcdToDec(Wire.receive() & 0x3f);  // Need to change this if 12 hour am/pm
  *dayOfWeek  = bcdToDec(Wire.receive());
  *dayOfMonth = bcdToDec(Wire.receive());
  *month      = bcdToDec(Wire.receive());
  *year       = bcdToDec(Wire.receive());
}


// sqw is set here
void sqw1() // set to 1Hz
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x07); // move pointer to SQW address
  Wire.send(0x10); //  sends 0x10 (hex) 00010000 (binary)
  Wire.endTransmission();
}
//-------------------



void setup()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  Wire.begin();
  Serial.begin(9600);

  // Change these values to what you want to set your clock to.
  // You probably only want to set your clock once and then remove
  // the setDateDs1307 call.

  second = 0;
  minute = 52;
  hour = 9;
  dayOfWeek = 7;
  dayOfMonth = 7;
  month = 1;
  year = 12;
// uncomment instruction below to set the time
// setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);

//----------------------------
sqw1();  //switch on 1Hz SQW 
//-----------------------------
}

void loop()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  Serial.print(hour, DEC);// convert the byte variable to a decimal number when being displayed
  Serial.print(":");
  if (minute<10)
  {
      Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
      Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print("  ");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  //Serial.print("  Day of week:");
  switch(dayOfWeek){
  case 1: 
    Serial.println(" Sunday");
    break;
  case 2: 
    Serial.println(" Monday");
    break;
  case 3: 
    Serial.println(" Tuesday");
    break;
  case 4: 
    Serial.println(" Wednesday");
    break;
  case 5: 
    Serial.println(" Thursday");
    break;
  case 6: 
    Serial.println(" Friday");
    break;
  case 7: 
    Serial.println(" Saturday");
    break;
  }
  //  Serial.println(dayOfWeek, DEC);
  delay(1000);
}

/* To access the RAM (65 bytes)
   void WriteRam(int address,byte data){
   Wire.beginTransmission(0x68);    // Select DS1307
   Wire.send(address+8);   // address location starts at 8, 0-6 are date, 7 is control
   Wire.send(data);        // send data
   Wire.endTransmission();
}
  
*/

/*
//12 hours:

void setDateDs1307
….
Wire.send(decToBcd(hour) | _BV(6)); // set bit 6 for 12 hour mode

void getDateDs1307:
….
*hour = bcdToDec(Wire.receive() & 0x1f); // mask output for 12 hour mode
*/
//----------
Below a program that will make the SQW/PWM pin flash at several frequencies (but your eyes won't see it at the higher frequencies)
/*
DS1307 Square-wave machine
 Used to demonstrate the four different square-wave outputs from Maxim DS1307
 See page nine of data sheet for more information
 John Boxall - tronixstuff.wordpress.com
 Register:
 OUT 0 0 SQWE 0 0 RS1 RS2
 */
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68 // each I2C object has a unique bus address, the DS1307 is 0x68
void setup()
{
  Wire.begin();
}
void sqw1() // set to 1Hz
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x07); // move pointer to SQW address
  Wire.send(0x10); //  sends 0x10 (hex) 00010000 (binary)
  Wire.endTransmission();
}
void sqw2() // set to 4.096 kHz
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x07); // move pointer to SQW address
  Wire.send(0x11); //  sends 0x11 (hex) 00010001 (binary)
  Wire.endTransmission();
}
void sqw3() // set to 8.192 kHz
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x07); // move pointer to SQW address
  Wire.send(0x12); // sends 0x12 (hex) 00010010 (binary)
  Wire.endTransmission();
}
void sqw4() // set to 32.768 kHz (the crystal frequency)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x07); // move pointer to SQW address
  Wire.send(0x13); // sends 0x13 (hex) 00010011 (binary)
  Wire.endTransmission();
}
void sqwOff()
// turns the SQW off
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x07); // move pointer to SQW address
  Wire.send(0x00); // turns the SQW pin off
  Wire.endTransmission();
}
void loop()
{
  sqw1();
  delay(5000);
  sqw2();
  delay(5000);
  sqw3();
  delay(5000);
  sqw4();
  delay(5000);
  sqwOff();
  delay(5000);
}