Repository navigation
DTMF
DTMF (dual tone multi frequency) is the touch tone signaling of telephones: each of the 16 keys 0-9, *, # and A-D is the sum of a row tone (697, 770, 852 or 941 Hz) and a column tone (1209, 1336, 1477 or 1633 Hz). It is not a data modem, but it is understood by telephones, telephone systems, radio repeaters and many cheap decoder chips.
Advantages
- Compatible with telephones, radios (remote control of repeaters) and DTMF decoder chips.
- Simple and robust: the receiver accepts frequency deviations of ±1.5% (like ITU-T Q.24) and ignores the echo at the end of a tone.
- All tones are below 1700 Hz: they pass every telephone line and radio.
Disadvantages
- Only 16 different characters: other characters are ignored by the transmitter.
- Slow: about 7 keys per second with the default timing.
- No error detection.
I2SStream i2s;
DTMFStream dtmf(i2s, RXTX_MODE);
void setup() {
DTMFConfig cfg = dtmf.defaultConfig();
cfg.sample_rate = 8000;
...
dtmf.begin(cfg);
}
void loop() {
dtmf.print("*123#"); // dial
dtmf.flush();
while (dtmf.available()) Serial.write(dtmf.read()); // received keys
}echo -n "0123456789*#ABCD" | tinymodem --tx -f dtmf.wav dtmf
tinymodem --rx -f dtmf.wav dtmfDTMFConfig, DTMFEncoder, DTMFDecoder, DTMFStream, DTMFStreamRTOS and DTMFKeys (the tones of the keys) are the DTMF classes. The encoder accepts the keys in upper or lower case. A , adds a pause of comma_ms, all other characters are ignored. writeKey() sends a single key. On the command line, -R, -v, -q, --rx-one and --Xrxnoise are supported.
DTMFConfig field |
Default | |
|---|---|---|
tone_ms |
70 | Transmitter: duration of a tone |
pause_ms |
70 | Transmitter: pause after a tone |
comma_ms |
500 | Transmitter: pause for a ,
|
volume |
1.0 | Transmit amplitude of the sum of both tones |
min_amplitude |
0.01 | Receiver: minimum amplitude of each tone |
max_twist_db |
16 | Receiver: max level difference of the row and the column tone |
group_ratio_db |
6 | Receiver: a tone must be this much stronger than the other tones of its group |
rx_timeout_ms |
250 | Receiver: a transmission ends after this silence |
rx_one |
false | Receiver: stop after the first transmission |
channel |
0 | Receiver: input channel |
sample_rate, channels, bits_per_sample
|
48000, 1, 16 | Audio format |
A small speaker attenuates the row tones and distorts: over the speaker and microphone of the ESP32-P4-WIFI6, max_twist_db = 26, group_ratio_db = 3 and a transmit volume of 0.4 were needed.
The transmitter sends the two tones with a fade in and out of 2 ms, to avoid clicks.
The receiver measures the 8 tones with Goertzel filters over windows of 25.6 ms (205 samples at 8000 Hz). Four windows overlap, so a new result is available every 6.4 ms. A key is detected when the strongest row and column tone are clearly stronger than the other tones of their group, have a similar level (twist) and contain most of the signal energy. A key is reported after 3 consecutive detections and released after 3 windows without it. The same key is only reported again if it is at least half as strong as before: this ignores the echo of a room at the end of a tone. The receiver needs tones and pauses of at least about 45 ms.
- All 16 keys at 8000 to 48000 Hz, also with 45 ms tones and pauses, with ±1.5% frequency deviation and with 5% of full scale.
- Noise (
--Xrxnoise) up to 1.0 at 8000 Hz. - No keys are reported from noise or a single tone.
- Over the air on the ESP32-P4 (speaker to the onboard microphone of the same board): all keys with the settings above.