I have a coworker who is fond of reminiscing about the good ol’ days, when his grandparents had a rotary dial phone on the wall that they were renting from the phone company. Combine this with his devotion to the tenkey pad on a full-size keyboard and the fact that I happened to have an old rotary dial in my bin of spare parts, and the path forward for this year’s April Fool’s prank was self-evident.
I mean, of course, that buying a cheap $13 mechanical keyboard off eBay and hacking the rotary dial into it was the most reasonable course of action.
Firmware
While the easy route out with a fabrication project like this is just to go for cosmetic completeness, I figured that it was imperative that the dial actually work for numeric input – especially since I was planning to remove the number row as well, thus forcing the use of the rotary dial for numeric or symbolic entry.
My rotary dial has two primary pairs of contacts. One goes open when the dial is moved past the 1
position, and the other creates the characteristic pulse train upon release (one pulse per numeric position). While one could use a pin-change interrupt, the timescale is so large that busy-waiting is acceptable. I used a DFRobot Beetle for this since its onboard ATMega32u4 provides native USB HID functionality.
while (digitalRead(ACTIVE)) // Active-low
{
int count = 0;
while (!digitalRead(ACTIVE))
{
if (digitalRead(PULSE))
{
count += 1;
delay(50);
}
}
if (count >= 2)
{
count /= 2;
count = (count == 10) ? 0 : count;
Keyboard.print(count);
}
}
Due to debouncing troubles, it seems to be double-reading each pulse. At some point I should throw a scope on it to confirm what the problem is, but it works quite adequately as-is. (My first try only had a 10ms delay, which empirically resulted in septuple-reading each pulse…)
Electrical
To power this keyboard, it seems like I would need two cables, one for the Arduino and one for the original keyboard controller. However, this is somewhat awkward. The topology that made the most sense to me was to shoehorn a USB hub into the keyboard, soldering both the Arduino and the keyboard controller to the hub’s device inputs.
This allowed me to solder the keyboard’s built-in USB port to the hub’s upstream connection. Thus, when I plug the physical keyboard into a computer, I am plugging in a USB hub that allows both devices to connect while preserving the illusion of a single-cable USB device.
The cheapest hub I could find with a useful form-factor was this wacky three-port beast.
As an interesting aside, the top-firing port on this hub is indeed SuperSpeed-compatible: the SSRX+/-
and SSTX+/-
pairs are an entirely independent interface from the D+/-
pair used for Full-Speed or High-Speed USB and so can be routed directly to the port without an intermediate hub.
The chip doing all the heavy lifting in this hub is the monolithic HS8836A
, which is supposedly rated for High-Speed USB traffic and has an impressively low count of support components.
In my case, I just had to desolder the existing ports in a clean enough fashion to avoid melting the hub IC (I definitely did not melt the first one I ordered) and wire in the USB signals from the keyboard and Arduino. Note how compact this board is thanks to the HS8836A
:
I used some shielded differential lines from an iMac’s LVDS display harness for the data connections to the Arduino because they were sitting in my junk pile and didn’t run away quickly enough. I suspect the impedance is totally off, but USB 1.1 is remarkably robust.
Keyboard
In order to replace the tenkey with the rotary dial, I had to remove the all of the switches for the number pad, which was relatively easy due to the fact that this keyboard has a single-sided PCB and my solder sucker is well-behaved.
Resting the base of the dial on top of the PCB would have been an option here, although it would make the dial itself sit very high in the air.
B