Here is yet another software DTMF decoder based on the GitHub - jacobrosenthal/Goertzel: Arduino Library implementation of the Goertzel algorithm library. The main differences are that this version does not control the sample frequency by calling analogRead() in a loop but uses a timer to drive the ADC at any user-selected frequency. The sample buffer is filled by the ISR of the ADC. Also, the bit resolution is 8 bits instead of the normal 10 to optimise the calculation speed.
It appears quite reliable even at quite high rates (50mS tone burst, 50mS space) although I need it only for detecting tones generated by a phone keypad which is far less demanding.
I also made a few other minor changes to the library because the original did not support multiple instances due to its use of global instead of instance variables. The solution described here uses 8 Goertzel objects, one for each detection frequency. However, there is only a single sample buffer.
In addition, in the test sketch, I have added a validation parameter to control the number of required identical consecutive repetitions of the detection of a tone before it is considered valid.
In principle, it works like this:
8 Goertzel objects are created, one for each detection frequency.
The shared sample buffer is initiated and a pointer is passed to the class.
The coefficients are then calculated for each Goertzel object.
During operation, the sample buffer is filled with the specified number of samples.
The 4 "row" Goertzel objects test the sample and the "winner" frequency is determined, that is the one which yields the highest magnitude.
The same applies to the 4 "column" Goertzel objects. At the end, the received DTMF character is determined.
The operation is repeated.
When the exact required number of identical consecutive detections is reached, the result is delivered together with a quality statistic.
There are a number of parameters to play with:
The number of samples: 64 is good with 9600sps. 128 is good with 19200sps.
The sample frequency (sps): see above
The ADC prescaler: ( /8 or /16 seems OK)
The number of consecutive matches required to validate a result: This however can be slow. For large numbers of samples and high DTMF rates, this parameter must be low, say 1 or even 0.
The magnitude threshold (this is now non-critical because the highest magnitude row and column matches are selected, but it must be low enough to ensure that no valid matches are lost). 500 is good for 8 bit ADC resolution. 2000 is good if you revert to 10 bits
On the hardware side, attempt to match the 2 resistors between Vcc and Ground to ensure that the the midpoint voltage is Vcc/2.
For testing, I use an old telephone, some online resources like Generate DTMF Tones and Online DTMF Tone Generator and the el_supremo test files contained in the zip file in the OP of this thread).
Do NOT use the supplied circuit to connect directly to a telephone network where voltages up 90VAC may be encountered.
To use, simply copy the 2 library parts (.h and .cpp) into the folder containing the .ino file.
Notes:
- This solution uses ATmega328P (Arduino Uno etc.) hardware registers and may have to be adapted for other boards.
- Since the ADC is connected to a timer, the simultaneous use of analogRead() may cause problems.
- Timer1 is used by this application.
Future:
- attempt to drop floats to optimize calculations
- Allow the timer driving the ADC to run only during the capture of the sample to free these resources for other purposes.
Goertzel.cpp (4.71 KB)
Goertzel.h (2.31 KB)

dtmf_v0_08P.ino (6.17 KB)