Construye un Decodificador DTMF Solo con Arduino – Sin CI Externos
Componentes y materiales
| Componente | Cantidad |
|---|---|
| Arduino UNO | 1 |
| LED (genérico) | 10 |
| Protoboard (genérica) | 1 |
| Cables de conexión (genéricos) | 20 |
Aplicaciones y servicios online
- Arduino IDE
Sobre el proyecto
Mientras revisaba la lista de proyectos de mi semestre, vi un coche controlado por DTMF que utilizaba el CI CM8870 como decodificador DTMF, y los datos binarios codificados se enviaban al Arduino para realizar operaciones de izquierda, derecha, adelante y atrás. La función de decodificación DTMF, la parte principal, usaba un CI externo que resultaba difícil de integrar. Busqué un código o librería que pudiera reemplazar el CI en el circuito con código adicional, pero no encontré una solución satisfactoria. Sin embargo, una librería basada en el algoritmo de Goertzel (Goertzel.h) podía detectar si una frecuencia específica estaba presente en el tono, calculando el número de pulsos por unidad de tiempo y su contribución de amplitud en la señal de tono dada.
Utilicé el código de ejemplo básico como base y escribí un código que puede detectar las frecuencias DTMF dominantes presentes en el tono y decodificarlas para obtener el número que se presionó en el otro extremo durante la llamada telefónica.
Código
Código Arduino para decodificador DTMF
Compila y sube el código en el Arduino IDE y no olvides añadir la librería primero. El enlace de la librería es: https://github.com/jacobrosenthal/Goertzel
/* Este código es una implementación básica de un decodificador DTMF para detectar los 16 caracteres DTMF desde el pin analógico A0 y da la salida decodificada comprobando todos los tonos superiores e inferiores en la matriz DTMF y nos da el número correspondiente activando el bit digital correspondiente para los números 0-9 e imprimiendo por serie el resto de caracteres. Este trabajo se basa enteramente en el código de Kevin Banks encontrado en https://www.embedded.com/design/embedded/4024443/The-Goertzel-Algorithm, por lo que todo el crédito es para él por su implementación genérica y desglose. El algoritmo de Goertzel es de larga data, ver https://en.wikipedia.org/wiki/Goertzel_algorithm para una descripción completa. A menudo se usa en detección de tonos DTMF como alternativa a la Transformada Rápida de Fourier porque es rápido con baja sobrecarga, ya que solo busca una sola frecuencia en lugar de mostrar la ocurrencia de todas las frecuencias. * ESTE CÓDIGO FUE HECHO/MODIFICADO POR "Mian Mohammad Shoaib" Y LIBERADO AL DOMINIO PÚBLICO. * Para cualquier consulta relacionada con el código, contactar en MMSHOAIB8452@GMAIL.COM */
#include <Goertzel.h>
int sensorPin = A0;
const int N = 100; // número de muestras que tomará el código, se puede cambiar para sensibilidad; si es grande puede ralentizar el Arduino
const float threshold = 2000; // amplitud mínima de tono para ser considerado, se puede cambiar para más sensibilidad
const float sampling_freq = 8900; // frecuencia máxima detectable es sampling_rate/2 y Arduino Uno con 16MHz soporta muestreo hasta 8900 Hz
float x_frequencies[4]; // dos arrays para guardar las frecuencias de los ejes X e Y a detectar
float y_frequencies[4];
void setup() {
pinMode(13, OUTPUT); // LED parpadeante para mostrar si se detecta algún tono
pinMode(2, OUTPUT); // inicializa 10 pines como salida para mostrar salidas DTMF del 2 al 12
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
Serial.begin(9600);
x_frequencies[0] = 1209; // inicializa arrays con frecuencias de tonos de ejes X e Y junto con su número de fila y columna
x_frequencies[1] = 1336;
x_frequencies[2] = 1477;
x_frequencies[3] = 1633;
y_frequencies[0] = 697;
y_frequencies[1] = 770;
y_frequencies[2] = 852;
y_frequencies[3] = 941;
}
bool detect_tone(float freq) {
Goertzel goertzel = Goertzel(freq, N, sampling_freq); // inicializa función de librería con frecuencia de muestreo, número de muestras y frecuencia objetivo
goertzel.sample(sensorPin); // Tomará N muestras
float magnitude = goertzel.detect(); // las comprueba para la frecuencia objetivo
if (magnitude > threshold) { // si obtienes falsos positivos o negativos, ajusta el threshold
digitalWrite(13, HIGH); // parpadea LED en 13 si se detecta un pulso
delay(250);
digitalWrite(13, LOW);
Serial.print(freq);
Serial.print("\n");
return true;
} else return false;
}
void print_number(int row, int column) {
int number = 0;
if (row == 0) { // encuentra el número correspondiente a la fila y columna encontradas
if (column == 0) number = 1;
else if (column == 1) number = 2;
else if (column == 2) number = 3;
else if (column == 3) number = 10;
} else if (row == 1) {
if (column == 0) number = 4;
else if (column == 1) number = 5;
else if (column == 2) number = 6;
else if (column == 3) number = 11;
} else if (row == 2) {
if (column == 0) number = 7;
else if (column == 1) number = 8;
else if (column == 2) number = 9;
else if (column == 3) number = 12;
} else if (row == 3) {
if (column == 0) number = 14;
else if (column == 1) number = 0;
else if (column == 2) number = 15;
else if (column == 3) number = 13;
}
if (number < 10) {
digitalWrite((number + 2), HIGH);
Serial.print(number);
} else if (number == 10) Serial.print('A');
else if (number == 11) Serial.print('B');
else if (number == 12) Serial.print('C');
else if (number == 13) Serial.print('D');
else if (number == 14) Serial.print('*');
else if (number == 15) Serial.print('#');
Serial.print("\n");
delay(800);
for (int i = 2; i <= 12; i++) {
digitalWrite(i, LOW);
}
}
void loop() {
int column = 0, row = 0;
int i = 0;
while (1) {
if (detect_tone(x_frequencies[i]) == true) {
column = i;
break;
}
i++;
if (i == 4) i = 0;
}
i = 0;
while (1) {
if (detect_tone(y_frequencies[i]) == true) {
row = i;
break;
}
i++;
if (i == 4) i = 0;
}
print_number(row, column);
}
Esquemático
El circuito usa 10 LEDs conectados desde el pin digital 2 al 12 que se encienden cuando se presiona cualquier tono para los números entre 0-9 respectivamente, y un LED de detección de pulso conectado en el pin 13 que dará un parpadeo corto cuando se detecte un pulso o señal. Los números mayores a 9 (caracteres especiales) se mostrarán mediante impresión en serie en el IDE. El pin de entrada desde el conector de audio o cable AUX se conectará al pin analógico A0 con un condensador de 1uF en serie que filtrará las bajas frecuencias y el offset DC.
Proceso de manufactura
- Crea un Impresionante Sistema Ambilight para Monitor con Arduino
- Construye un Dispositivo de Levitación Ultrasónica con Arduino – Guía Paso a Paso
- SERENA: Sistema de Alarma Personalizado Arduino Mega 2560 con Pantalla TFT LCD Táctil
- Construye un Voltímetro Inteligente con Arduino y Smartphone – Proyecto DIY Fácil
- Monitor de Frecuencia Cardíaca IoT en Tiempo Real con Arduino y MAX30100
- Comunicación Código Morse con Módulo Láser – Proyecto Arduino de Doble Lado
- Servidor Web Arduino Uno WiFi: Controla un LED desde el Navegador
- Contador Inteligente de Plazas de Aparcamiento: Seguimiento en Tiempo Real con Arduino, Processing y PHP
- Automatiza el Juego del Dinosaurio de Chrome con Arduino y Python
- Control Arduino UNO desde Python 3 – Envío de Comandos y Demo LED
- Construye una Radio FM Compacta con Arduino Nano y RDA5807M