3D printer Case
https://www.printables.com/model/1559069-6-button-rp2040-zero-macro-pad/comments
Software Design Specification
(1)RP2040-Zero pinout definitions are as follows:
#define KEY1 8
#define KEY2 9
#define KEY3 10
#define KEY4 11
#define KEY5 12
#define KEY6 13
#define KEY7 7
#define PUSH_SW 6
#define INTA 5
#define INTB 4
#define RGB_LED 14
(2)The button definitions are as follows:
KEY6 = Switch Mode, Mode = 0 to 3.
Mode 0 :
KEY1 = WIN+d
KEY2 = win+r -> wait 500ms -> "devmgmt.msc" -> enter -> wait 2000ms -> enter
KEY3 = win+r -> wait 500ms -> "calc.exe" -> enter
KEY4 = enter key
KEY5 = "PassWord" + enter key
Rotary encoder push SW = PAUSE/PLAY
Rotary encoder right turn = volume up
Rotary encoder left turn = volume down
Mode 1 :
KEY1 = CTRL+X
KEY2 = CTRL+C
KEY3 = CTRL+V
KEY4 = CTRL+Z
KEY5 = CTRL+Y
Rotary encoder push SW = PAUSE/PLAY
Rotary encoder right turn = volume up
Rotary encoder left turn = volume down
Mode 2 :
KEY1 = left key
KEY2 = down key
KEY3 = right key
KEY4 = mouse button left
KEY5 = up key
Rotary encoder push SW = PAUSE/PLAY
Rotary encoder right turn = mouse wheel down
Rotary encoder left turn = mouse wheel up
Mode 3 :
KEY1 = '<' key
KEY2 = key keypad subtract
KEY3 = '>' key
KEY4 = WIN+d
KEY5 = key keypad add
Rotary encoder push SW = PAUSE/PLAY
Rotary encoder right turn = volume up
Rotary encoder left turn = volume down
(3)RGB_LED color
Mode 0 = The breathing light breathes approximately every 2 seconds, changing color with each breath.
The colors cycle through R, R+G, G, G+B, B, B+R.
Mode 1 = all color (R)
Mode 2 = all color (G)
Mode 3 = all color (B + 30%G)
Arduino Code:
/*
* 6Key_3D_case.ino
* Waveshare RP2040-Zero + 6 keys + rotary encoder + WS2812B x8
*
* Board : Raspberry Pi Pico / RP2040 (earlephilhower arduino-pico core)
* USB : Tools -> USB Stack -> "Adafruit TinyUSB" (or "Pico SDK")
* Libs : Adafruit NeoPixel
*/
#include <Keyboard.h>
#include <Mouse.h>
#include <Adafruit_NeoPixel.h>
#include <math.h>
// ---------------- Pin map ----------------
#define KEY1 8
#define KEY2 9
#define KEY3 10
#define KEY4 11
#define KEY5 12
#define KEY6 13 // Mode switch
#define KEY7 7 // reserved
#define PUSH_SW 6 // encoder push
#define INTA 5 // encoder A
#define INTB 4 // encoder B
#define RGB_LED 14
#define NUM_LEDS 8
#define LED_BRIGHTNESS 80 // 0-255 overall brightness cap
#define DEBOUNCE_MS 20
Adafruit_NeoPixel strip(NUM_LEDS, RGB_LED, NEO_GRB + NEO_KHZ800);
// ---------------- Globals ----------------
uint8_t mode = 0; // 0..3
const uint8_t keyPins[6] = { KEY1, KEY2, KEY3, KEY4, KEY5, KEY6 };
bool keyState[6] = { HIGH, HIGH, HIGH, HIGH, HIGH, HIGH };
unsigned long keyLastChange[6] = { 0, 0, 0, 0, 0, 0 };
bool pushState = HIGH;
unsigned long pushLastChange = 0;
// Rotary encoder (quadrature, interrupt-driven)
volatile int8_t encoderDelta = 0;
volatile uint8_t encoderLastAB = 0;
// LED breathing
unsigned long modeStartMs = 0;
uint8_t colorIndex = 0;
// ---------------- Forward decl ----------------
void handleEncoderISR();
void updateLED();
void handleKeyPress(uint8_t idx);
void handlePushClick();
void handleEncoderStep(int8_t dir);
// ---------------- Helpers ----------------
static inline void tapMod(uint8_t mod, uint8_t key) {
Keyboard.press(mod);
Keyboard.press(key);
delay(30);
Keyboard.releaseAll();
}
static inline void tapWinKey(uint8_t key) { tapMod(KEY_LEFT_GUI, key); }
static inline void tapCtrlKey(uint8_t key){ tapMod(KEY_LEFT_CTRL, key); }
static inline void tapShiftKey(uint8_t key) { tapMod(KEY_LEFT_SHIFT, key); }
// ---------------- Setup ----------------
void setup() {
for (uint8_t i = 0; i < 6; i++) pinMode(keyPins[i], INPUT_PULLUP);
pinMode(KEY7, INPUT_PULLUP);
pinMode(PUSH_SW, INPUT_PULLUP);
pinMode(INTA, INPUT_PULLUP);
pinMode(INTB, INPUT_PULLUP);
encoderLastAB = (digitalRead(INTA) << 1) | digitalRead(INTB);
attachInterrupt(digitalPinToInterrupt(INTA), handleEncoderISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(INTB), handleEncoderISR, CHANGE);
Keyboard.begin();
Mouse.begin();
strip.begin();
strip.setBrightness(LED_BRIGHTNESS);
strip.clear();
strip.show();
modeStartMs = millis();
}
// ---------------- Main loop ----------------
void loop() {
unsigned long now = millis();
// ---- 6 keys ----
for (uint8_t i = 0; i < 6; i++) {
bool s = digitalRead(keyPins[i]);
if (s != keyState[i] && (now - keyLastChange[i]) > DEBOUNCE_MS) {
keyLastChange[i] = now;
keyState[i] = s;
if (s == LOW) handleKeyPress(i); // pressed
}
}
// ---- Encoder push ----
bool p = digitalRead(PUSH_SW);
if (p != pushState && (now - pushLastChange) > DEBOUNCE_MS) {
pushLastChange = now;
pushState = p;
if (p == LOW) handlePushClick();
}
// ---- Encoder rotation ----
noInterrupts();
int8_t d = encoderDelta;
encoderDelta = 0;
interrupts();
// Full detent = 4 quadrature steps (typical mechanical encoder)
static int8_t acc = 0;
acc += d;
while (acc >= 4) { handleEncoderStep(+1); acc -= 4; }
while (acc <= -4) { handleEncoderStep(-1); acc += 4; }
// ---- LED ----
updateLED();
}
// ---------------- Encoder ISR (quadrature decode) ----------------
void handleEncoderISR() {
uint8_t ab = (digitalRead(INTA) << 1) | digitalRead(INTB);
uint8_t comb = (encoderLastAB << 2) | ab;
switch (comb) {
case 0b0001: case 0b0111: case 0b1110: case 0b1000: encoderDelta++; break;
case 0b0010: case 0b1011: case 0b1101: case 0b0100: encoderDelta--; break;
default: break; // invalid / no change
}
encoderLastAB = ab;
}
// ---------------- Key actions ----------------
void handleKeyPress(uint8_t idx) {
// idx 5 == KEY6 : switch mode
if (idx == 5) {
mode = (mode + 1) & 0x03;
modeStartMs = millis();
colorIndex = 0;
return;
}
switch (mode) {
// ============ Mode 0 ============
case 0:
switch (idx) {
case 0: tapWinKey('d'); break; // KEY1 Win+D
case 1: // KEY2 devmgmt.msc
tapWinKey('r');
delay(500);
Keyboard.print("devmgmt.msc");
Keyboard.write(KEY_RETURN);
delay(2000);
Keyboard.write(KEY_RETURN);
break;
case 2: // KEY3 calc.exe
tapWinKey('r');
delay(500);
Keyboard.print("calc.exe");
Keyboard.write(KEY_RETURN);
break;
case 3: Keyboard.write(KEY_RETURN); break; // KEY4 Enter
case 4: // KEY5 PassWord + Enter
Keyboard.print("PassWord");
Keyboard.write(KEY_RETURN);
break;
}
break;
// ============ Mode 1 ============
case 1:
switch (idx) {
case 0: tapCtrlKey('x'); break;
case 1: tapCtrlKey('c'); break;
case 2: tapCtrlKey('v'); break;
case 3: tapCtrlKey('z'); break;
case 4: tapCtrlKey('y'); break;
}
break;
// ============ Mode 2 ============
case 2:
switch (idx) {
case 0: Keyboard.write(KEY_LEFT_ARROW); break;
case 1: Keyboard.write(KEY_DOWN_ARROW); break;
case 2: Keyboard.write(KEY_RIGHT_ARROW); break;
case 3: Mouse.click(MOUSE_LEFT); break;
case 4: Keyboard.write(KEY_UP_ARROW); break;
}
break;
// ============ Mode 3 ============
case 3:
switch (idx) {
case 0: tapShiftKey(','); break; // '<'
case 1: Keyboard.write(KEY_KP_MINUS);break; // keypad -
case 2: tapShiftKey('.'); break; // '>'
case 3: tapWinKey('d'); break; // Win+D
case 4: Keyboard.write(KEY_KP_PLUS); break; // keypad +
}
break;
}
}
// Encoder push (all modes): Play / Pause
void handlePushClick() {
Keyboard.write(KEY_PLAY_PAUSE);
}
// Encoder rotate: dir = +1 (CW / right) or -1 (CCW / left)
void handleEncoderStep(int8_t dir) {
if (mode == 2) {
// Mouse wheel: right = wheel down (negative), left = wheel up (positive)
Mouse.move(0, 0, (dir > 0) ? -1 : +1);
} else {
Keyboard.write((dir > 0) ? KEY_VOLUME_INCREMENT : KEY_VOLUME_DECREMENT);
}
}
// ---------------- LED ----------------
void updateLED() {
static unsigned long lastShow = 0;
unsigned long now = millis();
if (now - lastShow < 20) return; // ~50 Hz refresh
lastShow = now;
uint32_t color = 0;
switch (mode) {
case 0: {
// Breathing ~2 s per breath, cycle color each breath
const unsigned long PERIOD = 2000;
unsigned long elapsed = now - modeStartMs;
if (elapsed >= PERIOD) {
modeStartMs = now;
colorIndex = (colorIndex + 1) % 6;
elapsed = 0;
}
float ph = (float)elapsed / (float)PERIOD; // 0..1
uint8_t v = (uint8_t)(sinf(ph * (float)PI) * 255.0f); // 0..255..0
uint8_t r = 0, g = 0, b = 0;
switch (colorIndex) { // R, R+G, G, G+B, B, B+R
case 0: r = v; break;
case 1: r = v; g = v; break;
case 2: g = v; break;
case 3: g = v; b = v; break;
case 4: b = v; break;
case 5: r = v; b = v; break;
}
color = strip.Color(r, g, b);
break;
}
case 1: color = strip.Color(255, 0, 0); break; // Red
case 2: color = strip.Color( 0, 255, 0); break; // Green
case 3: color = strip.Color( 0, 77, 255); break; // Blue + 30% Green
}
for (uint8_t i = 0; i < NUM_LEDS; i++) strip.setPixelColor(i, color);
strip.show();
}
.jpg)
.jpg)



.jpg)












