Go Down

Topic: DTMF decoding with Arduino (Read 4753 times) previous topic - next topic

wicket

I've build a circuit based on DTMF decoder MT8870. A mobile phone is connected via headphone jack to MT8870. 4 outputs are then connected to 4 Arduino digital inputs as shown in schematic below.



Code: [Select]

int q_1 = 4;
int q_2 = 5;
int q_3 = 6;
int q_4 = 7;

void setup() {
  Serial.begin(9600);
  pinMode(q_1, INPUT);
  pinMode(q_2, INPUT);
  pinMode(q_3, INPUT);
  pinMode(q_4, INPUT);
}

void loop() {
  int q1 = digitalRead(q_1);
  int q2 = digitalRead(q_2);
  int q3 = digitalRead(q_3);
  int q4 = digitalRead(q_4);
 
  if (q1 == HIGH && q2 == LOW && q3 == LOW && q4 == LOW)
  {
    Serial.println("Input detected.");
  }

  delay(1000);
}


My problem: when I first power up DTMF circuit, arduino recognizes my if statement as true and serial answers with "Input detected.", evendo all 4 DTMF outputs are low. When MT8870 gets first dtmf signal (doesn't matter from which key), arduino starts working as it should - I only get "Input detected." if '1000' combination is active (key 1). If I turn the power off and then back on again, I'm stuck with the same problem again, until a key get pressed.

Any ideas why? Are these outputs somehow floating after power on?

And btw, grounds from arduino and my circuit are not connected, should they be? Because if I connect the grounds, keys 1, 2 and 3 from mobile aren't detected by MT8870. If I seperate the grounds, all keys work.

Graynomad

#1
May 27, 2012, 03:53 pm Last Edit: May 27, 2012, 03:56 pm by Graynomad Reason: 1
Grounds have to be connected, if that causes another problem then that has to be looked into.

Quote
Are these outputs somehow floating after power on?

Unlikely, but try moving the delay to the top of the loop to give any such behaviour time to settle.

When you get it working how will you detect the 0 code? It looks like you will have to read the StD signal.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

wicket

#2
May 27, 2012, 04:57 pm Last Edit: May 27, 2012, 05:57 pm by wicket Reason: 1
Hmm yeah, I also thought grounds have to be the same, but I can't seem to get the chip working OK if they are.

And this only happens if I power my arduino via USB. If I use an external power adapter it's OK but then I can't test my program simultaneusly...

So by using an external power supply I've got it to work as I wanted - with first key press I choose a device that I want to control and with second key press I turn it on or off. I want to simplify the code now, but I'm no expert in programming, so any tip would be aprecciated.

Maybe to use an array for 4 input combination? Or maybe as byte comparisson somehow?

Code: [Select]

int q_1 = 4;
int q_2 = 5;
int q_3 = 6;
int q_4 = 7;
int red = 8;                   // 1st device (red LED)
int green = 9;                 // 2nd device (green LED)
int std_out = 10;

void setup() {
 pinMode(q_1, INPUT);
 pinMode(q_2, INPUT);
 pinMode(q_3, INPUT);
 pinMode(q_4, INPUT);
 pinMode(std_out, INPUT);
 pinMode(red, OUTPUT);
 pinMode(green, OUTPUT);
}

void loop() {
 
 // wait a bit...
 delay(500);
 
 // read inputs
 int q1 = digitalRead(q_1);
 int q2 = digitalRead(q_2);
 int q3 = digitalRead(q_3);
 int q4 = digitalRead(q_4);
 
 if (q1 == HIGH && q2 == LOW && q3 == LOW && q4 == LOW)            // if 1st device detected with '1000' (key 1)
 {
   while (digitalRead(std_out) == LOW);                            // wait for next key press
   
   delay(100);
   
   q1 = digitalRead(q_1);                                          // when next key press detected, read it
   q2 = digitalRead(q_2);
   q3 = digitalRead(q_3);
   q4 = digitalRead(q_4);
   
   if (q1 == HIGH && q2 == HIGH && q3 == LOW && q4 == HIGH)        // if '1101' (key *) is pressed...
   {
     digitalWrite(red, HIGH);                                      // turn on 1st device
   }
   else if (q1 == LOW && q2 == LOW && q3 == HIGH && q4 == HIGH)    // if '0011' (key #) is pressed...
   {
     digitalWrite(red, LOW);                                       // turn off 1st device
   }
 }
 
 else if (q1 == LOW && q2 == HIGH && q3 == LOW && q4 == LOW)       // if 2nd device detected with '0100' (key 2)
 {
   while (digitalRead(std_out) == LOW);                            // wait for next key press
   
   delay(100);
   
   q1 = digitalRead(q_1);                                          // when next key press detected, read it
   q2 = digitalRead(q_2);
   q3 = digitalRead(q_3);
   q4 = digitalRead(q_4);
   
   if (q1 == HIGH && q2 == HIGH && q3 == LOW && q4 == HIGH)        // if '1101' (key *) is pressed...
   {
     digitalWrite(green, HIGH);                                    // turn on 2nd device
   }
   else if (q1 == LOW && q2 == LOW && q3 == HIGH && q4 == HIGH)    // if '0011' (key #) is pressed...
   {
     digitalWrite(green, LOW);                                     // turn off 2nd device
   }
 }

}

PeterH

It sounds as if you've got an unexpected voltage difference between the Arduino and your DTMF decoder. Can you measure the difference between the two grounds when the system is wired up in the way that works? Can you measure the signal voltage on those four pins relative to Arduino ground? If the grounds are close and you are getting a positive voltage in the right sort of range, it should work. So presumably you aren't. So you need to see what's actually happening on those pins.
I only provide help via the forum - please do not contact me for private consultancy.

iggykoopa

Someone may come up some better hints, but something along these lines should help cut the memory usage a lot. If you need any of it explained let me know.

Code: [Select]
#define Q1 4
#define Q2 5
#define Q3 6
#define Q4 7
#define RED 8                   // 1st device (RED LED)
#define GREEN 9                 // 2nd device (GREEN LED)
#define std_out 10

void setup() {
  pinMode(Q1, INPUT);
  pinMode(Q2, INPUT);
  pinMode(Q3, INPUT);
  pinMode(Q4, INPUT);
  pinMode(std_out, INPUT);
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
}

void loop() {
  byte key;
 
  // wait a bit...
  delay(500);
 
  // read inputs
  key = read_inputs();
 
  if (key == B1000)            // if 1st device detected with '1000' (key 1)
  {
    while (digitalRead(std_out) == LOW);                            // wait for next key press
   
    delay(100);
   
    key = read_inputs();
   
    if (key == B1101)        // if '1101' (key *) is pressed...
    {
      digitalWrite(RED, HIGH);                                      // turn on 1st device
    }
    else if (key == B0011)    // if '0011' (key #) is pressed...
    {
      digitalWrite(RED, LOW);                                       // turn off 1st device
    }
  }
 
  else if (key == B0100)       // if 2nd device detected with '0100' (key 2)
  {
    while (digitalRead(std_out) == LOW);                            // wait for next key press
   
    delay(100);
   
    key = read_inputs();
   
    if (key == B1101)        // if '1101' (key *) is pressed...
    {
      digitalWrite(GREEN, HIGH);                                    // turn on 2nd device
    }
    else if (key == B0011)    // if '0011' (key #) is pressed...
    {
      digitalWrite(GREEN, LOW);                                     // turn off 2nd device
    }
  }

}

byte read_inputs(){
  byte key = 0;
  if(digitalRead(Q1)) key &= 1;
  key <<= 1;
  if(digitalRead(Q2)) key &= 1;
  key <<= 1;
  if(digitalRead(Q3)) key &= 1;
  key <<= 1;
  if(digitalRead(Q4)) key &= 1;
  return key;
}

retrolefty

You should be wiring the valid data available to read signal ( StD )to an ardino input pin and only read the other four data pin values when StD goes high.

Lefty


Graynomad

#6
May 28, 2012, 01:09 am Last Edit: May 28, 2012, 04:58 am by Graynomad Reason: 1
Here's my refactored version

Code: [Select]
int q_1 = 4;
int q_2 = 5;
int q_3 = 6;
int q_4 = 7;
int red = 8;                   // 1st device (red LED)
int green = 9;                 // 2nd device (green LED)
int std_out = 10;

void setup() {
  pinMode(q_1, INPUT);
  pinMode(q_2, INPUT);
  pinMode(q_3, INPUT);
  pinMode(q_4, INPUT);
  pinMode(std_out, INPUT);
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
}

int getKey () {
  int keyVal = 0;

  while (digitalRead(std_out) == HIGH); // wait for key to be released
  while (digitalRead(std_out) == LOW); // wait for next key press
  delay(10); // debounce if needed
 
  keyVal |= digitalRead(q_4) << 3; // depends on HIGH always being defined as 1
  keyVal |= digitalRead(q_3) << 2;
  keyVal |= digitalRead(q_2) << 1;
  keyVal |= digitalRead(q_1);
 
  return keyVal;
}


void loop() {
  int keyVal = 0;
  // wait a bit...
  delay(500);
 
  keyVal = getKey();

  switch (keyVal) {
case B1000:
keyVal = getKey();
switch (keyVal) {
case B1101:
digitalWrite(red, HIGH);                                      // turn on 1st device
break;
case B0011:
digitalWrite(red, LOW);                                       // turn off 1st device
break;
}

case B0100:
keyVal = getKey();
switch (keyVal) {
case B1101:
digitalWrite(green, HIGH);                                      // turn on 1st device
break;
case B0011:
digitalWrite(green, LOW);                                       // turn off 1st device
break;
}
}
}


You could also accumulate the two key values and combine them to make a single case statement, if you had more options I would be inclined to do that.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

RandallR

I have to say I was a little disappointed when I read the description of the problem after reading the title.

I was hoping someone was using the Arduino to decode DTMF tones.  Maybe some routine using FFT or something.

It looks like you should be getting good reads from you decoder chip now.

wicket


It sounds as if you've got an unexpected voltage difference between the Arduino and your DTMF decoder. Can you measure the difference between the two grounds when the system is wired up in the way that works? Can you measure the signal voltage on those four pins relative to Arduino ground? If the grounds are close and you are getting a positive voltage in the right sort of range, it should work. So presumably you aren't. So you need to see what's actually happening on those pins.


I'm powering my arduino via USB and my circuit from external 5V (230V) supply. Ground difference is 0,36V. If I join grounds only, half of the keys stop working. If I join grounds and external 5V + arduino 5V it starts working again. Does this make sense? Does is maybe have to do something with laptop power supplies and/or some 230V installation having GND an N joined together?

@iggykoopa & @Graynomad:
Yeah, that's what I had in mind. I understand the code, but for some reason it's not working. It's doesn't enter any case statement. I've played with both codes for a bit, but didn't get it to work.  :~

I mean it's not a huge problem if I don't use a tweaked code, but as you said, it would help me if I start adding more devices. Thanks anyway, I'll try some more minor changes and see if it starts working.

@RandallR:
Yeah sorry, could've picked a better suited title. Although I'm also interested in how to decode DTMF tones with Arduino... ;)

