Yes, you read the title correct. Have you ever forgot your birthday, that you need someone else to remind you about it ? Or what if you can gift to someone you love, a device that'll wish them on their birthday for 50 times ? I kid you not, this simple Arduino powered Birthday Alarm that runs on a single CR2450 coin cell can wish your loved ones (or yourself) a happy birthday for 50 years, before the battery run out of juice.

This is my first project on Hackaday. I was really intrigued by the Coin Cell contest here and wanted to make something awesome. This birthday alarm thing simply popped into my head and I started researching on how long we can run something on a coin cell. I've never used the sleep modes of any microcontrollers before. So I had to learn everything about making MCUs run at insanely low currents and save every bit of energy from a cell. It was a challenge really! I used ATmega168P as the microcontroller (actually I modified an Arduino Nano that has ATmega168P on it by removing all the unwanted components such as the voltage regulator, USB bridge etc.) and used Arduino IDE to develop the firmware.

The time and birthday date can be programmed via serial monitor over USB. Once the time and alarm are set, the MCU goes to sleep mode. When the current RTC time matches your birthday every year, the LED will flash for a minute and will print a happy birthday message to the serial monitor. The average current consumption is around 1.2 uAh (including self-discharge)  which makes it possible to run it for more than 50 years on a CR2450 (540mAh) Lithium coin cell.


Now I'll walk you through the instructions on how to build this and show you the actual current consumption test.

1. Modifying the Arduino Nano

For this project you can use a bare microcontroller or use an Arduino Nano or Mini boards. All that is required is we must run it with internal oscillator (1MHz) and at full 1.8 - 5V operating range. The CR2450 or similar Lithium cells have a nominal voltage of 3V, and so we can run the MCU without using a voltage regulator. Chinese clones or Nano and Mini are extremely cheap that you can buy them for the chip's price! I used such a Nano clone that has CH340G as the USB to serial bridge. Below is the one I used.

Arduino Nano clone
Has CH340G

I had both ATmega168 and 328 versions. I bought the 168 versions by mistake a few years ago (now I found a use for it). In this particular board you need to remove,

I used the LED on pin 13 for debugging and as the main flasher, and so I didn't remove it. The capacitors need not be removed as they'll help attenuate noise. Once the regulator is removed, you need to short the pads of the voltage regulator as shown in the image. This is due to the routing used in the PCB design. Do not remove the crystal oscillator of the MCU yet becasue we'll need it to change the fuse bits. The MCUs will be having the default Arduino boot-loader and fuse settings that makes it run at external 16MHz crystal. If we remove the crystal before setting the fuse to use internal OSC, we simply can't program the chip with an ISP programmer. Below is the modified version of the Arduino Nano.

I still haven't removed the RX and TX LEDs becasue they're needed for debugging.
Look how I have shorted the voltage regulator pads.

2. Changing Fuse Bits of ATmega168P

Normally, the chips on the Arduino boards will be coming with the Arduino bootloader and fuse bits. We need to change this in order to run the MCU at low power modes. In order to achieve this we need to,

Fuse configuration for ATmega168P-AU

Above is the fuse settings for ATmega168P. Note that you need the "P" versions of the ATmega chips becasue they have the pico-power feature. The normal versions (non P) don't support these extra power saving modes. So make sure you get the P versions. You might now wonder why I'm using 168 instead of 328. That's becasue when I was testing the circuit, 328 seemed consuming around 30 uA for the same code and setting I used for 168 which only consumed around 2 uA. I don't know why this is. Like I said before, this is the first time I'm fiddling around with power saving modes such as deep sleep. So I might be missing something. If you know anything about it, please let me know in the comments. [Update : I later found the fuse setting of the 328 to be the culprit. I had set it wrong. I corrected it and obtained the exact result as the 168. So you can also use ATmega328P for this project.]

To change the fuse bits, we need an ISP programmer. There are many ISP programmers and compatible softwares. I used the USBasp as programmer and ProgISP as programming software. The chip ID or signature of the ATega168P-AU I used is 1E940B. This might vary depending on the version you have. To change the fuse bits,

ProgISP Configuration

If successful, a message will be printed to the console. From now on you'll need the ISP to flash the MCU. Below is the USBasp I used.

USBasp Version 2 with 10-pin connector
Selectable 5V or 3.3V

