Hanging on the Telephone, Part 2: the Code September 26, 2013
Turning a rotary telephone dial into a USB device was easy. As I (re-)discovered, the dial is basically just a pair of switches: a normally-open ‘dialing’ switch, which closes while the dial is in motion, and a normally-closed ‘pulse’ switch, which opens and closes the same number of times as the number dialed. All I needed to do was count the number of pulses that occur while the ‘dialing’ switch is closed, then send a USB keypress event based on that number when the ‘dialing’ switch opens again.
I used a Digispark for this project, so the code reflects a few of its oddities. In order to cram software USB emulation onto a tiny microcontroller and still leave room for user code, they had to make some compromises. There are no interrupts available, and their own version of the delay()
function needed to be used to keep everything in sync. The hardware side is also a little odd: because the Digispark’s main header doesn’t provide a ground connection, I just set one of the digital I/O pins LOW
and used that. This seemed like a hack at the time, but I later saw this technique on one of Digistump’s own lists of power user tips, so I don’t feel so bad.
Here’s the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
/* Rotary "Keypad" (for Digispark) David Stokes, 2013 */ #include "DigiKeyboard.h" // 'Pulse' pin: normally closed, opens on pulse // This is one of the dial's blue wires. const byte PULSE_PIN = 0; // 'Dialing' pin: closes while dial is in motion (either direction) // This is one of the dial's white wires. const byte DIALING_PIN = 2; // A data pin used as a GND connection (for convenience) // This is the remaining blue and white wires from the dial. const byte GND_PIN = 1; // Debounce time. const unsigned long delayTime = 50; // Previous states of the inputs, to detect changes boolean lastPulse, lastDialing; // The number being dialed (i.e. pulse count) byte number; void setup() { // Set the pins as inputs, write HIGH to // activate the internal pull-up. pinMode(PULSE_PIN, INPUT); digitalWrite(PULSE_PIN, HIGH); pinMode(DIALING_PIN, INPUT); digitalWrite(DIALING_PIN, HIGH); // Use one of the data pins as a ground pinMode(GND_PIN, OUTPUT); digitalWrite(GND_PIN, LOW); // Get the initial states of the switches lastPulse = digitalRead(PULSE_PIN); lastDialing = digitalRead(DIALING_PIN); } void loop() { // This is supposed to help on some systems, // so I'm just going to cargo-cult it in. DigiKeyboard.sendKeyStroke(0); boolean pulse = digitalRead(PULSE_PIN); boolean dialing = digitalRead(DIALING_PIN); if (lastPulse && !pulse) { // PULSE_PIN changed HIGH to LOW number++; DigiKeyboard.delay(delayTime); } if (!lastDialing && dialing && number) { // DIALING_PIN changed from LOW to HIGH // and number is greater than 0 number = number == 10 ? 0 : number; DigiKeyboard.print(char(number + 48)); DigiKeyboard.delay(delayTime); number = 0; } lastPulse = pulse; lastDialing = dialing; } |
Leave a Reply
You must be logged in to post a comment.