{"id":23530,"date":"2025-04-11T15:53:13","date_gmt":"2025-04-11T15:53:13","guid":{"rendered":"https:\/\/wolles-elektronikkiste.de\/?p=23530"},"modified":"2025-04-19T21:06:32","modified_gmt":"2025-04-19T21:06:32","slug":"ds3231-based-alarm-clock","status":"publish","type":"post","link":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock","title":{"rendered":"DS3231-based alarm clock"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">About this Post<\/h2>\n\n<p>In this article, I would like to introduce you to concepts for a DS3231-based alarm clock. I have already reported on the DS3231 real-time clock module in detail <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-real-time-clock\" target=\"_blank\" rel=\"noopener\">here<\/a>, including the alarm function. I have now dedicated a separate article to the alarm clock, as it is a certain challenge to implement settings such as the time, the alarm time or the snooze function with just a few buttons. I will also show you how you can reduce the power requirement to such an extent that you can operate the alarm clock with batteries.<\/p><p>You will also learn about the Nokia 5110 display and the EA DOG display series. And finally, you will learn how to send an Arduino Pro Mini into deep sleep mode and wake it up again. All in one post!<\/p><p> <strong>Expectation management<\/strong>: This article is not a ready-made blueprint for an alarm clock with circuit board layout, 3D print template, etc. I have also refrained from defining the acoustic alarm. For me, it was about addressing the biggest stumbling blocks from my point of view. I&#8217;ll leave the rest to your creativity.<\/p>\n\n<ul>\r\n<li><a href=\"#basic_clock\">Preparation: the &#8220;basic clock&#8221; (version 1)<\/a><\/li>\r\n<li><a href=\"#alarm_clock_version_2\">Alarm clock &#8211; Version 2 with two buttons<\/a><\/li>\r\n<li><a href=\"#alarm_clock_v3\">Alarm clock &#8211; Version 3 with two buttons and a slide switch<\/a><\/li>\r\n<li><a href=\"#power_consumption_v1_v3\">Power consumption of versions 1 &#8211; 3<\/a><\/li>\r\n<li><a href=\"#concept_for_battery_use\">Concept for battery operation<\/a><\/li>\r\n<li><a href=\"#alarm_clock_v4\">Alarm clock &#8211; Version 4 with Nokia 5110 display<\/a><\/li>\r\n<li><a href=\"#alarm_clock_v5\">Alarm clock &#8211; Version 5 with DOGS164 display<\/a><\/li>\r\n<li><a href=\"#alarm_clock_v6\">Alarm clock -Version 6 with ST7567 based display<\/a><\/li>\r\n<li><a href=\"#transfer_to_other_boards\">Transfer of the concept to other boards<\/a><\/li>\r\n<li><a href=\"#appendix_1\">Appendix 1: &#8220;Repair&#8221; of the Nokia 5110 display<\/a><\/li>\r\n<li><a href=\"#appendix_2\">Appendix 2: Alternative versions of the Nokia 5110 display<\/a><\/li>\r\n<li><a href=\"#appendix_3\">Appendix 3: A simple clock using an e-paper display<\/a><\/li>\r\n<\/ul>\n\n<h2 class=\"wp-block-heading\" id=\"basic_clock\">Preparation: the &#8220;basic clock&#8221; (version 1)<\/h2>\n\n<p>I will not go into detail about the DS3231 module in this article. Take a look <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-real-time-clock\" target=\"_blank\" rel=\"noopener\">here<\/a> if you want to find out more. Nevertheless, to start with, we will begin by \u2018warming up\u2019 with the bare clock without any setting functions.<\/p><p>I am initially using a classic Arduino Nano to control the project. An I2C-controlled LCD is used as the display. You can replace the board and display relatively easily with your favorite devices &#8211; as long as we don&#8217;t go into battery operation.<\/p><p>I use Adafruit&#8217;s <a href=\"https:\/\/github.com\/adafruit\/RTClib\" target=\"_blank\" rel=\"noopener\">RTCLib<\/a> library to control the DS3231 module. You can install it via the library manager of the Arduino IDE. The same applies to the <a href=\"https:\/\/github.com\/johnrickman\/LiquidCrystal_I2C\" target=\"_blank\" rel=\"noopener\">LiquidCrystal_I2C<\/a> library from John Rickman, which I use to control the LCD.<\/p><p>All components run on 5 volts and are controlled via I2C, which makes wiring simple:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_basic_clock-1024x380.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"380\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_basic_clock-1024x380.png\" alt=\"Basic circuit for the DS3231 alarm clock\" class=\"wp-image-23371\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_basic_clock-1024x380.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_basic_clock-300x111.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_basic_clock-768x285.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_basic_clock-1320x490.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_basic_clock.png 1390w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock, version 1 &#8211; Basic circuit<\/figcaption><\/figure>\n\n<p>I use the DS3231 module without a battery. Applying battery <em>and<\/em> external power supply is not a good idea (see my <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-real-time-clock\" target=\"_blank\" rel=\"noopener\">DS3231 article<\/a>).<\/p>\n\n<p>Here is the corresponding sketch:<\/p>\n\n<div class=\"scroll-paragraph-long\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"basic_clock.ino\" data-enlighter-title=\"basic_clock.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;RTClib.h&gt; \/\/ Adafruit library for the DS3231\r\n#include &lt;LiquidCrystal_I2C.h&gt; \/\/ library for the LCD display\r\n\r\nRTC_DS3231 rtc;  \/\/ create RTC_DS3231 object\r\nLiquidCrystal_I2C lcd(0x27,20,2);  \/\/ create display object (address, columns, rows)\r\n\r\nvoid setup () {\r\n    Serial.begin(115200);\r\n\r\n    lcd.init(); \r\n    lcd.backlight();\r\n    lcd.clear();\r\n\r\n    if (! rtc.begin()) {\r\n        Serial.println(F(\"Couldn't find RTC\"));\r\n        while(1){}\r\n    }\r\n    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));  \/\/ set rtc to date\/time of compilation\r\n    rtc.disable32K();  \/\/ stop signal at the 32K pin\r\n    rtc.writeSqwPinMode(DS3231_OFF); \/\/ stop signal at the SQW pin\r\n}\r\n\r\nvoid loop() {\r\n    if(millis()%1000 == 0){ \/\/ update date\/time every second\r\n        printDateTime();\r\n        delay(1);\r\n    }\r\n}\r\n\r\nvoid printDateTime(){\r\n    DateTime now = rtc.now();\r\n\r\n    char datBuf[] = \"DDD, DD.MM.YYYY\"; \/\/ define the date format\r\n    char timeBuf[] = \"hh:mm:ss\"; \/\/ define the time format\r\n    Serial.println(now.toString(datBuf)); \/\/ print date\r\n    Serial.println(now.toString(timeBuf));  \/\/ print time\r\n    lcd.setCursor(0,0);\r\n    lcd.print(datBuf);  \/\/ display date \r\n    lcd.setCursor(0,1);\r\n    lcd.print(timeBuf);  \/\/ display time\r\n}\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div><br>\n\n<p>The current time is set with <code>rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));<\/code>. This is the system time of your computer when the sketch is compiled. Since the upload takes some time, the clock is somewhat delayed.<\/p><p>Here is the result on the display:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1-1024x182.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"182\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1-1024x182.jpg\" alt=\"Alarm clock: Display of date and time. \" class=\"wp-image-23360\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1-1024x182.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1-300x53.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1-768x136.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1-1536x273.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1-1320x234.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_normal-1.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Output on the LCD<\/figcaption><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"alarm_clock_version_2\">Alarm clock &#8211; Version 2 with two buttons<\/h2>\n\n<h3 class=\"wp-block-heading\" id=\"concept\">The operating concept<\/h3>\n\n<p>In version 2, we turn our clock into an alarm clock. The clock time and the alarm time are set using two buttons. Here is the circuit:<\/p>\n\n<p><\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons-1024x368.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"368\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons-1024x368.png\" alt=\"Circuit for the DS3231 alarm clock with two buttons.\" class=\"wp-image-23352\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons-1024x368.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons-300x108.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons-768x276.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons-1536x552.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons-1320x474.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_2_buttons.png 1573w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock, version 2 &#8211; circuit with two buttons<\/figcaption><\/figure>\n\n<p>The buttons have dual functions:<\/p><ul>\r\n<li>Button 1 &#8211; &#8220;Item Key&#8221;:<ul>\r\n<li>Press for 1 second to enter the time setting mode.<\/li>\r\n<li>In time setting mode, the time units year, month, day, hour and minute are set one after the other. Press briefly to accept the setting and move to the next time unit (\u2018Item\u2019).<\/li>\r\n<li>In the alarm setting mode, you can set the hour and minute and activate the alarm.<\/li>\r\n<li>When the minutes are confirmed, the seconds are set to zero.<\/li><\/ul><\/li><li>\r\nButton 2 &#8211; &#8220;Value Key&#8221;:<ul>\r\n<li>Press for 1 second to enter the alarm setting mode.<\/li><li>\r\nIn the mode for setting the time and alarm clock, briefly pressing the button increases the setting value by 1 up to the maximum value. If the maximum value is exceeded, the setting value returns to the minimum value.<\/li><\/ul><\/li><\/ul>\n\n<h4 class=\"wp-block-heading\" id=\"time_setting\">Time setting<\/h4>\n\n<p>Once again, in detail: If you press the &#8220;Item Key&#8221;, the display will ask you to do so for one second. When the following message appears, release it:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time-1024x181.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"181\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time-1024x181.jpg\" alt=\"Time setting mode is started\" class=\"wp-image-23376\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time-1024x181.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time-300x53.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time-768x136.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time-1536x272.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time-1320x234.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_se_date_time.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Time setting mode is started<\/figcaption><\/figure>\n\n<p>At first, if necessary, you can set the year. Pressing the &#8220;Value Key&#8221; increases the year by 1. Pressing it continuously increases the value in a continuous loop. After 2050, the value returns to 2025. Pressing the &#8220;Item Key&#8221; accepts the value. Then it&#8217;s the turn of the months, then the day and so on down to the minutes:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins-1024x182.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"182\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins-1024x182.jpg\" alt=\"Time setting - minutes\" class=\"wp-image-23378\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins-1024x182.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins-300x53.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins-768x136.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins-1536x273.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins-1320x234.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_mins.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Time setting mode: Example minutes<\/figcaption><\/figure>\n\n<p>As the seconds are &#8220;zeroed&#8221; when the minutes are confirmed, you can set the time to the exact second.<\/p>\n\n<h4 class=\"wp-block-heading\" id=\"alarm_setting\">Alarm setting<\/h4>\n\n<p>The DS3231 is very flexible when it comes to setting alarms (see <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-real-time-clock\" target=\"_blank\" rel=\"noopener\">my article<\/a> on this). I have decided to only implement a daily alarm at a specific time. If you press the &#8220;Value Key&#8221; for one second, you enter the alarm setting mode:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm-1024x180.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"180\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm-1024x180.jpg\" alt=\"Alarm setting mode is started\" class=\"wp-image-23380\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm-1024x180.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm-300x53.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm-768x135.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm-1536x270.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm-1320x232.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm setting mode is started. <\/figcaption><\/figure>\n\n<p>As in time setting mode, you increment the value with the &#8220;Value Key&#8221; and accept it with the &#8220;Item Key&#8221;. You do this down to the minutes:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins-1024x178.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"178\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins-1024x178.jpg\" alt=\"Alarm setting mode: Example minutes\" class=\"wp-image-23384\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins-1024x178.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins-300x52.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins-768x134.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins-1536x267.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins-1320x230.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_set_alarm_mins.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm setting mode: Example minutes<\/figcaption><\/figure>\n\n<p>The alarm time and the activation status then appear on the display:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm-1024x179.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"179\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm-1024x179.jpg\" alt=\"Alarm setting mode: Completion\" class=\"wp-image-23386\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm-1024x179.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm-300x52.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm-768x134.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm-1536x268.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm-1320x230.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_activate_alarm.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm setting mode: Completion<\/figcaption><\/figure>\n\n<p>If you now press the &#8220;Value Key&#8221;, the display changes from &#8220;Activate: no&#8221; to &#8220;Activate: yes&#8221;. Press the &#8220;Item Key&#8221; to complete the setting. The time appears on the display again, and the activated alarm is indicated by an &#8220;A&#8221; at the bottom right:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated-1024x181.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"181\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated-1024x181.jpg\" alt=\"Date\/time with activated alarm\" class=\"wp-image-23388\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated-1024x181.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated-300x53.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated-768x136.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated-1536x271.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated-1320x233.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_activated.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Date\/time with activated alarm<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\" id=\"alarm_event\">Alarm event<\/h3>\n\n<p>When the alarm goes off, the following display flashes:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2-1024x180.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"180\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2-1024x180.jpg\" alt=\"Alarm was triggered\" class=\"wp-image-23391\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2-1024x180.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2-300x53.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2-768x135.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2-1536x270.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2-1320x232.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_alarm_2.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm was triggered<\/figcaption><\/figure>\n\n<p>Of course, just a flashing display would not wake you up. This is where you need to expand the concept accordingly, for example to wake you up with your favorite song. You could use an MP3 player module such as the <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/arduino-controlled-dfplayer-mini\" target=\"_blank\" rel=\"noopener\">DFPlayer Mini<\/a> or the <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/mp3-player-yx5300\" target=\"_blank\" rel=\"noopener\">YX5300<\/a>.<\/p>\n\n<p>I have programmed the alarm to stop by itself after 60 seconds. If you are not at home and your alarm clock makes a lot of noise, your neighbors will be grateful for this function. You can extend the maximum alarm period as you wish (<code>#define MAX_ALARM_DURATION<\/code>).<\/p><p>\r\nIf the maximum alarm time has not yet been exceeded, you can switch to snooze mode by briefly pressing one of the two buttons. I have preset the snooze time to one minute. It starts at the time you press the button. After the snooze time has elapsed, a new alarm goes off.<\/p><p>Snooze mode is indicated by an &#8220;S&#8221; on the display:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze-1024x183.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"183\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze-1024x183.jpg\" alt=\"Display in snooze mode\" class=\"wp-image-23394\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze-1024x183.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze-300x54.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze-768x137.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze-1536x275.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze-1320x236.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_alarm_clock_snooze.jpg 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Date\/time in snooze mode<\/figcaption><\/figure>\n\n<p>To switch off the alarm, go to the alarm settings mode and switch to the &#8220;Activate: no&#8221; setting.<\/p>\n\n<h3 class=\"wp-block-heading\" id=\"sketch_version_2\">The alarm clock sketch (version 2)<\/h3>\n\n<p>Here is the sketch for version 2:<\/p>\n\n<div class=\"scroll-paragraph-long\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ds3231_alarm_clock.ino\" data-enlighter-title=\"ds3231_alarm_clock.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;RTClib.h&gt;  \/\/ library for the DS3231\r\n#include &lt;LiquidCrystal_I2C.h&gt;  \/\/ library for the LCD display\r\n#define SNOOZE_TIME 60  \/\/ set snooze time in seconds \r\n#define SET_INCREMENT_DELAY 260 \/\/ incrementation time for settings\r\n#define MAX_ALARM_DURATION 60000  \/\/ maximum duration of an alarm in milliseconds\r\nvolatile bool setItemKeyPressed = false; \/\/ flag for item key\r\nvolatile bool setValueKeyPressed = false; \/\/ flag for value key\r\nvolatile unsigned long lastLow; \/\/ needed to handle bouncing\r\nbool alarmOn = false;  \/\/ alarm activated?\r\nconst int setItemPin = 2; \/\/ choose item to set \/ time setting mode\r\nconst int setValuePin = 3; \/\/ set (increment) value \/ alarm setting mode\r\n\r\ntypedef enum TIME_UNIT { \/\/ needed for struct \"timeElement\"\r\n    YEAR, MONTH, DAY, HOUR, MINUTE, SECOND\r\n} timeUnit;\r\n\r\ntypedef enum SET_MODE { \/\/ setting modes\r\n    DATE_TIME, ALARM\r\n} setMode;\r\n\r\nstruct timeElement{  \/\/ for date\/time\/alarm setting\r\n    timeUnit tUnit;  \r\n    uint16_t tMin; \/\/ minimum value\r\n    uint16_t tMax; \/\/ maximum value\r\n    char tname[7]; \/\/ name to display\r\n};\r\n\r\ntimeElement tElementYear = {YEAR, 2025, 2050, \"Year\"};\r\ntimeElement tElementMonth = {MONTH, 1, 12, \"Month\"};\r\ntimeElement tElementDay = {DAY, 1, 31, \"Day\"};\r\ntimeElement tElementHour = {HOUR, 0, 23, \"Hour\"};\r\ntimeElement tElementMinute = {MINUTE, 0, 59, \"Minute\"};\r\n\r\nRTC_DS3231 rtc;  \/\/  \/\/ create RTC_DS3231 object\r\nDateTime alarmTime = DateTime(2014, 1, 1, 7, 0, 0);\r\nLiquidCrystal_I2C lcd(0x27,20,2); \/\/ create display object (address, columns, rows)\r\n\r\nvoid setup () {\r\n    Serial.begin(115200);\r\n\r\n    lcd.init(); \r\n    lcd.backlight();\r\n    lcd.clear();\r\n\r\n    if (! rtc.begin()) {\r\n        Serial.println(F(\"Couldn't find RTC\"));\r\n        while(1){}\r\n    }\r\n    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); \/\/ \/\/ set rtc to date\/time of compilation\r\n    rtc.disable32K(); \/\/ stop signal at the 32K pin\r\n    rtc.clearAlarm(1); \/\/ clear alarm\r\n    rtc.clearAlarm(2);\r\n    rtc.disableAlarm(1);  \/\/ disable alarm function\r\n    rtc.disableAlarm(2);\r\n    rtc.writeSqwPinMode(DS3231_OFF); \/\/ stop signal at the SQW pin\r\n    \r\n    \/* pressing the item or value button will cause a low signal at the corresponding pin\r\n       and trigger an interrupt *\/\r\n    pinMode(setItemPin, INPUT_PULLUP); \r\n    pinMode(setValuePin, INPUT_PULLUP);\r\n    attachInterrupt(digitalPinToInterrupt(setItemPin), setItemKeyISR, FALLING);\r\n    attachInterrupt(digitalPinToInterrupt(setValuePin), setValueKeyISR, FALLING);\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid loop() {\r\n    if(millis()%1000 == 0){ \/\/ update date\/time every second\r\n        printDateTime();\r\n        delay(1); \/\/ avoids multiple updates per second\r\n    }\r\n    \r\n    if(setItemKeyPressed){ \/\/ item key = date\/time setting key\r\n        goIntoSetMode(DATE_TIME);\r\n    }\r\n\r\n    if(setValueKeyPressed){  \/\/ value key = alarm key\r\n        goIntoSetMode(ALARM); \r\n    }\r\n    \r\n    if(rtc.alarmFired(1) &amp;&amp; alarmOn){\r\n        alarmAction();   \/\/ act on alarm\r\n    }\r\n}\r\n\r\nvoid goIntoSetMode(setMode settingMode){\r\n    lcd.clear();\r\n    lcd.setCursor(0,0);\r\n    lcd.print(F(\"Press 1 sec\"));\r\n    delay(1000); \/\/ press 1 second to go into setting mode\r\n    if (digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){\r\n        lcd.setCursor(0,0);\r\n        lcd.print(F(\"Setting Mode\"));\r\n        lcd.setCursor(0,1);\r\n        if(settingMode == DATE_TIME){\r\n            lcd.print(F(\"Date\/Time\"));\r\n        }\r\n        else{\r\n            lcd.print(F(\"Alarm\"));\r\n        }\r\n        \/* wait until button is released *\/\r\n        while(digitalRead(setItemPin) == LOW){}\r\n        while(digitalRead(setValuePin) == LOW){}\r\n        delay(50); \/\/ debouncing\r\n        if(settingMode == DATE_TIME){\r\n            setDateTime();\r\n        }\r\n        else{\r\n            setAlarmTime();\r\n        }\r\n    }\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid setDateTime(){ \/\/ date\/time setting procedure\r\n    DateTime now = rtc.now();  \/\/ get current time\r\n    uint16_t tItem = 0;\r\n    tItem = setDateTimeElement(&amp;tElementYear, now.year());\r\n    adjustRTC(YEAR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMonth, now.month());\r\n    adjustRTC(MONTH, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementDay, now.day());\r\n    adjustRTC(DAY, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementHour, now.hour());\r\n    adjustRTC(HOUR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMinute, now.minute());\r\n    adjustRTC(MINUTE, tItem);\r\n    adjustRTC(SECOND, 0);\r\n    lcd.clear();\r\n    if(alarmOn){\r\n        lcd.setCursor(15,1);\r\n        lcd.print(\"A\"); \/\/ display \"alarm is on\" flag\r\n    }\r\n    printDateTime();\r\n}\r\n\r\nvoid setAlarmTime(){  \/\/ procedure to set an alarm\r\n    uint16_t value = 0;\r\n    value = setDateTimeElement(&amp;tElementHour, alarmTime.hour());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), value, alarmTime.minute(), 0);\r\n    value = setDateTimeElement(&amp;tElementMinute, alarmTime.minute());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), alarmTime.hour(), value, 0);\r\n    lcd.clear();\r\n    char alarmTimeBuf[] = \"hh:mm\";\r\n    alarmTime.toString(alarmTimeBuf);\r\n    lcd.setCursor(0,0);\r\n    lcd.print(\"Alarm: \");\r\n    lcd.print(alarmTimeBuf);\r\n    lcd.setCursor(0,1);\r\n    alarmOn = false;\r\n    lcd.print(F(\"Activate: no \"));\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n    while(!setItemKeyPressed &amp;&amp; !setValueKeyPressed){}\r\n    if(setValueKeyPressed){\r\n        setValueKeyPressed = false;\r\n        while(!setItemKeyPressed){\r\n            if(digitalRead(setValuePin) == LOW){\r\n                if(alarmOn){\r\n                    lcd.setCursor(10,1);\r\n                    lcd.print(\"no \");\r\n                    alarmOn = false;\r\n                    rtc.disableAlarm(1);\r\n                    delay(500); \r\n                }\r\n                else{\r\n                    lcd.setCursor(10,1);\r\n                    lcd.print(F(\"yes \"));\r\n                    alarmOn = true;\r\n                    rtc.setAlarm1(alarmTime, DS3231_A1_Hour);\r\n                    delay(500);\r\n                }\r\n            }           \r\n        }\r\n    }\r\n    lcd.clear();\r\n    if(alarmOn){\r\n        lcd.setCursor(15,1);\r\n        lcd.print(\"A\");\r\n    }\r\n    printDateTime();\r\n}\r\n\r\nvoid alarmAction(){\r\n    lcd.clear();\r\n    unsigned long alarmStart = millis();\r\n    \/* alarm was fired, not key pressed, and alarm did not exceed max. duration *\/\r\n    while(!setItemKeyPressed &amp;&amp; !setValueKeyPressed &amp;&amp; (millis() - alarmStart &lt; MAX_ALARM_DURATION)){\r\n        lcd.setCursor(5,0);\r\n        lcd.print(F(\"Alarm!\"));\r\n        delay(500); \r\n        lcd.clear();\r\n        delay(500);\r\n        if(millis() &lt; alarmStart) {   \/\/ if millis() overflow occured\r\n            alarmStart = 0;\r\n        }\r\n    }\r\n    \/* wait till buttons are released: *\/\r\n    while(digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){} \r\n    rtc.clearAlarm(1);\r\n    delay(50); \/\/ debouncing\r\n    DateTime now = rtc.now();\r\n    if(millis() - alarmStart &lt; MAX_ALARM_DURATION){\r\n        alarmTime = now + TimeSpan(SNOOZE_TIME); \/\/ set new alarm (snooze)\r\n        rtc.setAlarm1(alarmTime, DS3231_A1_Hour);\r\n        lcd.setCursor(15,1);\r\n        lcd.print(\"S\"); \/\/ display snooze flag\r\n    }\r\n    else{\r\n        alarmOn = false;\r\n    }\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\n\/* This functions sets a time element. Pressing the value key increments the value until\r\n   the maximum value is reached. Pressing the item key will return. *\/ \r\nuint16_t setDateTimeElement(timeElement *tE, uint16_t currentSet){\r\n    char buf[13];\r\n    clearLineLCD(0);\r\n    lcd.setCursor(0,0);\r\n    sprintf(buf, \"Set %s: \", tE-&gt;tname);\r\n    lcd.print(buf);\r\n    lcd.setCursor(12,0);\r\n    sprintf(buf, \"%02d\", currentSet);\r\n    lcd.print(buf);\r\n    setItemKeyPressed = false;\r\n    while(!setItemKeyPressed){    \r\n        if(setValueKeyPressed){\r\n            while(digitalRead(setValuePin) == LOW){\r\n                currentSet++;\r\n                if(currentSet &gt; tE-&gt;tMax){\r\n                    currentSet = tE-&gt;tMin;\r\n                }\r\n                lcd.setCursor(12,0);\r\n                sprintf(buf, \"%02d\", currentSet);\r\n                lcd.print(buf);\r\n                delay(SET_INCREMENT_DELAY);                \r\n            }\r\n        }\r\n    }\r\n    setItemKeyPressed = false;\r\n    return currentSet;\r\n}\r\n\r\nvoid printDateTime(){ \/\/ display date\/time \r\n    DateTime now = rtc.now();\r\n\r\n    char datBuf[] = \"DDD, DD.MM.YYYY\";  \/\/ define the date format\r\n    char timeBuf[] = \"hh:mm:ss\"; \/\/  \/\/ define the time format\r\n    Serial.println(now.toString(datBuf)); \/\/ print date\r\n    Serial.println(now.toString(timeBuf)); \/\/ print time\r\n    lcd.setCursor(0,0);\r\n    lcd.print(datBuf); \/\/ display date \r\n    lcd.setCursor(0,1);\r\n    lcd.print(timeBuf); \/\/ display time\r\n}\r\n\r\nvoid adjustRTC(timeUnit tU, uint16_t value){ \/\/ adjust year, month, day etc.\r\n    DateTime now = rtc.now();\r\n    switch(tU){\r\n        case(YEAR):\r\n            rtc.adjust(DateTime(value, now.month(), now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(MONTH):\r\n            rtc.adjust(DateTime(now.year(), value, now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(DAY):\r\n            rtc.adjust(DateTime(now.year(), now.month(), value, now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(HOUR):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), value, now.minute(), now.second()));\r\n            break;\r\n        case(MINUTE):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), value, now.second()));\r\n            break;\r\n        case(SECOND):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), value));\r\n            break;\r\n    }\r\n    delay(10);\r\n}\r\n\r\nvoid clearLineLCD(int line){ \/\/ clears on line on the display\r\n    char buf[17];\r\n    sprintf(buf, \"%16s\", \" \");\r\n    lcd.setCursor(0, line);\r\n    lcd.print(buf);\r\n}\r\n\r\nvoid setItemKeyISR(){ \/\/ ISR for pressed item key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setItemKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nvoid setValueKeyISR(){  \/\/ ISR for pressed value key\r\n    if(millis()-lastLow &gt;= 50){ \/\/ ignore bouncing when button is released\r\n        setValueKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div><br>\n\n<h4 class=\"wp-block-heading\" id=\"explanation_code_v2\">Explanations of the code<\/h4>\n\n<p>I don&#8217;t want to go through the sketch line by line and hope that it is reasonably understandable with the comments in the sketch and the following notes.<\/p><ul><li>\r\nThe push-buttons are located on interrupt pins 2 and 3. Pressing the push-buttons triggers an interrupt. In the ISR, the query <code>if(millis()-lastLow &gt;= 300)<\/code> ensures that bouncing is not evaluated as a button press when the button is released. <\/li>\r\n<li>If a valid interrupt is triggered, the corresponding flags are set (<code>setItemKeyPressed<\/code> \/ <code>setValueKeyPressed<\/code>), which causes the setting function <code>goIntoSetMode()<\/code> to be called (provided the sketch is in <code>loop()<\/code> ).<\/li>\r\n<li>from <code>goIntoSetMode()<\/code> it then goes to <code>setDateTime()<\/code> or <code>setAlarmTime()<\/code>. As the setting of years, months, days, hours and minutes always follows the same pattern, I have written the function <code>setDateTimeElement()<\/code> for this purpose. This function is passed a structure of the type <code>timeElement<\/code>, which specifies what the value is, its minimum and maximum and the designation on the display. Furthermore, the current value of the time element is passed and the value to be set is returned.   <\/li>\r\n<li>The value to be set is sent to the DS3231 using the function <code>adjustRTC()<\/code>.<\/li><\/ul>\n\n<h2 class=\"wp-block-heading\" id=\"alarm_clock_v3\">Alarm clock &#8211; Version 3 with two buttons and a slide switch<\/h2>\n\n<p>In version 2, I was annoyed by the process of switching off the alarm. I don&#8217;t like the idea of having to work my way through a setting procedure in the morning. That&#8217;s why, in version 3, I added a slide switch to Arduino pin 4 that turns the alarm on or off:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch-1024x355.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"355\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch-1024x355.png\" alt=\"Alarm clock, version 3 - extended by a slide switch\" class=\"wp-image-23399\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch-1024x355.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch-300x104.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch-768x266.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch-1536x532.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch-1320x457.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/DS3231_alarm_clock_with_switch.png 1588w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock, version 3 &#8211; extended by a slide switch<\/figcaption><\/figure>\n\n<p>Nothing else changes in the operation. In the sketch, the corresponding item at the end of the alarm time setting has been removed. However, it is now necessary to check in <code>loop()<\/code> whether the alarm has been switched on or off. To do this, the status of pin 4 is compared with the alarmOn flag.\r\n<\/p><br>\n\n<div class=\"scroll-paragraph-long\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ds3231_alarm_clock_with_switch.ino\" data-enlighter-title=\"ds3231_alarm_clock_with_switch.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;RTClib.h&gt;  \/\/ library for the DS3231\r\n#include &lt;LiquidCrystal_I2C.h&gt; \/\/ library for the LCD display\r\n#define SNOOZE_TIME 60  \/\/ set snooze time\r\n#define SET_INCREMENT_DELAY 260 \/\/ incrementation time for settings\r\n#define MAX_ALARM_DURATION 20000 \/\/ maximum duration of an alarm\r\nvolatile bool setItemKeyPressed = false; \/\/ flag for item key\r\nvolatile bool setValueKeyPressed = false; \/\/ flag for value key\r\nvolatile unsigned long lastLow; \/\/ needed to handle bouncing\r\nbool alarmOn = false; \/\/ alarm activated\r\nconst int setItemPin = 2; \/\/ choose item to set \/ time setting mode\r\nconst int setValuePin = 3; \/\/ set (increment) value \/ alarm setting mode\r\nconst int alarmPin = 4;  \/\/ Pin for the alarm switch\r\n\r\ntypedef enum TIME_UNIT { \/\/ needed for struct \"timeElement\"\r\n    YEAR, MONTH, DAY, HOUR, MINUTE, SECOND\r\n} timeUnit;\r\n\r\ntypedef enum SET_MODE { \/\/ setting modes\r\n    DATE_TIME, ALARM\r\n} setMode;\r\n\r\nstruct timeElement{ \/\/ for date\/time\/alarm setting\r\n    timeUnit tUnit;\r\n    uint16_t tMin; \/\/ minimum value\r\n    uint16_t tMax; \/\/ maximum value\r\n    char tname[7]; \/\/ name to display\r\n};\r\n\r\ntimeElement tElementYear = {YEAR, 2025, 2050, \"Year\"};\r\ntimeElement tElementMonth = {MONTH, 1, 12, \"Month\"};\r\ntimeElement tElementDay = {DAY, 1, 31, \"Day\"};\r\ntimeElement tElementHour = {HOUR, 0, 23, \"Hour\"};\r\ntimeElement tElementMinute = {MINUTE, 0, 59, \"Minute\"};\r\n\r\nRTC_DS3231 rtc;   \/\/ create RTC_DS3231 object\r\nDateTime alarmTime = DateTime(2014, 1, 1, 7, 0, 0);\r\nLiquidCrystal_I2C lcd(0x27,20,2);  \/\/ create display object (address, columns, rows)\r\n\r\nvoid setup () {\r\n    Serial.begin(115200);\r\n\r\n    lcd.init(); \r\n    lcd.backlight();\r\n    lcd.clear();\r\n\r\n    if (! rtc.begin()) {\r\n        Serial.println(F(\"Couldn't find RTC\"));\r\n        while(1){}\r\n    }\r\n    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); \/\/ \/\/ set rtc to date\/time of compilation\r\n    rtc.disable32K();  \/\/ stop signal at the 32K pin\r\n    rtc.clearAlarm(1);\r\n    rtc.clearAlarm(2);\r\n    rtc.disableAlarm(1);\r\n    rtc.disableAlarm(2);\r\n    rtc.writeSqwPinMode(DS3231_OFF); \/\/ stop signal at the SQW pin\r\n    \r\n     \/* pressing the item or value button will cause a low signal at the corresponding pin\r\n       and trigger an interrupt *\/\r\n    pinMode(setItemPin, INPUT_PULLUP);\r\n    pinMode(setValuePin, INPUT_PULLUP);\r\n    pinMode(alarmPin, INPUT_PULLUP);\r\n    attachInterrupt(digitalPinToInterrupt(setItemPin), setItemKeyISR, FALLING);\r\n    attachInterrupt(digitalPinToInterrupt(setValuePin), setValueKeyISR, FALLING);\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid loop() {\r\n    if(millis()%1000 == 0){ \/\/ update date\/time every second\r\n        printDateTime();\r\n        delay(1);\r\n    }\r\n    \r\n    if(setItemKeyPressed){ \/\/ item key = date\/time setting key\r\n        goIntoSetMode(DATE_TIME);\r\n    }\r\n\r\n    if(setValueKeyPressed){ \/\/ value key = alarm key\r\n        goIntoSetMode(ALARM); \r\n    }\r\n    \r\n    if(rtc.alarmFired(1) &amp;&amp; alarmOn){\r\n        alarmAction();   \/\/ act on alarm\r\n    }\r\n\r\n    checkAlarmSetting();  \/\/ check whether alarm was (de-)activated\r\n    \r\n}\r\n\r\nvoid checkAlarmSetting(){\r\n    if(!digitalRead(alarmPin) &amp;&amp; !alarmOn){\r\n        alarmOn = true;\r\n        lcd.setCursor(15,1);\r\n        lcd.print(\"A\");  \/\/ display alarm flag\r\n        rtc.setAlarm1(alarmTime, DS3231_A1_Hour);\r\n    }\r\n    else if (digitalRead(alarmPin) &amp;&amp; alarmOn){\r\n        alarmOn = false;\r\n        lcd.setCursor(15,1);\r\n        lcd.print(\" \");  \/\/ delete alam flag\r\n        rtc.disableAlarm(1);\r\n    }\r\n}\r\n\r\nvoid goIntoSetMode(setMode settingMode){\r\n    alarmOn = false;\r\n    lcd.clear();\r\n    lcd.setCursor(0,0);\r\n    lcd.print(F(\"Press 1 sec\"));\r\n    delay(1000); \/\/ press 1 second to go into setting mode\r\n    if (digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){\r\n        lcd.setCursor(0,0);\r\n        lcd.print(F(\"Setting Mode\"));\r\n        lcd.setCursor(0,1);\r\n        if(settingMode == DATE_TIME){\r\n            lcd.print(F(\"Date\/Time\"));\r\n        }\r\n        else{\r\n            lcd.print(F(\"Alarm\"));\r\n        }\r\n        \/* wait until button is released *\/\r\n        while(digitalRead(setItemPin) == LOW){}\r\n        while(digitalRead(setValuePin) == LOW){}\r\n        delay(50); \/\/ debouncing\r\n        if(settingMode == DATE_TIME){\r\n            setDateTime();\r\n        }\r\n        else{\r\n            setAlarmTime();\r\n        }\r\n    }\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid setDateTime(){  \/\/ date\/time setting procedure\r\n    DateTime now = rtc.now(); \/\/ get current time\r\n    uint16_t tItem = 0; \r\n    tItem = setDateTimeElement(&amp;tElementYear, now.year());\r\n    adjustRTC(YEAR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMonth, now.month());\r\n    adjustRTC(MONTH, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementDay, now.day());\r\n    adjustRTC(DAY, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementHour, now.hour());\r\n    adjustRTC(HOUR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMinute, now.minute());\r\n    adjustRTC(MINUTE, tItem);\r\n    adjustRTC(SECOND, 0);\r\n    lcd.clear();\r\n    if(alarmOn){\r\n        lcd.setCursor(15,1);\r\n        lcd.print(\"A\");  \/\/ display \"alarm is on\" flag\r\n    }\r\n    printDateTime();\r\n}\r\n\r\nvoid setAlarmTime(){  \/\/ procedure to set an alarm\r\n    uint16_t value = 0;\r\n    value = setDateTimeElement(&amp;tElementHour, alarmTime.hour());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), value, alarmTime.minute(), 0);\r\n    value = setDateTimeElement(&amp;tElementMinute, alarmTime.minute());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), alarmTime.hour(), value, 0);\r\n    lcd.clear();\r\n    char alarmTimeBuf[] = \"hh:mm\";\r\n    alarmTime.toString(alarmTimeBuf);\r\n    lcd.setCursor(0,0);\r\n    lcd.print(\"Alarm: \");\r\n    lcd.print(alarmTimeBuf);\r\n    delay(1000); \/\/ Show Alarm Time for one second\r\n    lcd.clear();\r\n    printDateTime();\r\n}\r\n\r\nvoid alarmAction(){\r\n    lcd.clear();\r\n    unsigned long alarmStart = millis();\r\n    \/* alarm was fired, not key pressed, and alarm did not exceed max. duration *\/\r\n    while(!setItemKeyPressed &amp;&amp; !setValueKeyPressed &amp;&amp; (millis() - alarmStart &lt; MAX_ALARM_DURATION)){\r\n        lcd.setCursor(5,0);\r\n        lcd.print(F(\"Alarm!\"));\r\n        delay(500); \r\n        lcd.clear();\r\n        delay(500);\r\n        if(millis() &lt; alarmStart) {   \/\/ if millis() overflow occured\r\n            alarmStart = 0;\r\n        }\r\n    }\r\n    \/* wait till buttons are released: *\/\r\n    while(digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){}\r\n    rtc.clearAlarm(1);\r\n    delay(50); \/\/ debouncing\r\n    DateTime now = rtc.now();\r\n    if(millis() - alarmStart &lt; MAX_ALARM_DURATION){\r\n        alarmTime = now + TimeSpan(SNOOZE_TIME);  \/\/ set new alarm (snooze)\r\n        rtc.setAlarm1(alarmTime, DS3231_A1_Hour);\r\n        lcd.setCursor(15,1);\r\n        lcd.print(\"S\"); \/\/ display snooze flag\r\n    }\r\n    else{\r\n        alarmOn = false;\r\n    }\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\n\/* This functions sets a time element. Pressing the value key increments the value until\r\n   the maximum value is reached. Pressing the item key will return. *\/ \r\nuint16_t setDateTimeElement(timeElement *tE, uint16_t currentSet){\r\n    char buf[13];\r\n    clearLineLCD(0);\r\n    lcd.setCursor(0,0);\r\n    sprintf(buf, \"Set %s: \", tE-&gt;tname);\r\n    lcd.print(buf);\r\n    lcd.setCursor(12,0);\r\n    sprintf(buf, \"%02d\", currentSet);\r\n    lcd.print(buf);\r\n    setItemKeyPressed = false;\r\n    while(!setItemKeyPressed){    \r\n        if(setValueKeyPressed){\r\n            while(digitalRead(setValuePin) == LOW){\r\n                currentSet++;\r\n                if(currentSet &gt; tE-&gt;tMax){\r\n                    currentSet = tE-&gt;tMin;\r\n                }\r\n                lcd.setCursor(12,0);\r\n                sprintf(buf, \"%02d\", currentSet);\r\n                lcd.print(buf);\r\n                delay(SET_INCREMENT_DELAY);                \r\n            }\r\n        }\r\n    }\r\n    setItemKeyPressed = false;\r\n    return currentSet;\r\n}\r\n\r\nvoid printDateTime(){  \/\/ display date\/time\r\n    DateTime now = rtc.now();\r\n\r\n    char datBuf[] = \"DDD, DD.MM.YYYY\";  \/\/ define the date format\r\n    char timeBuf[] = \"hh:mm:ss\";  \/\/ define the time format\r\n    Serial.println(now.toString(datBuf));  \/\/ print date \r\n    Serial.println(now.toString(timeBuf));  \/\/ print time \r\n    lcd.setCursor(0,0);\r\n    lcd.print(datBuf); \/\/ display date\r\n    lcd.setCursor(0,1);\r\n    lcd.print(timeBuf); \/\/ display time\r\n}\r\n\r\nvoid adjustRTC(timeUnit tU, uint16_t value){  \/\/ adjust year, month, day etc.\r\n    DateTime now = rtc.now();\r\n    switch(tU){\r\n        case(YEAR):\r\n            rtc.adjust(DateTime(value, now.month(), now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(MONTH):\r\n            rtc.adjust(DateTime(now.year(), value, now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(DAY):\r\n            rtc.adjust(DateTime(now.year(), now.month(), value, now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(HOUR):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), value, now.minute(), now.second()));\r\n            break;\r\n        case(MINUTE):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), value, now.second()));\r\n            break;\r\n        case(SECOND):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), value));\r\n            break;\r\n    }\r\n    delay(10);\r\n}\r\n\r\nvoid clearLineLCD(int line){ \/\/ clears on line on the display\r\n    char buf[17];\r\n    sprintf(buf, \"%16s\", \" \");\r\n    lcd.setCursor(0, line);\r\n    lcd.print(buf);\r\n}\r\n\r\nvoid setItemKeyISR(){ \/\/ ISR for pressed item key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setItemKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nvoid setValueKeyISR(){ \/\/ ISR for pressed value key\r\n    if(millis()-lastLow &gt;= 50){ \/\/ ignore bouncing when button is released\r\n        setValueKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\n\n<h2 class=\"wp-block-heading\" id=\"power_consumption_v1_v3\">Power consumption of versions 1 &#8211; 3<\/h2>\n\n<p>This alarm clock concept has a current consumption of ~44 mA. The display draws around 24 mA, the Nano around 16.5 mA and the DS3231 a good 3.5 mA. This is far too much for a battery power supply.<\/p><p>\r\nIf you supply the DS3231 module with power via a button cell and cut the line to VCC, the module&#8217;s consumption is no significant. You could save approx. 20 mA by switching off the display&#8217;s backlight. To do this, you could insert the following lines into <code>loop()<\/code>: <\/p>\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">if(millis()-lastLow &lt; 20000){\r\n    lcd.backlight();\r\n}\r\nelse lcd.noBacklight();<\/pre>\n\n<p>If you press one of the setting buttons, the backlight comes on for 20 seconds. This might suit you if the bright display is annoying at night. But admittedly, this is not ideal. At least during the day you would like to be able to read the display without having to press any buttons. And the remaining ~20 mA is still a killer for battery operation, unless you want to change batteries every few days.<\/p>\n\n<h2 class=\"wp-block-heading\" id=\"concept_for_battery_use\">Concept for battery operation<\/h2>\n\n<p>So what we need is a low-power microcontroller board and a low-power display.<\/p>\n\n<h3 class=\"wp-block-heading\">Microcontroller board<\/h3>\n\n<p>As the board, I chose the <strong>3.3 V \/ 8 MHz version<\/strong> of the Arduino Pro Mini. Like the classic Arduino Nano, the Pro Mini is based on the ATmega328P. In normal operation, the ATmega328P is not a world champion in power saving, but in deep sleep mode its consumption can be reduced to less than &lt; 1 \u00b5A (see also my article on sleep modes <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/sleep-modes-and-power-management\" target=\"_blank\" rel=\"noopener\">here<\/a>).  &nbsp;<\/p><p>To wake up every second, we use a <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/interrupts-part-2-pin-change-interrupts\" target=\"_blank\" rel=\"noopener\">pin change interrupt<\/a>, which we trigger via a second alarm of the DS3231. The interrupts triggered via the push-buttons also wake up the Pro Mini. <\/p><p>Like almost all boards, the Pro Mini has an LED that lights up permanently when it is supplied with power. You should remove this. This can be done with a soldering iron or simply with some force, e.g. by carefully scratching it off with a screwdriver. <\/p>\n\n<h3 class=\"wp-block-heading\">Display <\/h3>\n\n<p>During my research for energy-efficient displays, I found the following alternatives:<\/p><ul>\r\n<li>The Nokia 5110 display.<\/li>\r\n<li>EA DOG Displays from Display Visions.<\/li>\r\n<li>E-paper displays, e.g. from Waveshare.<\/li>\r\n<li>ST7567 based display from OPEN-SMART.<\/li>\r\n<\/ul>\n\n<p>In the following, I will discuss the Nokia 5110, the DOGS164 display from the EA DOGS series and the ST7567 based display. You find an example with an e-paper display (MH-ET LIVE) in the appendix, but only as a simple clock.<\/p><p>\r\nE-paper displays are the world champions when it comes to saving energy, but they do have certain peculiarities. Among other things, they require a lot of RAM and most do not have a backlight, which is not good for an alarm clock in the dark. Or you can build your own display lighting.<\/p>\n\n<h3 class=\"wp-block-heading\">DS3231<\/h3>\n\n<p>The DS3231 module consumes very little power in battery mode (i.e. with a button cell in the module). However, I had problems waking up the Arduino Pro Mini with the alarm interrupt of the DS3231 in battery mode. I therefore switched back to power supply via VCC. As the power LED then lights up and consumes power, I simply removed it. This means that the DS3231 module consumes around 80 \u00b5A which I considered as acceptable. <\/p>\n\n<h2 class=\"wp-block-heading\" id=\"alarm_clock_v4\">Alarm clock &#8211; Version 4 with Nokia 5110 display<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-full is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"543\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110.jpg\" alt=\"Nokia 5110 Display\" class=\"wp-image-23510\" style=\"width:338px;height:auto\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110.jpg 600w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110-300x272.jpg 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><figcaption class=\"wp-element-caption\">Nokia 5110 display, 84 x 48 pixels<\/figcaption><\/figure>\n<\/div>\n<p>First of all, the bad news about the Nokia 5110 display: The quality of most displays leaves a lot to be desired. I have now ordered a whole series of displays from various stores. In Germany, I ordered three displays twice from a well-known store and both times two out of three did not work straight away. However, I was able to get three of the non-functioning displays to work. More on this in the <a href=\"#appendix_1\">appendix 1<\/a>.<\/p><p>Then I made a few test purchases on AliExpress. Here I got three different versions. One version was the same as the one I had already bought in Germany &#8211; but I couldn&#8217;t get it to work at all. The other versions had other problems. More about this in <a href=\"#appendix_2\">appendix_2<\/a>. <\/p>\n\n<p>The good sides of this display (if it works!) are:<\/p><ul>\r\n<li>Very low power consumption (approx. 100 &#8211; 200 \u00b5A without illumination).<\/li>\r\n<li>Its &#8220;nostalgic charm&#8221;.<\/li>\r\n<\/ul><br>\n\n<p>The following setup was used:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1-1024x491.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"491\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1-1024x491.png\" alt=\"\" class=\"wp-image-23462\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1-1024x491.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1-300x144.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1-768x368.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1-1536x737.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1-1320x633.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_nokia5110_alarm_clock-1.png 1570w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock, version 4 &#8211; with Nokia 5110 display <\/figcaption><\/figure>\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>You can use the top or bottom connectors of the Nokia 5110 display pins, it doesn&#8217;t matter. I have connected them as follows: <\/p><ul>\r\n<li><strong>RST<\/strong> (Reset) &#8211; Arduino pin 6<\/li>\r\n<li><strong>CE<\/strong> (Chip Enable) &#8211; Arduino Pin 7<\/li>\r\n<li><strong>DC<\/strong> (Data\/Control) &#8211; Arduino Pin 8<\/li>\r\n<li><strong>DIN<\/strong> (Data In) &#8211; Arduino Pin 9<\/li>\r\n<li><strong>CLK<\/strong> (Clock) &#8211; Arduino pin 10<\/li>\r\n<li><strong>VCC<\/strong> &#8211; 3.3 Volt<\/li>\r\n<li><strong>LIGHT<\/strong> &#8211; Arduino pin 11<\/li>\r\n<li><strong>GND<\/strong> &#8211; GND<\/li>\r\n<\/ul>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_backjpg.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"850\" height=\"833\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_backjpg.jpg\" alt=\"Nokia 5110 display, back\" class=\"wp-image-23470\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_backjpg.jpg 850w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_backjpg-300x294.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_backjpg-768x753.jpg 768w\" sizes=\"auto, (max-width: 850px) 100vw, 850px\" \/><\/a><figcaption class=\"wp-element-caption\">Nokia 5110 display, back<\/figcaption><\/figure>\n<\/div>\n<\/div>\n\n<h4 class=\"wp-block-heading\">A few remarks<\/h4>\n\n<p>The backlight lights up (in this version!) when you connect the LIGHT pin to GND. Or you can connect the LIGHT pin to an I\/O pin and switch the light on by setting the I\/O pin to OUTPUT\/LOW. Via PWM or <code>analogWrite()<\/code> you could dim it.<\/p><p> The Nokia 5110 display is incompatible with 5 volts. However, as we are using a 3.3 volt Arduino Pro Mini, we do not need a level shifter or voltage divider. A USB-to-TTL adapter, which can be set to 3.3 volts, is ideal for programming the Arduino Pro Mini. In standard operation, you can alternatively supply the circuit with higher voltages via the 3.3-volt voltage regulator of the Arduino Pro Mini. To do this, use the RAW pin. But once again: this only works in this form with the 3.3 volt version of the Pro Mini!<\/p>\n\n<h3 class=\"wp-block-heading\" id=\"sketch_version_4\">The alarm clock sketch &#8211; Version 4<\/h3>\n\n<p>I used the <a href=\"https:\/\/github.com\/platisd\/nokia-5110-lcd-library\" target=\"_blank\" rel=\"noopener\">Nokia 5110 LCD library<\/a> from Dimitris Platis(<a href=\"https:\/\/github.com\/platisd\" target=\"_blank\" rel=\"noopener\">platisd<\/a>) to control the Nokia 5110 display. I won&#8217;t go into the details here. A special feature of the library is that the cursor position is specified vertically in lines (0 to 5) and horizontally in pixels (0 to 83).<\/p><p>Then the hardware-specific sleep functions for the ATmega328P are added. If you want to know more details about this, take a look at <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/sleep-modes-and-power-management\" target=\"_blank\" rel=\"noopener\">this article<\/a>. The <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/interrupts-part-2-pin-change-interrupts\" target=\"_blank\" rel=\"noopener\">pin change interrupt functions<\/a> are also hardware-specific.<\/p><p>As alarm1 offers the option of triggering an alarm every second (DS3231_A1_PerSecond), we use it to wake up the Pro Mini regularly from sleep mode. We moved the alarm clock&#8217;s wake-up function to alarm 2.<\/p><p>I think that&#8217;s basically it. The code is simply too long to go through line by line.<\/p>\n\n<div class=\"scroll-paragraph-long\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ds3231_with_sleep_and_nokia5110_lcd.ino\" data-enlighter-title=\"ds3231_with_sleep_and_nokia5110_lcd.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;RTClib.h&gt;  \/\/ library for the DS3231\r\n#include &lt;Nokia_LCD.h&gt;  \/\/ Nokia 5110 display lib\r\n#include \"Bold_LCD_Fonts.h\" \/\/ bold fonts for time display\r\n#include &lt;avr\/sleep.h&gt; \/\/ hardware-specific sleep library for AVR MCUs\r\n#define SNOOZE_TIME 60  \/\/ set snooze time\r\n#define SET_INCREMENT_DELAY 260 \/\/ incrementation time for settings\r\n#define MAX_ALARM_DURATION 20000 \/\/ maximum duration of an alarm\r\nvolatile bool setItemKeyPressed = false; \/\/ flag for item key\r\nvolatile bool setValueKeyPressed = false; \/\/ flag for value key\r\nvolatile unsigned long lastLow; \/\/ needed to handle bouncing\r\nbool alarmOn = false; \/\/ alarm activated\r\nconst int setItemPin = 2; \/\/ choose item to set \/ time setting mode\r\nconst int setValuePin = 3; \/\/ set (increment) value \/ alarm setting mode\r\nconst int alarmPin = 4;  \/\/ Pin for the alarm switch\r\nconst int wakeUpPin = 5;\r\nconst int backlightPin = 11;\r\n\r\ntypedef enum TIME_UNIT { \/\/ needed for struct \"timeElement\"\r\n    YEAR, MONTH, DAY, HOUR, MINUTE, SECOND\r\n} timeUnit;\r\n\r\ntypedef enum SET_MODE { \/\/ setting modes\r\n    DATE_TIME, ALARM\r\n} setMode;\r\n\r\nchar daysOfTheWeek[7][12] = {\"Sunday   \", \"Monday   \", \"Tuesday  \", \"Wednesday\", \"Thursday \", \"Friday   \", \"Saturday \"};\r\n\r\nstruct timeElement{ \/\/ for date\/time\/alarm setting\r\n    timeUnit tUnit;\r\n    uint16_t tMin; \/\/ minimum value\r\n    uint16_t tMax; \/\/ maximum value\r\n    char tname[7]; \/\/ name to display\r\n};\r\n\r\nconst LcdFont BoldFont{  \/\/ Bold Font for Nokia 5110 Display\r\n    [](char c) {\r\n        return Bold_LCD_Fonts::kFont_Table[c - 0x20];\r\n    },                                       \/\/ method to retrieve the character\r\n    Bold_LCD_Fonts::kColumns_per_character,  \/\/ width of each char\r\n    Bold_LCD_Fonts::hSpace,                  \/\/ horizontal spacing array\r\n    1                                        \/\/ size of horizontal spacing array\r\n};\r\n\r\ntimeElement tElementYear = {YEAR, 2025, 2050, \"Year\"};\r\ntimeElement tElementMonth = {MONTH, 1, 12, \"Month\"};\r\ntimeElement tElementDay = {DAY, 1, 31, \"Day\"};\r\ntimeElement tElementHour = {HOUR, 0, 23, \"Hour\"};\r\ntimeElement tElementMinute = {MINUTE, 0, 59, \"Minute\"};\r\n\r\nRTC_DS3231 rtc;   \/\/ create RTC_DS3231 object\r\nDateTime alarmTime = DateTime(2014, 1, 1, 7, 0, 0);\r\nNokia_LCD lcd(10 \/* CLK *\/, 9 \/* DIN *\/, 8 \/* DC *\/, 7 \/* CE *\/, 6 \/* RST *\/);\r\n\r\nvoid setup () {\r\n    Serial.begin(115200);\r\n    ADCSRA = 0; \/\/ ADC off (would consume current in deep sleep)\r\n\r\n    lcd.begin(); \r\n    lcd.setContrast(60);\r\n    lcd.clear(false);\r\n    setBacklight(false); \/\/ Light off\r\n\r\n    if (! rtc.begin()) {\r\n        Serial.println(F(\"Couldn't find RTC\"));\r\n        while(1){}\r\n    }\r\n    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); \/\/ \/\/ set rtc to date\/time of compilation\r\n    rtc.disable32K();  \/\/ stop signal at the 32K pin\r\n    rtc.clearAlarm(1);\r\n    rtc.clearAlarm(2);\r\n    rtc.disableAlarm(1);\r\n    rtc.disableAlarm(2);\r\n    rtc.writeSqwPinMode(DS3231_OFF); \/\/ stop signal at the SQW pin\r\n    rtc.setAlarm1(alarmTime, DS3231_A1_PerSecond);\r\n    \r\n     \/* pressing the item or value button will cause a low signal at the corresponding pin\r\n       and trigger an interrupt *\/\r\n    pinMode(setItemPin, INPUT_PULLUP);\r\n    pinMode(setValuePin, INPUT_PULLUP);\r\n    pinMode(alarmPin, INPUT_PULLUP);\r\n    attachInterrupt(digitalPinToInterrupt(setItemPin), setItemKeyISR, FALLING);\r\n    attachInterrupt(digitalPinToInterrupt(setValuePin), setValueKeyISR, FALLING);\r\n    PCICR = (1&lt;&lt;PCIE2);    \/\/ enable PCINT[23:16] interrupts\r\n    PCMSK2 = (1&lt;&lt;PCINT21); \/\/ D5 = PCINT21 for wake up\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid loop() {\r\n\r\n    printDateTime();\r\n        \r\n    if(digitalRead(setItemPin) == LOW){ \/\/ item key = date\/time setting key\r\n        goIntoSetMode(DATE_TIME);\r\n    }\r\n\r\n    if(digitalRead(setValuePin) == LOW){ \/\/ value key = alarm key\r\n        goIntoSetMode(ALARM); \r\n    }\r\n    \r\n    if(rtc.alarmFired(2) &amp;&amp; alarmOn){\r\n        alarmAction();   \/\/ act on alarm\r\n    }\r\n\r\n    checkAlarmSetting();  \/\/ check whether alarm was (de-)activated\r\n\r\n    set_sleep_mode(SLEEP_MODE_PWR_DOWN); \/\/ choose power down mode\r\n    sleep_mode(); \/\/ sleep now!\r\n    rtc.clearAlarm(1);   \r\n}\r\n\r\nvoid checkAlarmSetting(){\r\n    if(!digitalRead(alarmPin) &amp;&amp; !alarmOn){\r\n        alarmOn = true;\r\n        lcd.setCursor(77,5);\r\n        lcd.print(\"A\");  \/\/ display alarm flag\r\n        rtc.setAlarm2(alarmTime, DS3231_A2_Hour);\r\n    }\r\n    else if (digitalRead(alarmPin) &amp;&amp; alarmOn){\r\n        alarmOn = false;\r\n        lcd.setCursor(77,5);\r\n        lcd.print(\" \");  \/\/ delete alarm flag\r\n        rtc.disableAlarm(2);\r\n    }\r\n}\r\n\r\nvoid goIntoSetMode(setMode settingMode){\r\n    alarmOn = false;\r\n    lcd.clear(false);\r\n    lcd.setCursor(0,0);\r\n    lcd.print(\"Press 1 sec\");\r\n    delay(1000); \/\/ press 1 second to go into setting mode\r\n    clearLineLCD(0);\r\n    if (digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){\r\n        lcd.setCursor(0,0);\r\n        lcd.print(\"Setting Mode\");\r\n        lcd.setCursor(0,2);\r\n        if(settingMode == DATE_TIME){\r\n            lcd.print(\"Set Date\/Time\");\r\n        }\r\n        else{\r\n            lcd.print(\"Set Alarm\");\r\n        }\r\n        \/* wait until button is released *\/\r\n        while(digitalRead(setItemPin) == LOW){}\r\n        while(digitalRead(setValuePin) == LOW){}\r\n        delay(50); \/\/ debouncing\r\n        if(settingMode == DATE_TIME){\r\n            setDateTime();\r\n        }\r\n        else{\r\n            setAlarmTime();\r\n        }\r\n    }\r\n    rtc.clearAlarm(1);   \r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid setDateTime(){  \/\/ date\/time setting procedure\r\n    DateTime now = rtc.now(); \/\/ get current time\r\n    uint16_t tItem = 0; \r\n    tItem = setDateTimeElement(&amp;tElementYear, now.year());\r\n    adjustRTC(YEAR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMonth, now.month());\r\n    adjustRTC(MONTH, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementDay, now.day());\r\n    adjustRTC(DAY, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementHour, now.hour());\r\n    adjustRTC(HOUR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMinute, now.minute());\r\n    adjustRTC(MINUTE, tItem);\r\n    adjustRTC(SECOND, 0);\r\n    lcd.clear(false);\r\n    if(alarmOn){\r\n        lcd.setCursor(77,5);\r\n        lcd.print(\"A\");  \/\/ display \"alarm is on\" flag\r\n    }\r\n    printDateTime();\r\n}\r\n\r\nvoid setAlarmTime(){  \/\/ procedure to set an alarm\r\n    uint16_t value = 0;\r\n    value = setDateTimeElement(&amp;tElementHour, alarmTime.hour());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), value, alarmTime.minute(), 0);\r\n    value = setDateTimeElement(&amp;tElementMinute, alarmTime.minute());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), alarmTime.hour(), value, 0);\r\n    lcd.clear(false);\r\n    char alarmTimeBuf[] = \"hh:mm\";\r\n    alarmTime.toString(alarmTimeBuf);\r\n    lcd.setCursor(0,0);\r\n    lcd.print(\"Alarm: \");\r\n    lcd.print(alarmTimeBuf);\r\n    delay(1000); \/\/ Show Alarm Time for one second\r\n    lcd.clear();\r\n    printDateTime();\r\n}\r\n\r\nvoid alarmAction(){\r\n    lcd.clear();\r\n    unsigned long alarmStart = millis();\r\n    \/* alarm was fired, not key pressed, and alarm did not exceed max. duration *\/\r\n    while(!setItemKeyPressed &amp;&amp; !setValueKeyPressed &amp;&amp; (millis() - alarmStart &lt; MAX_ALARM_DURATION)){\r\n        lcd.setCursor(23,3);\r\n        lcd.print(\"Alarm!\");\r\n        delay(500); \r\n        lcd.clear();\r\n        delay(500);\r\n        if(millis() &lt; alarmStart) {   \/\/ if millis() overflow occurred\r\n            alarmStart = 0;\r\n        }\r\n\r\n    }\r\n    \/* wait till buttons are released: *\/\r\n    while(digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){}\r\n    delay(50); \/\/ debouncing\r\n    DateTime now = rtc.now();\r\n    if(millis() - alarmStart &lt; MAX_ALARM_DURATION){\r\n        alarmTime = now + TimeSpan(SNOOZE_TIME);  \/\/ set new alarm (snooze)\r\n        rtc.setAlarm2(alarmTime, DS3231_A2_Hour); \/\/ alarm if hours\/minutes match\r\n        lcd.setCursor(77,5);\r\n        lcd.print(\"S\"); \/\/ display snooze flag\r\n    }\r\n    else{\r\n        alarmOn = false;\r\n    }\r\n    rtc.clearAlarm(2);\r\n    rtc.clearAlarm(1);\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\n\/* This functions sets a time element. Pressing the value key increments the value until\r\n   the maximum value is reached. Pressing the item key will return. *\/ \r\nuint16_t setDateTimeElement(timeElement *tE, uint16_t currentSet){\r\n    char buf[13];\r\n    clearLineLCD(0);\r\n    lcd.setCursor(0,0);\r\n    sprintf(buf, \"%s:\", tE-&gt;tname);\r\n    lcd.print(buf);\r\n    lcd.setCursor(47,0);\r\n    sprintf(buf, \"%02d\", currentSet);\r\n    lcd.print(buf);\r\n    setItemKeyPressed = false;\r\n    while(!setItemKeyPressed){    \r\n        if(setValueKeyPressed){\r\n            while(digitalRead(setValuePin) == LOW){\r\n                currentSet++;\r\n                if(currentSet &gt; tE-&gt;tMax){\r\n                    currentSet = tE-&gt;tMin;\r\n                }\r\n                lcd.setCursor(47,0);\r\n                sprintf(buf, \"%02d\", currentSet);\r\n                lcd.print(buf);\r\n                delay(SET_INCREMENT_DELAY);                \r\n            }\r\n        }\r\n    }\r\n    setItemKeyPressed = false;\r\n    return currentSet;\r\n}\r\n\r\nvoid printDateTime(){  \/\/ display date\/time\r\n    DateTime now = rtc.now();\r\n\r\n    char datBuf[] = \"DD.MM.YYYY\";  \/\/ define the date format\r\n    char timeBuf[] = \"hh:mm:ss\";  \/\/ define the time format\r\n    Serial.println(now.toString(datBuf));  \/\/ print date \r\n    Serial.println(now.toString(timeBuf));  \/\/ print time \r\n    lcd.setCursor(0,0);\r\n    lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);\r\n    lcd.setCursor(0,2);\r\n    lcd.print(datBuf); \/\/ display date\r\n    lcd.setCursor(0,4);\r\n    lcd.setFont(&amp;BoldFont);\r\n    lcd.print(timeBuf); \/\/ display time\r\n    lcd.setDefaultFont();\r\n}\r\n\r\nvoid adjustRTC(timeUnit tU, uint16_t value){  \/\/ adjust year, month, day etc.\r\n    DateTime now = rtc.now();\r\n    switch(tU){\r\n        case(YEAR):\r\n            rtc.adjust(DateTime(value, now.month(), now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(MONTH):\r\n            rtc.adjust(DateTime(now.year(), value, now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(DAY):\r\n            rtc.adjust(DateTime(now.year(), now.month(), value, now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(HOUR):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), value, now.minute(), now.second()));\r\n            break;\r\n        case(MINUTE):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), value, now.second()));\r\n            break;\r\n        case(SECOND):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), value));\r\n            break;\r\n    }\r\n    delay(10);\r\n}\r\n\r\nvoid clearLineLCD(int line){ \/\/ clears on line on the display\r\n    char buf[15];\r\n    sprintf(buf, \"%14s\", \" \");\r\n    lcd.setCursor(0, line);\r\n    lcd.print(buf);\r\n}\r\n\r\nvoid setBacklight(bool on){\r\n    if(on){\r\n        pinMode(backlightPin, OUTPUT);\r\n    }\r\n    else pinMode(backlightPin, INPUT);\r\n}\r\n\r\nvoid setItemKeyISR(){ \/\/ ISR for pressed item key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setItemKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nvoid setValueKeyISR(){ \/\/ ISR for pressed value key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setValueKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nISR (PCINT2_vect){} \/\/ PCINT2_vect: interrupt vector for PORTD<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\n\n<h3 class=\"wp-block-heading\">The result<\/h3>\n\n<p>This is how the date and time appear on the display.<\/p>\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\"><\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_nokia5110.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"974\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_nokia5110.jpg\" alt=\"Alarm clock, version 4 - with Nokia 5110 display\" class=\"wp-image-23421\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_nokia5110.jpg 1000w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_nokia5110-300x292.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/ds3231_nokia5110-768x748.jpg 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock, version 4 &#8211; with Nokia 5110 display<\/figcaption><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\"><\/div>\n<\/div>\n\n<p>With this setup (including the removed LEDs), I measured a current consumption of 0.224 mA in the sleep phase. I have determined a power consumption of 2.8 mA for the waking phase. The waking phase takes 166 ms and is therefore quite relevant. The total current consumption is approx. 0.65 mA. You can move more in the direction of 0.224 mA by dispensing with the display of seconds. We&#8217;ll get to that shortly.<\/p>\n\n<h3 class=\"wp-block-heading\" id=\"variations\">Variations<\/h3>\n\n<h4 class=\"wp-block-heading\">Minutes instead of seconds display<\/h4>\n\n<p>If you want to do without the seconds display, only a few changes are required in the sketch:<\/p>\n\n<ul><li>Change line 85 to: <code>PCMSK2 = (1&lt;&lt;PCINT21) | (1&lt;&lt;PCINT20);<\/code><ul><li>\r\nThis will also wake up the Arduino Pro Mini when you press the slide switch on pin 4 (= PCINT20).<\/li><\/ul><\/li><li>\r\nTo change alarm 1 from seconds to minutes, replace line 75 with : <code>rtc.setAlarm1(alarmTime, DS3231_A1_Second);<\/code><\/li><li>\r\nYou define displaying only hours and minutes in line 272: <code>char timeBuf[] = \"hh:mm\";<\/code><\/li><li>\r\nTo center the time display, write in line 279: <code>lcd.setCursor(23,4);<\/code><\/li><li>\r\nThen I noticed that the date\/time display had disappeared after setting the clock and alarm time. To change this, insert an <em>additional<\/em> line after line 231:  <code>printDateTime();<\/code><\/li><\/ul>\n\n<h4 class=\"wp-block-heading\">Using the backlight<\/h4>\n\n<p>For alarm clock version 3, I have shown you how to switch on the backlight for a limited period. This does not work if you are using sleep mode, as the timer0 responsible for <code>millis()<\/code> is off. The pragmatic solution is to only count the waking time and reduce the value for the backlight period accordingly. However, you would then have to leave the light on for at least one minute if you choose the option to display only minutes.<\/p><p>Alternatively, you can use the RTC instead of <code>millis()<\/code> to measure the backlight period. With <code>now.unixtime()<\/code> you get the time since 1.1.1970 in seconds and can use it for convenient calculations. Or you can add another slide switch that activates the backlight and switches off the sleep function. However, there is a risk of forgetting to turn off the light, draining the battery and then oversleeping. But you could also install an upper limit here. Or, or, or&#8230; &#8211; there are many options you can choose from.<\/p>\n\n<h2 class=\"wp-block-heading\" id=\"alarm_clock_v5\">Alarm clock &#8211; Version 5 with DOGS164 display<\/h2>\n\n<p>The DOGS164 belongs to the EA DOG display family. They are based on an interesting modular concept. You put together the display, the backlight module and, if necessary, a touch panel according to your wishes. You can choose between various text or graphic displays. An overview is available <a href=\"https:\/\/www.displayvisions.us\/products\/chip-on-glass-displays-with-spi-in-various-sizes-and-colours.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p><p>The letter after &#8220;DOG&#8221; gives you an indication of the (font) size, i.e. S, M, L or XL. For the text displays, the next two numbers indicate the number of characters per line. The third number tells you the number of lines.  &nbsp;<\/p><p>You can then select how the characters are to be shown on the display. For example, there is a <strong>DOGS164B<\/strong>, <strong>DOGS164W<\/strong> and a <strong>DOGS164N<\/strong>: <\/p><ul><li><strong>B<\/strong>: blue background, transmissive, i.e. the font color is determined by the backlight (i.e. similar appearance to the LCD used in clock versions 1-3).<\/li><li>\r\n<strong>W<\/strong>: black font, background color is determined by the backlight module.<\/li><li>\r\n<strong>N<\/strong>: black font, no backlight possible, looks like &#8220;W&#8221;-version without backlight (bottom right image).<\/li>\r\n<\/ul><p>The backlight panels are also available in different versions, e.g. in amber or green\/red\/white (switchable). So take a close look at what you order! The B version, for example, is only really legible with a backlight.<\/p><p>I opted for the DOGS164W text display with amber-colored backlight. I&#8217;ll show you the result in advance: &nbsp;<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164-1024x415.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"415\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164-1024x415.jpg\" alt=\"Alarm clock, version 5 with DOGS164 display, left with backlight, right without\" class=\"wp-image-23448\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164-1024x415.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164-300x122.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164-768x311.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164-1536x622.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164-1320x535.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/ds3231_dogs164.jpg 1600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock, version 5 with DOGS164 display, left with backlight, right without<\/figcaption><\/figure>\n\n<p>A certain disadvantage of the EA DOG displays is that once they are fixed to the backlight panel, they can no longer be inserted into breadboards. The pins are then too short. I cut off jumper cables on one side and soldered them to the pins for my trials:  <\/p><br>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables-1024x327.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"327\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables-1024x327.jpg\" alt=\"DOGS164W Display with backlight and connection cables\" class=\"wp-image-23468\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables-1024x327.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables-300x96.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables-768x245.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables-1536x491.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables-1320x422.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/dogs164_with_cables.jpg 1700w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">DOGS164W Display with backlight and connection cables<\/figcaption><\/figure>\n\n<p>According to the data sheet, the backlight connections should be soldered &#8220;with a little tin from the top&#8221;. Well, it worked anyway.  <\/p>\n\n<h3 class=\"wp-block-heading\">Connection to the Arduino Pro Mini<\/h3>\n\n<p>The various EA DOG displays differ in terms of the number and assignment of their pins. With some displays, you have the choice between SPI (3-wire), SPI (4-wire) and I2C. The DOGS164 can be addressed via I2C or SPI (3-wire). As the DS3231 module is already connected via I2C, I did the same with the DOG display. This saved three Arduino pins compared to SPI.<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DOGS164_connections-1024x387.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"387\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DOGS164_connections-1024x387.png\" alt=\"DOGS164 pinout when using I2C (source: data sheet)\" class=\"wp-image-23451\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DOGS164_connections-1024x387.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DOGS164_connections-300x113.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DOGS164_connections-768x290.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DOGS164_connections.png 1305w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">DOGS164 pinout when using I2C (source: data sheet)<\/figcaption><\/figure>\n\n<p>Here is the circuit without connected backlight:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1-1024x593.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"593\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1-1024x593.png\" alt=\"Alarm clock, version 5 - with DOGS164 display\" class=\"wp-image-23517\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1-1024x593.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1-300x174.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1-768x445.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1-1536x890.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1-1320x765.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/DS3231_dogs164_alarm_clock-1.png 1552w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock, version 5 &#8211; with DOGS164 display<\/figcaption><\/figure>\n\n<p>A few more tips (especially for the DOGS164 \/ I2C):<\/p><ul><li>All connections only tolerate 3.3 volts. If you are using a 5V board, you must use level shifters or voltage dividers. <\/li>\r\n<li>You can leave <strong>VOUT<\/strong> and <strong>CS<\/strong> unconnected.<\/li>\r\n<li>Use <strong>SA0<\/strong> to set the I2C address. The specification above is the 8-bit I2C address! In the Arduino world, the 7-bit address is used. The last bit must therefore be deleted. 0x7A becomes 0x3D and 0x78 becomes 0x3C.    <\/li>\r\n<li>Use <strong>IM1<\/strong> to set I2C (GND) or SPI (VDD).<\/li>\r\n<li><strong>SID<\/strong> and <strong>SOD<\/strong> are connected SDA.<\/li>\r\n<li><strong>SCLK<\/strong> is attached to SCL.<\/li>\r\n<li>The backlight is controlled via the pins <strong>A1<\/strong>\/<strong>A2<\/strong> (anode) and <strong>C1<\/strong>\/<strong>C2 <\/strong> (cathode).\r\n<ul><li><strong>Series resistors are mandatory!<\/strong> The backlight current can exceed the limit of the Arduino pins. You could control the backlight via <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/the-mosfet-as-switch\" target=\"_blank\" rel=\"noopener\">MOSFETs<\/a> with the Arduino. <\/li><\/ul><\/li><li>\r\n<strong>Read the data sheet!<\/strong> It is easy to understand and available in German \/ English. It also contains the recommended resistor sizes for the backlight.  <\/li><\/ul>\n\n<h3 class=\"wp-block-heading\">The alarm clock sketch &#8211; Version 5<\/h3>\n\n<p>I used the <a href=\"https:\/\/github.com\/sstaub\/SSD1803A_I2C\" target=\"_blank\" rel=\"noopener\">SSD1803A_I2C<\/a> library from Stefan Staub(<a href=\"https:\/\/github.com\/sstaub\" target=\"_blank\" rel=\"noopener\">sstaub<\/a>) to control the DOGS164 display. It is convenient to use. The code should be easy to understand. Otherwise, everything remains the same.   <\/p>\n\n<div class=\"scroll-paragraph-long\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ds3231_with_sleep_and_dogs164_lcd.ino\" data-enlighter-title=\"ds3231_with_sleep_and_dogs164_lcd.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;RTClib.h&gt;  \/\/ library for the DS3231\r\n#include &lt;SSD1803A_I2C.h&gt; \/\/ DOGS164 Lib\r\n#include &lt;avr\/sleep.h&gt;\r\n#define SNOOZE_TIME 60  \/\/ set snooze time\r\n#define SET_INCREMENT_DELAY 260 \/\/ incrementation time for settings\r\n#define MAX_ALARM_DURATION 20000 \/\/ maximum duration of an alarm\r\nvolatile bool setItemKeyPressed = false; \/\/ flag for item key\r\nvolatile bool setValueKeyPressed = false; \/\/ flag for value key\r\nvolatile unsigned long lastLow; \/\/ needed to handle bouncing\r\nbool alarmOn = false; \/\/ alarm activated\r\nconst int setItemPin = 2; \/\/ choose item to set \/ time setting mode\r\nconst int setValuePin = 3; \/\/ set (increment) value \/ alarm setting mode\r\nconst int alarmPin = 4;  \/\/ Pin for the alarm switch\r\nconst int wakeUpPin = 5;\r\nconst uint8_t i2caddr = 0x3D;\r\nconst uint8_t resetPin = 8;\r\n\r\n\r\ntypedef enum TIME_UNIT { \/\/ needed for struct \"timeElement\"\r\n    YEAR, MONTH, DAY, HOUR, MINUTE, SECOND\r\n} timeUnit;\r\n\r\ntypedef enum SET_MODE { \/\/ setting modes\r\n    DATE_TIME, ALARM\r\n} setMode;\r\n\r\nchar daysOfTheWeek[7][12] = {\"Sunday   \", \"Monday   \", \"Tuesday  \", \"Wednesday\", \"Thursday \", \"Friday   \", \"Saturday \"};\r\n\r\nstruct timeElement{ \/\/ for date\/time\/alarm setting\r\n    timeUnit tUnit;\r\n    uint16_t tMin; \/\/ minimum value\r\n    uint16_t tMax; \/\/ maximum value\r\n    char tname[7]; \/\/ name to display\r\n};\r\n\r\ntimeElement tElementYear = {YEAR, 2025, 2050, \"Year\"};\r\ntimeElement tElementMonth = {MONTH, 1, 12, \"Month\"};\r\ntimeElement tElementDay = {DAY, 1, 31, \"Day\"};\r\ntimeElement tElementHour = {HOUR, 0, 23, \"Hour\"};\r\ntimeElement tElementMinute = {MINUTE, 0, 59, \"Minute\"};\r\n\r\nRTC_DS3231 rtc;   \/\/ create RTC_DS3231 object\r\nDateTime alarmTime = DateTime(2014, 1, 1, 7, 0, 0);\r\nSSD1803A_I2C lcd(i2caddr);\r\n\r\nvoid setup () {\r\n    Serial.begin(115200);\r\n    ADCSRA = 0; \/\/ ADC off\r\n\r\n    lcd.begin(DOGS164, resetPin);\r\n\r\n    if (! rtc.begin()) {\r\n        Serial.println(F(\"Couldn't find RTC\"));\r\n        while(1){}\r\n    }\r\n    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); \/\/ \/\/ set rtc to date\/time of compilation\r\n    rtc.disable32K();  \/\/ stop signal at the 32K pin\r\n    rtc.clearAlarm(1);\r\n    rtc.clearAlarm(2);\r\n    rtc.disableAlarm(1);\r\n    rtc.disableAlarm(2);\r\n    rtc.writeSqwPinMode(DS3231_OFF); \/\/ stop signal at the SQW pin\r\n    rtc.setAlarm1(alarmTime, DS3231_A1_PerSecond);\r\n    \r\n     \/* pressing the item or value button will cause a low signal at the corresponding pin\r\n       and trigger an interrupt *\/\r\n    pinMode(setItemPin, INPUT_PULLUP);\r\n    pinMode(setValuePin, INPUT_PULLUP);\r\n    pinMode(alarmPin, INPUT_PULLUP);\r\n    attachInterrupt(digitalPinToInterrupt(setItemPin), setItemKeyISR, FALLING);\r\n    attachInterrupt(digitalPinToInterrupt(setValuePin), setValueKeyISR, FALLING);\r\n    PCICR = (1&lt;&lt;PCIE2);    \/\/ enable PCINT[23:16] interrupts\r\n    PCMSK2 = (1&lt;&lt;PCINT21); \/\/ D5 = PCINT21 for wake up\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid loop() {\r\n    \r\n    printDateTime();\r\n        \r\n    if(digitalRead(setItemPin) == LOW){ \/\/ item key = date\/time setting key\r\n        goIntoSetMode(DATE_TIME);\r\n    }\r\n\r\n    if(digitalRead(setValuePin) == LOW){ \/\/ value key = alarm key\r\n        goIntoSetMode(ALARM); \r\n    }\r\n    \r\n    if(rtc.alarmFired(2) &amp;&amp; alarmOn){\r\n        alarmAction();   \/\/ act on alarm\r\n    }\r\n\r\n    checkAlarmSetting();  \/\/ check whether alarm was (de-)activated\r\n\r\n    set_sleep_mode(SLEEP_MODE_PWR_DOWN); \/\/ choose power down mode\r\n    sleep_mode(); \/\/ sleep now!\r\n    rtc.clearAlarm(1);   \r\n}\r\n\r\nvoid checkAlarmSetting(){\r\n    if(!digitalRead(alarmPin) &amp;&amp; !alarmOn){\r\n        alarmOn = true;\r\n        lcd.locate(4,16);\r\n        lcd.print(\"A\");  \/\/ display alarm flag\r\n        rtc.setAlarm2(alarmTime, DS3231_A2_Hour);\r\n    }\r\n    else if (digitalRead(alarmPin) &amp;&amp; alarmOn){\r\n        alarmOn = false;\r\n        lcd.locate(4,16);\r\n        lcd.print(\" \");  \/\/ delete alam flag\r\n        rtc.disableAlarm(2);\r\n    }\r\n}\r\n\r\nvoid goIntoSetMode(setMode settingMode){\r\n    alarmOn = false;\r\n    lcd.cls();\r\n    lcd.locate(1,1);\r\n    lcd.print(\"Press 1 sec\");\r\n    delay(1000); \/\/ press 1 second to go into setting mode\r\n    lcd.clr(1);\r\n    if (digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){\r\n        lcd.locate(1,1);\r\n        lcd.print(\"Setting Mode\");\r\n        lcd.locate(2,1);\r\n        if(settingMode == DATE_TIME){\r\n            lcd.print(\"Set Date\/Time\");\r\n        }\r\n        else{\r\n            lcd.print(\"Set Alarm\");\r\n        }\r\n        \/* wait until button is released *\/\r\n        while(digitalRead(setItemPin) == LOW){}\r\n        while(digitalRead(setValuePin) == LOW){}\r\n        delay(50); \/\/ debouncing\r\n        if(settingMode == DATE_TIME){\r\n            setDateTime();\r\n        }\r\n        else{\r\n            setAlarmTime();\r\n        }\r\n    }\r\n    rtc.clearAlarm(1);   \r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid setDateTime(){  \/\/ date\/time setting procedure\r\n    DateTime now = rtc.now(); \/\/ get current time\r\n    uint16_t tItem = 0; \r\n    tItem = setDateTimeElement(&amp;tElementYear, now.year());\r\n    adjustRTC(YEAR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMonth, now.month());\r\n    adjustRTC(MONTH, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementDay, now.day());\r\n    adjustRTC(DAY, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementHour, now.hour());\r\n    adjustRTC(HOUR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMinute, now.minute());\r\n    adjustRTC(MINUTE, tItem);\r\n    adjustRTC(SECOND, 0);\r\n    lcd.cls();\r\n    if(alarmOn){\r\n        lcd.locate(4,16);\r\n        lcd.print(\"A\");  \/\/ display \"alarm is on\" flag\r\n    }\r\n    printDateTime();\r\n}\r\n\r\nvoid setAlarmTime(){  \/\/ procedure to set an alarm\r\n    uint16_t value = 0;\r\n    value = setDateTimeElement(&amp;tElementHour, alarmTime.hour());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), value, alarmTime.minute(), 0);\r\n    value = setDateTimeElement(&amp;tElementMinute, alarmTime.minute());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), alarmTime.hour(), value, 0);\r\n    lcd.cls();\r\n    char alarmTimeBuf[] = \"hh:mm\";\r\n    alarmTime.toString(alarmTimeBuf);\r\n    lcd.locate(1,1);\r\n    lcd.print(\"Alarm: \");\r\n    lcd.print(alarmTimeBuf);\r\n    delay(1000); \/\/ Show Alarm Time for one second\r\n    lcd.cls();\r\n    printDateTime();\r\n}\r\n\r\nvoid alarmAction(){\r\n    lcd.cls();\r\n    unsigned long alarmStart = millis();\r\n    \/* alarm was fired, not key pressed, and alarm did not exceed max. duration *\/\r\n    while(!setItemKeyPressed &amp;&amp; !setValueKeyPressed &amp;&amp; (millis() - alarmStart &lt; MAX_ALARM_DURATION)){\r\n        lcd.locate(2,5);\r\n        lcd.print(\"Alarm!\");\r\n        delay(500); \r\n        lcd.cls();\r\n        delay(500);\r\n        if(millis() &lt; alarmStart) {   \/\/ if millis() overflow occured\r\n            alarmStart = 0;\r\n        }\r\n\r\n    }\r\n    \/* wait till buttons are released: *\/\r\n    while(digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){}\r\n    delay(50); \/\/ debouncing\r\n    DateTime now = rtc.now();\r\n    if(millis() - alarmStart &lt; MAX_ALARM_DURATION){\r\n        alarmTime = now + TimeSpan(SNOOZE_TIME);  \/\/ set new alarm (snooze)\r\n        rtc.setAlarm2(alarmTime, DS3231_A2_Hour); \/\/ alarm if hours\/minutes match\r\n        lcd.locate(4,16);\r\n        lcd.print(\"S\"); \/\/ display snooze flag\r\n    }\r\n    else{\r\n        alarmOn = false;\r\n    }\r\n    rtc.clearAlarm(2);\r\n    rtc.clearAlarm(1);\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\n\/* This functions sets a time element. Pressing the value key increments the value until\r\n   the maximum value is reached. Pressing the item key will return. *\/ \r\nuint16_t setDateTimeElement(timeElement *tE, uint16_t currentSet){\r\n    char buf[13];\r\n    lcd.clr(1);\r\n    lcd.locate(1,1);\r\n    sprintf(buf, \"%s:\", tE-&gt;tname);\r\n    lcd.print(buf);\r\n    lcd.locate(1,9);\r\n    sprintf(buf, \"%02d\", currentSet);\r\n    lcd.print(buf);\r\n    setItemKeyPressed = false;\r\n    while(!setItemKeyPressed){    \r\n        if(setValueKeyPressed){\r\n            while(digitalRead(setValuePin) == LOW){\r\n                currentSet++;\r\n                if(currentSet &gt; tE-&gt;tMax){\r\n                    currentSet = tE-&gt;tMin;\r\n                }\r\n                lcd.locate(1,9);\r\n                sprintf(buf, \"%02d\", currentSet);\r\n                lcd.print(buf);\r\n                delay(SET_INCREMENT_DELAY);                \r\n            }\r\n        }\r\n    }\r\n    setItemKeyPressed = false;\r\n    return currentSet;\r\n}\r\n\r\nvoid printDateTime(){  \/\/ display date\/time\r\n    DateTime now = rtc.now();\r\n\r\n    char datBuf[] = \"DD.MM.YYYY\";  \/\/ define the date format\r\n    char timeBuf[] = \"hh:mm:ss\";  \/\/ define the time format\r\n    Serial.println(now.toString(datBuf));  \/\/ print date \r\n    Serial.println(now.toString(timeBuf));  \/\/ print time \r\n    lcd.locate(1,4);\r\n    lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);\r\n    lcd.locate(2,4);\r\n    lcd.print(datBuf); \/\/ display date\r\n    lcd.locate(4,4);\r\n    lcd.print(timeBuf); \/\/ display time\r\n}\r\n\r\nvoid adjustRTC(timeUnit tU, uint16_t value){  \/\/ adjust year, month, day etc.\r\n    DateTime now = rtc.now();\r\n    switch(tU){\r\n        case(YEAR):\r\n            rtc.adjust(DateTime(value, now.month(), now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(MONTH):\r\n            rtc.adjust(DateTime(now.year(), value, now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(DAY):\r\n            rtc.adjust(DateTime(now.year(), now.month(), value, now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(HOUR):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), value, now.minute(), now.second()));\r\n            break;\r\n        case(MINUTE):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), value, now.second()));\r\n            break;\r\n        case(SECOND):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), value));\r\n            break;\r\n    }\r\n    delay(10);\r\n}\r\n\r\nvoid setItemKeyISR(){ \/\/ ISR for pressed item key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setItemKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nvoid setValueKeyISR(){ \/\/ ISR for pressed value key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setValueKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nISR (PCINT2_vect){} \/\/ PCINT2_vect: interrupt vector for PORTD<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\n\n<h3 class=\"wp-block-heading\">The result<\/h3>\n\n<p>I measured a total current of approx. 0.85 milliamperes. This is slightly more than with the Nokia display, but still within a range that makes battery operation possible. According to the manufacturer, the display itself draws 440 \u00b5A, according to my measurement it is 560 \u00b5A.<\/p><p>The EA DOG display appears to be much faster than the Nokia 5110, with a waking phase of just 8 ms. In this respect, it is not really worth switching from displaying seconds to minutes only. <\/p>\n\n<h2 class=\"wp-block-heading\" id=\"alarm_clock_v6\">Alarm clock -Version 6 with ST7567 based display<\/h2>\n\n<p>I found the ST7567-based display from OPEN-SMART on AliExpress. It is representative of other LCDs that work without a backlight. I ordered two and both worked(!). I&#8217;ll give you the result straight away:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-1024x380.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"380\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-1024x380.jpg\" alt=\"Alarm clock -Version 6 with ST7567 based display\" class=\"wp-image-23677\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-1024x380.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-300x111.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-768x285.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-1536x570.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-2048x759.jpg 2048w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/open_smart-1320x489.jpg 1320w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alarm clock -Version 6 with ST7567 based display<\/figcaption><\/figure>\n\n<p>I won&#8217;t provide a Fritzing scheme for the circuit here. It should be clear from the previous examples and the sketch. It was controlled via the U8x8 library, which is part of the <a href=\"https:\/\/github.com\/olikraus\/u8g2\/tree\/master\" target=\"_blank\" rel=\"noopener\">U8g2 library<\/a> from <a href=\"https:\/\/github.com\/olikraus\" target=\"_blank\" rel=\"noopener\">olikraus<\/a>. With it, I achieved a current consumption of approx. 0.8 mA in the sleep phase.<\/p><p>To provide a little variety, I have added a function to the sketch that switches on the backlight for 10 seconds (= 10x wake-up) when one of the push-buttons is pressed:<\/p>\n\n<div class=\"scroll-paragraph-long\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ds3231_with_sleep_and_st7567_lcd.ino\" data-enlighter-title=\"ds3231_with_sleep_and_st7567_lcd.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;RTClib.h&gt;  \/\/ library for the DS3231\r\n#include &lt;U8x8lib.h&gt;\r\n#include &lt;SPI.h&gt;\r\n#include &lt;avr\/sleep.h&gt; \/\/ hardware-specific sleep library for AVR MCUs\r\n#define SNOOZE_TIME 60  \/\/ set snooze time\r\n#define SET_INCREMENT_DELAY 260 \/\/ incrementation time for settings\r\n#define MAX_ALARM_DURATION 20000 \/\/ maximum duration of an alarm\r\n#define BACKLIGHT_ON_PERIOD 10 \/\/ backlight on period in seconds\r\nvolatile bool setItemKeyPressed = false; \/\/ flag for item key\r\nvolatile bool setValueKeyPressed = false; \/\/ flag for value key\r\nvolatile unsigned long lastLow; \/\/ needed to handle bouncing\r\nunsigned long wakeUpNo = 0;\r\nunsigned long int lastKeyPress = 0;\r\nbool alarmOn = false; \/\/ alarm activated\r\nconst int setItemPin = 2; \/\/ choose item to set \/ time setting mode\r\nconst int setValuePin = 3; \/\/ set (increment) value \/ alarm setting mode\r\nconst int alarmPin = 4;  \/\/ Pin for the alarm switch\r\nconst int wakeUpPin = 5;\r\nconst int backlightPin = 6;\r\n\r\ntypedef enum TIME_UNIT { \/\/ needed for struct \"timeElement\"\r\n    YEAR, MONTH, DAY, HOUR, MINUTE, SECOND\r\n} timeUnit;\r\n\r\ntypedef enum SET_MODE { \/\/ setting modes\r\n    DATE_TIME, ALARM\r\n} setMode;\r\n\r\nchar daysOfTheWeek[7][12] = {\"SUNDAY   \", \"MONDAY   \", \"TUESDAY  \", \"WEDNESDAY\", \"THURSDAY \", \"FRIDAY   \", \"SATURDAY \"};\r\n\r\nstruct timeElement{ \/\/ for date\/time\/alarm setting\r\n    timeUnit tUnit;\r\n    uint16_t tMin; \/\/ minimum value\r\n    uint16_t tMax; \/\/ maximum value\r\n    char tname[7]; \/\/ name to display\r\n};\r\n\r\ntimeElement tElementYear = {YEAR, 2025, 2050, \"YEAR\"};\r\ntimeElement tElementMonth = {MONTH, 1, 12, \"MONTH\"};\r\ntimeElement tElementDay = {DAY, 1, 31, \"DAY\"};\r\ntimeElement tElementHour = {HOUR, 0, 23, \"HOUR\"};\r\ntimeElement tElementMinute = {MINUTE, 0, 59, \"MINUTE\"};\r\n\r\nRTC_DS3231 rtc;   \/\/ create RTC_DS3231 object\r\nDateTime alarmTime = DateTime(2014, 1, 1, 7, 0, 0);\r\nU8X8_ST7567_JLX12864_4W_HW_SPI u8x8(\/* cs=*\/ 7, \/* dc=*\/ 9, \/* reset=*\/ 8); \r\n\r\nvoid setup () {\r\n    Serial.begin(115200);\r\n    ADCSRA = 0; \/\/ ADC off (would consume current in deep sleep)\r\n\r\n    u8x8.begin();\r\n    u8x8.setPowerSave(0);\r\n    pinMode(backlightPin, OUTPUT);\r\n    u8x8.setFont(u8x8_font_saikyosansbold8_u);\r\n    setBacklight(true); \/\/ Light on\r\n\r\n    if (! rtc.begin()) {\r\n        Serial.println(F(\"Couldn't find RTC\"));\r\n        while(1){}\r\n    }\r\n    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); \/\/ \/\/ set rtc to date\/time of compilation\r\n    rtc.disable32K();  \/\/ stop signal at the 32K pin\r\n    rtc.clearAlarm(1);\r\n    rtc.clearAlarm(2);\r\n    rtc.disableAlarm(1);\r\n    rtc.disableAlarm(2);\r\n    rtc.writeSqwPinMode(DS3231_OFF); \/\/ stop signal at the SQW pin\r\n    rtc.setAlarm1(alarmTime, DS3231_A1_PerSecond);\r\n    \r\n     \/* pressing the item or value button will cause a low signal at the corresponding pin\r\n       and trigger an interrupt *\/\r\n    pinMode(setItemPin, INPUT_PULLUP);\r\n    pinMode(setValuePin, INPUT_PULLUP);\r\n    pinMode(alarmPin, INPUT_PULLUP);\r\n    attachInterrupt(digitalPinToInterrupt(setItemPin), setItemKeyISR, FALLING);\r\n    attachInterrupt(digitalPinToInterrupt(setValuePin), setValueKeyISR, FALLING);\r\n    PCICR = (1&lt;&lt;PCIE2);    \/\/ enable PCINT[23:16] interrupts\r\n    PCMSK2 = (1&lt;&lt;PCINT21); \/\/ D5 = PCINT21 for wake up\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid loop() {\r\n\r\n    printDateTime();\r\n        \r\n    if(digitalRead(setItemPin) == LOW){ \/\/ item key = date\/time setting key\r\n        goIntoSetMode(DATE_TIME);\r\n        lastKeyPress = wakeUpNo; \r\n    }\r\n\r\n    if(digitalRead(setValuePin) == LOW){ \/\/ value key = alarm key\r\n        goIntoSetMode(ALARM);\r\n        lastKeyPress = wakeUpNo;\r\n    }\r\n    \r\n    if(rtc.alarmFired(2) &amp;&amp; alarmOn){\r\n        alarmAction();   \/\/ act on alarm\r\n    }\r\n\r\n    checkAlarmSetting();  \/\/ check whether alarm was (de-)activated\r\n\r\n    set_sleep_mode(SLEEP_MODE_PWR_DOWN); \/\/ choose power down mode\r\n    sleep_mode(); \/\/ sleep now!\r\n    rtc.clearAlarm(1); \r\n    \r\n    wakeUpNo++;\r\n    backlightCheck();  \r\n}\r\n\r\nvoid checkAlarmSetting(){\r\n    if(!digitalRead(alarmPin) &amp;&amp; !alarmOn){\r\n        alarmOn = true;\r\n        u8x8.drawString(15,0,\"A\"); \/\/ display alarm flag\r\n        rtc.setAlarm2(alarmTime, DS3231_A2_Hour);\r\n    }\r\n    else if (digitalRead(alarmPin) &amp;&amp; alarmOn){\r\n        alarmOn = false;\r\n        u8x8.drawString(15,0,\" \"); \/\/ delete alarm flag\r\n        rtc.disableAlarm(2);\r\n    }\r\n}\r\n\r\nvoid goIntoSetMode(setMode settingMode){\r\n    alarmOn = false;\r\n    u8x8.clear();\r\n    u8x8.drawString(0,0,\"PRESS 1 SEC\");\r\n    delay(1000); \/\/ press 1 second to go into setting mode\r\n    u8x8.clearLine(0);\r\n    if (digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){\r\n        u8x8.drawString(0,0,\"SETTING MODE\");\r\n        if(settingMode == DATE_TIME){\r\n            u8x8.drawString(0,2,\"SET DATE\/TIME\");\r\n        }\r\n        else{\r\n            u8x8.drawString(0,2,\"SET ALARM\");\r\n        }\r\n        \/* wait until button is released *\/\r\n        while(digitalRead(setItemPin) == LOW){}\r\n        while(digitalRead(setValuePin) == LOW){}\r\n        delay(50); \/\/ debouncing\r\n        if(settingMode == DATE_TIME){\r\n            setDateTime();\r\n        }\r\n        else{\r\n            setAlarmTime();\r\n        }\r\n    }\r\n    rtc.clearAlarm(1);   \r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\nvoid setDateTime(){  \/\/ date\/time setting procedure\r\n    DateTime now = rtc.now(); \/\/ get current time\r\n    uint16_t tItem = 0; \r\n    tItem = setDateTimeElement(&amp;tElementYear, now.year());\r\n    adjustRTC(YEAR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMonth, now.month());\r\n    adjustRTC(MONTH, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementDay, now.day());\r\n    adjustRTC(DAY, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementHour, now.hour());\r\n    adjustRTC(HOUR, tItem);\r\n    now = rtc.now();\r\n    tItem = setDateTimeElement(&amp;tElementMinute, now.minute());\r\n    adjustRTC(MINUTE, tItem);\r\n    adjustRTC(SECOND, 0);\r\n    u8x8.clear();\r\n    if(alarmOn){\r\n        u8x8.drawString(15,0,\"A\"); \/\/ display \"alarm is on\" flag\r\n    }\r\n    printDateTime();\r\n}\r\n\r\nvoid setAlarmTime(){  \/\/ procedure to set an alarm\r\n    uint16_t value = 0;\r\n    value = setDateTimeElement(&amp;tElementHour, alarmTime.hour());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), value, alarmTime.minute(), 0);\r\n    value = setDateTimeElement(&amp;tElementMinute, alarmTime.minute());\r\n    alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), alarmTime.hour(), value, 0);\r\n    u8x8.clear();\r\n    char alarmTimeBuf[] = \"hh:mm\";\r\n    alarmTime.toString(alarmTimeBuf);\r\n    u8x8.drawString(0,0,\"ALARM: \");\r\n    u8x8.drawString(8,0, alarmTimeBuf);\r\n    delay(1000); \/\/ Show Alarm Time for one second\r\n    u8x8.clear();\r\n    printDateTime();\r\n}\r\n\r\nvoid alarmAction(){\r\n    u8x8.clear();\r\n    unsigned long alarmStart = millis();\r\n    \/* alarm was fired, not key pressed, and alarm did not exceed max. duration *\/\r\n    while(!setItemKeyPressed &amp;&amp; !setValueKeyPressed &amp;&amp; (millis() - alarmStart &lt; MAX_ALARM_DURATION)){\r\n        u8x8.drawString(4,3,\"ALARM!\");\r\n        delay(500); \r\n        u8x8.clear();\r\n        delay(500);\r\n        if(millis() &lt; alarmStart) {   \/\/ if millis() overflow occurred\r\n            alarmStart = 0;\r\n        }\r\n\r\n    }\r\n    \/* wait till buttons are released: *\/\r\n    while(digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW){}\r\n    delay(50); \/\/ debouncing\r\n    DateTime now = rtc.now();\r\n    if(millis() - alarmStart &lt; MAX_ALARM_DURATION){\r\n        alarmTime = now + TimeSpan(SNOOZE_TIME);  \/\/ set new alarm (snooze)\r\n        rtc.setAlarm2(alarmTime, DS3231_A2_Hour); \/\/ alarm if hours\/minutes match\r\n        u8x8.drawString(15,0,\"S\"); \/\/ display snooze flag\r\n    }\r\n    else{\r\n        alarmOn = false;\r\n    }\r\n    rtc.clearAlarm(2);\r\n    rtc.clearAlarm(1);\r\n    setItemKeyPressed = false;\r\n    setValueKeyPressed = false;\r\n}\r\n\r\n\/* This functions sets a time element. Pressing the value key increments the value until\r\n   the maximum value is reached. Pressing the item key will return. *\/ \r\nuint16_t setDateTimeElement(timeElement *tE, uint16_t currentSet){\r\n    char buf[13];\r\n    u8x8.clearLine(0);\r\n    u8x8.setCursor(0,0);\r\n    sprintf(buf, \"%s:\", tE-&gt;tname);\r\n    u8x8.drawString(0,0,buf);\r\n    sprintf(buf, \"%02d\", currentSet);\r\n    u8x8.drawString(8,0,buf);\r\n    setItemKeyPressed = false;\r\n    while(!setItemKeyPressed){    \r\n        if(setValueKeyPressed){\r\n            while(digitalRead(setValuePin) == LOW){\r\n                currentSet++;\r\n                if(currentSet &gt; tE-&gt;tMax){\r\n                    currentSet = tE-&gt;tMin;\r\n                }\r\n                sprintf(buf, \"%02d\", currentSet);\r\n                u8x8.drawString(8,0,buf);\r\n                delay(SET_INCREMENT_DELAY);                \r\n            }\r\n        }\r\n    }\r\n    setItemKeyPressed = false;\r\n    return currentSet;\r\n}\r\n\r\nvoid printDateTime(){  \/\/ display date\/time\r\n    DateTime now = rtc.now();\r\n\r\n    char datBuf[] = \"DD.MM.YYYY\";  \/\/ define the date format\r\n    char timeBuf[] = \"hh:mm:ss\";  \/\/ define the time format\r\n    Serial.println(now.toString(datBuf));  \/\/ print date \r\n    Serial.println(now.toString(timeBuf));  \/\/ print time \r\n    \r\n    u8x8.drawString(0,0,daysOfTheWeek[now.dayOfTheWeek()]);\r\n    u8x8.drawString(0,2,datBuf); \/\/ display date\r\n    u8x8.setFont(u8x8_font_courB18_2x3_f);\r\n    u8x8.drawString(0,4,timeBuf); \/\/ display time\r\n    u8x8.setFont(u8x8_font_saikyosansbold8_u);\r\n}\r\n\r\nvoid adjustRTC(timeUnit tU, uint16_t value){  \/\/ adjust year, month, day etc.\r\n    DateTime now = rtc.now();\r\n    switch(tU){\r\n        case(YEAR):\r\n            rtc.adjust(DateTime(value, now.month(), now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(MONTH):\r\n            rtc.adjust(DateTime(now.year(), value, now.day(), now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(DAY):\r\n            rtc.adjust(DateTime(now.year(), now.month(), value, now.hour(), now.minute(), now.second()));\r\n            break;\r\n        case(HOUR):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), value, now.minute(), now.second()));\r\n            break;\r\n        case(MINUTE):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), value, now.second()));\r\n            break;\r\n        case(SECOND):\r\n            rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), value));\r\n            break;\r\n    }\r\n    delay(10);\r\n}\r\n\r\nvoid setBacklight(bool on){\r\n    if(on){\r\n        digitalWrite(backlightPin, LOW);\r\n    }\r\n    else digitalWrite(backlightPin, HIGH);\r\n}\r\n\r\nvoid backlightCheck(){\r\n    if(wakeUpNo - lastKeyPress &lt; BACKLIGHT_ON_PERIOD){\r\n        setBacklight(true);\r\n    }\r\n    else setBacklight(false);\r\n}\r\n\r\nvoid setItemKeyISR(){ \/\/ ISR for pressed item key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setItemKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nvoid setValueKeyISR(){ \/\/ ISR for pressed value key\r\n    if(millis()-lastLow &gt;= 300){ \/\/ ignore bouncing when button is released\r\n        setValueKeyPressed = true;\r\n    }\r\n    lastLow = millis();\r\n}\r\n\r\nISR (PCINT2_vect){} \/\/ PCINT2_vect: interrupt vector for PORTD<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\n\n<h2 class=\"wp-block-heading\" id=\"transfer_to_other_boards\">Transfer of the concept to other microcontrollers <\/h2>\n\n<p>If you want to transfer the alarm clock concept in battery mode to other microcontrollers or boards, you first need to familiarize yourself with the available sleep modes, their power consumption and the wake-up methods.<\/p><p>Let&#8217;s take the ESP32 as an example. This is basically a real power guzzler. In deep sleep, however, some ESP32 boards (e.g. Adafruit ESP32 Feather V2 or FireBeetle) consume very little current. The timer, external interrupts or touch pins are available as wake-up methods. So, enough options are available.    <\/p><p>However, the ESP32 performs a restart when it wakes up from deep sleep. In other words, it has forgotten everything if you do not take any further action. You can query the time and alarm time in the DS3231. But how is the ESP32 supposed to know that the alarm clock is in snooze mode, for example? This could be written to the RTC memory or the flash (e.g. via the EEPROM function).    &nbsp;<\/p><p>So, there is a solution for everything. But the point is: changing the microcontroller can be a challenge. <\/p>\n\n<h2 class=\"wp-block-heading\" id=\"appendix_1\">Appendix 1: Repairing Nokia 5110 displays<\/h2>\n\n<p>If your Nokia display does not show anything and you have ruled out any wiring or code problems, then it could be due to contact problems with the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Elastomeric_connector\" target=\"_blank\" rel=\"noopener\">elastomeric connector<\/a>. What looks like a damper or spacer is an important electrical component that establishes contact between the circuit board and the display. <\/p><p>To access the rubber, detach the display from the circuit board by bending the four retaining clips outwards. The rubber is located at the top edge. Clean the rubber and the contact points with alcohol and reassemble the display. In my experience, there is a certain chance that it will then work.   <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_repair-1024x439.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"439\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_repair-1024x439.jpg\" alt=\"&quot;Repair&quot; of the Nokia 5110 display\" class=\"wp-image-23508\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_repair-1024x439.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_repair-300x129.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_repair-768x329.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_displ_repair.jpg 1258w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">&#8220;Repair&#8221; of the Nokia 5110 display, right: fit of the elastomeric connector<\/figcaption><\/figure>\n\n<h2 class=\"wp-block-heading\" id=\"appendix_2\">Appendix 2: Alternative versions of the Nokia 5110 display<\/h2>\n\n<p>There are (at least) two other versions of the display. Here is another red one, which differs first of all in the pinout: <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/Nokia_5110_alternative_version-1024x457.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"457\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/Nokia_5110_alternative_version-1024x457.jpg\" alt=\"Alternative version of the Noia 5110 display.\" class=\"wp-image-23639\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/Nokia_5110_alternative_version-1024x457.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/Nokia_5110_alternative_version-300x134.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/Nokia_5110_alternative_version-768x343.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/Nokia_5110_alternative_version.jpg 1118w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Alternative version of the Noia 5110 display.<\/figcaption><\/figure>\n\n<p>The pins are basically the same, but the order is different. In addition, the backlight lights up when you connect it to VCC. Now to the problem with this version: With a low contrast setting (<code>setContrast(30)<\/code>), the display was easy to read. However, when the backlight was switched on, everything was blurred. At a higher contrast (<code>setContrast(60)<\/code>) the display was readable with backlight, but without backlight all pixels were so dark that nothing could be recognized. <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_bad_display-1024x527.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"527\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_bad_display-1024x527.jpg\" alt=\"Nokia 5110 display - poor quality\" class=\"wp-image-23650\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_bad_display-1024x527.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_bad_display-300x154.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_bad_display-768x395.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_bad_display.jpg 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Nokia 5110 display &#8211; poor quality<\/figcaption><\/figure>\n\n<p>And finally, I tested this blue module:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_blue-1024x599.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"599\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_blue-1024x599.jpg\" alt=\"Nokia 5110 Display - blue version\" class=\"wp-image-23653\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_blue-1024x599.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_blue-300x175.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_blue-768x449.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_blue-1320x772.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/nokia_5110_blue.jpg 1500w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Nokia 5110 Display &#8211; blue version<\/figcaption><\/figure>\n\n<p>Apart from the backlight, nothing worked! Very unsatisfactory. <\/p>\n\n<h2 class=\"wp-block-heading\" id=\"appendix_3\">Appendix 3: A simple clock using an e-paper display<\/h2>\n\n<p>As already mentioned, e-paper displays are somewhat unique. They should be used for applications where the screen content does not change too frequently. In addition, larger microcontrollers should be used due to the high flash and SRAM requirements. However, they then stand out due to their excellent display and low power consumption. Here is the result of the simple clock on a 1.54-inch display from MH-ET LIVE:<\/p>\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\"><\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/MH_ET_LIVE_1_54-1024x646.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"646\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/MH_ET_LIVE_1_54-1024x646.jpg\" alt=\"Clock using an e-paper display\" class=\"wp-image-23690\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/MH_ET_LIVE_1_54-1024x646.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/MH_ET_LIVE_1_54-300x189.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/MH_ET_LIVE_1_54-768x484.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/MH_ET_LIVE_1_54-1320x832.jpg 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/MH_ET_LIVE_1_54.jpg 1500w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Clock using an e-paper display<\/figcaption><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\"><\/div>\n<\/div>\n\n<p>Here is the circuit (with 3.3 V version of the Arduino Pro Mini!):<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit-1024x597.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"597\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit-1024x597.png\" alt=\"Circuit for the e-paper-based clock\" class=\"wp-image-23688\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit-1024x597.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit-300x175.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit-768x447.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit-1536x895.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit-1320x769.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/04\/epaper_circuit.png 1579w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Circuit for the e-paper-based clock<\/figcaption><\/figure>\n\n<p>My example sketch below occupied 29254 bytes of the flash, which is pretty tight. The whole thing only works on the Pro Mini with &#8220;Paged Writing&#8221;. This means that the screen content is rendered in one goo, but piece-wise. It works, but not quite ideally. Incidentally, the power consumption was 0.32 mA in the sleep phase. <\/p><p>I will refrain from further explanations here, but only present the sketch. Maybe I&#8217;ll publish a separate post for e-paper displays sometime.\u00a0<\/p><p>I used the <a href=\"https:\/\/github.com\/ZinggJM\/GxEPD2\" target=\"_blank\" rel=\"noopener\">GxEPD2<\/a> library from <a href=\"https:\/\/github.com\/ZinggJM\" target=\"_blank\" rel=\"noopener\">Jean-Marc Zingg<\/a> to control the display. <\/p>\n\n<div class=\"scroll-paragraph-long\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ds3231_epaper_clock.ino\" data-enlighter-title=\"ds3231_epaper_clock.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;RTClib.h&gt;  \/\/ library for the DS3231\r\n#include &lt;avr\/sleep.h&gt; \/\/ hardware-specific sleep library for AVR MCUs\r\n#include &lt;GxEPD2_BW.h&gt;\r\n#include &lt;GxEPD2_3C.h&gt;\r\n#include &lt;GxEPD2_4C.h&gt;\r\n#include &lt;GxEPD2_7C.h&gt;\r\n#include &lt;Fonts\/FreeMonoBold12pt7b.h&gt;\r\n#include &lt;Fonts\/FreeMonoBold24pt7b.h&gt;\r\n#include \"GxEPD2_display_selection_new_style.h\"\r\n#define COMPILE_DURATION 40 \/\/ to \r\nconst int wakeUpPin = 5; \u00a0char daysOfTheWeek[7][12] = {\"Sunday   \", \"Monday   \", \"Tuesday  \", \"Wednesday\", \"Thursday \", \"Friday   \", \"Saturday \"};\r\n\r\nRTC_DS3231 rtc;   \/\/ create RTC_DS3231 object\r\nDateTime alarmTime = DateTime(2014, 1, 1, 7, 0, 0);\r\n\r\nvoid setup () {\r\n    Serial.begin(115200);\r\n    ADCSRA = 0; \/\/ ADC off (would consume current in deep sleep)\r\n\r\n    display.init(115200); \/\/ default 10ms reset pulse, e.g. for bare panels with DESPI-C02\r\n    \/\/display.init(115200, true, 2, false); \/\/ USE THIS for Waveshare boards with \"clever\" reset circuit, 2ms reset pulse\r\n    display.setRotation(1);\r\n    display.setFont(&amp;FreeMonoBold12pt7b);\r\n    display.setTextColor(GxEPD_BLACK);\r\n    display.fillScreen(GxEPD_WHITE);\r\n\r\n    if (! rtc.begin()) {\r\n        Serial.println(F(\"Couldn't find RTC\"));\r\n        while(1){}\r\n    }\r\n    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); \/\/ \/\/ set rtc to date\/time of compilation\r\n    rtc.disable32K();  \/\/ stop signal at the 32K pin\r\n    rtc.clearAlarm(1);\r\n    rtc.disableAlarm(1);\r\n    rtc.writeSqwPinMode(DS3231_OFF); \/\/ stop signal at the SQW pin\r\n    rtc.setAlarm1(alarmTime, DS3231_A1_Second);\r\n    rtc.adjust(rtc.now() + TimeSpan(COMPILE_DURATION));\r\n    \r\n     \/* pressing the item or value button will cause a low signal at the corresponding pin\r\n       and trigger an interrupt *\/\r\n    PCICR = (1&lt;&lt;PCIE2);    \/\/ enable PCINT[23:16] interrupts\r\n    PCMSK2 = (1&lt;&lt;PCINT21); \/\/ \r\n}\r\n\r\nvoid loop() {\r\n\r\n    printDateTime();\r\n        \r\n    set_sleep_mode(SLEEP_MODE_PWR_DOWN); \/\/ choose power down mode\r\n    sleep_mode(); \/\/ sleep now!\r\n    rtc.clearAlarm(1);   \r\n}\r\n\r\nvoid printDateTime(){  \/\/ display date\/time\r\n    DateTime now = rtc.now();\r\n\r\n    char datBuf[] = \"DD.MM.YYYY\";  \/\/ define the date format\r\n    char timeBuf[] = \"hh:mm\";  \/\/ define the time format\r\n    Serial.println(now.toString(datBuf));  \/\/ print date \r\n    Serial.println(now.toString(timeBuf));  \/\/ print time \r\n\r\n    display.firstPage();\r\n    do\r\n    {\r\n        display.setCursor(30, 20);\r\n        display.print(daysOfTheWeek[now.dayOfTheWeek()]);\r\n        display.setCursor(30, 60);\r\n        display.print(datBuf);\r\n        display.setFont(&amp;FreeMonoBold24pt7b);\r\n        display.setCursor(30, 150);\r\n        display.print(timeBuf);\r\n        display.setFont(&amp;FreeMonoBold12pt7b);\r\n    }\r\n    while (display.nextPage());\r\n    display.hibernate();  \r\n}\r\n\r\n\r\nISR (PCINT2_vect){} \/\/ PCINT2_vect: interrupt vector for PORTD<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ds3231_epaper_clock.ino\" data-enlighter-title=\"GxEPD2_display_selection_new_style.h\">#define GxEPD2_DISPLAY_CLASS GxEPD2_BW\r\n#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN  \/\/ DEPG0150BN 200x200, SSD1681, (FPC8101), TTGO T5 V2.4.1\r\n\r\n#ifndef EPD_CS\r\n#define EPD_CS SS\r\n#endif\r\n\r\n#if defined(GxEPD2_DISPLAY_CLASS) &amp;&amp; defined(GxEPD2_DRIVER_CLASS)\r\n#define GxEPD2_BW_IS_GxEPD2_BW true\r\n#define GxEPD2_3C_IS_GxEPD2_3C true\r\n#define GxEPD2_4C_IS_GxEPD2_4C true\r\n#define GxEPD2_7C_IS_GxEPD2_7C true\r\n#define GxEPD2_1248_IS_GxEPD2_1248 true\r\n#define GxEPD2_1248c_IS_GxEPD2_1248c true\r\n#define IS_GxEPD(c, x) (c##x)\r\n#define IS_GxEPD2_BW(x) IS_GxEPD(GxEPD2_BW_IS_, x)\r\n#define IS_GxEPD2_3C(x) IS_GxEPD(GxEPD2_3C_IS_, x)\r\n#define IS_GxEPD2_4C(x) IS_GxEPD(GxEPD2_4C_IS_, x)\r\n#define IS_GxEPD2_7C(x) IS_GxEPD(GxEPD2_7C_IS_, x)\r\n#define IS_GxEPD2_1248(x) IS_GxEPD(GxEPD2_1248_IS_, x)\r\n#define IS_GxEPD2_1248c(x) IS_GxEPD(GxEPD2_1248c_IS_, x)\r\n\r\n\r\n#if defined(ARDUINO_ARCH_AVR)\r\n#define MAX_DISPLAY_BUFFER_SIZE 800 \/\/ \r\n#endif\r\n#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS)\r\n#define MAX_HEIGHT(EPD) (EPD::HEIGHT &lt;= MAX_DISPLAY_BUFFER_SIZE \/ (EPD::WIDTH \/ 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE \/ (EPD::WIDTH \/ 8))\r\n#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS)\r\n#define MAX_HEIGHT(EPD) (EPD::HEIGHT &lt;= (MAX_DISPLAY_BUFFER_SIZE \/ 2) \/ (EPD::WIDTH \/ 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE \/ 2) \/ (EPD::WIDTH \/ 8))\r\n#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS)\r\n#define MAX_HEIGHT(EPD) (EPD::HEIGHT &lt;= (MAX_DISPLAY_BUFFER_SIZE) \/ (EPD::WIDTH \/ 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) \/ (EPD::WIDTH \/ 2))\r\n#endif\r\nGxEPD2_DISPLAY_CLASS&lt;GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)&gt; display(GxEPD2_DRIVER_CLASS(\/*CS=*\/ EPD_CS, \/*DC=*\/ 8, \/*RST=*\/ 9, \/*BUSY=*\/ 7));\r\n#endif<\/pre><br><p>\u00a0<\/p><br>\n","protected":false},"excerpt":{"rendered":"<p>I present concepts for a DS3231-based alarm clock. The alarm clock is controlled with only two buttons and a slide switch. I use the Nokia 5110 and the DOGS164 as energy-saving displays.  <\/p>\n","protected":false},"author":1,"featured_media":23350,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[571],"tags":[1377,2682,556,1060,2690,1506,2685,2686,1371,2684,666,2683,2687,1970,2689,2688],"class_list":["post-23530","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-projects","tag-alarm-en","tag-alarm-clock","tag-arduino-en-2","tag-arduino-pro-mini-en","tag-conductive-rubber","tag-deep-sleep-en","tag-dogs164-en","tag-dogs164w-en","tag-ds3231-en","tag-ea-dog-en","tag-i2c-en","tag-lcd-display-en","tag-nokia-5110-en","tag-power-consumption-en","tag-quality","tag-repair"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>DS3231-based alarm clock &#8226; Wolles Elektronikkiste<\/title>\n<meta name=\"description\" content=\"I&#039;ll show you how to build an alarm clock based on a DS3231 and an LCD. The alarm clock is controlled by just two push-buttons.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"DS3231-based alarm clock &#8226; Wolles Elektronikkiste\" \/>\n<meta property=\"og:description\" content=\"I&#039;ll show you how to build an alarm clock based on a DS3231 and an LCD. The alarm clock is controlled by just two push-buttons.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock\" \/>\n<meta property=\"og:site_name\" content=\"Wolles Elektronikkiste\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-11T15:53:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-04-19T21:06:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/Post_image.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"1000\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Wolfgang Ewald\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Wolfgang Ewald\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"55 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock\"},\"author\":{\"name\":\"Wolfgang Ewald\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"headline\":\"DS3231-based alarm clock\",\"datePublished\":\"2025-04-11T15:53:13+00:00\",\"dateModified\":\"2025-04-19T21:06:32+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock\"},\"wordCount\":4284,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/Post_image.jpg\",\"keywords\":[\"alarm\",\"Alarm clock\",\"Arduino\",\"Arduino Pro Mini\",\"conductive rubber\",\"deep sleep\",\"DOGS164\",\"DOGS164w\",\"DS3231\",\"EA DOG\",\"I2C\",\"LCD display\",\"Nokia 5110\",\"power consumption\",\"quality\",\"repair\"],\"articleSection\":[\"Projects\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock\",\"name\":\"DS3231-based alarm clock &#8226; Wolles Elektronikkiste\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/Post_image.jpg\",\"datePublished\":\"2025-04-11T15:53:13+00:00\",\"dateModified\":\"2025-04-19T21:06:32+00:00\",\"description\":\"I'll show you how to build an alarm clock based on a DS3231 and an LCD. The alarm clock is controlled by just two push-buttons.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#primaryimage\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/Post_image.jpg\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/Post_image.jpg\",\"width\":1000,\"height\":1000},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/ds3231-based-alarm-clock#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DS3231-based alarm clock\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\",\"name\":\"Wolles Elektronikkiste\",\"description\":\"Die wunderbare Welt der Elektronik\",\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\",\"name\":\"Wolfgang Ewald\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"width\":512,\"height\":512,\"caption\":\"Wolfgang Ewald\"},\"logo\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"DS3231-based alarm clock &#8226; Wolles Elektronikkiste","description":"I'll show you how to build an alarm clock based on a DS3231 and an LCD. The alarm clock is controlled by just two push-buttons.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock","og_locale":"en_US","og_type":"article","og_title":"DS3231-based alarm clock &#8226; Wolles Elektronikkiste","og_description":"I'll show you how to build an alarm clock based on a DS3231 and an LCD. The alarm clock is controlled by just two push-buttons.","og_url":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock","og_site_name":"Wolles Elektronikkiste","article_published_time":"2025-04-11T15:53:13+00:00","article_modified_time":"2025-04-19T21:06:32+00:00","og_image":[{"width":1000,"height":1000,"url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/Post_image.jpg","type":"image\/jpeg"}],"author":"Wolfgang Ewald","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Wolfgang Ewald","Est. reading time":"55 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#article","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock"},"author":{"name":"Wolfgang Ewald","@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"headline":"DS3231-based alarm clock","datePublished":"2025-04-11T15:53:13+00:00","dateModified":"2025-04-19T21:06:32+00:00","mainEntityOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock"},"wordCount":4284,"commentCount":2,"publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/Post_image.jpg","keywords":["alarm","Alarm clock","Arduino","Arduino Pro Mini","conductive rubber","deep sleep","DOGS164","DOGS164w","DS3231","EA DOG","I2C","LCD display","Nokia 5110","power consumption","quality","repair"],"articleSection":["Projects"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock","url":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock","name":"DS3231-based alarm clock &#8226; Wolles Elektronikkiste","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#website"},"primaryImageOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#primaryimage"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/Post_image.jpg","datePublished":"2025-04-11T15:53:13+00:00","dateModified":"2025-04-19T21:06:32+00:00","description":"I'll show you how to build an alarm clock based on a DS3231 and an LCD. The alarm clock is controlled by just two push-buttons.","breadcrumb":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#primaryimage","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/Post_image.jpg","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2025\/03\/Post_image.jpg","width":1000,"height":1000},{"@type":"BreadcrumbList","@id":"https:\/\/wolles-elektronikkiste.de\/en\/ds3231-based-alarm-clock#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/wolles-elektronikkiste.de\/en"},{"@type":"ListItem","position":2,"name":"DS3231-based alarm clock"}]},{"@type":"WebSite","@id":"https:\/\/wolles-elektronikkiste.de\/en#website","url":"https:\/\/wolles-elektronikkiste.de\/en","name":"Wolles Elektronikkiste","description":"Die wunderbare Welt der Elektronik","publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wolles-elektronikkiste.de\/en?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46","name":"Wolfgang Ewald","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","width":512,"height":512,"caption":"Wolfgang Ewald"},"logo":{"@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png"}}]}},"_links":{"self":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/23530","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/comments?post=23530"}],"version-history":[{"count":97,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/23530\/revisions"}],"predecessor-version":[{"id":23781,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/23530\/revisions\/23781"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media\/23350"}],"wp:attachment":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media?parent=23530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/categories?post=23530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/tags?post=23530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}