DS3231 OLED Alarm Clock With 2-button Menu Setting and Temperature Display

103,160

275

119

Introduction: DS3231 OLED Alarm Clock With 2-button Menu Setting and Temperature Display

UPDATE: V1.3 of clock packages uploaded with bug fix and enhancements. See below for details,

Video at:: http://youtu.be/ikNw1iLE9vg

Alarm demo video: http://youtu.be/jlZBCuQeswA

This is an OLED alarm clock I built using an Arduino Micro, a tiny OLED 128x64 display using the SSD1306 controller and I2C interface, and a precision DS3231-based real-time clock module with rechargeable battery backup. It features a menu system for setting the RTC (no serial port or USB required)

Two versions are shown - the basic digital/analog clock and a version with "Pusheen" graphics and animation.

It uses the Adafruit graphics libraries and DS3231 library, included in the distribution.

Code for both, including needed libraries, may be downloaded directly from the link below in Step 4.

v1.3

I fixed a problem with the v1.2 code that would cause compilation errors for any non-ATmega32U4 Arduino. I had added a compact "note" function to generate a frequency on Pin 10 if the "speaker" alarm output option was selected. The function I included uses the timer structures for ATmega32U4. In v1.3, I added a non-ATmega32U4 version of the "note" function and added conditional compilation directives to automatically compile the correct version. I also compile the "note" function only if the "speaker" output is selected, saving memory if any other output option is selected. I tested the code with all board types in the IDE and received no compilation errors.


v1.2

I fixed a bug that would cause the alarm to timeout after less than the full 60 seconds if the previous alarm was silenced with a button press.

The status of alarm enable/disable is now stored in EEPROM and will survive a power failure. Previously, the alarm was always enabled after a power failure.

If the clock is left in setting mode, it will return to the normal display after 30 seconds without a button press.

I moved the alarm enable/disable indicator from the analog clock to between the time and temperature.

When the alarm sounds, the entire display now flashes in inverse/normal video at 5 Hz until the alarm is silenced. Previously, an asterisk flashed within the analog clock.

There is an optional feature to dim the display between 10 PM and 5 AM. Uncomment this line at the beginning of the program to enable this feature.

//#define dimming

The behavior of the alarm output at Pin 10 of the Arduino can be selected by uncommenting ONE of the following lines at the beginning of the code:

The first option is the default and supplies an intermittent (5 Hz) voltage on pin 10 when the alarm is triggered.

//#define beeper //Uncomment if 5 volt continuous tone beeper or buzzer is connected to pin 10 (5 Hz output)

The second option supplies an intermittent (5 Hz) 1580 Hz tone on pin 10 when the alarm is triggered. Pin 10 should be connected to the + terminal of the speaker through a 0.5 to 1.0 microfarad capacitor and possibly a 150 ohm resistor. The capacitor blocks DC voltage from the speaker to preserve the magnet in the speaker from damage. Piezo speakers may be connected directly to Pin 10. Use the resistor for low-impedance (< 150 ohm) speakers.

//#define speaker //Uncomment if speaker is connected to pin 10 through 1 microfarad capacitor and 100 ohm resistor in series (1480 Hz at 5 Hz output)

The final option provides a steady +5 volts on Pin 10 as long as the alarm is active. The voltage drops to zero when the alarm is silent.

//#define voltage //Uncomment if pin 10 is connected to alarm device requiring steady output while alarm is activated

Step 1: Connect the DS3231 Module and 128x64 OLED Module to the Arduino

  • Connect ground connection from Arduino to the DS3231 RTC module and OLED display.
  • Connect +5v from the Arduino to the +5v connections on the DS3231 RTC module and OLED display.
  • Connect the pin assigned to the SCL function on your Arduino to the SCL pins on both the DS3231 module and the OLED display.
  • Connect the pin assigned to the SDA function on your Arduino to the SDA pins on both the DS3231 module and the OLED display.
  • Connect one side of two SPST normally open push buttons to an Arduino ground connection.
  • Connect the other side of one push button to pin 8 of the Arduino. This is the time/date/alarm set mode select button.
  • Connect the other side of the other push button to pin 9 of the Arduino. This is the time/date/alarm set change button.
  • Connect the black wire on a piezo 5 volt buzzer/beeper to the Arduino ground connection. Connect the red wire from the piezo buzzer/beeper to pin 10 of the Arduino. Be sure to use a piezo beeper (NOT a piezo speaker) that generates its own tone when 5 volts is applied. If you use a piezo speaker instead of a piezo beeper, it will only click rapidly when the alarm is triggered. A unit that sounds continuously when power is applied is best, as the code generates a 5Hz interrupted voltage source to pin 10 on its own. NEW!!! Speaker and continuous alarm output now supported. See Step 1 for details on how to enable.
  • Download either the regular or "Pusheen" version of the clock code from here or the link in the introduction.
  • Install the Arduino libraries in the software distribution .zip file.
  • Compile and download the code to your Arduino. The clock and display will start to run. NEW!!! Optional night display dimming supported. See Step 1 for details on how to enable.
  • Set the clock and alarm per the instructions in the next step.

