You've Reached the Center of the Internet
It's a blog
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: 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:
It’s a basically circuit on a panel mounted inside a laser-cut dodecahedron. Here’s that panel:
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:
The layout:
An Onshape model of the dodecahedron:
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.
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(INTERRUPT_PIN, INPUT_PULLUP);
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);
pinMode(BEEPER_PIN, OUTPUT);
double_beep();
rtc.begin();
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
alarm = rtc.now() + TimeSpan(6, 20, 0, 0);
ready_to_beep = false;
// we don't need the 32K Pin, so disable it
rtc.disable32K();
// stop oscillating signals at SQW Pin
// otherwise setAlarm1 will fail
rtc.writeSqwPinMode(DS3231_OFF);
// 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
rtc.clearAlarm(2);
rtc.disableAlarm(2);
set_alarm();
// 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) {
beep();
rtc.clearAlarm(1);
} else {
double_beep();
set_alarm();
}
}
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
rtc.clearAlarm(1);
if (rtc.now() + WAKEUP_PERIOD + BUFFER_PERIOD > alarm) {
ready_to_beep = true;
rtc.setAlarm1(alarm, DS3231_A1_Date);
} else {
rtc.setAlarm1(rtc.now() + WAKEUP_PERIOD, DS3231_A1_Date);
}
}
void loop() {
LowPower.sleep();
}
void beep()
{
digitalWrite(BEEPER_PIN, HIGH);
delayMicroseconds(1000000);
digitalWrite(BEEPER_PIN, LOW);
}
void short_beep()
{
digitalWrite(BEEPER_PIN, HIGH);
delayMicroseconds(100000);
digitalWrite(BEEPER_PIN, LOW);
}
void double_beep() {
short_beep();
delayMicroseconds(100000);
short_beep();
}