Rotary Dial Arduino Input

1,778

9

4

Introduction: Rotary Dial Arduino Input

This project was intended to serve as a proof of concept for using a rotary phone’s dial as an interface between a user and the Arduino microcontroller. However, this experiment quickly turned into an opportunity to learn all about the Atmega328P’s various timer and interrupt capabilities and how to manually set registers within the Arduino IDE in order to utilize them and handle IO operations more efficiently. This section includes a brief video demonstration of the rotary dial's use as an input to a microcontroller.

Step 1: Connecting the Rotary Dial to the Arduino

While disassembling a few legacy phones, I was excited to learn that their dials are completely self-contained devices that operates as mechanical switch. When the user draws the dial back to a specific number the switch will periodically open that number of times, with a specific timing that is dictated by the rotary dial’s inner clockwork. In order to test the possibility of using the device to act as a sort of keypad, the circuit depicted in the top diagram was constructed. Both LEDs have their own digital pins (D3 and D4) which are simply used to communicate whether the correct predetermined code has been entered into the dial. The microcontroller counts the low pulses at the rotary dials pin (D2) in order to determine which number has been entered.

Step 2: Coding for Rotary Dial Input

Though the circuit is very straight forward, programming for this operation required an intimate knowledge of the Atmega328P’s timers. A timer had to be utilized in unique ways in order to distinguish one pulse from another, debounce the rotary dial's switching, and decide when to stop counting pulses for one digit and start counting pulses for the next digit. The project has left me with a much deeper understanding of the registers used to control the 328P and a comfortability with the technical documentation involved. Below is the entire program used to run the demonstration in the introductory video.

#define dialPin  2 
#define redLED   4
#define greenLED 3

bool checkPin ( int *input, int *truePin );

bool keep_count = 1;
int  Pindex     = 0;
volatile int Cycle = 0;
volatile int Tick  = 0;

int inputPin[5] = { 0, 0, 0, 0, 0}; //we add an extra element to avoid buffer overflow
int truePin [4] = { 1, 7, 3, 8};

void setup() {

    pinMode (dialPin, INPUT);
    pinMode (redLED , OUTPUT);
    pinMode (greenLED,OUTPUT);
    pinMode ( 11, OUTPUT);
    digitalWrite(11, LOW);

    noInterrupts();
    TCCR2A = 0; // Timer/Counter ContRol Registers used to set mode, prescalar, other options
    TCCR2B = 0;  

    TCCR2B |= ( 1 << CS22); // we set the Clock Select bit of this register so that our prescalar is 64
    // desired f = 1000 Hz
    // Clock Speed /( prescaler * ( counter max - start of count ) ) = f
    // 16 000 000 / ( 64 * ( 256 - x ) )  = 1000 Hz
    // x = 6
    TCNT2  = 6; // Timer CouNTer register. This is what is incremented.  We start OUR specific count at 48

    TIMSK2 = 0;
    TIMSK2 |= ( 1 << TOIE1 ); // on the Timer Interrupt Mask Register   the  TimerOverflowInteruptEnable bit is set
 
    Serial.begin (9600);
    
}


//IMPORTANT NOTE: with an 8 bit counter running with a prescalar of 64 and an initial count of 6 we get about 1000Hz
//So we want 3 seconds at 1000 cycles per second = MAX_CYCLES of 3000
//For a debounce of 50ms we likewise need 75 cycles 

#define MAX_CYCLES 1500 //for 1.5 seconds
#define MAX_WAIT   20 // for 20 ms debounce
void loop()
{
  
  Pindex = 0;

  digitalWrite ( redLED, HIGH );
  digitalWrite ( greenLED, LOW);
  while ( Pindex < 4 )
  {
      noInterrupts();
      Cycle     =  0;
      keep_count =  1;
      
          if ( digitalRead(dialPin) == HIGH )
          {

              interrupts();
              //inputPin [Pindex] ++;
              //wait_a_tick(1);

              while ( Cycle < MAX_CYCLES )
              {
                  if ( keep_count && digitalRead( dialPin ) == HIGH)
                  {
                      inputPin [Pindex] += 1;
                      keep_count = 0;  
                      wait_a_tick(1);
                  }

                  else if ( digitalRead ( dialPin ) == LOW )
                  {
                      keep_count = 1; 
                      wait_a_tick(1);
                  }
                  
              }

              noInterrupts();
              TCNT2  = 0;
              Pindex ++;
              
              
            }

            Serial.print(inputPin [0] );Serial.print(inputPin [1] );
              Serial.print(inputPin [2] );Serial.print(inputPin [3] );
              Serial.print("\n");
  }

  if ( checkPin ( inputPin, truePin ) )// Lets check to see if our pin number is right
  {
       digitalWrite ( redLED, LOW );
       digitalWrite ( greenLED, HIGH);

       interrupts();
       wait_a_tick(100 ); //1 tick = 20ms so 2 seconds = 100 ticks
  }

  memset ( inputPin, 0, sizeof(inputPin)); // we reset the entered pin to zero
}


///////////////////////////////////

bool checkPin ( int *input, int *truePin )
{
    bool pinCorrect = 1;
    
    for ( int i = 0; i < 4; i ++ )
    {
        if ( (*(input + i)) != (*(truePin + i)) )
        {
            pinCorrect = 0;  
        }      
    }  

    return pinCorrect;

}
/////////////////////////////////////////
void wait_a_tick (int ticks)
{
  for ( int tocks = 0; tocks <= ticks; tocks ++)
  {
     Tick = 0;
     while ( 1 == 1 )
     {
        if ( Tick >= MAX_WAIT )
        {
            break;
        }
      }
  }
      return;
}



///////////////////////////////////////////////////
ISR(TIMER2_OVF_vect)          // timer compare interrupt service routine
{
  Cycle ++;
  Tick  ++;
}

Be the First to Share

    Recommendations

    • Halloween Contest

      Halloween Contest
    • Tinkercad Student Design Contest

      Tinkercad Student Design Contest
    • Pumpkins & Gourds Speed Challenge

      Pumpkins & Gourds Speed Challenge

    4 Comments

    0
    lastchancename
    lastchancename

    5 days ago

    What happens if you don’t dial all four code digits?

    0
    jakeofalltrade
    jakeofalltrade

    Reply 3 days ago

    In the case of the demo program, the arduino will simply wait for the remaining digits to be entered. So if I entered a 2 and a 4, but nothing else, those numbers would just stay stored until 2 more were entered.

    0
    lastchancename
    lastchancename

    Reply 2 days ago

    How long does it wait ?
    I need to open the door, and I misdialled the second digit…

    0
    jakeofalltrade
    jakeofalltrade

    Reply 2 days ago

    This sketch waits indefinitely until the rotary dial is pulled again. The way the interrupts are set up, the rotary dial needs to begin switching in order for the arduino to begin counting the pulses for the next digit.