Step 2: Set Your Clock

  • Press the mode set button , then release. The cursor will flash on the day-of-week field. Press and hold the set button to advance the day-of week to the next day at a 5Hz rate, or do a short press to advance to the next setting. Note: the RTC will use whatever day-of-week you set. It will not automatically calculate the day-of-week for the date and year.
  • Press and release the mode set button to advance the cursor to the month field. Press and hold the set button to scroll through the months quickly, or do a short press to advance to the next setting.
  • Press and release the mode set button to advance the cursor to the date field. Press and hold the set button to scroll through the dates quickly, or do a short press to advance to the next setting. Note that the clock chip knows the correct number of days in each month. However, you can set an illegal date for months with less than 31 days, like "February 30". If you do, the clock will advance the date at midnight until the 31st is reached, then roll over to the first. Thereafter, the date will roll over to 1 at the correct date for the set month. Just don't set an illegal date and all will be well!
  • Press and release the mode set button to advance the cursor to the year field. Press and hold the set button to scroll through the years quickly, or do a short press to advance to the next setting. Valid ranges are 2000 to 2099. The RTC keeps track of leap years automatically. When you first power up the clock, the date will be January 1, 1900. Just advance the year to the correct value as normal.
  • Press and release the mode set button to advance the cursor to the hour field. Press and hold the set button to scroll through the hours quickly, or do a short press to advance to the next setting. The clock uses only the 12--hour mode with AM/PM indications.
  • Press and release the mode set button to advance the cursor to the minutes field. Press and hold the set button to scroll through the minutes quickly, or do a short press to advance to the next setting.
  • Press and release the mode set button to advance the cursor to the seconds field. Press the button momentarily to reset the seconds to zero, or hold the button to freeze the seconds at zero and release to synchronize with an external time source.
  • Press and release the mode set button to advance to the alarm setting screen. Press and hold the set button to scroll through the alarm hours setting quickly, or do a short press to advance to the next setting.
  • Press and release the mode set button to advance to the alarm minutes setting field.Press and hold the set button to scroll through the alarm minutes setting quickly, or do a short press to advance to the next setting.

  • Press and release the mode set button to advance to the alarm enable/disable field. Press and hold the set button to toggle repeatedly between alarm on and off settings, or do a short press to advance to the alternate setting. Note that when the alarm is on, an asterisk appears between the time and temperature. When the alarm is triggered, the entire display flashes in inverse video. The piezo buzzer will also beep at a 5 Hz rate (default option). The alarm will time out after 60 seconds if not manually silenced. A short press of the set button silences the alarm, leaving it on for the next day. In the event of a power failure, the alarm enable flag state is stored in EEPROM and restored on power-up. If an alarm has occurred during the power failure and the alarm was enabled, the alarm will sound immediately when power is restored. The alarm will sound, even if the clock is left in the setting modes.

  • Press and release the mode set button to return to normal mode. The display will automatically exit setting mode 30 seconds after the last button press.

Step 3: Technical Details

The software enables a very accurate 1Hz PPS signal on the "SQW" pin of the DS3231 module.

The DS3231 module uses the temperature sensor to compensate for clock drift, keeping time accurate to 1 or 2 minutes/year.

The temperature is normally checked and updated by the RTC once every 64 seconds. However, the software forces a temperature reading and oscillator adjustment as often as 5 times/second. This results in better accuracy and faster updating of the temperature display.

The on-board battery is not a disposable Lithium, but a rechargeable Lithium Ion unit. When connected to power, the RTC module charges the battery. A fully charged battery will maintain the time setting for up to one year without applying additional power.