3. Compiling and Uploading

Now that we have changed the fuse bits of our microcontroller, we also need to tell the Arduino software and the compiler about the changes we made so that we can compile the code properly inside the Arduino IDE. How we do this is by adding a custom board definition in the "boards.txt" file that resides in the Arduino installation directory that is normally at <installed location>/Arduino/hardware/arduino/avr/boards.txt" on Windows systems. This might might be different for you depending on which OS you have, or version of the IDE you have. I'm using the IDE version 1.8.5

Once we locate the boards.txt file, you need to add a custom definition of a new Arduino Pro Mini board. Around line 655 will be the starting of the existing Pro Mini board definitions. There'll be many versions of the boards. So we need to add a new variant. Add the following definition to it and save.

## Arduino Pro or Pro Mini (3.3V, 1 MHz) w/ ATmega168
## -------------------------------------------------- (3.3V, 1 MHz) 

And here's a screenshot.

The highlighted part is the new board definition/variant

You need to edit the boards.txt while the Arduino is not running. Once you save the new boards.txt file and restart Arduino IDE you'll see the new board we just added in the list. Take a look at the screenshots below.

Select Arduino Pro or Pro Mini
And then 3.3V, 1MHz version we just added

Now we're ready to compile Arduino codes for our new board. As we're not using the Arduino bootloader (BL), we need to create a hex file of the program and use USBasp and ProgISP to flash the microcontroller. We can do this using the "Export compiled binary" option from Sketch menu of the IDE or hit Ctrl + Alt + S. When we do that, two hex files (intel format) will be created in the same directory our sketch resides. One hex file is with BL, and the other is without BL.

The second one is the hex file we need.

Once we have the hex file, in the ProgISP choose the Load Flash option to load the hex file we want to flash the MCU with then hit Auto button. If uploading is success, it'll be printed to the ProgISP's console.

4. Intersil ISL1208 I2C RTC

The Intersil ISL1208 is a low power RTC chip with I2C interface. It uses an external 32.768 KHz crucial to keep track of the time. It has month-date-hour-min-sec alarm registers. It only consumes around 400 nA at VBAT operation and a maximum of 1.2 uA at VDD. The operating voltage is from 1.8V to 5.5V. What makes this a good candidate are the power consumption and the month-date alarm feature. Normal RTCs such as DS1307 doesn't have a month setting in alarm register without which we can't generate a birthday alarm every year. ISL1208 has an interrupt output pin which will generate a 250 mS active LOW signal when the current time matches the alarm date and time. We'll use this to wake the MCU up from sleep mode which I'll explain further below.

As I had an SMD version of the ISL1208 I had to make a breakout board in order to be plugged onto my main board. Below is what I made.

I'll change the berg connector later
Clean the PCB after soldering.

Features of ISL1208

Current consumption while on VBAT
Time and Alarm registers accepts BCD values

5. CR2450N Coin Cell


6. Schematic

Use the above schematic to solder the modules on a perfboard. Add a jumper between VDD and VCC pins of the ISL1208 which is not shown in the figure. I'll explain later why you need this. The two 4.7K resistors are the I2C pull-ups. The values can range from 3.3K to above 5.6K. The R2 and R3 are pull-ups for the interrupt pins. Arduino Nano has two hardware interrupt pins - digital pin 3 and 2. Digital pin 2 will be used for the alarm wake up interrupt from the RTC and digital pin 3 will be used to wake the MCU up when you need to set the time. Below is the CP2102 USB-to-Serial module I used.

CP2102 USB-To-Serial module from rhydoLabz
We don't need the power from USB.

The USB-to-Serial module will be used to communicate over the serial monitor. The RX and TX pins of CP2102 are connected to RX and TX pins of Nano respectively. Note that you shouldn't connect the +5V from the USB to the main VCC voltage.

7. How Does It Work ?

The working of the device actually quiet simple. Let's see how the main algorithm works,

When powered up for the first time, all RTC registers will be zero and it doesn't increment until we first write any of them. To set the time on the RTC,

1. Turn the time update switch ON (connect the digital pin 3 to GND). We can not set time without pulling the pin 3 LOW.

2. First connect the device to your computer with a USB cable. A COM port will be established on your PC to communicate.

3. Find the COM port of the device from device manager.

4. Open any serial monitor software or Arduino serial monitor with the COM port of the device.

The MCU will print the below message to the serial monitor.

Serial Established.
Ready to update time.

5. Sending "t" command will print the current time, "a" will print the alarm date and time, and "c" will cancel the time setting operation and put the MCU into sleep mode.

6. You need to send the current time in the format shown below,



T = indicates time information

YY = least significant digits of a year (eg. 18 for 2018, range is from 00 to 99)

MM = month (eg. 01 for January, range is 01 to 12)

DD = date (eg. 24, range is 01 to 31)

hh = hours (eg. 06, range is 01 to 12 for 12 hour format)

mm = minutes (eg. 55, range is 00 to 59)

ss = seconds (eg. 30, range is 00 to 59)

p = period of the day for 12 hour format (0 = AM, 1 = PM)

# = delimiter

For example, to set the time and date "08:35:12 AM, 05-01-2018", we should send


to the device where,

= indicates time information

18 = the year 2018

01 = month January

05 = date

08 = hours

35 = minutes

12 = seconds

0 = AM

# = delimiter

If the operation is successful the MCU will print the received time to the console as,

Time update received = T1801050835120
Date and Time is 8:35:12 AM, 5-1-18

If the time string you entered is invalid, the below message will be printed,

Invalid time input - <original string>, <length of original string>

Once you successfully set the time, the RTC will keep track of it as long as there's power available to it. You can verify the time you just set by sending the "t" command. Setting the alarm is similar to this except the data format is different. To set the alarm you need to send it as,



A = indicates alarm information

MM = month

DD = date

hh = hours

mm = minutes

ss = seconds

p = time period (0 = AM, 1 = PM)

# = delimiter

Note that there's no year information with the alarm string becasue obviously we don't need it. For example to set my birthday "08:00:00 AM, 28-08" I need to send,


You can check the alarm time anytime with the command "a". Once the alarm time and date is set, it's time to put the MCU into sleep. So the device will print the following message,

Everything's set. Please disable the time set pin now.

Now you need to turn the time setting switch OFF ie, pull the digital pin 3 HIGH (the 10K pull-up will do that). The system won't sleep until you do this. When the time setting switch is turned OFF, the device will enter into sleep mode in 6 seconds and print the below message before it.

Well done! Sleeping in 6 seconds..

So, that's how you set the time and alarm. Now whenever you need to check the time or update it, you can turn ON the time setting switch and the system will wake up, establish serial communication and prompt you to send the time. It will print the following message up on waking up,

Serial Established.
Time update wake up.
Ready to update time.

If you're just checking if time is correct and don't want to change anything, send "c"command to cancel the operation and put the system into sleep again. You need to also disable the time setting switch at this point.

When the current time matches the alarm time ie. your birthday, the RTC will generate a 250 mS interrupt signal to the digital pin 2 of the Nano. This signal will wake up the system. Up on waking up the device will know that it's your birthday and will establish serial communication (only if you have the USB connected) and print the following message,

Tada! It's your birthday! Happy B'Day <your name> :)
See you on your next birthday! TC. Bye!
Sleeping in 6 seconds..

and it'll also flash the LED connected to digital pin 13. Here's a screenshot of the Arduino serial monitor while I was testing the system.

So, that's how operate this device. To understand this in the code level read the next section.

8. Code

This project is completely open source and therefore I've published the source code for the firmware on my GitHub at under MIT License. You're free to adapt, modify and redistribute without any restrictions. If you would add a backlink to this project from your modified one, that'd be appreciated. I've thoroughly commented the code and made it straight forward wherever possible.

We have total 13 functions/procedures in the code. They are,

1. void setup()

This is the Arduino's setup function that'll initialize everything and set the configuration registers of the ISl1208 RTC.

2. void loop()

The main loop function.

3. void sleepNow()

This function terminates all communications, disables the MCU's internal peripherals, attaches the interrupts to digital pins 3 and 2, and puts the system into deep sleep mode. Up on any interrupt, the program execution continues from the line after sleep_mode() . Note that before this normal program execution resumes, the MCU would've completed the interrupt service routines associated with the interrupt pins which are alarmInterrupt() and timeUpdateInterrupt()

4. void alarmInterrupt()

The ISR associated with the INT0 interrupt on digital pin 2.

5. void timeUpdateInterrupt()

The ISR associated with the INT1 interrupt on digital pin 3.

6. void fetchTime()

fetchTime() reads the time registers of the RTC and will print the current time to the console.

7. void blinkLED()

Blinks the LEDs obviously.

8. bool establishSerial()

Establishes serial communication with the help of USB-to-Serial module.

9. bool endSerial()

Ends serial communication.

10. byte bcdToDec(byte)

Accepts a BCD (Binary Coded Digits) value and translate it into corresponding decimal format. We need this becasue the RTC registers stores and accepts BCD values. So we need to convert to and from BCD occasionally.

11. byte decToBcd(byte)

Accepts a decimal value and translates it into corresponding BCD value.

12. void printTime()

Reads the RTC time registers and prints the current time to the console when "t"command is received.

13. void printAlarmTime()

Reads the RTC alarm registers and prints the alarm time and date to the console when the "a" command is received.

9. Testing

Good friend breadboard!

This would be the most interesting part of this project where you'll know how I ended up making a device that run for 50 years on a coin cell! I first protyped the entire circuit on a breadboard and finalized the design. I used a Li-Ion battery (3.6V) for testing purpose so as to save my brand new coin cells. I used my Fluke 87 True RMS multimeter for the current measurements. It has a 0.1 uA precision for the micro ampere range.

This was my table like when designing this..

Let's see how we can put the Atmega168P into deep sleep mode and reduce the current consumption drastically.

noInterrupts(); //temporarily disable interrupts 
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Choose our preferred sleep mode: 
sleep_enable(); // Set sleep enable (SE) bit: 
ADCSRA = 0; //disable ADC 
power_all_disable(); //disables all modules 
digitalWrite(LED_PIN, LOW);  //turn LED off to indicate sleep 
interrupts(); //re-enable interrupts 
sleep_mode(); //goes to sleep  

As I've said before this was the first time I used sleep modes in a microcontroller (MCU) becasue I've never needed it before. Most of the information related to AVR sleep modes was found from this forum thread and the AVR library documentation.

ATmega168P has five sleep modes.

More info on the sleep modes can be found here and inthis video. We're using the SLEEP_MODE_PWR_DOWN mode as you can see there. At this mode, the current consumption at 3.6V is only around 0.2 uA See the below graph from the ATmega168PA datasheet that shows the relation between active current vs supply voltage and power down current vs supply voltage.

Around 0.4 uA at 3V
Power down mode current of ATmega168P is <0.2 uA at 3V

Here's the actual reading of the current consumed by sleeping ATmega168P @1MHz consuming only 0.2 uA.

The minus sign is becasue I have connected the terminals in reverse.

The value hops between 0.1 uA and 0.2 uA due to the lack of precision. But such a precise measurement isn't necessary but would've been interesting to see.

The power consumption of ISL1208 RTC at max is 1.2 uA as per the datasheet. So if we add this with the power down mode current of the MCU we get 1.2 + 0.2 = 1.4 uA. My meter measured between 1.4 uA and 1.6 uA which justifies the calculations. The variations is only due to the lack of precision and our approximation or rounding of numbers.

Screenshot taken from the testing video

Here's an unlisted video from my YouTube channel where I show the testing.

Now let's do the simple math to find how long we can the system on a coin cell. The CR2450N from Reneta has a nominal capacity of 540mAh. I have two red SMD LEDs on the system which consume about 6 mA (even with two LEDs) with when turned ON. So that's the peak current consumption of the device at worst. How long these LEDs light up can be summarized as,

1. As long as the time setting switch is activated while you're setting the time (but you don't have to do this every year)

2. The 6 second delay before sleep.

3. LED flashes on your birthday and stay ON for about 19 seconds.

Let's not be accurate here but just make an approximation. Let's assume the time setting requires 2 minutes (LEDs will be ON for 2 mins) and and additional 1 minute ON time for other things including the birthday flashing. So it's total 3 minutes or 180 seconds for which the system consumes 3 mA current. Let's take the sleep or idle current as 1.6 uA, though it's lower actually. There's 31557600 seconds in a year of 365.25 days. If LEDs stay ON for 180 seconds in a year and OFF for (31557600 - 180) seconds, then the average current consumption will be,

