Fifty Year Beep (work in progress)

Phil, Will, and I are working on a project called The Fifty Year Beep. Here’s the idea: It’s a self-contained battery-powered circuit that beeps once and only once at a specified date and time fifty years in the future.

It would feature sleek, futuristic design. Our prototype looks like this: Photo front It could use some work.

You keep it in your home as a piece of art. On the day of your beep, you gather your friends and family to hear it. You’ve been waiting for fifty years! The moment finally comes and the device emits a single electronic beep.

I love this idea. I’m only half joking when I say this could be an actual product. A ten year beep would be a perfect wedding gift. Any big life event would be an occasion to give a beep.

We’ve been building one. Here’s what it looks like on the inside: Model front

It’s a basically circuit on a panel mounted inside a laser-cut dodecahedron. Here’s that panel: Model front

It’s based around SAMD21 microcontroller on a QT Py breakout board and an DS3231 RTC module. It’s powered by a TL2300 D-sized lithium thionyl chloride battery containing 19000 mAh at 3.6 V. The beep is produced by a small piezo buzzer.

The schematic: Photo front

The layout: Photo front

An Onshape model of the dodecahedron: Photo front

We removed all LEDs from the microcontroller and RTC module. We developed a scheme for setting an alarm on the RTC module and configuring the microcontroller to wake on an interrupt. This gets us down to a quiescent current of about 100 μA. Some naive math says that this version can last 190000 hours or about 21 years. The discharge curve for this battery chemistry is very flat, so we think this estimate might not be too far off.

Photo front

Here’s the code we used:

#include "ArduinoLowPower.h"
#include <RTClib.h>

RTC_DS3231 rtc;

// Pin used to trigger a wakeup
const int INTERRUPT_PIN = 1;
const int BEEPER_PIN = 0;

bool ready_to_beep;
DateTime alarm;
TimeSpan WAKEUP_PERIOD =  TimeSpan(1, 0, 0, 0);
TimeSpan BUFFER_PERIOD =  TimeSpan(0, 0, 0, 10);

void setup() {
  // enable internal pullup on all
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);


  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  alarm = + TimeSpan(6, 20, 0, 0);
  ready_to_beep = false;

  // we don't need the 32K Pin, so disable it

  // stop oscillating signals at SQW Pin
  // otherwise setAlarm1 will fail

  // turn off alarm 2 (in case it isn't off already)
  // again, this isn't done at reboot, so a previously set alarm could easily go overlooked

  // Attach a wakeup interrupt on pin 8, calling repetitionsIncrease when the device is woken up
  LowPower.attachInterruptWakeup(INTERRUPT_PIN, interrupt_handler, FALLING);

void interrupt_handler() {
  if (ready_to_beep) {
  } else {

void set_alarm() {
  // set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
  // if not done, this easily leads to problems, as both register aren't reset on reboot/recompile

  if ( + WAKEUP_PERIOD + BUFFER_PERIOD > alarm) {
    ready_to_beep = true;
    rtc.setAlarm1(alarm, DS3231_A1_Date);
  } else {
    rtc.setAlarm1( + WAKEUP_PERIOD, DS3231_A1_Date);

void loop() {

void beep()
    digitalWrite(BEEPER_PIN, HIGH);
    digitalWrite(BEEPER_PIN, LOW);

void short_beep()
    digitalWrite(BEEPER_PIN, HIGH);
    digitalWrite(BEEPER_PIN, LOW);

void double_beep() {

Author | Ben Wiener

Background in physics. Also interested in computing, robotics, hiking, woodworking, and other things.