You can "freeze" the display at any point by pressing and holding the mode set button. When the button is released, updating will resume. Clock accuracy is not affected.

The clock module contains a 32K EEPROM chip that can be used for data storage. It has an independent I2C address. It is not used for this project.

The code should work with the Sparkfun Chronodot module.

Step 4:

Code and library downloads, in .zip archive.....

Make it Glow!

Participated in the
Make it Glow!

9 People Made This Project!

Recommendations

  • Battery Powered Contest

    Battery Powered Contest
  • Plywood Challenge

    Plywood Challenge
  • Plastic Contest

    Plastic Contest

119 Discussions

0
john_aek
john_aek

5 years ago on Step 4

Arduino: 1.6.3 (Windows 7), Board: "Arduino Uno"

Build options changed, rebuilding all

Pusheen_Clock_Generic.ino: In function 'void set_alarm()':

Pusheen_Clock_Generic.ino:759:54: error: cannot convert 'boolean* {aka bool*}' to 'const uint8_t* {aka const unsigned char*}' for argument '5' to 'void DS3231_set_a1(uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*)'

Multiple libraries were found for "Adafruit_GFX.h"

Used: C:\Users\johnp51\Documents\Arduino\libraries\GFX

Not used: C:\Users\johnp51\Documents\Arduino\libraries\Adafruit-GFX-Library-master

Multiple libraries were found for "Adafruit_SSD1306.h"

Used: C:\Users\johnp51\Documents\Arduino\libraries\Adafruit_SSD1306-master

Not used: C:\Users\johnp51\Documents\Arduino\libraries\oled

Error compiling.

This report would have more information with

"Show verbose output during compilation"

enabled in File > Preferences.

0
df99
df99

Reply 5 years ago on Introduction

I uploaded new packages with both errors fixed. It should work with old and new IDE versions.

0
df99
df99

Reply 5 years ago

The code for both versions is found on the last step of the Instructable. I tested just now. Both download links work fine.

0
fkhan56
fkhan56

Reply 3 years ago

Nice work! I just made one on proto board. Could you please kindly tell me where I can find the generic code with alarm and without pusheen? both codes are same on this page. I would like to incorporate it in an application with rotary encoder and data input with one hour to 24 hour alarm duration. That would be very useful in animal feed management. I have a feeder designed to feed my pigeons and dogs while I am away.

Hope to hear from you soon.

My best regards.

Felix

0
JohnO77
JohnO77

Reply 5 years ago

the code links are broken - can you provide the link for the non pusheen code?

0
df99
df99

Reply 5 years ago

The code for both versions is found on the last step of the Instructable. I tested just now. Both download links work fine.

0
df99
df99

Reply 5 years ago on Introduction

It appears the latest IDEs have stricter type checking and require the changes mentioned in these board postings

http://forum.arduino.cc/index.php?topic=309872.0

http://forum.arduino.cc/index.php?topic=309119.0

Try this:

Change this line in both of the clock sketches within the set_alarm() function::

boolean flags[5] = { 0, 0, 0, 1, 1 }; //Set alarm to trigger every 24 hours on time match

...to this:

byte flags[5] = { 0, 0, 0, 1, 1 }; //Set alarm to trigger every 24 hours on time match

ALSO:

In the Adafruit_SSD1306.h header file in the Adafruit library, change:

void dim(uint8_t contrast);

to:

void dim(boolean contrast);

The clock sketches now compile and run correctly with IDE v1.6.4.

In both cases the issue is a type mismatch between "boolean" and "uint8_t". v1.06 of the IDE allowed it, but the newer IDE versions do not.

Best,

Don

0
lkndave
lkndave

Reply 4 years ago

that fixed it. thanks v1.6.5

0
NoOne38
NoOne38

2 months ago

Hello,
Owl clock
I want to add a second alarm
what would be the addresses to put in the code please?
cordially

0
df99
df99

Reply 4 weeks ago

Adding a separate alarm is not that trivial, but I believe the RTC module has a second alarm capability. The entire user interface would need modification, as well as adding the interface to the RTC chip to access and control the second alarm. The documentation is readily available and my code is well-commented. Have at it!

0
NoOne38
NoOne38

Reply 4 weeks ago

