Documente Academic
Documente Profesional
Documente Cultură
Introducción
Existen varias maneras de implementar la generación de tonos de audiofrecuencia de manera
digital usando software: tabla Lookup, interpolación, aproximaciones polinomiales y filtros
digitales. Esto tiene aplicación en la generación de tonos DTMF, la síntesis de sonidos de
diferentes frecuencias, Modulación etc.. En microcontroladores es poco práctico el uso de
métodos tradicionales, como la aproximación por series, CORDIC o filtros digitales. La técnica
denominada tabla lookup resulta bien apropiada, sin embargo la literatura acerca del tema
resulta algo confusa. El presente trabajo enfoca el tema de una manera sencilla y práctica lo
que permitirá al lector realizar sus propios desarrollos, tanto de hardware como de software. El
mismo aborda, la generación de ondas sinusoidales de diferentes frecuencias partiendo del
acceso a una tabla de senos previamente construida y almacenada en el programa. La
frecuencia generada esta en función de un valor incremento agregado a un apuntador utilizado
para acceder a la tabla en cada periodo de muestreo. Como salida se puede utilizar el módulo
PWM o algún DAC externo. Finalmente se revisa la aplicación práctica de generar tonos DTMF.
A pesar de que existen un gran número de circuitos integrados análogos que pueden realizar
estas funciones, hay dos razones fundamentales para considerar la generación de tonos
usando software: la primera es que normalmente existe un microcontrolador como parte del
producto final, por lo que generar tonos por software ahorra muchos componentes de hardware
necesarios para realizar esta función. La segunda es la flexibilidad que ofrece la
implementación por software la cual resulta inexistente o cara cuando se implementa por
hardware.
y= fix(65536.0*sin(pi*N/65536.0)+0.5)
En el primer caso se escala por 127 lo que da una rango de –127 a +127 apropiado cuando se
utiliza números complemento a 2 de 8 bits. En el segundo se escala por 63 para un rango de –
63 a +63 apropiado para números complemento a 2 de 7 bits.
Se puede también generar tablas de 64 entradas y escalar a 63 para mantener el rango entre –
63 y +63 es decir:
Y = 63 * sin( 2π * N 64) 0 ≤ N ≤ 63
En este caso tenemos 64 muestras cuyo escalamiento natural debería ser 31 para obtener un
rango entre –31 y +31. El efecto de escalar a 63 es que los valores quedan representados en 7
bits y al convertirlos en formato unipolar sin signo, como veremos más adelante, el valor
máximo es 127. Si tuviéramos que sumar dos ondas como en el caso de la implementación de
tonos DTMF, el valor máximo sería 127+127 = 255 es decir 8 bits que pueden ser aplicados
directamente a un DAC de 8 bits.
Se tomaron sólo 65 valores que representan el seno del primer cuadrante en hexadecimal:
000h,003h,006h,009h,00ch,010h,013h,016h
019h,01ch,01fh,022h,025h,028h,02bh,02eh
031h,033h,036h,039h,03ch,03fh,041h,044h
047h,049h,04ch,04eh,051h,053h,055h,058h
05ah,05ch,05eh,060h,062h,064h,066h,068h
06ah,06bh,06dh,06fh,070h,071h,073h,074h
075h,076h,078h,079h,07ah,07ah,07bh,07ch
07dh,07dh,07eh,07eh,07eh,07fh,07fh,07fh
07fh
Y = 64 + 63 * sin( 2π * N 64) 0 ≤ N ≤ 63
Al agregar el valor 64, los números son convertidos de complemento 2 a unipolar sin signo
como veremos más adelante.
La tabla 1, representa un ciclo completo de una onda sinusoidal utilizando 256 entradas en
complemento 2 y en hexadecimal:
La figura 1 muestra la gráfica de 128 muestras en el rango –64 a +63 y la fig. 2 muestra la
misma gráfica con sus valores convertidos a formato unipolar sin signo. Estos últimos valores
pueden ser aplicados directamente al módulo PWM o un DAC externo.
y=63*sin(2*pi*N/128
80
60
40
20
-20
-40
-60
-80
0 20 40 60 80 100 120 140
N
120
100
80
60
40
20
0
0 20 40 60 80 100 120 140
N
Frecuencia de Muestreo
Una vez construida la tabla, necesitamos definir la frecuencia de muestreo. Esto es cada
cuanto tiempo T debo acceder a la tabla continuamente. Así la frecuencia de muestreo puede
definirse como:
T = 1 Fs
Si tenemos una tabla de 128 muestras que corresponden a un ciclo completo de una onda
sinusoidal y las tomamos de la tabla una a una cada T segundos ó a una frecuencia
Fs = 1 T , entonces se generará una onda sinusoidal cuya frecuencia es:
F = FS 128
F = 1 8000 = 62.5 Hz
De acuerdo con Nyquist la frecuencia de muestreo debe se por lo menos el doble que la
frecuencia más alta que se desee generar, así, si usamos una frecuencia de muestreo de
8Khz, podemos generar señales de hasta 4Khz.
F = 2 * Fs 128 = 125 Hz
1 ≤ incremento ≤ 64
Si incremento es igual a 64, se puede obtener la máxima frecuencia que en este caso es
4000Hz según Nyquist.
La amplitud de la onda de salida, puede ser variada digitalmente, multiplicando cada muestra
por un factor de escala antes de que sea enviada al DAC. Esta también puede ser controlada
por hardware externo, bien sea el DAC o circuitos analógicos basados en amplificadores
operacionales.
Una manera más apropiada es almacenar en la tabla más muestras que las necesarias y
entonces saltar un número especifico de muestras para cada valor enviado al DAC. Ya que la
frecuencia de salida es igual a la frecuencia de muestreo dividida por el número de muestras
por ciclo de la onda, saltar un número de entradas en la tabla por cada muestra de salida
(ejemplo: incremento > 1), equivale a multiplicar la frecuencia de salida, esto es:
Si por ejemplo el número de entradas en la tabla es 256 (un ciclo de onda sinusoidal), la
frecuencia de muestreo 8 Khz y el valor de incremento igual a 1, la frecuencia de salida es:
Hardware
La figura 3 muestra el diagrama esquemático utilizado para la generación de una onda
sinusoidal. Para ello utilizamos un PIC16F88 y un DAC MAX517, este último trabaja utilizando
el bus I2C y es de 8 bits.
VCC
0.1uf
VCC
10K U1
1 8
2 O0 O1 7
U2 4.7K 4.7K 3 GNDVDD 6
1N4148 4 SCL AD0 5
2 11 SDA AD1
3 RA0/AN0 RC0/T1OSO/T1CKI 12
RA1/AN1 RC1/T1OSI/CCP2 MAX517
100 4 13
5 RA2/AN2/VREF- RC2/CCP1 14
6 RA3/AN3/VREF+ RC3/SCK/SCL 15
S1 7 RA4/T0CKI RC4/SDI/SDA 16
RESET RA5/SS/AN4 RC5/SDO 17 I2C BUS J1
21 RC6/TX/CK 18 4.7K
22 RB0/INT RC7/RX/DT 2
23 RB1 10 1 Salida
24 RB2 OSC2/CLKOUT 0.01uf
25 RB3/PGM
26 RB4
27 RB5
28 RB6/PGC
33pf RB7/PGD
9
OSC1/CLKIN
20Mhz 1
MCLR/VPP/THV
20
VDD
33pf
PIC16F873
#include <16F873.h>
#fuses HS,NOWDT,PUT, NOPROTECT, NOBROWNOUT,NOLVP,NOCPD
#use delay(clock=20000000)
#define MAX517_SDA PIN_C4
#define MAX517_CLK PIN_C3
#use i2c(master, sda=MAX517_SDA, scl=MAX517_CLK, FAST)
i2c_start();
i2c_write(0x5e); // Envía la dirección del dispositivo
i2c_write(0);
i2c_write(data_byte); // Envía datos al dispositivos
i2c_stop();
}
128,131,134,137,140,144,147,150,153,156,159,162,165,168,171,174,
177,179,182,185,187,191,193,196,199,201,204,206,209,211,213,216,
218,220,222,224,226,228,230,232,233,235,237,239,240,241,243,244,
245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,
255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246,
245,244,243,241,240,239,237,235,234,232,230,228,226,224,222,220,
218,216,213,211,209,206,203,201,199,196,193,191,188,185,182,179,
177,174,171,168,165,162,159,156,153,150,147,144,140,137,134,131,
128,125,122,119,116,112,109,106,103,100,97,94,91,88,85,82,79,76,
74,71,68,65,63,60,57,54,52,49,47,45,43,40,38,36,34,32,30,28,26,
24,22,21,19,17,16,15,13,12,11,10,8,7,6,6,5,4,3,3,2,1,1,1,1,1,1,
1,1,1,2,2,2,3,3,4,5,6,6,7,8,10,11,12,13,15,16,17,19,21,24,26,28,
30,32,34,36,38,40,43,45,47,50,52,55,57,60,63,65,68,71,74,77,79,
82,85,88,91,94,97,100,103,106,109,112,116,119,122,125,128};
BYTE sine_index;
#int_rtcc
void isr() {
write_dac(SINE_WAVE[sine_index]);
if(++sine_index==256) {
sine_index=0;
}
}
while (TRUE) ;
}
Tonos DTMF
La señalización DTMF (Dual Tone Multi-Frecuency) es usada para transmitir números
telefónicos en la red de telefonía pública, en sistemas de seguridad, en instrumentación y
adquisición de datos, en modems, etc. Aquí ilustramos los conceptos sobre generación DTMF
por software, haciendo uso de microcontroladores.
Como presenta la tabla 2, un tono DTMF esta asociado con una fila y una columna de un
teclado de teléfono. Un tono DTMF consiste en la suma de la frecuencia de una fila con la
frecuencia de una columna, transmitida por período mínimo de 50ms, seguido de un periodo de
silencio de al menos 50ms.
A fin de reducir el contenido armónico al mínimo, la salida debe ser muestreada a una rata alta
para así filtrar el ruido introducido por la frecuencia de muestreo. Un período de 125us, se
escogió en este proyecto, el cual es un período estándar de la industria de telecomunicaciones.
Incremento: valor en que debe ser incrementado el apuntador para cada período de muestreo.
Por ejemplo, para generar la frecuencia 697Hz, si la tabla de seno tiene 256 entradas, el valor
de incremento es:
Como no podemos usar un intervalo en fracción, lo redondeamos a 22. Introduciendo este valor
en la ecuación, obtenemos como frecuencia generada:
La tabla 3, resume los cálculos realizados para una frecuencia de muestreo de 7812 Hz y una
tabla de 256 entradas.
Cuando una frecuencia del grupo alto es leída de la tabla de seno, esta es desplazada a la
derecha 2 bits (dividida por 4), entonces el mismo valor del seno es agregado al resultado,
produciendo la multiplicación por 1.25. La pre-énfasis es:
De tal manera que los valores en la tabla seno deben estar entre –14563 y +14563.
VCC
1 2 3
4 5 6
7 8 9
* 0 #
10K U2
2 11
3 RA0/AN0 RC0/T1OSO/T1CKI 12
4 RA1/AN1 RC1/T1OSI/CCP2 13
1N4148 5 RA2/AN2/VREF- RC2/CCP1 14
6 RA3/AN3/VREF+ RC3/SCK/SCL 15 Salida al
100 7 RA4/T0CKI RC4/SDI/SDA 16 Filtro pasa
RA5/SS/AN4 RC5/SDO 17 bajos
21 RC6/TX/CK 18
S1 22 RB0/INT RC7/RX/DT
23 RB1 10
24 RB2 OSC2/CLKOUT
25 RB3/PGM
26 RB4
27 RB5
28 RB6/PGC
RB7/PGD
9
33pf OSC1/CLKIN
1
20Mhz MCLR/VPP/THV
20
VDD
PIC16F873
33pf
LM324
1K
4
3 + 1K 8.2K
1 5 +
0.1uF 2 - 7
0.01uF 6 -
11
Software
/*************************************************************************/
/* DTMF.C */
/* */
/* Programa para generar tonos DTMF a partir de un teclado 4x4. */
/* Usa el módulo de Captura CCP1 en modo PWM */
/* */
/* Autor: Carlos A. Narváez */
/* Fecha: Septiembre, 2005 */
/*************************************************************************/
#include <16F873.h>
#fuses HS,NOWDT,PUT, NOPROTECT, NOBROWNOUT,NOLVP,NOCPD
#use delay(clock=20000000)
#include <kbd.c>
#byte PORTA = 5
128,131,134,137,140,144,147,150,153,156,159,162,165,168,171,174,
177,179,182,185,187,191,193,196,199,201,204,206,209,211,213,216,
218,220,222,224,226,228,230,232,233,235,237,239,240,241,243,244,
245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,
255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246,
245,244,243,241,240,239,237,235,234,232,230,228,226,224,222,220,
218,216,213,211,209,206,203,201,199,196,193,191,188,185,182,179,
177,174,171,168,165,162,159,156,153,150,147,144,140,137,134,131,
128,125,122,119,116,112,109,106,103,100,97,94,91,88,85,82,79,76,
74,71,68,65,63,60,57,54,52,49,47,45,43,40,38,36,34,32,30,28,26,
24,22,21,19,17,16,15,13,12,11,10,8,7,6,6,5,4,3,3,2,1,1,1,1,1,1,
1,1,1,2,2,2,3,3,4,5,6,6,7,8,10,11,12,13,15,16,17,19,21,24,26,28,
30,32,34,36,38,40,43,45,47,50,52,55,57,60,63,65,68,71,74,77,79,
82,85,88,91,94,97,100,103,106,109,112,116,119,122,125,128};
index1 += inc1;
index2 += inc2;
index1=0;
index2=0;
inc1=0;
inc2=0;
if((keypad=='1')||(keypad=='2')||(keypad=='3'))
inc1=DTMF_ROW1;
else if((keypad=='4')||(keypad=='5')||(keypad=='6'))
inc1=DTMF_ROW2;
else if((keypad=='7')||(keypad=='8')||(keypad=='9'))
inc1=DTMF_ROW3;
else if((keypad=='*')||(keypad=='0')||(keypad=='#'))
inc1=DTMF_ROW4;
if((keypad=='1')||(keypad=='4')||(keypad=='7')||(keypad=='*'))
inc2=DTMF_COLA;
else if((keypad=='2')||(keypad=='5')||(keypad=='8')||(keypad=='0'))
inc2=DTMF_COLB;
else if((keypad=='3')||(keypad=='6')||(keypad=='9')||(keypad=='#'))
inc2=DTMF_COLC;
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(duration-- > 0)
{
delay_ms(1);
}
disable_interrupts(GLOBAL);
disable_interrupts(INT_TIMER2);
set_pwm1_duty(0x80);
}
set_pwm1_duty(0x80);