Tabla de contenido:
Video: Detector DTMF: 4 pasos
2024 Autor: John Day | [email protected]. Última modificación: 2024-01-30 08:43
Visión general
Me inspiré para construir este dispositivo con una tarea en casa del curso en línea Procesamiento de señales digitales. Este es un decodificador DTMF implementado con Arduino UNO, detecta un dígito presionado en el teclado de un teléfono en el modo de tono por el sonido que produce.
Paso 1: comprensión del algoritmo
En DTMF, cada símbolo está codificado con dos frecuencias de acuerdo con la tabla de la imagen.
El dispositivo captura la entrada del micrófono y calcula amplitudes de ocho frecuencias. Dos frecuencias con amplitudes máximas dan una fila y una columna del símbolo codificado.
Adquisición de datos
Para realizar el análisis del espectro, las muestras deben capturarse a una cierta frecuencia predecible. Para lograr esto, utilicé el modo ADC de ejecución libre con la máxima precisión (prescaler 128) que proporciona una frecuencia de muestreo de 9615Hz. El siguiente código muestra cómo configurar el ADC de Arduino.
void initADC () {
// Init ADC; f = (16MHz / prescaler) / 13 ciclos / conversión ADMUX = 0; // Sel de canal, ajuste a la derecha, use el pin AREF ADCSRA = _BV (ADEN) | // ADC habilita _BV (ADSC) | // Inicio de ADC _BV (ADATE) | // Disparador automático _BV (ADIE) | // Habilitación de interrupciones _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Modo de ejecución libre DIDR0 = _BV (0); // Apague la entrada digital para el pin ADC TIMSK0 = 0; // Timer0 off} Y el controlador de interrupciones se ve así ISR (ADC_vect) {uint16_t sample = ADC; samples [samplePos ++] = sample - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Búfer lleno, interrumpir}}
Análisis de espectro
Después de recolectar muestras, calculo amplitudes de 8 frecuencias que codifican símbolos. No necesito ejecutar FFT completo para esto, así que utilicé el algoritmo de Goertzel.
void goertzel (uint8_t * muestras, flotante * espectro) {
flotar v_0, v_1, v_2; flotar re, im, amp; para (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); flotar a = 2. * c; v_0 = v_1 = v_2 = 0; para (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (flotante) (muestras ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); espectro [k] = amperio; }}
Paso 2: el código
La imagen de arriba muestra el ejemplo de codificación del dígito 3 donde la amplitud máxima corresponde a las frecuencias 697Hz y 1477Hz.
El boceto completo se ve como sigue
/ ** * Conexiones: * [Mic a Arduino] * - Salida -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Display to Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 * / #include #include
#incluir
#define CS_PIN 9
#define N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t muestras [N];
volátil uint16_t samplePos = 0;
espectro flotante [IX_LEN];
// Frecuencias [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// Calculado para 9615 Hz 256 muestras const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.634393284167025713, 0.59978 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025451;, 0.883549212643
typedef struct {
dígito char; uint8_t index; } digit_t;
digito_t digito_detectado;
tabla de caracteres const [4] [4] PROGMEM = {
{'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', ' C '}, {' * ',' 0 ',' # ',' D '}};
const uint8_t char_indexes [4] [4] PROGMEM = {
{1, 2, 3, 10}, {4, 5, 6, 11}, {7, 8, 9, 12}, {15, 0, 14, 13} };
fuente de bytes [16] [8] = {
{0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38}, // 0 {0x04, 0x0c, 0x14, 0x24, 0x04, 0x04, 0x04, 0x04}, // 1 {0x00, 0x30, 0x48, 0x04, 0x04, 0x38, 0x40, 0x7c}, // 2 {0x00, 0x38, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38}, // 3 {0x00, 0x04, 0x0c, 0x14, 0x24, 0x7e, 0x04, 0x04 }, // 4 {0x00, 0x7c, 0x40, 0x40, 0x78, 0x04, 0x04, 0x38}, // 5 {0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38}, // 6 {0x00, 0x7c, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10}, // 7 {0x00, 0x3c, 0x44, 0x44, 0x38, 0x44, 0x44, 0x78}, // 8 {0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x04, 0x78}, // 9 {0x00, 0x1c, 0x22, 0x42, 0x42, 0x7e, 0x42, 0x42}, // A {0x00, 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x7c}, / / B {0x00, 0x3c, 0x44, 0x40, 0x40, 0x40, 0x44, 0x7c}, // C {0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78}, // D {0x00, 0x0a, 0x7f, 0x14, 0x28, 0xfe, 0x50, 0x00}, // # {0x00, 0x10, 0x54, 0x38, 0x10, 0x38, 0x54, 0x10} // *};
void initADC () {
// Init ADC; f = (16MHz / prescaler) / 13 ciclos / conversión ADMUX = 0; // Sel de canal, ajuste a la derecha, use el pin AREF ADCSRA = _BV (ADEN) | // ADC habilita _BV (ADSC) | // Inicio de ADC _BV (ADATE) | // Disparador automático _BV (ADIE) | // Habilitación de interrupciones _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Modo de ejecución libre DIDR0 = _BV (0); // Apague la entrada digital para el pin ADC TIMSK0 = 0; // Temporizador0 apagado}
void goertzel (uint8_t * muestras, flotante * espectro) {
flotar v_0, v_1, v_2; flotar re, im, amp; para (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); flotar a = 2. * c; v_0 = v_1 = v_2 = 0; para (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (flotante) (muestras ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); espectro [k] = amperio; }}
float avg (float * a, uint16_t len) {
resultado flotante =.0; para (uint16_t i = 0; i <len; i ++) {resultado + = a ; } return result / len; }
int8_t get_single_index_above_threshold (flotar * a, uint16_t len, flotar umbral) {
if (umbral <UMBRAL) {retorno -1; } int8_t ix = -1; para (uint16_t i = 0; i umbral) {if (ix == -1) {ix = i; } else {return -1; }}} return ix; }
void detect_digit (flotante * espectro) {
flotar avg_row = avg (espectro, 4); flotar avg_col = avg (& espectro [4], 4); int8_t fila = get_single_index_above_threshold (espectro, 4, avg_row); int8_t col = get_single_index_above_threshold (& espectro [4], 4, avg_col); if (fila! = -1 && col! = -1 && avg_col> 200) {dígitos_detectados.digito = pgm_read_byte (& (tabla [fila] [col])); dígitos_detectados.index = pgm_read_byte (& (char_indexes [fila] [col])); } más {dígitos_detectados. dígitos = 0; }}
void drawSprite (byte * sprite) {
// La máscara se usa para obtener el bit de columna del byte de la fila del sprite mask = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] y máscara));
// desplaza la máscara un píxel a la derecha
máscara = máscara >> 1; }
// restablecer la máscara de columna
máscara = B10000000; }}
configuración vacía () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (verdadero); lmd.setIntensity (2); lmd.clear (); lmd.display ();
dígitos_detectados.digito = 0;
}
unsigned long z = 0;
bucle vacío () {
while (ADCSRA & _BV (ADIE)); // Espere a que termine el muestreo de audio goertzel (muestras, espectro); detect_digit (espectro);
si (dígitos_detectados. dígitos! = 0) {
drawSprite (fuente [dígitos_detectados.index]); lmd.display (); } if (z% 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (espectro ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) dígitos_detectados.digito); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Reanudar la interrupción del muestreo
}
ISR (ADC_vect) {
uint16_t sample = ADC;
samples [samplePos ++] = sample - 400;
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Búfer lleno, interrumpir}}
Paso 3: esquemas
Deben realizarse las siguientes conexiones:
Micrófono a Arduino
Fuera -> A0
Vcc -> 3.3V Gnd -> Gnd
Es importante conectar AREF a 3.3V
Mostrar a Arduino
Vcc -> 5 V
Tierra -> Tierra DIN -> D11 CLK -> D13 CS -> D9
Paso 4: Conclusión
¿Qué se podría mejorar aquí? Usé N = 256 muestras a una tasa de 9615Hz que tiene alguna fuga de espectro, si N = 205 y la tasa es de 8000Hz, entonces las frecuencias deseadas coinciden con la cuadrícula de discretización. Para eso, el ADC debe usarse en modo de desbordamiento del temporizador.
Recomendado:
DTMF VIDEO STREAMING ROVER: 3 pasos
DTMF VIDEO STREAMING ROVER: hola después de mi LINUX TERMINAL CONTROLLED ROVER y WIFI DTMF PC CONTROLLED ROBOT, este es mi tercer robot. y al igual que otros dos aquí, tampoco utilicé ningún microcontrolador o programación para mantenerlo simple y fácil de hacer. También transmite video en vivo a través de wifi
Cómo hacer un decodificador de línea telefónica DTMF (tono) simple: 3 pasos
Cómo hacer un decodificador de línea telefónica DTMF (tono) simple: este es un proyecto simple que le permite decodificar señales DTMF básicamente en cualquier línea telefónica. En este tutorial, usamos el decodificador MT8870D. Estamos usando un decodificador de tonos prediseñado porque, créanme, es un dolor de cabeza intentar hacerlo con
ROBOT WIFI DTMF: 5 Pasos
ROBOT WIFI DTMF: hola en este tutorial voy a mostrarte cómo puedes hacer un rover controlado por PC sin usar un microcontrolador, esto significa que en este proyecto no hay código de alto nivel involucrado, solo necesitas conocimientos básicos sobre la página html para hacer eso. puede verlo completo
Cómo hacer un robot controlado por un móvil »Wiki Ùtil Basado en DTMF - Sin microcontrolador y programación - Control desde cualquier lugar del mundo - RoboGeeks: 15 pasos
Cómo hacer un robot controlado por un móvil »Wiki Ùtil Basado en DTMF | Sin microcontrolador y programación | Control desde cualquier lugar del mundo | RoboGeeks: Quiero hacer un robot que se pueda controlar desde cualquier parte del mundo, ¡¡¡hagámoslo
Detector de humo IOT: actualice el detector de humo existente con IOT: 6 pasos (con imágenes)
Detector de humo IOT: Actualización del detector de humo existente con IOT: Lista de contribuyentes, Inventor: Tan Siew Chin, Tan Yit Peng, Tan Wee Heng Supervisor: Dr. Chia Kim Seng Departamento de Ingeniería Mecatrónica y Robótica, Facultad de Ingeniería Eléctrica y Electrónica, Universiti Tun Hussein Onn Malaysia.Distribut