PeterH


I'm powering my arduino via USB and my circuit from external 5V (230V) supply. Ground difference is 0,36V. If I join grounds only, half of the keys stop working. If I join grounds and external 5V + arduino 5V it starts working again. Does this make sense? Does is maybe have to do something with laptop power supplies and/or some 230V installation having GND an N joined together?


Having ground and 5V rails connected doesn't sound right - you'll end up with the two regulators fighting each other.

Can you measure the DC voltage from the signal line to ground on your DTMF detectors and the same on the Arduino when you have the grounds connected? It may be that those fractions of a volt difference are enough to take your signal below the threshold that the digital input will detect.
I only provide help via the forum - please do not contact me for private consultancy.

kg4wsv

Read the datasheet - your circuit is broken.  In particular, INH and POWERDOWN (pins 5 and 6) should be tied to ground.  I'm also not convinced the 5k resistor on the ground side of the input is needed - it may result in too much attenuation. a 0.1uF for C2 should be sufficient for headphone/speaker level audio sources.  How large are the LED resistors?  Check the datasheet to make sure the 8870 Qn outputs have enough drive, or just disconnect them temporarily.



Here's a sketch for the circuit above (may have Q1-Q4 mirrored): http://www.eng.uah.edu/~jdw/avr/servo_dtmf_cutdown.pde  Note this sketch uses direct PORT manipulation and uses interrupts.

-j

Go Up