DTMF decoding using a decoder chip

Hi I am a extra newbie at programming. I can do any sort of hardware interfacing etc but for the life of me I am finding that this programming does not compute in my brain. I can do the easy stuff like turning a port on or off and making delays..all the easy stuff but I am having a hard time trying to understand how to read 4 bits of a port then use that binary number as part of a security code. Maybe a small explaination is easier. I want to make a dtmf controller. it will be using a decoder chip like a 8870 or similar. This puts out the 16 dtmf digits in a 4 bit binary output also it has a DV pin which goes high when it detects a valid tone pair so this needs to be looked at by the arduino. So I need to read when the DV pin goes high then scan 4 bits of the port and stehn compare that number to one that is programmed into the software as a security number. The sequence will be 4625 (security number) then the next 2 digits denote the uotput port and then the state. so to turn channel 1 on it would be 462511... the last number 1 is the state 1 being on and 0 being off. I have looked all over the net and have found some code in assembler but its all gobbldygook and I dont understand what they are doing. The arduino seems a bit simpler in its code for what I have played with. I am sure it will be easy for a lot of you out there. Any help or snipets of code would be really appreciated Regards


Hi Mark,

You will find it easier if you break your project down into small tasks. Start of by just detecting that a valid DTMF digit has arrived by checking to see if the DV pin has gone high. Perhaps write a test sketch that just prints a message to the serial port to day the DV pin has gone high.

Next you could write a function that reads four consecutive input pins and returns the binary value. Here is one way to do this:

int getDigit()        
  int bit = 0;
  int digit = 0;
  for(int pin = 2; pin <= 5; pin++)
    bitWrite(digit, bit, digitalRead(pin));  // set the bit to 0 or 1 depending
                                             // on value of the given pin
    bit = bit + 1;                           // increment to the next bit 
  return digit;


If you call this function when the DV pin goes high you should get the DTMF value. You would then need to wait for the DV pin to go low indicating the end of the tone. You could collect the digits into an array of characters and when you have enough digits you can do the security code check.

I hope that helps.

I wrote this sketch to interface with an 8870 decoder. It uses an interrupt service routine, a variable length password, and uses * and # to toggle a servo between two (hard-coded) positions. Schematic is below. Note it uses direct port input and bit shifting to grab all 4 bits at the same time.

It has flown on a few (3 or 4?) balloon flights as the cutdown system.


Hi guys

Thanks for the info from both of you. I am slowly working on understanding this. As I said I can do the simple stuff but Jason your code is way beyond me at this stage. I am going through your sketch and trying to understand what is going on but I need to sort out some of the C commands and what they do. I have looked all over the net to try to find some sort of course or info that SIMPLY explains all the different ways of variables and commands and how they work. This really cheeses me off I can understand and make and design all the hardware I like and have no problems what so ever in doing any hardware but the software side to me just does not make any sense unless its turning things on or off etc. Jason what you have done in the hardware is pretty much standard hardware design and I have all that done and it was easy as but understanding how it all flows is difficult. What are all the serial commands?...you have no display to output those commands or is it serial writing to a eeprom?...sorry for the dumbar*e questions but I am so frustrated as to why I can not get my head around this programming




Ok you are programming what you want out to a pc or some sort of display via a TTL rs232 port and I see you have made a array to sort out the dtmf digits etc. I can understand parts of your sketch but its how it all comes together that is the issue. Mark

That program is probably a bit esoteric to use for learning C/C++. :)

As with all arduino sketches, the main() function is elsewhere; the setup() function is called once, and loop() is called repeatedly forever.

setup() sets the mode and level of the various IO pins; attaches the interrupt service routine (ISR) for grabbing the DTMF bits when the tone detect (STD) output of the 8870 goes high; and extracts some configuration data from EEPROM storage.

loop() immediately begins to watch for tones and watch for characters from serial input to see if it should go into configuration mode. Config mode is only allowed for a few seconds after the program starts, and talks to the user over the rs232 port. The configuration part of loop() is a bit complex because it is non-blocking - the program can still detect and process tones until the configuration function is actually called. There is a timeout for receiving the password, so that if the user gets confused the password entry will reset after this timeout. Once the password is entered, the servo can be repeatedly set to either of the two states using # or * until the DTMF input has been silent for another timeout period. Further input requires re-entering the password.

There are functions to save the configuration to EEPROM, read it from EEPROM, get an integer from the serial input (arduino doesn't support scanf), test a character to see if it's a digit, another to test a character to see if it's a DTMF "digit", etc.

There are also some reasonably advanced data structure uses happening: the configuration data is stored in a struct (a heterogeneous user defined data type), and a union is used to map the struct to a byte buffer for easier transfer to/from EEPROM (since EEPROM deals with bytes, not ints and strings).

The interrupt service routine is called by the hardware when it detects the specified change in the STD pin (rising edge triggered). The ISR simply sets a global variable, which the loop() function checks and acts upon if it has been set.

Hope that nutshell description helps a bit. If you've got specific questions about any of it I'll do my best to answer.


Hi Jason

Most of that is way over my head at this stage but I do understand some of it now with your explanation. I will keep battling on with doing this...my biggest problem is getting the time to sit down with no disruptions and get this stuff into my head. In a week or so I should have the time to spend in much greater time to do more on this. it is like 1 step forward and 3 steps backwards at the moment with learning programming.


Kg4wsv, thanks for posting that code. I'm learning a lot pouring over it. A couple questions... What does PIND in the code do? I don't see it declared anywhere.

Also, any thoughts on if it would be possible to limit config access to certain phones by using CallerID info? Can you get that out of the mt8870?

What does PIND in the code do?

This is direct port manipulation of the ATmega's IO pins, specifically the group of pins known as port D. This is the sort of operation that digitalRead() and digitalWrite() wrap up nice and neat so that you don't have to to logical operations to strip that one bit for pin X out of the 8 bit grouping. In this project, however, I'm using 4 bits at a time as provided by the 8870, so it was actually easier for me to grab all 8 bits and strip off the half I didn't need (as opposed to doing 4 separate digitalRead() operations, then manipulating the 4 results into a single value from 0 to 15).

any thoughts on if it would be possible to limit config access to certain phones by using CallerID info?

The 8870 doesn't do caller ID - that's more of a modem function. The devices would be similar, but you'd probably get the data serially rather than in parallel like the 8870.


Oh, PIN D :slight_smile: That space alone takes me in the proper direction. Thanks for explaining it further. That makes a lot of sense.

I was looking around the web and found another Mitel chip that does the CID stuff, MT88E46. I’ll probably not get around to it, but I’ve got ideas running in my head that make that chip look really interesting.

Re PIND etc, see here if you're interested in the gory details: http://www.arduino.cc/playground/Learning/PortManipulation