Project showcase

OldArduiPhone (or the Hipster Cellphone!) © GPL3+

Connect a rotary dial telephone from the 80s to a cheap cellphone with an Arduino.

  • 8,328 views
  • 5 comments
  • 41 respects

Components and supplies

Ard nano
Arduino Nano R3
I used a UNO to do my prototyping and testing.
×1
A cheap Cellphone
The one I used is a ZTE Black S751
×1
An old rotary dial Telephone
Mine is a South African Telkom model - Good luck finding this exact one :D
×1
Mfr 25frf52 1k sml
Resistor 1k ohm
×13
Mfr 25frf52 10k sml
Resistor 10k ohm
×2
optoisolator
I used the KingBright KB817. Couldn't find is online :(
×13
11026 02
Jumper wires (generic)
×1
Omron b3f 1000 image 75px
SparkFun Pushbutton switch 12mm
×1

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

Overview

I was digging in my box of random electronic things that I don't use anymore and hope to find a way to recycle, one day and found this cute little cellphone.

And I thought "What if I took the cute little phone, tore it apart, ripped its entrails out and attached it to another older less cute phone!" And so I went and bought an old rotary dial telephone and started my adventure...

FYI, old rotary dial phones aren't easy to come by these days.

Step 1

Unfortunately, for this project, I can only show you a few pictures and share the code with you. I have no idea how much changes are going to be required in the code if you use another cellphone than the one I used.

But let's start on the easy piece. The dial itself.

When I started this project, this was my biggest worry. How was I going to read the dial? And the answer was... disappointingly easy.

The back of the dial is actually super simple. I'm guessing that the technology didn't vary that much from one phone to the other back then so you'll probably find a similar configuration when taking your old telephone apart...

The colors of the wires on the prototyping board below match the colors on the dial above. (The pink wire on my dial is connected to the brown. That's why there's no pink on the diagram)

Step 2

In the code, this is what does the work:

 int activeState = PIND;
 activeState = PIND & PULSE_ACTIVE; 
 while(activeState){
   off_hook = true;
   unsigned long val = myPulseIn(3, LOW, PULSE_IN_TIMEOUT); 
   //Serial.println(val); //for debugging
   if(val > MIN_VALID_PULSE && val < MAX_VALID_PULSE){
     digit++;
   }
   activeState = PIND;
   activeState = PIND & PULSE_ACTIVE;
   hasDigit = true;
 }   

On my dial, when nothing is happening on the dial, the orange wire reads 0v because the switch is open on that side, the grey one is closed so it reads 3.3v (But we don't care). When the dial is wound, the orange wire gets connected. This causes activeState to be true (sort of). Then when the dial unwinds, the other switch will start pulsing and the myPulseIn function counts the amount of time between on and off states. Everytime the switch is off for between MIN_VALID_PULSE (50000) and MAX_VALID_PULSE (150000 units of time - those aren't human units), digit is incremented. For a 1 this happens only once, for a 3, three times,... you get the idea :D

Now we have a digit to dial, so we dial it. The dialCellDigit does this and it's explained in the code.

Step 3

Next we connect this to the cellphone:

The keypad of my little phone works on the same principle as the keypad on the Arduino tutorial. The left side of the prototype board shows the circuit needed to connect one button. On my cellphone, the green wire is connected to a point on the keyboard that corresponds to a row and the blue one to a column. This is easy to figure out once the phone is open by connecting a wire between various points on the naked keypad and checking what it does.

The little black ICs are Opto-Isolators. They work more or less like relays so the Arduino circuit stays independent from the phone one.

Once you have figured out your rows and columns, you just have to connect them to one another correctly. 1,2,3 on the keypad will have the same row (green) but different columns (blue), 4 has the same column as 1 (blue) but a different row (green) .

Step 4

The "Call" and "Hang Up" buttons were weird because they both had their own special green and blue.

Dialer test #4377

Once you have the dialer talking to the keypad, the rest becomes assembly. You'll need to take apart the receiver to figure out which wires are for the microphone and which are for the speaker. I couldn't figure out the positive and negative for each set on my receiver. It doesn't seem to really matter.

They just need to get connected to their counterpart on the cellphone. The speaker was easy because the poles on the circuit board were about 3mm x 3mm. The microphone on the other hand, is located at the bottom of the keypad somewhere. The connection poles are minuscule and less than a millimeter apart.

And at this point, I have to take a second to officially thank Chantal for her help with the soldering. She did 80% of the soldering onto the 2 circuit boards and she did the microphone one! Without her, I don't think my phone would have had a microphone at all.

On the chassis of the old telephone, we need to add wiring to connect the 'hang-up' lever button of the old telephone to our Arduino. I used pin 18 (A4) for this. My phone had 3 of those lever switches. I used the one that was normally closed so the current would only flow when the phone is off the hook (Which is less often than on hook)

