Macropad Design Files
Flux stopped
Mapping note: this schematic maps D18/D19 using the common ATmega32U4 Leonardo mapping: D18 = PF7, D19 = PF6. The pasted requirement labels these as A4/A5; verify the exact firmware variant before committing production firmware.
Table
| Function | Arduino pin | ATmega32U4 pin/net | Connected to | Direction | Notes |
|---|---|---|---|---|---|
| Key 1 | D2 | PD1 | SW1 + D1 | Input pull-up | Active-low through diode |
| Key 2 | D3 | PD0 | SW2 + D2 | Input pull-up | Active-low through diode |
| Key 3 | D4 | PD4 | SW3 + D3 | Input pull-up | Active-low through diode |
| Key 4 | D5 | PC6 | SW4 + D4 | Input pull-up | Active-low through diode |
| Key 5 | D6 | PD7 | SW5 + D5 | Input pull-up | Active-low through diode |
| Key 6 | D7 | PE6 | SW6 + D6 | Input pull-up | Active-low through diode |
| Key 7 | D8 | PB4 | SW7 + D7 | Input pull-up | Active-low through diode |
| Key 8 | D9 | PB5 | SW8 + D8 | Input pull-up | Active-low through diode |
| Key 9 | D10 | PB6 | SW9 + D9 | Input pull-up | Active-low through diode |
| Key 10 | D14 | PB3 / MISO | SW10 + D10 | Input pull-up | Active-low through diode |
| Key 11 | D15 | PB1 / SCK | SW11 + D11 | Input pull-up | Active-low through diode |
| Encoder push | D16 | PB2 / MOSI | ENC1 push + D12 | Input pull-up | Active-low through diode |
| Encoder A | D18 | PF7 | ENC1 A | Input pull-up | Quadrature channel A |
| Encoder B | D19 | PF6 | ENC1 B | Input pull-up | Quadrature channel B |
| Reset | RESET | RESET | SW_RESET + R1 | Hardware | R1 = 10 kΩ pull-up |
| HWB | HWB | PE2 / HWB | R2 | Boot strap | R2 = 10 kΩ pull-down |
| USB | Native | D+ / D- | J1 via U2/R3/R4 | USB | USB HID device |
platformio.ini:Ini
[env:leonardo] platform = atmelavr board = leonardo framework = arduino monitor_speed = 115200 lib_deps = nicohood/HID-Project@^2.8.4
Cpp
#include <Arduino.h> #include <HID-Project.h> // Key inputs: active-low, using internal pull-ups. static const uint8_t KEY_PINS[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 16 }; static const uint8_t NUM_KEYS = sizeof(KEY_PINS) / sizeof(KEY_PINS[0]); static const uint8_t ENC_A_PIN = 18; static const uint8_t ENC_B_PIN = 19; static const uint16_t DEBOUNCE_MS = 5; static bool keyState[NUM_KEYS]; static bool lastRawState[NUM_KEYS]; static uint32_t lastChangeMs[NUM_KEYS]; static int8_t lastEncState = 0; static int32_t encoderPosition = 0; // Example keymap. Replace with QMK-style actions or custom HID shortcuts as needed. static const KeyboardKeycode KEYMAP[NUM_KEYS] = { KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, KEY_F24 }; static int8_t readEncoderState() { uint8_t a = digitalRead(ENC_A_PIN) == LOW ? 1 : 0; uint8_t b = digitalRead(ENC_B_PIN) == LOW ? 1 : 0; return (a << 1) | b; } static void handleEncoder() { static const int8_t transitionTable[16] = { 0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0 }; int8_t state = readEncoderState(); int8_t transition = (lastEncState << 2) | state; int8_t delta = transitionTable[transition & 0x0F]; lastEncState = state; if (delta != 0) { encoderPosition += delta; // Two quadrature transitions per detent is common; adjust for your encoder. if (encoderPosition >= 2) { Consumer.write(MEDIA_VOLUME_UP); encoderPosition = 0; } else if (encoderPosition <= -2) { Consumer.write(MEDIA_VOLUME_DOWN); encoderPosition = 0; } } } static void scanKeys() { uint32_t now = millis(); for (uint8_t i = 0; i < NUM_KEYS; i++) { bool rawPressed = (digitalRead(KEY_PINS[i]) == LOW); if (rawPressed != lastRawState[i]) { lastRawState[i] = rawPressed; lastChangeMs[i] = now; } if ((now - lastChangeMs[i]) >= DEBOUNCE_MS && rawPressed != keyState[i]) { keyState[i] = rawPressed; if (keyState[i]) { BootKeyboard.press(KEYMAP[i]); } else { BootKeyboard.release(KEYMAP[i]); } } } } void setup() { for (uint8_t i = 0; i < NUM_KEYS; i++) { pinMode(KEY_PINS[i], INPUT_PULLUP); keyState[i] = false; lastRawState[i] = false; lastChangeMs[i] = 0; } pinMode(ENC_A_PIN, INPUT_PULLUP); pinMode(ENC_B_PIN, INPUT_PULLUP); lastEncState = readEncoderState(); BootKeyboard.begin(); Consumer.begin(); } void loop() { scanKeys(); handleEncoder(); delay(1); }
Bash
pio run pio run -t upload pio device monitor
Platform & Toolchain
Pin Mapping
PlatformIO Setup
Complete Starter Firmware
Build & Flash