j'ai fait cela et souhaiterai votre avis merci
////////////////////////////////////////////////////////////////
// Subroutine Valeur alarm 2 /////////////////////////////////
///////////////////////////////////////////////////////////////
void get_alarm2()
{
uint8_t n[3];
uint8_t t[3]; // minute,hour,day
uint8_t f[4]; // flags
uint8_t i;
Wire.beginTransmission(DS3231_I2C_ADDR); // 0x68
Wire.write(DS3231_ALARM2_ADDR); // 0x0B
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDR, 3);
for (i = 0; i <= 2; i++) {
n[i] = Wire.read();
f[i] = (n[i] & 0x80) >> 11;
t[i] = bcdtodec(n[i] & 0x7F);
}
f[3] = (n[2] & 0x40) >> 6;
t[2] = bcdtodec(n[2] & 0x3F);
wake_MINUTE2 = t[0];
wake_HOUR2 = t[1];
}

0
DaKramSta
DaKramSta

4 weeks ago

Is there a way to do this on a 128x32 without the analog clock.
I tried just commenting out the "clock face", but I just get the error
" error: 'get_alarm' was not declared in this scope "
" error: 'printDay' was not declared in this scope "
" error: 'printMonth' was not declared in this scope "
and a bunch of other errors that are defined and not commented out.

Does anyone know how to do this on a 128x32 without the analog clock face?
I want everything else to be the same, but fit 128x32 oled. thx


/*
// Now draw the clock face
display.drawCircle(display.width()/2, display.height()/2 + 8, 20, WHITE); //Draw and position clock outer circle
//display.fillCircle(display.width()/2+25, display.height()/2 + 8, 20, WHITE); //Fill circle only if displaying inverted colors
if(flash){display.drawCircle(display.width()/2, display.height()/2 + 8, 2, WHITE);} //Draw, position and blink tiny inner circle
display.drawRect(41,17,47,47,WHITE); //Draw box around clock
//Position and draw hour tick marks
for( int z=0; z < 360;z= z + 30 ){
//Begin at 0° and stop at 360°
float angle = z ;
angle=(angle/57.29577951) ; //Convert degrees to radians
int x2=(64+(sin(angle)*20));
int y2=(40-(cos(angle)*20));
int x3=(64+(sin(angle)*(20-5)));
int y3=(40-(cos(angle)*(20-5)));
display.drawLine(x2,y2,x3,y3,WHITE);
}
//Position and display second hand
float angle = t.sec * 6 ; //Retrieve stored seconds and apply
angle=(angle/57.29577951) ; //Convert degrees to radians
int x3=(64+(sin(angle)*(20)));
int y3=(40-(cos(angle)*(20)));
display.drawLine(64,40,x3,y3,WHITE);
//Position and display minute hand
angle = t.min * 6; //Retrieve stored minutes and apply
angle=(angle/57.29577951) ; //Convert degrees to radians
x3=(64+(sin(angle)*(20-3)));
y3=(40-(cos(angle)*(20-3)));
display.drawLine(64,40,x3,y3,WHITE);
//Position and display hour hand
angle = t.hour * 30 + int((t.min / 12) * 6); //Retrieve stored hour and minutes and apply
angle=(angle/57.29577951) ; //Convert degrees to radians
x3=(64+(sin(angle)*(20-11)));
y3=(40-(cos(angle)*(20-11)));
display.drawLine(64,40,x3,y3,WHITE);
}
*/



0
df99
df99

Reply 4 weeks ago

The code is customized to the specific dimensions of that specific OLED display, with hard-coded coordinates. It will not work on a display with any other pixel dimensions than the original display that I used. Different display controller types supported by the graphics library MIGHT work by changing the display definition, but the pixel dimensions would need to remain the same for everything to be in its proper place and the animations to work. The code is commented well enough, you should be able to make it work, but it will require considerable effort and recoding of the image files to fit the new display dimensions.

0
EduardoG89
EduardoG89

8 months ago

Hello, excellent project, but I need to program around 11 different alarms, I have the idea of duplicating only the "set alarm" and "get alarm" sub routines, but I'm not sure if that would work because I would also need to display each alarm on the screen to configure them, can someone help me please? Thanks in advance.

0
karnyupin1
karnyupin1

1 year ago

thank you

0
df99
df99

Reply 1 year ago

You're welcome!

0
youbet1
youbet1

Question 1 year ago

I have been able to completely set it up here myself. I want to include a stopwatch functionality. Can you help me with that please.