Average Current = [((6 x 10^-3) x 180) + ((1.6 x 10^-6) x 31557420))] / 31557600

= (1.08 + 50.491872) / 31557600

= 51.571872 / 31557600

= 1.634 x 10^-6 = 1.634 uAh

If the average current consumption is 1.634 uA, then the 540 mAh cell can run the device for,

Time Span (approx) = (540 x 10^-3) / (1.634 x 10^-6) = 330477.3562 hours

= 13769.88 days

37.699 years

Note than this approximation is do not consider self-discharge of the battery. It'll be taken into account later. You can also use the ElectroDroid app to calculate battery life. Here's a screenshot of the calculations we just did.

From ElectroDroid android app


Can we reduce the current consumption further ? YES WE CAN! This came after I read @Ted Yapo 's TritilLED project that'll only consume 1.15 uA on average. That shook me! If I want to challenge others in running something cool for the longest time period on a coin cell, I need to do better than that, at least in the theoretical time span I can come up with. So I made further optimizations to my design to limit the average current consumption to 0.6 uA, yes I did that. Not let's see what optimizations I did,

1. To remove the extra red SMD LED to reduce the current when the system is active/running. Before it was 6 mA at max with two LEDs. So with one LED, it'll be reduced to half, ie 3 mA.

2. To reduce the current consumption of RTC, we need to disconnect the VDD pin of the ISL1208 RTC from the VBAT pin. Previously the VDD pin was connected to the VBAT pin where I supplied the 3V from the cell (you can see this in the schematic). In that configuration, I also had the LOW_POWER mode bit (LPMOD) of the RTC set to 1 activating the low power mode. So now you might think if the low power mode is set, then the chip might be consuming the lowest current. But that's not the case when we have the VDD tied to VBAT. Because low power mode bit is only useful if we have VDD > VBAT all the time. At such situation, the RTC's internal power switch will select VBAT as power source reducing the current further by 600 nA  when VDD >= VBAT (from typical 1.2 uA which I've mentioned before). But if we can run the RTC in VBAT only with VDD = 0, the current consumption can be reduced to the minimum ie, 400 nA as per the datasheet. So what I did is, first I disabled the low power mode by setting LPMOD to 0. Then added a jumper to the RTC breakout board to disconnect the VDD pin from VBAT when I don't need it. Why need the jumper is becasue, the VDD pin must be greater than or equal to VBAT in order for the I2C to work. So I can connect the jumpers when I need I2C while I'm setting the time, and can disconnect it after. This will let the RTC to consume the targeted 400 nA current. Tada! We did it!

Here's what the ISL1208 datasheet says about the low power mode - warns about the I2C problem. I encountered this once.

Now that we have reduced the current consumption of the RTC from 1.2 uA to 0.4 uA (400 nA), we can do the math again!

System Active Current = 3 mAh max

System Sleep Mode Current  = 0.4 uA (RTC) + 0.2 uA (MCU) = 0.6 uAh

System ON time = 60 s (time setting) + 19 s (birthday flashing) + 6 s (before sleep) = 85 seconds

System Sleeping Time = 31557600 s - 85 s = 31557515 seconds

Total time in a year = 31557600 seconds

Battery capacity = 540 mAh

The sleep mode current of the system measured by the Fluke 87 (screenshot taken from the test video)

Here's the current consumption test video after the optimizations and mods.


If we put those new values to the ElectroDroid's battery life calculator, we get, 101 years and 136 days. A theoretical operating time of more than a century! The average current consumption is now only 608 nA. Here's the screenshot.

Okay, What's the actual operating time ?

Batteries aren't perfect, nor anything we design. So let's also consider the 1% self discharge of the cell into account.

1% of initial capacity of 540 mAh CR2450N = 5.4 mAh

Self-discharge current =  5.4 mA per year or 616.4 nAh (5.4 mA / hours in a year)

Adding this 616.4 nAh with the 600 nAh sleep current = 1.216 uAh

Expected operating time with average current of 1.224 uAh = 50 years, and 131 days.

That's the actual operating time if the cell will be fine

Here's a table of actual operating times of different types of coin cells with the 1% self-discharge of initial capacity every year.

Cell Capacity Self discharge current (Isd) *Average current consumption Expected operating time
225 mAh
256 nAh 864 nAh 29 years, 264 days
540 mAh
616.4 nAh 1224 nAh (1.224 uAh) 50 years, 131 days
950 mAh
1084 nAh (1.084 uAh) 1692 nAh (1.692 uAh) 64 years, 33 days

*Average current is calculated with 3 mA active current and (Isd + 600 nA) sleeping current and doing the same math we previously did.

The main practical concerns associated with running the device for such long periods are,

1. Will the battery retain the charge and voltage for that long ?

2. The effects of environmental variations on the circuit and battery performance.

3. And you screwing up things! XD (don't drop it, chew it, sit on it, run your car through it or launch it into space!)

Coin cells are usually made to last for 10 years, which is their shelf life, and some even last longer than that. But that doesn't mean they'll start to disintegrate to an useless state after that. If the cell is physically fine, it can still power things. As per Renata datasheet, the self-discharge rate of CR2450N is less than 1% of the capacity every year. As per this datasheet from Energizer, that 1% figure is of the fresh capacity. Below is a chart that shows the standard discharge time in years (this doesn't consider the self-discharge or other exceptions). It clearly shows the theoretical expected operating time is way too longer than 10 years.

Source : Renata
Source : Renata

Self-discharging not only reduces the capacity but also reduces the voltage. Both ATmega168P and ISL1208 are designed to be operated fine at voltages as low as 1.8V. So the reduction in voltage might not be a problem. You can learn more about running systems with coin cells here.

To ensure long operating span, we must make sure the device is properly concealed against much of the environmental changes such as temperature, humidity, corrosion etc. These are some things you can do to protect your circuits,

1. Coat the PCB with long lasting conformal coating.

2. Place a pack of silica gel inside the enclosure.

3. Seal the enclosure with less temperature conductive materials and make it air tight.

4. Place it somewhere safe from naughty hands!

10. Building

I used a perfboard to solder everything as per the schematic. I used berg connectors for the battery, switch and LED so that it'll be easy to remove them if needed to. Below are the some images of the PCB.

Fully modular
Hand soldered maze!

To build the enclosure I used a 4" x 4" switch box which I bought from an electrical shop. I made two rectangular holes for the switch and USB. You can 3D print an enclosure if you want; sadly I don't have one. The dome was snatched from a cheap LED light and used super glue to fix it on the box. I painted it with silver spray paint.

Red SMD LED with 1K SMD resistor
The light with dome
I didn't have a coin cell holder and so i directly soldered onto the cell itself.
Needs some decorations! It looks naked :D

What missing is some decorations. I'm not good at decorating things. If you are going to gift this to someone, you know what to do ;)

USB connector from CP2102
Time Setting Switch (SPST)
Not the best paint job.

The final output is satisfying to the extend of my handwork. I might find someone else to decorate it.

11. Improvements

There's always room for improvement. Some of my suggestions are,

1. Using a Nokia 5110 LCD with or instead of the LED bulb. The LCD controller only consumes a couple of 100 uA at normal operating modes without the LED backlighting of course. Monochrome LCDs only consume extremely low currents. So using it would be better than a flashing LED, where you can actually print the happy birthday message on the screen itself. I might do this in future because I have couple of them lying around here.

2. A software that runs on the computer that'll set/sync the time accurately and automatically. I'm thinking of developing a simple one using Processing.

3. Flashing the LEDs to indicate the current age - for example if it's your 5th birthday (OMG are you're reading this ?!), it'll flash a sequence for 5 times. Currently you can not set the current age in the system. You may add this.

4. Designing a dedicated PCB in eagle (planned).

5. If blinking LED isn't your thing you can actually make this more exciting with for example using an opto-coupler you can turn on an AC alarm, music player, lights or anything you want to blink, move and scream on the birthday of the one you wish. You can even exclude the microcontroller and only use the interrupt from the RTC. Everything's possible!

So what are you waiting for ? Make one, decorate it with stickers, color papers, glitter or anything and gift to your loved ones or even yourself! And tell them to wait for this magical device to wish them happy birthday. 

What you see here is actually a prototype of a device that'll refine and release in future. So stay tuned. Please feel free to share if you have found any errors with this documentation or have any improvement suggestions. Happy making :)