Over the past several weeks I had to pack up my entire bench, all parts, all tools, and everything else I own, and move them to a rental place across town while my psychiatrist wife's house gets a new foundation.
Moving, especially when you are older and fully set in your ways, is stressful and generally not recommended.
We're moved in. Sort of.
To shake out my new geek space I built a simple USB-HID keyboard using perf, Arduino IDE, Claude Code, a DS3231 RTC (realtime clock) breakout board and an RP2040 MCU--specifically the Seeed XIAO-RP2040.
Press a button, the current date and time are displayed on whatever PC you have the widget plugged into. Press the other 2 and 2 pre-programmed strings appear.
Worked first time, here's what the finished thingy looks like--I may put labels and dumb decals on it, but good enough for now:
![]() |
| Hohner harp cases are great for small projects! |
PCBLESS
I hadn't built anything with perf in a long time, it was--fun?
![]() |
| Parts are mostly from the junk box.... |
The DS3231 I2C RTC breakout board is a no-name from Amazon. Without it, the RP2040 loses track of time during a power outage.
If you want this BOB, check the link here, but the link may break after a few months....whatever; this is a common BoB and is probably available from your favorite tariff-ingesting retailer--match the photo:
THE CODE
#include
#include
RTC_DS3231 rtc;
void setup() {
Serial.begin(115200);
Wire.begin();
if (!rtc.begin()) {
Serial.println("DS3231 not found!");
while (true);
}
// >>> SET YOUR CURRENT TIME HERE <<<
// Format: DateTime(YYYY, MM, DD, HH, MM, SS) — 24-hour time
rtc.adjust(DateTime(2026, 3, 15, 18, 50, 0));
Serial.println("RTC time has been set!");
// Verify by reading it back
DateTime now = rtc.now();
Serial.print("Time is now: ");
Serial.print(now.month()); Serial.print("/");
Serial.print(now.day()); Serial.print("/");
Serial.print(now.year()); Serial.print(" ");
Serial.print(now.hour()); Serial.print(":");
if (now.minute() < 10) Serial.print("0");
Serial.print(now.minute()); Serial.print(":");
if (now.second() < 10) Serial.print("0");
Serial.println(now.second());
}
void loop() {
// Nothing — time is set, job done.
}
The second sketch makes pushing the buttons display current date/time as well as a couple of strings--replace string1 and string2 values below with your own.
#include
#include
#include
/* Board manager:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
Board: Seeed XIAO RP2040
USB Stack: PICO SDK
Library required: RTClib by Adafruit (Library Manager)
DS3231 Wiring:
VCC -> 3.3V
GND -> GND
SDA -> D4 (GPIO 6)
SCL -> D5 (GPIO 7)
NOTE: Button 3 (Email 2) moved from D4 to D6 to free up I2C SDA.
*/
RTC_DS3231 rtc;
// Button pins
const int buttonD1 = D1; // Date/Time
const int buttonD3 = D3; // Email 1
const int buttonD6 = D6; // Email 2 — moved from D4 to avoid I2C conflict
// Button states
bool lastStateD1 = HIGH;
bool lastStateD3 = HIGH;
bool lastStateD6 = HIGH;
void setup() {
pinMode(buttonD1, INPUT_PULLUP);
pinMode(buttonD3, INPUT_PULLUP);
pinMode(buttonD6, INPUT_PULLUP);
Keyboard.begin();
Wire.begin();
if (!rtc.begin()) {
// RTC not found — flash onboard LED as error indicator
pinMode(LED_BUILTIN, OUTPUT);
while (true) {
digitalWrite(LED_BUILTIN, HIGH); delay(200);
digitalWrite(LED_BUILTIN, LOW); delay(200);
}
}
// If the RTC lost power (dead/missing battery), set it to compile time.
// Once the coin cell is installed this will not overwrite a valid time.
// if (rtc.lostPower()) {
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// }
}
void loop() {
bool currentStateD1 = digitalRead(buttonD1);
bool currentStateD3 = digitalRead(buttonD3);
bool currentStateD6 = digitalRead(buttonD6);
if (currentStateD1 == LOW && lastStateD1 == HIGH) {
delay(50);
printRTCTime();
delay(300);
}
if (currentStateD3 == LOW && lastStateD3 == HIGH) {
delay(50);
Keyboard.print("string1");
delay(300);
}
if (currentStateD6 == LOW && lastStateD6 == HIGH) {
delay(50);
Keyboard.print("string2");
delay(300);
}
lastStateD1 = currentStateD1;
lastStateD3 = currentStateD3;
lastStateD6 = currentStateD6;
}
void printRTCTime() {
DateTime now = rtc.now();
Keyboard.print(now.month());
Keyboard.print("/");
Keyboard.print(now.day());
Keyboard.print("/");
Keyboard.print(now.year());
Keyboard.print(" ");
if (now.hour() < 10) Keyboard.print("0");
Keyboard.print(now.hour());
Keyboard.print(":");
if (now.minute() < 10) Keyboard.print("0");
Keyboard.print(now.minute());
Keyboard.print(":");
if (now.second() < 10) Keyboard.print("0");
Keyboard.print(now.second());
}
THE PLUG
At some point I will need a PCB for the next one of these I build, and maybe a more durable case as well. For this, this blog's sponsor, PCBWAY, can fabricate the PCB's. In addition to top shelf PCB fabrication they also do fantastic work with assembly, 3D printing, injection molding, and much more. As always--you can help this blog by checking out the PCBWAY site. 










No comments:
Post a Comment