Introduction: Bat Phone From Old Rotary Phone

About: Retired Math teacher who needs a hobby! So I tinker with stuff: Arduino, welding, my 1958 TR-3 , my tennis serve
Disclaimer: No old rotary phones were hurt in this project!   I had bought a lot of rotary phones from an estate sale and included in this purchase was a box of broken phones and phone parts.  It is from this box that I got my raw materials not from a working rotary phone. 

This is not a full Instructable as I failed to take the proper pictures along the way but I hope to make another one of these(better I hope) and will document better at that time.

I saw the following Instructable  by guidomax: (thanks guidomax!!!) and having a collection of rotary phones/parts, I wanted to see what I could do with them.

 I decide I would try to make the bat phone with the signal and present it as a gift to my daughter for the holidays.

Here is a short video of it working .  The music is much louder in person.

my steps:
1. First I referred to the above Instructable to see if I could get the interface working and as suggested in the Instructable, it was pretty easy to do so.

2. I took an old phone body and primed and spray painted red.  I did the handset also and the cord.

3. I wanted the Arduino code to play the theme from Batman and produce a bat signal when "B","A","T","M","A","N" was dialed on the phone. 

The code was just taking the code from guidomax  and modifing it so instead of a serial output to the computer, it just checked for the proper string of numbers being dialed.  For exanple BATMAN is "228626" . When the Arduino saw this string, it started the song and turned on the bat signal.

The song:  I had a Adafruit Wave Shield which I had never used and saw this as an opportunity to check it out. It took a good day for me to build it (it comes as a kit) and then there is a procedure that must be followed to get your wav file onto the shield.  It is an easy procedure if you use iTunes.  Just buy the song and convert it as required using the iTunes menus and drag to the shield. Without iTunes it is more involved but the Adafruit page walks you thru it.

The Bat Signal: Several other Instructables show how to make a signal and I took what I could from them but it was more or less trial and error before I came up with the end idea.  I cut a water bottle about in half and put a small hole in the screw cap. I inserted a red LED into the small hole. I painted the bottle cap black.  To get the image to show up pretty good, I needed to cut a small bat symbol and attach it in front of the bottle.  That worked but I think there must be a neater way.   I hot glued the bottle to an opening I made in the back of the phone(Hot Glue is wonderful!!).

The code:  My original idea was to have several super heros be in the code. ie if you dialed Batman, you got the theme music and the signal, if you dialed SUPERMAN, you got different music, etc.  So you will see some code that is there for that purpose but I never got that far.  It is just BATMAN.

// Batmanv2
// This an attempt to have multiple wav files and play the proper one
// based on the sequence of numbers dialed on the phone
// if 228626b then play the batman theme

 #include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"

SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card
FatReader f;      // This holds the information for the file we're play

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

#define DEBOUNCE 100  // button debouncer

// -- from V1 -----
// -----------------
int needToPrint = 0;
int count;
// mine
int redLed = 8;
int in_from_dial = 7;
int lightOn = 6;
int craddleUp = 9;
int val = LOW;     // variable to store the read value
int lastState = LOW;
int trueState = LOW;
long lastStateChangeTime = 0;
int cleared = 0;

// constants

int dialHasFinishedRotatingAfterMs = 100;
int debounceDelay = 10;

// strings
String newstring;
char Tester[ ] =  "123" ;
char Batman[ ] =  "228626" ;
char Spiderman[ ] =  "774337626" ;
char Superman[ ] =  "78737626" ;
char Batgirl[ ] =  "2284475" ;

 // - end from V!----------

