Multi Micro Macro
Acquisition of a bunch of spare cherry switches and a couple of pro-micros made me hanker after some Macro pad tinkering.
Upshot is a multi mode Macro pad, on power up hitting one of the buttons on the right selects either Keyboard mode, Mouse mode or Gamepad mode, indicated by one of the leds on the RHS (currently in ‘Mouse’ mode).
Following functionality is exposed in each mode:
Building the Macro Pad.
Body was cut (hacked/filed) out of 5mm Ply, with nylon standoffs.
Directional keys got 4 brown tactile switches, the top Tab/LMB and Enter/RMB keys got a couple of clicky switches (blue/white), the two LHS keys got a couple of linear reds. Basically pillaging the switch tester I got plus a couple of extras that I had lying around.
Magnet wire was used to wire up one pin of the switches to ground, looped around each pin and soldered in place. Solder is meant to burn off the insulation on the Magnet wire. I had to re-do a couple of the joins for a little longer to ensure this actually happened.
Other switch pins wired into specific pins on the Micro. Only 8 switches so anything more complicated like row/column wasn’t really necessary. Arduino is mounted on little stand offs that I’d previously glued in, and hotglued into place.
Next the indicator LEDs get soldered into place. They’re positioned so that when the top is hinged over, the 3 leds pop neatly into the three pre-drilled holes in the top plate.
And lastly the firmware. Just used the Arduino IDE to put something together quickly for it, uploaded to github as below.
Writing the firmware I immediately ran into the bane of every person who has ever connected a hardware switch to a microcontroller: switch bouncing.
In software land everything is, of course, beautifully simple. Flip a switch? Value transitions instantly from 0 to 1 or 1 to 0. Job done. In the real world things are not so simple, and clicking a switch can result in a stream of noise which eventually settles on a value. On a GPIO pin this will potentially result in a bunch of different transitions before the value steadies.
Cherry MX switches are reasonably well behaved, Cherry claim 5ms max (or possibly 1ms for newer switches) debounce time. There are different solutions, both software and hardware based. I went with a reasonably simple solution of requiring that the value be the same for 5 consecutive scans, at a scan interval of 5ms. Pretty conservative. Downside is of course that it will take 25ms before a keypress is registered.
In addition the number of iterations for which the key is depressed is sent to the relevant handler. This is used in the mouse handler to approximate a kind of mouse acceleration, as otherwise moving the mouse cursor slllooowwwwlllyyyy around the screen with the arrow keys gets boring pretty quickly.
Couple of predefined pins are checked at startup to set the mode. Keyboard by default, otherwise Mouse/Gamepad.
Depending on the mode, handling the individual key presses/releases is handed off to a handler.
The Keyboard Handler is pretty straightforward.
The mouse handler is a little more involved.
The mouse handler handles the rightmost keys as a mousewheel, but as discreet buttons rather than an ‘axis’. The X and Y axes have a kind of hybrid acceleration applied based on how long the button is pressed. Works reasonably well but is based on iteration count at the moment, would be better based off timestamping.
Full source is available on github here: