Understanding Rotary Phone/Arduino interface code by instructables auth:guidomax

Hello,

I'm working on a project that requires a rotary phone to interface with my Arduino UNO to control a sparkfun Mp3 trigger break out board. I uploaded the following program authored by guidomax from Instructables. It works perfectly as far as sending the correct dialed number to the Arduino software serial monitor.

int needToPrint = 0;
int count;
int in = 2;
int lastState = LOW;
int trueState = LOW;
long lastStateChangeTime = 0;
int cleared = 0;

// constants

int pulselengthMs = 100;
int debounceDelay = 10;

void setup()
{
Serial.begin(9600);
pinMode(in, INPUT);
}

void loop()
{
int reading = digitalRead(in);

if ((millis() - lastStateChangeTime) > pulselengthMs) {
// the dial isn't being dialed, or has just finished being dialed.
if (needToPrint) // !!I NEED HELP UNDERSTANDING!!
{
// 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.print(count % 10, DEC);
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.
count++; 
needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)
} 
}
}
lastState = reading;
}

The command "if (needToPrint)" is confusing me. It is initially zero. After the first increment of the pulse counter it is changed to one. Is this just simply a matter of running the following part of the program if the variable value is one and skipping it if the value is zero?

Also my project requires me to collect two consecutively dialed numbers and send via serial.print the 2 digit number to the breakout board. Can someone please advise me on the most efficient strategy to achieve this goal. I'm trying to learn as fast as I can. I attempted to modify this code and received the wrong result.

Thank you , John Mac

The if statement execuites the code following if the statement in the brackets is true. In logic a value of zero is considerd to be false and anything else is considerd true. So this simply prints when it has a number.

Thank you. I was hoping that was the case. How would you advise collecting two cosecutively dialed numbers to send using Seriel.print. I tried using an index to let the program know the first number was captured then after the second number was squired I reset the index. I got a stream of zeros. I'm very inexperienced at programming. I get the basic idea from taking a class on assembly language using an SDK 85.

Basically you need to use an array to hold the numbers. It sounds like you were on the right track but got something wrong.
If you want help with what you wrote then post the code after you have read the how to use this forum sticky and can post it correctly using the correct tags.

Ok. I will do that.

@ Grumpy_Mike,

Hello,

The modification i did originally was actually correct except for my bracket placement and the order of my assignment operators. I only need two digits. Here's my sketch:

int index=0;
int secondcount;
int firstcount;
int needtoprint=0;
int count=0;
int in=2;
int laststate=LOW;
int truestate=LOW;
long lstatechangetime=0;
int pulsewidthMs=100;
int debouncedelay=10;
void setup()
{Serial.begin(9600);
pinMode(in,INPUT);
}
void loop()
{int reading=digitalRead(in);
if ((millis()-lstatechangetime)>(pulsewidthMs)) //Check time compared to pulse width
{
if(needtoprint) // Advance only if a pulse count is acquired 
{index++;
if(index==1) // Check for first pulse count 
{
firstcount=count;
needtoprint=0;
count=0;
}
if(index==2) // Check for second pulse count
{
secondcount=count;
Serial.print("t");  // Assemble data to send to  Sparkfun Mp3 break out board ( not sure this is correct format)
Serial.print(((firstcount%10)*10)+(secondcount%10),BIN);
needtoprint=0;
count=0;
index=0;
}
}}
if(reading!=laststate){lstatechangetime=millis(); // Check for state change
}
if ((millis()-lstatechangetime)>debouncedelay) // Check that debounce delay is exceeded
{   
  if(reading!=truestate) // recheck state 
{
    truestate=reading;
    if(truestate==HIGH) // count one pulse if state is high
{
      count++;
      needtoprint=1; // allow the transmission of count when finished
    }
  }
}
laststate=reading;
}

It works just fine. I was hoping you could help me with a follow up question. This is the format required by the break out board to trigger individual tracks:

Command: Trigger (binary)
Number of bytes: 2
Command byte: ‘t’
Data byte: n = 1 to 255
Comments: If it exists, the track with the filename “NNNxxxx.MP3” will be started, where NNN is the ASCII equivalent
of the data byte n with leading 0s. xxxx can be any valid filename characters of any length.

I have a feeling what I am sending is not completely following this format. Any tips? I changed what I originally posted today to something closer I hope. I'm still not sure.

I am making a listening station for my friends new record store. Its going to be an old rotary phone with headphones instead of a headset. I want each track to be triggered by dialing 2 numbers.

Thank you for your help. I did try the array and it failed but maybe for the same reasons that my first attempt failed. I will definitely try the array again to get a grasp of that method.

Serial.print(((firstcount%10)*10)+(secondcount%10),BIN);

Close but why take the remander of the second count, you need that intact. Try that line as

Serial.write((firstcount*10)+secondcount);

I have to take the remainder of both because the rotary mechanism makes 10 pulses for the number 0 so if a user dials say 20 it will be correct.

When I actually do communicate with the mp3 trigger board will I be using Serial.write()?

Thank you

Frenchfry222:

Here is the difference:

Writes binary data to the serial port. This data is sent as a byte or series of bytes; to send the characters representing the digits of a number use the print() function instead.

Do not be afraid to experiment; the forum is a poor place for chats - that is, specific questions are likely to get answered but things you can figure out for yourself... Research, Read, and Try first.

Ray

Ok gotcha. I am trying it at the moment.

Thank you

Frenchfry222:
I have to take the remainder of both because the rotary mechanism makes 10 pulses for the number 0 so if a user dials say 20 it will be correct.

If it were me I would simply do:-

if(number > 9) number=0;

When I actually do communicate with the mp3 trigger board will I be using Serial.write()?

Yes because you said:-

Command: Trigger (binary)
Number of bytes: 2
Command byte: ‘t’
Data byte: n = 1 to 255

and the only way to get the number n into a byte is to use Serial.write. Using the BIN word prints out the number as a series of eight ASCII digits / bytes not one as you need.

Ok thank you !!

I rewrote it as:

int intvalue=((firstcount%10)*10)+(secondcount%10));
Serial.write("t");
Serial.write(lowByte(intvalue));
Serial.write(highByte(intvalue));

Everything's cool in the serial monitor. I'm on a learning curve so I just copied guidomax's code. I definitely need to know the way you described. Thank you again.

Writing it like this sends two bytes and you need to send only one.
Just use:-

Serial.write(intvalue);

Thank you!! I was copying what I read from the Arduino cookbook. I really appreciate your help. Now I just have to wire it all together. What a relief.