Phone dial on an Arduino Uno
A telephone rotary dial on two pins: the Uno counts the pulses while the off-normal contacts are closed, and builds up the number dialed. The whole build, an Arduino Uno and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $39. On Mokxi they're free.
What you'll learn
- Counting pulses to read a digit
- INPUT_PULLUP inputs wired to ground
- Debouncing by waiting a few milliseconds
- Detecting the end of an action by a pin change
- Difficulty: Beginner
- Time: About 15 minutes
- Board: Arduino Uno R3
- Parts: 2
How it works
A rotary phone dial has two sets of contacts. DIAL goes to pin 2 and PULSE goes to pin 3. Both use the internal pull-up, so they read low when the contacts are closed.
While the wheel runs back, DIAL reads low. During that time the pulse contacts open once per step, and the sketch counts the pulses. One pulse is a 1 and ten pulses is a 0.
A pulse counts only after PULSE stays high for more than 5 ms, which filters out contact bounce. When DIAL goes high again, the count becomes a digit. The sketch adds it to a number up to 16 digits long and prints it.
Parts list
2 parts, plus the jumper wires. They retail for about $39; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Rotary dial
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Rotary dial pin GND | Arduino Uno R3 pin GND |
| Rotary dial pin PULSE | Arduino Uno R3 pin 3 |
| Rotary dial pin DIAL | Arduino Uno R3 pin 2 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Phone dial: an Uno reads the number dialed on an old telephone's rotary
// dial.
//
// dial GND -> GND DIAL -> pin 2 PULSE -> pin 3 (INPUT_PULLUP on both)
//
// While the wheel runs back, the off-normal contacts hold DIAL low, and the
// pulse contacts open once a step: PULSE goes high once for 1 and ten times
// for 0, ten pulses a second. Counting the pulses while DIAL is low, and
// reading the count when DIAL goes high again, gives the digit. A real dial's
// contacts bounce, so the count only takes a pulse that has stayed high for
// a few milliseconds.
//
// Click the holes of the dial.
const int DIAL_PIN = 2;
const int PULSE_PIN = 3;
int pulses = 0;
bool wasDialing = false;
bool wasHigh = false;
unsigned long highSince = 0;
bool counted = false;
char number[17];
int length = 0;
void setup() {
Serial.begin(9600);
pinMode(DIAL_PIN, INPUT_PULLUP);
pinMode(PULSE_PIN, INPUT_PULLUP);
Serial.println("Phone dial ready");
}
void loop() {
bool dialing = digitalRead(DIAL_PIN) == LOW;
bool high = digitalRead(PULSE_PIN) == HIGH;
if (dialing) {
if (high && !wasHigh) {
highSince = millis();
counted = false;
}
if (high && !counted && millis() - highSince > 5) {
pulses++;
counted = true;
}
}
wasHigh = high;
if (wasDialing && !dialing) {
int digit = pulses == 10 ? 0 : pulses;
if (length < 16) {
number[length++] = '0' + digit;
number[length] = 0;
}
Serial.print("digit ");
Serial.print(digit);
Serial.print(" number ");
Serial.println(number);
pulses = 0;
}
wasDialing = dialing;
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
It starts the serial port at 9600 and sets the dial pin and the pulse pin to INPUT_PULLUP. Then it prints "Phone dial ready".
void setup() {
Serial.begin(9600);
pinMode(DIAL_PIN, INPUT_PULLUP);
pinMode(PULSE_PIN, INPUT_PULLUP);
Serial.println("Phone dial ready");
}loop sketch.ino
While DIAL is low it counts each pulse that has stayed high for more than 5 ms. When DIAL goes high again, it turns the count into a digit, treating ten pulses as 0. It adds the digit to number, prints it with the number so far, and resets the count.
void loop() {
bool dialing = digitalRead(DIAL_PIN) == LOW;
bool high = digitalRead(PULSE_PIN) == HIGH;
if (dialing) {
if (high && !wasHigh) {
highSince = millis();
counted = false;
}
if (high && !counted && millis() - highSince > 5) {
pulses++;
counted = true;
}
}
wasHigh = high;
if (wasDialing && !dialing) {
int digit = pulses == 10 ? 0 : pulses;
if (length < 16) {
number[length++] = '0' + digit;
number[length] = 0;
}
Serial.print("digit ");
Serial.print(digit);
Serial.print(" number ");
Serial.println(number);
pulses = 0;
}
wasDialing = dialing;
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The digits come out wrong or too high. This project
Contact bounce is being counted as extra pulses. Keep the check that a pulse must stay high for more than 5 ms. - Nothing prints. This project
Check GND on the dial goes to GND, DIAL goes to pin 2 and PULSE goes to pin 3. - The number of pulses is wrong. Rotary dial
Count pulses only while the off-normal contact says the dial is turning. Use INPUT_PULLUP, debounce the pulse contact, and treat ten pulses as the digit 0. - Digits are read too early or doubled. Rotary dial
Pulses come about ten per second. Wait until the off-normal contact releases, or until a gap of about 200 ms passes, before you use the count. - Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected. - Pins misbehave or the board resets when you power motors or servos from it. Arduino Uno R3
Each I/O pin gives about 20 mA, 40 mA max. Power motors and servos from their own supply and join its ground to the Uno's GND.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.