Arduino HID Pushbuttons in a Harmonica Case; New Workshop (and) Moving Sucks

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

....centers on the incredible C/C++ RP2040 SDK to Arduino port from Earle Philhower III, check out the documentation here, the Swiss accent guy's video here

Wow, Earle worked super hard so we don't have to--we owe Earle our gratitude!

Being an employable up-to-date tech (also intellectually disinterested?) I used Claude Code to geneate the Sketches for the project.

This bot is both amazing and terrifying....the damn thing got most of what is below right in one pass, making only a few stupid mistakes--whatever, easily fixed.....

This first sketch sets the RTC to current time. Modify the rtc.adjust line, compile, and upload.



#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. 

BENCHED MACH II

Here's the new setup. We are struggling with getting moved in and simple things like getting cold water from the kitchen sink.  But what you see below works--sorta.



Good enough to perf...Guess so.

See you next time.

No comments:

Post a Comment