Basic RTC using the SQW pin

Maybe it's me, but I have found it unreasonably difficult and confusing to get a basic clock running off the square wave output from the DS3231 module. I don't understand why this isn't more common - it's just one more wire, after all.

I think I have a result at last, which others may find useful.

I take no great credit, I just adapted the standard clock I have used for years, and that was done largely by blunder.

The code is for Mega, using interrupt 4, being pin 19, which is right next to the I2C bus. using interrupt 0, pin 2, would work for both Mega and Uno. I guess it will work without change on a DS1307.

#include "Wire.h"
#define DS3231_ADDRESS 0x68
volatile bool ledstate = 0;
volatile bool interrupt = 1;

void setup(){
Wire.begin();
Serial.begin(9600);
pinMode(13, OUTPUT);//Led

Wire.beginTransmission(0x68); //DS3231 address
Wire.write(0x0E); //ADDRESS The configuration register
Wire.write(0); // DATA To enable the interrupt at 1Hz 
Wire.endTransmission();

attachInterrupt(4, rtc_interrupt, FALLING);// pin 19 Mega
//attachInterrupt(0, rtc_interrupt, FALLING); pin 2 Uno OR Mega
}
void loop(){
if (interrupt) 
 {
digitalWrite(13, ledstate);
//DO STUFF HERE
interrupt = 0;
printDate();// possibly redundant
 }
}

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

void printDate(){
// Reset the register pointer
Wire.beginTransmission(DS3231_ADDRESS);
byte zero = 0x00;
Wire.write(zero);
Wire.endTransmission();
Wire.requestFrom(DS3231_ADDRESS, 7);
int second = bcdToDec(Wire.read());
int minute = bcdToDec(Wire.read());
int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
int monthDay = bcdToDec(Wire.read());
int month = bcdToDec(Wire.read());
int year = bcdToDec(Wire.read());

Serial.print(month);
Serial.print("/");
Serial.print(monthDay);
Serial.print("/");
Serial.print(year);
Serial.print(" ");
Serial.print(hour);
Serial.print(":");
Serial.print(minute);
Serial.print(":");
Serial.println(second);
}

void rtc_interrupt()
{
ledstate = !ledstate;
interrupt = 1;
} 

Is that correct ?

It make more sense to use the digitalPinToInterrupt() function rather than the interrupt number to avoid any confusion

OK, I will look at that. I think I saw somebody else do it, and I will go with anything to make this painless.

(from Sami Hamdi)
Board....int.0 int.1 int.2 int.3 int.4 int.5
Uno, EtherTen,
Mini............2.... 3
Mega2560 2.....3.....21.....20....19......18

My apologies, interrupt 4 is on pin 19, but using digitalPinToInterrupt() is still a good idea

OK. Here is the modified code. It makes a long line but is simpler - one less number......

#include "Wire.h"
#define DS3231_ADDRESS 0x68
volatile bool ledstate = 0;
volatile bool interrupt = 1;
const byte interruptPin = 19;  // For Mega only. Pin 2 or 3 for both Uno and Mega

void setup(){
Wire.begin();
Serial.begin(9600);
pinMode(13, OUTPUT);//LED

Wire.beginTransmission(0x68); //DS3231 address
Wire.write(0x0E); //ADDRESS    The configuration register
Wire.write(0);      // DATA    To enable the interrupt at 1Hz 
Wire.endTransmission();

attachInterrupt(digitalPinToInterrupt(interruptPin), rtc_interrupt, FALLING);
}

void loop(){
if (interrupt) 
 {
digitalWrite(13, ledstate);
//DO STUFF HERE
interrupt = 0;
printDate();// possibly redundant
 }
}

byte bcdToDec(byte val) // Only used if you use the printDate srtn below
{
// Convert binary coded decimal to normal decimal numbers
return ( (val/16*10) + (val%16) );
}

void printDate(){
// Reset the register pointer
Wire.beginTransmission(DS3231_ADDRESS);
byte zero = 0x00;
Wire.write(zero);
Wire.endTransmission();
Wire.requestFrom(DS3231_ADDRESS, 7);
int second = bcdToDec(Wire.read());
int minute = bcdToDec(Wire.read());
int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
int monthDay = bcdToDec(Wire.read());
int month = bcdToDec(Wire.read());
int year = bcdToDec(Wire.read());

Serial.print(month);
Serial.print("/");
Serial.print(monthDay);
Serial.print("/");
Serial.print(year);
Serial.print(" ");
Serial.print(hour);
Serial.print(":");
Serial.print(minute);
Serial.print(":");
Serial.println(second);
}

void rtc_interrupt()
{
ledstate = !ledstate;
interrupt = 1;
} 

Do you see that square wave? Does it toggle the LED?

Your code works on an UNO using pin 2 for the interrupt input.

a7

Yes. On a Mega, if the serial is transmitting, it looks like the LED is moving. I guess a Uno will be the same.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.