Usando un PIC para la Generación de Tonos de Audio Autor: Ing. Carlos Narváez Universidad de Oriente email: cnarvaez@udo.edu.ve 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. Generando la Tabla de Senos Una de las primeras confusiones es como generar la tabla de senos que encontramos en muchos programas y cuales son sus distintas variantes. El caso general, cuando utilizamos 16 bits para almacenamiento, implica generar 65536 muestras 216. Utilizando programas como Matlab podemos realizar esto de la siguiente manera: Y = sin( 2π * N 65536) 0 ≤ N ≤ 65535 Escalando por 32767, es decir: Y = 32767 * sin( 2π * N 65536) Obtenemos un rango que va desde –32767 a +32767 apropiado al utilizar números en complemento a 2 de 16 bits. Más exactamente, la tabla es generada utilizando: y= fix(65536.0*sin(pi*N/65536.0)+0.5) Carlos A. Narváez 2005 Naturalmente una tabla de 65536 entradas no es apropiada, pues utiliza mucha memoria, por lo que normalmente se utilizan tablas de 256 y 128 entradas, generadas de la siguiente manera: Y = 127 * sin( 2π * N 256) 0 ≤ N ≤ 255 Y = 63 * sin( 2π * N 128) 0 ≤ N ≤ 127 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. Asimismo es posible utilizar un solo cuadrante de la tabla (0 a π/2) ó 65 entradas en el caso de una tabla generada de 256 entradas y utilizar algunas identidades trigonométrica en el programa para cubrir la totalidad de un ciclo de onda seno. Veamos algunos ejemplos: La siguiente tabla de 65 valores (0 a 90 grados) fue calculada de la siguiente manera: Y = 127 * sin( 2π * N 256) 0 ≤ N ≤ 255 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 La siguiente tabla dada en decimal, consta de 64 muestras y fue generada de la siguiente manera: Y = 64 + 63 * sin( 2π * N 64) 0 ≤ N ≤ 63 Carlos A. Narváez 2005 64,70,76,82,88,94,99,104,109,113,117,120,123,125,126,127 127,127,125,124,121,118,115,111,107,102,97,91,85,79,73,67 60,54,48,42,36,30,25,20,16,12,9,6,3,2,0,0 0,1,2,4,7,10,14,18,23,28,33,39,45,51,57,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: Tabla 1. Seno(x) 256 entradas Complemento 2 y Hexadecimal Carlos A. Narváez 2005 Conversión Números Complemento 2 a Unipolar sin signo Como hardware de salida normalmente se utiliza el módulo PWM o un convertidor Digital/Analógico los cuales utilizan valores unipolares sin signo. Para convertir números complemento 2 a formato unipolar sin signo, le sumamos 32768 en caso de números complemento a 2 de 16 bits, 128 en caso de 8 bits y 64 en el caso de 7 bits. Si la tabla es generada, de tal manera, que no incluya números en complemento 2 entonces los valores obtenidos pueden ser aplicados directamente al módulo PWM o al convertidor DAC. Esto es, generar la tabla de la siguiente manera: y = 32768 + 32767 * sin( 2π * N 65536) Caso 16 bits y = 128 + 127 * sin( 2π * N 256) Caso 8 bits y = 64 + 63 * sin( 2π * N 128) Caso 7 bits 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 0 -20 -40 -60 -80 0 20 40 60 80 100 120 140 N Fig. 1 Valores en complemento 2. Carlos A. Narváez 2005 y = 6 4 *6 3 *s in (2 *p i*N / 1 2 8 140 120 100 80 60 40 20 0 0 20 40 60 80 100 120 140 N Fig. 2 Valores Unipolares sin signo 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 Donde Fs es la frecuencia de muestreo en Hz. 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 Suponiendo Fs = 8Khz tenemos: 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. Carlos A. Narváez 2005 Como vimos anteriormente la tabla se accedió con un incremento de 1 en cada periodo de muestreo, es decir tomamos el primer valor en la tabla, luego el segundo y así sucesivamente. Pero que pasa si tomamos el primer valor de la tabla, luego el tercero, luego el quinto y así sucesivamente, entonces la frecuencia generada es: F = 2 * Fs 128 = 125 Hz En general la frecuencia generada para 128 muestras de un ciclo completo es: F = incremento * Fs 128 donde, 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. Algunas características del método Tabla Lookup Cualquier forma de onda puede ser generada con este método, con sólo cambiar los valores almacenados en la tabla. Adicionalmente, varias señales, pueden ser generadas, realizando múltiples accesos a la misma, las señales pueden ser sumadas y luego enviadas al DAC. Se pueden usar varias tablas o sólo una con el fin de ahorrar memoria. Ondas de diferentes frecuencias pueden ser generadas de una misma tabla usando la técnica que se describe más adelante. También deben evitarse los overflow por suma, escalando los datos a valores apropiados, técnica que también será tratada más adelante. 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. Cambiando la Frecuencia de la Señal de Salida Para cambiar la frecuencia de salida, se puede variar la frecuencia de muestreo, pero esta no es la mejor manera de hacerlo, particularmente en telecomunicaciones, donde la mayoría de los sistemas requieren de una frecuencia de muestreo fija. 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: Fsalida = incremento * Fs TamañoTabla 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: Fsalida = 1 * 8000 256 = 31.25 Hz Carlos A. Narváez 2005 Si incremento es igual a 2, que implica tomar de la tabla sólo las muestras impares, entonces, la frecuencia de salida es: Fsalida = 2 * 8000 256 = 62.5 Hz La resolución en frecuencia se obtiene sustituyendo incremento por 1, en este caso: Fresolucion = Fs TamañoTabla = 31.5 Hz Así, la frecuencia puede ser controlada en unidades de 31.25Hz Para incrementar la resolución en frecuencia, se puede incrementar el tamaño de la tabla, manteniendo constante la frecuencia de muestreo. También es útil acotar el rango de incremento a los límites de la tabla usando: incremento = incremento & (TamañoTabla − 1) 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 U1 10K 1N4148 100 S1 RESET U2 2 3 4 5 6 7 21 22 23 24 25 26 27 28 33pf 9 20Mhz 1 20 33pf RA0/AN0 RC0/T1OSO/T1CKI RA1/AN1 RC1/T1OSI/CCP2 RA2/AN2/VREFRC2/CCP1 RA3/AN3/VREF+ RC3/SCK/SCL RA4/T0CKI RC4/SDI/SDA RA5/SS/AN4 RC5/SDO RC6/TX/CK RB0/INT RC7/RX/DT RB1 RB2 OSC2/CLKOUT RB3/PGM RB4 RB5 RB6/PGC RB7/PGD 4.7K 11 12 13 14 15 16 17 18 10 4.7K 1 2 3 4 O0 O1 GNDVDD SCL AD0 SDA AD1 8 7 6 5 MAX517 I2C BUS J1 4.7K 0.01uf 2 1 Salida OSC1/CLKIN MCLR/VPP/THV VDD PIC16F873 Fig. 3. Diagrama esquemático Generador Onda Sinusoidal Carlos A. Narváez 2005 Software /******************************************************************/ /* SENO.C */ /* */ /* Programa que genera una onda sinusoidal de 15Hz */ /* usa la interrupción por desbordamiento del RTCC (timer0) y */ /* el DAC MAX517 I2C */ /* */ /* Autor: Carlos A. Narváez */ /* Fecha: septiembre, 2005 */ /******************************************************************/ #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) void write_dac(int data_byte) { i2c_start(); i2c_write(0x5e); i2c_write(0); i2c_write(data_byte); i2c_stop(); // Envía la dirección del dispositivo // Envía datos al dispositivos } BYTE CONST SINE_WAVE[256] = { 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() { set_rtcc(0x66); // Fs = 1/4*tosc*(256-N)*rango divisor write_dac(SINE_WAVE[sine_index]); if(++sine_index==256) { sine_index=0; } } Carlos A. Narváez 2005 void main() { setup_counters( RTCC_INTERNAL, RTCC_DIV_8); enable_interrupts(INT_RTCC); enable_interrupts(GLOBAL); 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. Tabla 2 DTMF Frecuencias filas y columnas Filas Teclado 697 Hz 770 Hz 852 Hz 941 Hz 1209 Hz 1 4 7 * Columnas Teclado 1336 Hz 1477 Hz 2 3 5 6 8 9 0 # 1633 Hz A B C D La especificación industrial de DTMF requiere de un error en frecuencia de menos del 1%, y una distorsión armónica total de menos de 10%. Adicionalmente, la respuesta en frecuencia de una línea telefónica, atenúa las frecuencias altas, por lo que la transmisión del grupo de frecuencias altas, requiere de mayor amplitud que el grupo de bajas frecuencias. Generación DTMF por Software En este proyecto se usa una tabla de seno con dos apuntadores, una para el tono columna y otro para el tono fila. Cada apuntador tiene su propio valor de incremento, tal que se puede generar tonos de diferentes frecuencias. 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. Calculando el incremento para los apuntadores La forma general de la ecuación es: Fsalida = incremento * Fs TamañoTabla Carlos A. Narváez 2005 Donde, Fsalida: frecuencia a generar Fs: Frecuencia de muestreo TamañoTabla: Número de muestra en tabla seno para un ciclo completo Incremento: valor en que debe ser incrementado el apuntador para cada período de muestreo. Despejando incremento tenemos: incremento = Fsalida * TamañoTabla Fs Por ejemplo, para generar la frecuencia 697Hz, si la tabla de seno tiene 256 entradas, el valor de incremento es: incremento = 697 * 256 7812 = 23 Como no podemos usar un intervalo en fracción, lo redondeamos a 22. Introduciendo este valor en la ecuación, obtenemos como frecuencia generada: Fsalida = 23 * 7812 256 = 701.86 Hz Lo cual da un error en frecuencia de 0.7% lo cual es aceptable. La tabla 3, resume los cálculos realizados para una frecuencia de muestreo de 7812 Hz y una tabla de 256 entradas. Tabla 3 Cálculos Tonos DTMF Período de Muestreo Tamaño tabla 128us (7812,5Hz) 256 Frecuencia Incremento Frecuencia actual % Error 697 23 701.86 0.7 770 25 763 -0.92 852 28 854 0.29 941 31 946 0.53 Frecuencia incremento Frecuencia actual % Error 1209 40 1221 0.96 1336 44 1343 0.5 1477 48 1465 -0.83 1633 54 1648 0.91 Carlos A. Narváez 2005 Implementando Pre-énfasis de los tonos altos A fin de compensar la atenuación de las frecuencias altas, lo cual es característica de la mayoría de las líneas telefónicas, la amplitud de estos tonos deben estar de 1 a 3dB por encima de la amplitud de las frecuencias bajas, eso equivale a multiplicar la amplitud actual por valores entre 1.12 a 1.41. Un valor apropiado es 1.25, ya que 0.25 puede ser obtenido dividiendo la unidad entre 4 que a su vez equivale a realizar desplazamiento a la derecha de 2 bits. 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: dB = 20 log(V 2 V 1) = 20 log(1.25) = 1.94dB Calculando los valores de seno para evitar desbordamiento Los valores de la tabla seno deben ser calculados para evitar error por desbordamiento cuando dos muestras son sumadas. Si por ejemplo, se usan 16 bits para almacenar los valor de la tabla, el rango a representar esta entre –32768 y +32767. Para evitar desbordamiento, los valores deben se escalados tal que el rango esté entre –16384 y +16383. Ya que a los tonos de las columnas se le aplica pre-énfasis, el valor debe ser algo menor que el máximo. MaxSalida = MaxSin * (1 + preenfasis) Resolviendo para MaxSin, MaxSin = MaxSalida * (1 + preenfasis ) = 32767 (1 + 1.259) = 14563.11 De tal manera que los valores en la tabla seno deben estar entre –14563 y +14563. Filtro Pasa Bajos Es necesario agregar un filtro pasa bajos que opere como integrador a la salida PWM del microcontrolador. En este proyecto se uso un filtro activo Butterworth de 3 orden con frecuencia de corte de 1.7 Khz, diseñado utilizando el programa FilterLab de Microchip. Este filtro utiliza un integrado LM324 alimentado con fuente de poder unipolar de 5 voltios, la misma que utiliza el resto del circuito. La fig. 5 muestra el filtro pasa bajos diseñado. Carlos A. Narváez 2005 Hardware VCC 10K 10K VCC KB1 1 2 3 4 5 6 7 8 9 * 0 # Key board 10K U2 2 3 4 5 6 7 1N4148 100 21 22 23 24 25 26 27 28 S1 9 33pf 20Mhz 33pf 1 20 RC0/T1OSO/T1CKI RA0/AN0 RC1/T1OSI/CCP2 RA1/AN1 RC2/CCP1 RA2/AN2/VREFRC3/SCK/SCL RA3/AN3/VREF+ RC4/SDI/SDA RA4/T0CKI RC5/SDO RA5/SS/AN4 RC6/TX/CK RB0/INT RC7/RX/DT RB1 RB2 OSC2/CLKOUT RB3/PGM RB4 RB5 RB6/PGC RB7/PGD 11 12 13 14 15 16 17 18 Salida al Filtro pasa bajos 10 OSC1/CLKIN MCLR/VPP/THV VDD PIC16F873 Fig. 4 Diagrama Esquemático del Generador de Tonos DTMF Carlos A. Narváez 2005 0.1uF +5VDC 4 1K 8.2K 1 2 - 5 + 0.01uF 6 - 7 11 0.1uF LM324 1K 3 + Fig. 5 Diagrama Esquemático del Filtro Pasa bajos 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 CONST unsigned int SINE_WAVE[256] = { 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}; unsigned long index1,index2; int inc1,inc2; Carlos A. Narváez 2005 #INT_TIMER2 void timer2_isr(void) { int wave = 0; wave = ((long)SINE_WAVE[index1]+(long)SINE_WAVE[index2])/2; set_pwm1_duty(wave); index1 += inc1; index2 += inc2; if(index1 >= 256) index1 -= 256; if(index2 >= 256) index2 -= 256; } #define #define #define #define #define #define #define DTMF_ROW1 DTMF_ROW2 DTMF_ROW3 DTMF_ROW4 DTMF_COLA DTMF_COLB DTMF_COLC 23 26 28 31 40 44 49 // // // // // // // incremento incremento incremento incremento incremento incremento incremento para para para para para para para 700 Hz, cada 128us 750 Hz, cada 128us 850 Hz, cada 128us 950 Hz, cada 128us 1200 Hz, cada 128us 1350 Hz, cada 128us 1500 Hz, cada 128us void generate_dtmf_tone(char keypad, long duration) { 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); } Carlos A. Narváez 2005 void main() { char k; setup_ccp1(CCP_PWM); // // // // // // Configure CCP1 as a PWM El tiempo que dura un ciclo de PWM es:(1/clock)*4*t2div*(periodo+1) En este programa: clock=20000000 y periodo=127 entonces el periodo PWM es: (1/20000000)*4*1*128 = 25.6 us ó 39.06 khz Fs = 25.6 * 5 = 7812.5 Hz. set_pwm1_duty(0x80); setup_timer_2(T2_DIV_BY_1, 127, 5); // // // // kbd_init(); while(TRUE) { k=kbd_getc(); if(k!=0) generate_dtmf_tone(k, 5000); } Timer2 se incrementa cada 200nseg overflow cada 25.6 useg y genera una interrupción cada 25.6 * 5 = 128; Fs = 7812.5 Hz } Carlos A. Narváez 2005