In the casing of the telephone, I drilled a small hole to squeeze a push button that I then connected directly to the green-blue wire combination for the 'Dial' button on the cellphone.

Step 5

Finally, we squeeze everything back into the casing of the old telephone

And we put the case back on.

I use a standard mini USB cable to connect the Arduino Nano (red circuit board above) to the power and run my phone from a portable cellphone charger. There's already a gap to let the wire out because this phone used to connect to a land line.

On a final note,

#define PHONE_NUMBER_LENGTH 10 

This defines the number of digits the cellphone will dial before calling automatically. In SA, we have 10 digit numers. You might have to change this value for your country.

The push button that I added on the case is for international numbers. Here they start with 00 ('+' on your cellphone is the shortcut for this but good luck getting a '+' out of the rotary dialer :)

This is the code in charge of preventing automatic dialing at PHONE_NUMBER_LENGTH digits.

if(digit == 10 && digitCount == 2)
   digit2zero = true;

It only checks that the second digit is a 0 (that's because in SA, all numbers start with 0. You will have to modify this also to get the international calling working if your country works differently.

Conclusions

If you need explanations on the code or additional details, please feel free to ask. I can't however help you with technical questions. I don't know cellphones, nor do I know old telephones. This is one specific cellphone connecting to one specific telephone and a lot of trial and error.

I hope you got this far and got excited about building one of those!

If you do, please drop me a message or leave a comment and we can make a plan for me to call you OldArduiPhone to OldArduiPhone!

Code

OldArduiPhoneArduino
Load it into your favorite Arduino IDE and upload it to the board.
Some parameters might need to be tweeked if you didn't use the same cellphone as I did...
#define PULSE_ACTIVE B00000100 // Pin 2 but here this is used to identify the pin in register PIND.
#define PULSE_IN 3
#define CALL_PIN 14
#define CLEAR_PIN 15
#define BOOT_PIN 16
#define HANGUP_BUTTON 18
#define HANGUP_BUTTON_PIN B00010000  // Pin 18 but here this is used to identify the pin in register PINC.
#define MIN_VALID_PULSE 50000
#define MAX_VALID_PULSE 150000
#define PULSE_IN_TIMEOUT 300000

/*
 *In SA phone numbers are 10 digit long - to be changed for your country 
 *For international calls, the code looks at the second digit. 
 *If it's also a 0, the automatic dialing is disabled. See comment down below.
 */
#define PHONE_NUMBER_LENGTH 10 

bool off_hook = false;
byte digitCount = 0;
byte digit = 0;
bool hasDigit = false;
bool digit2zero = false;

void setup() {
  /*
   * pins for the dialer
   */
  pinMode(PULSE_ACTIVE, INPUT);
  pinMode(PULSE_IN, INPUT);
  pinMode(HANGUP_BUTTON, INPUT);
  /*
   * pins for the cellphone 
   */
  pinMode(4, OUTPUT); //1
  pinMode(5, OUTPUT); //2
  pinMode(6, OUTPUT); //3
  pinMode(7, OUTPUT); //4
  pinMode(8, OUTPUT); //5
  pinMode(9, OUTPUT); //6
  pinMode(10, OUTPUT); //7
  pinMode(11, OUTPUT); //8
  pinMode(12, OUTPUT); //9
  pinMode(13, OUTPUT); //0

  pinMode(CALL_PIN, OUTPUT);
  pinMode(CLEAR_PIN, OUTPUT);
  pinMode(BOOT_PIN, OUTPUT);

  delay(2000);
  
  digitalWrite(BOOT_PIN, HIGH);
  delay(1000);
  digitalWrite(BOOT_PIN, LOW);

  off_hook = false;
  
  //Serial.begin(9600); //for debugging
  //Serial.println("Starting"); //for debugging
}

void loop() {
  /* 
   * This bit was taught to me by this article. Read it! It's really good.
   * http://www.instructables.com/id/Fast-digitalRead-digitalWrite-for-Arduino/
   * Those next 2 lines effectively replace a digitalRead() by looking straight at the registers
   * Using digitalRead() I was sometimes getting 1s instead of 2s etc... 
   * This solves most of them. 
   */
  int hookState = PINC;
  hookState = hookState & HANGUP_BUTTON_PIN;
  if(hookState){
    //Serial.println("on hook"); //for debugging
    /*
     * This prevents the HangUp() function from being called all the time when the receiver in down.
     * On my cellphone, the hangup and shutdown button are the same.
     * I don't want the phone to shutdown.
     * Turning off the cellphone will be manual due to lack of features on the old telephone.
     */
    if(off_hook){ 
      hangUp();
    }
    return;
  }
  
  /* 
   * This bit was taught to me by this article. Read it! It's really good.
   * http://www.instructables.com/id/Fast-digitalRead-digitalWrite-for-Arduino/
   * Those next 2 lines effectively replace a digitalRead() by looking straight at the registers
   * Using digitalRead() I was sometimes getting 1s instead of 2s etc... 
   * This solves most of them. 
   */
  int activeState = PIND;
  activeState = PIND & PULSE_ACTIVE;
    
  //if(activeState) //Serial.println("Active"); //for debugging
  
  while(activeState){
    off_hook = true;
    
    unsigned long val = myPulseIn(3, LOW, PULSE_IN_TIMEOUT); 
    //Serial.println(val); //for debugging
    if(val > MIN_VALID_PULSE && val < MAX_VALID_PULSE){
      digit++;
    }
    activeState = PIND;
    activeState = PIND & PULSE_ACTIVE;
    hasDigit = true;
    
  }
  if(hasDigit){
    //Serial.print("digit "); //for debugging
    //Serial.println(digit); //for debugging
    dialCellDigit(digit);
    //Serial.println("Sleeping"); //for debugging
    digit = 0;
    hasDigit = false;
  }
}

void dialCellDigit(byte digit){
  /*
  * add a digit to the phone number
   */
  digitCount++;

  /*
   * if the 2nd digit is 0, I'm dialing an international number 
   * Will disable auto-dialing based on that.
   */
  if(digit == 10 && digitCount == 2)
    digit2zero = true;
    
  /*
   * the pin number is 3 more than the digit I'm dialing
   */
  byte numberPin = digit + 3;
  
  /*
   * 'press' a button on the cellphone
   */
  digitalWrite(numberPin, HIGH);
  delay(250);
  digitalWrite(numberPin, LOW);

  /*
   * When we get to the proper length for a phone number
   * If the second digit was a 0, we are doing an international call.
   * Then dialing will be manual.
   */
  if(digitCount == PHONE_NUMBER_LENGTH && !digit2zero){
    /*
     * Call the number
     */
    //Serial.println("Calling"); //for debugging
    call(500);
  }
}

/*
* Pretty obvious
* But also turns on the phone at the start
*/
void call(int press_delay){
  digitalWrite(CALL_PIN, HIGH);
  delay(press_delay);
  digitalWrite(CALL_PIN, LOW);
}

/*
* Pretty obvious too
* But also used to clear the digits on the cell
*/
void hangUp(){
  digitalWrite(BOOT_PIN, HIGH);
  delay(100);
  digitalWrite(BOOT_PIN, LOW);
  digitalWrite(CLEAR_PIN, HIGH);
  delay(100);
  digitalWrite(CLEAR_PIN, LOW);
  digitCount = 0;
  digit2zero = false;
  off_hook = false;
}

/*
 * This code replaces the default Arduino PulseIn
 * Credits to Jims in this thread.
 * https://forum.arduino.cc/index.php?topic=46011.0
 * I panelbeated it a little because it got stuck if when the PULSE_ACTIVE resets.
 */
unsigned long myPulseIn(uint8_t pin, uint8_t state, long timeOut)
{
   // cache the port and bit of the pin in order to speed up the
   // pulse width measuring loop and achieve finer resolution.  calling
   // digitalRead() instead yields much coarser resolution.
   uint8_t bit = digitalPinToBitMask(pin);
   uint8_t port = digitalPinToPort(pin);
   uint8_t stateMask = (state ? bit : 0);
   unsigned long width = 0; // keep initialization out of time critical area */
       
   // wait for the pulse to start
   while ( (*portInputRegister(port) & bit) != stateMask)
       ;
   
   // wait for the pulse to stop
   while ( (*portInputRegister(port) & bit) == stateMask){
       width++;
       if(width > timeOut) //Time out if the wait is too long
        break; 
   }

   return width; 
}

Schematics

Very basic diagram
This diagram shows only the very basic circuit. Drawing the full circuit is a lot of repetition really and would just make the drawing way too busy.
oldarduiphonebasic_QDc9CA7cZG.fzz

Comments

Similar projects you might like

Cocktail Parasol

by alain_haerri

  • 186 views
  • 5 comments
  • 2 respects

Ethernet Connected CNC Mill or Other Machines

Project tutorial by Garrett Kendrick

  • 95 views
  • 0 comments
  • 3 respects

Arduino-Powered Robotic Arm Controlled with T-Skin!

Project showcase by Michele Valentini and Massimiliano

  • 2,381 views
  • 2 comments
  • 23 respects

GRawler - The Glass Roof Cleaner

Project tutorial by Gelstronic

  • 5,246 views
  • 3 comments
  • 23 respects

Homemade Claw Machine

Project tutorial by -MMM-

  • 3,410 views
  • 4 comments
  • 23 respects

SpeechLess

by tazasproject

  • 264 views
  • 0 comments
  • 5 respects
Add projectSign up / Login