void setup() {
  // set up serial port
  putstring_nl("WaveHC with select songs");

   putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
  Serial.println(freeRam());      // if this is under 150 bytes it may spell trouble!

  // Set the output pins for the DAC control. This pins are defined in the library
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

// from V1  
  pinMode(in_from_dial, INPUT);  // 12
pinMode(lightOn, OUTPUT);    // 11
pinMode(craddleUp,INPUT);  // 9
pinMode(redLed,OUTPUT);  // 9
// end v1

  // pin13 LED
  pinMode(13, OUTPUT);

  //  if (!card.init(true))   //play with 4 MHz spi if 8MHz isn't working for you
  if (!card.init()) {         //play with 8 MHz spi (default faster!) 
    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!

  // enable optimize read - some cards may timeout. Disable if you're having problems

// Now we will look for a FAT partition!
  uint8_t part;
  for (part = 0; part < 5; part++) {     // we have up to 5 slots to look in
    if (vol.init(card, part))
      break;                             // we found one, lets bail
  if (part == 5) {                       // if we ended up not finding one  :(
    putstring_nl("No valid FAT partition!");
    sdErrorCheck();      // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!

  // Lets tell the user about what we found
  putstring("Using partition ");
  Serial.print(part, DEC);
  putstring(", type is FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?

  // Try to open the root directory
  if (!root.openRoot(vol)) {
    putstring_nl("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!

  // Whew! We got past the tough parts.

// idea here is
// the looping will continue until the reciever is pickerd up
// then the sequence of dialing is recorded and checked
// if a hit is found, then turn on light (for Batman) and /or
// play the song

void loop() {

   // wait for the reciever to be lifted
 // once lifted, then the dialing can be checked
 // turn on red led to show the phone is alive
 val = digitalRead(craddleUp);   // read the input pin

 if (val == HIGH) {

 digitalWrite(redLed, HIGH);

int reading = digitalRead(in_from_dial);

if ((millis() - lastStateChangeTime) > dialHasFinishedRotatingAfterMs) {
// the dial isn't being dialed, or has just finished being dialed.
if (needToPrint) {
// if it's only just finished being dialed, we need to send the number down the serial
// line and reset the count. We mod the count by 10 because '0' will send 10 pulses.
Serial.println(count % 10, DEC);

// now need to add the count to the test string and then test it against the
// required string to get a hit

// if string equals Batman, turn on light and start wav file
//  Serial.println(newstring);
//  delay(2000);
 // --------------------
 // -------------- Batman -----------------
if ((newstring.equals(Batman)) || (newstring.equals(Tester))) {
  digitalWrite(lightOn, HIGH);


 // -------------- Spiderman----------------
if (newstring.equals(Spiderman)) {
 // bat_signal();
 // --------------Superman -----------------
if (newstring.equals(Superman)) {
 // bat_signal();
 // -------------- BatGirl -----------------
if (newstring.equals(Batgirl)) {
 // bat_signal();

needToPrint = 0;
count = 0;
cleared = 0;


if (reading != lastState) {
lastStateChangeTime = millis();
if ((millis() - lastStateChangeTime) > debounceDelay) {
// debounce - this happens once it's stablized
if (reading != trueState) {
// this means that the switch has either just gone from closed->open or vice versa.
trueState = reading;
if (trueState == HIGH) {
// increment the count of pulses if it's gone high.
needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)
lastState = reading;
newstring  = "";
digitalWrite(lightOn, LOW);


// Plays a full file from beginning to end with no pause.
void playcomplete(char *name) {
  // call our helper to find and play this name
  while (wave.isplaying) {
  // do nothing while its playing
  // now its done playing

void playfile(char *name) {
  // see if the wave object is currently doing something
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  // look in the root directory and open the file
  if (!, name)) {
    putstring("Couldn't open file "); Serial.print(name); return;
  // OK read the file and turn it into a wave object
  if (!wave.create(f)) {
    putstring_nl("Not a valid WAV"); return;

  // ok time to play! start playback;

// this handy function will return the number of bytes currently free in RAM, great for debugging!  
int freeRam(void)
  extern int  __bss_end;
  extern int  *__brkval;
  int free_memory;
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval);
  return free_memory;

void sdErrorCheck(void)
  if (!card.errorCode()) return;
  putstring("\n\rSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  putstring(", ");
  Serial.println(card.errorData(), HEX);

The Arduino I used was an UNO

Again, I wish I had more pictures and better documentation. Next time.

My daughter thought is a neat gift and she seemed happy but that is what daughters do. :)

Make It Glow Challenge

Participated in the
Make It Glow Challenge

Toy Challenge 2

Participated in the
Toy Challenge 2

Holiday Gifts Challenge

Participated in the
Holiday Gifts Challenge