Professional Documents
Culture Documents
Facultad de Ingeniera
Ingeniera Electrnica y Telecomunicaciones
Laboratorio de Procesamiento
Digital de Seales
Kenneth S. Palacio Baus
kenneth.palacio@ucuenca.edu.ec
Marzo 21, 2016
Nombre: Carlos Guerrero Granda Cedula: 0302681911
Juan Bernardo Tenesaca Cedula: 0104857560
Recursos de Laboratorio:
a) Filtros Antialiasing.
La explicacin terica de la necesidad de utilizar una frecuencia de muestreo del doble de las
frecuencia que se quieren obtener viene dada por Teorema de muestreo de Nyquist-
Shannon.
1
Cualquier muestreo realizado que cumpla esta norma no destruir todos los datos, lo que
significa que siempre ser posible recuperar la seal analgica original a partir de las
muestras finales.
Proceso de Muestreo
Al escoger la frecuencia de muestreo, esta debe ser mayor que dos veces la componente de
frecuencia ms alta de la seal que se muestrea.
Una funcin de tiempo continuo (seal analgica) x(t) que no contiene componentes
frecuenciales ms grandes que la frecuencia determina por nyquist, se la puede determinar
por los valores de x(t) de cualquier conjunto de puntos espaciados de acuerdo a la frecuencia
de muestreo.
Reconstruccin
El proceso de conversin digital a analgica que proporciona una seal continua a partir de
una seal discreta puede aproximarse con un dispositivo de reconstruccin, formado por un
puerto de n pines que nos dan un rango de 2^n valores posibles de salida y un retenedor.
2
El retenedor como su nombre lo dice retiene la seal muestreada x[n], y cambia hasta que se
presente la siguiente muestra, en este proceso de la prctica de muestreo y reconstruccin
de seales, se ver que para retener estos valores simplemente enviamos nuestro valor al
puerto de salida del microcontrolador.
a) Plataforma de Hardware:
3
En esta parte se muestra un generador de funciones el cual representa la seal de entrada
previamente procesada, adems de 5 botones que cumplen una funcin en especfico para
tratar los datos ledos desde la memoria hacia los puertos D y E, adems se muestra la
conexin de la memoria 23LC1024 y un conversor DAC para visualizar la seal de salida en el
osciloscopio.
b) Funcionamiento Software:
Primero se procede a definir los bits de configuracin donde se establece el cristal con el que
trabajaremos y el multiplicador PLL para obtener una mayor velocidad:
// CONFIG1L
#pragma config PLLDIV = 1 // PLL Prescaler Selection bits (Divide by 5 (20 MHz
oscillator input))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary
Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 2 // USB Clock Selection bit (used in Full-Speed USB mode
only; UCFG:FSEN = 1) (USB clock source comes from the 96 MHz PLL divided by 2)
// CONFIG1H
#pragma config FOSC = HSPLL_HS // Oscillator Selection bits (HS oscillator, PLL enabled
(HSPLL))
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock
Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator
Switchover mode disabled)
4
// CONFIG2L
#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = ON // Brown-out Reset Enable bits (Brown-out Reset enabled
in hardware only (SBOREN is disabled))
#pragma config BORV = 3 // Brown-out Reset Voltage bits (Minimum setting)
#pragma config VREGEN = ON // USB Voltage Regulator Enable bit (USB voltage
regulator enabled)
// CONFIG2H
#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is
placed on the SWDTEN bit))
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = ON // CCP2 MUX bit (CCP2 input/output is multiplexed with
RC1)
#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are
configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer 1 Oscillator Enable bit (Timer1
configured for higher power operation)
#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input
pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack
full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP
disabled)
#pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port
(ICPORT) Enable bit (ICPORT disabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set
extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) is not
code-protected)
#pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) is not
code-protected)
#pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) is not
code-protected)
#pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) is not
code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-
5
0007FFh) is not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM is not
code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) is not
write-protected)
#pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) is not
write-protected)
#pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) is not
write-protected)
#pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) is not
write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit
(Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-
0007FFh) is not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM is
not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh)
is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh)
is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh)
is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh)
is not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block
(000000-0007FFh) is not protected from table reads executed in other blocks)
6
void main(void){
//CONFIGURACION PUERTOS
TRISA = 0b00111111;
TRISB = 0b10111101;
TRISC = 0b00000000;
TRISD = 0b00000000;
TRISE = 0b00000000;
//Configuracion ADC
//ADCON1
ADCON1bits.VCFG1 = 0;
ADCON1bits.VCFG0 = 0;
ADCON1bits.PCFG3 = 1;
ADCON1bits.PCFG2 = 1;
ADCON1bits.PCFG1 = 1;
ADCON1bits.PCFG0 = 0;
TRISAbits.TRISA0 = 1;
//ADCON0
ADCON0bits.CHS3 = 0;
ADCON0bits.CHS2 = 0;
ADCON0bits.CHS1 = 0;
ADCON0bits.CHS0 = 0;
//ADCON2
ADCON2bits.ADFM = 1;
ADCON2bits.ACQT2 = 0;
ADCON2bits.ACQT1 = 0;
ADCON2bits.ACQT0 = 0;
ADCON2bits.ADCS2 = 1;
ADCON2bits.ADCS1 = 1;
ADCON2bits.ADCS0 = 0;
TRISBbits.TRISB3 = 0;
TRISBbits.TRISB4 = 1;
TRISBbits.TRISB5 = 1;
LATBbits.LATB3 = 0;
//Configuracion Interrupciones
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.TMR0IE = 1;
INTCONbits.TMR0IF = 0;
//OpenPORTB( PORTB_CHANGE_INT_ON );
//INTCONbits.RBIF = 0;
//Configuracion Timer0
T0CONbits.TMR0ON = 1;
7
T0CONbits.T08BIT = 1;
T0CONbits.T0CS = 0;
//T0CONbits.T0SE = 0;
T0CONbits.PSA = 0;
//Prescaler
TMR=140;
T0CONbits.T0PS2 = 0;
T0CONbits.T0PS1 = 1;
T0CONbits.T0PS0 = 0;
//SSI_CONFIGURE
TRISCbits.TRISC7 = 0; //SO
TRISBbits.TRISB0 = 1; //SI
TRISBbits.TRISB1 = 0; //SCK
TRISCbits.TRISC2 = 0; //CS
//CONFIGURACION SPI
SSPSTAT = 0b01000000;
SSPCON1 = 0b00100000;
i=0;
j=0;
k=0;
ban=0;
memoryseq();
memorywrite();
ADCON0bits.ADON = 1;
while(1){
delayzz();
}
void memoryseq(void){
//CONFIGURACION MEMORIA MODO SECUENCIAL
8
LATCbits.LATC2 = 0; //CS ENABLE SIGNAL
SSPBUF=0b00000001; //WRITE MODE REGISTER
while(SSPSTATbits.BF==0);
void memorywrite(void){
LATCbits.LATC2 = 0; //CS ENABLE SIGNAL
spiwrite(0b00000010); //WRITE COMMAND SENT
spiwrite(0b00000000);
spiwrite(0b00000000);
spiwrite(0b00000000);
return;
}
void memoryread(void){
LATCbits.LATC2 = 0; //CS ENABLE SIGNAL
spiwrite(0b00000011); //READ COMMAND SENT
spiwrite(0b00000000);
spiwrite(0b00000000);
spiwrite(0b00000000);
return;
}
void delayzz(void){
int i, j;
for(i=0;i<32000;i++){
for(j=0;j<4;j++){
}
}
}
9
Dado el siguiente modelo de filtro, se procede a calcular los valores para una frecuencia de
4KHz, Nos imponemos un capacitor de 1uF, y solo nos quedara calcular la resistencia. Porlo
tanto:
10
Y por ltimo se procede a sumar las dos seales anteriores mediante otro amplificador
configurado de manera de sumador:
11
Dado el siguiente modelo de filtro, se procede a calcular los valores para una frecuencia de
5KHz, Nos imponemos un capacitor de 0.1uF, y solo nos quedara calcular la resistencia.
Porlo tanto:
5) Operacin del mdulo de memoria RAM para la creacin del buffer de audio.
Cuando se entra a la interrupcin, lo primero que se hace es comprobar la bandera que inicia
en 0 la cual indica que la memoria est grabndose, as despus de esto se manda a convertir
la seal se entrada a digital que se graba en el registro ADRESH y se la escribe a la memoria
mediante spiwrite, y de la misma forma se enva ADRESL, guardando un valor de la funcin
de entrada en dos posiciones de la memoria.
Este proceso se repite hasta que se escriban 131072 veces en la memoria, mediante una
variable de tipo entero que llega hasta el valor 32768, y por medio de otra variable se hace
que la variable de tipo entero de desborde 4 veces hasta obtener 131072 y terminar la
escritura.
Cuando termina de desbordarse por cuarta vez se procede a dejarla a la memoria de manera
de lectura secuencial, subir el chip-select, prender un led que nos indicara en el hardware
que se ha terminado la escritura y finalmente cambiar el valor de la bandera a 1, que nos
llevara a la parte de lectura de la memoria en la interrupcin.
void interrupcion(void){
if(INTCONbits.TMR0IF == 1){
INTCONbits.TMR0IF = 0;
LATCbits.LATC0 =~ LATCbits.LATC0;
if (ban==0){
ADCON0bits.GO = 1;
while(ADCON0bits.GO == 1);
spiwrite(ADRESH);
i++;
spiwrite(ADRESL);
i++;
if (i>32765){
i=0;
j++;
if (j==4){
j=0;
ban=1;
LATCbits.LATC2 = 1;
memoryread();
LATCbits.LATC6 = 1;
}
12
}
}
TMR0L = TMR;
}
}
Al momento de la lectura se utiliza el mismo bucle anterior para leer todos los datos de la
memoria y simplemente asignamos a dos variables E y D, los valores que llegan de la
memoria para posteriormente asignarlos a los puertos.
if (ban==1){
E=spiwrite(0b11111111);
i++;
D=spiwrite(0b11111111);
i++;
if (i>32765){
i=0;
j++;
if (j==4){
j=0;
LATCbits.LATC2 = 1;
memoryread();
}
}
}
13
Al momento de multiplicar la lectura por nuestra ganancia, es necesario que este valor este
centrado en 0. Por esto primeramente a la variable E que contiene el valor del registro
ADRESH se la multiplica por 256 y se la suma la variable D que contiene el valor del registro
ADRESL, obteniendo un valor que vara de 0 a 1024 por los 10 bits de lectura y se le asigna a
la variable ED. Ahora para centrarla a 0 es necesario restarle 512 para que el valor vare de
512 a -512. En esta parte se la multiplica por la ganancia y se la sube otra vez los 512.
Finalmente, los valores de los bits de la variable ED desde la posicin mayores a 8 son
asignados al puerto E y el resto al puerto D.
ED= E*256 + D;
ED= ED-512;
ED= ED*gain;
ED= ED+512;
LATE=ED>>8;
LATD=ED;
Para esto se maneja una variable denominada selec que vara de 0 a 2 e inicializa en 1, la cual
se la sube o se la resta por medio del cambio a cero en los pines RA3 y RA4.
else if (PORTAbits.RA3==0){
delayzz();
if (selec<2){
selec++;
}
}
else if (PORTAbits.RA4==0){
delayzz();
if (selec>0){
selec--;
}
}
En cada opcin se tiene el valor del TMR0L y los bits de prescaler para obtener frecuencias
de 10Khz, 20Khz y 5Khz respectivamente:
if (selec==0){
TMR = 255;
T0CONbits.T0PS2 = 0;
T0CONbits.T0PS1 = 0;
T0CONbits.T0PS0 = 0;
}
if (selec==1){
TMR = 140;
14
T0CONbits.T0PS2 = 0;
T0CONbits.T0PS1 = 1;
T0CONbits.T0PS0 = 0;
}
if (selec==2){
TMR = 80;
T0CONbits.PSA = 0;
T0CONbits.T0PS2 = 0;
T0CONbits.T0PS1 = 1;
T0CONbits.T0PS0 = 1;
}
Este es activado cuando el bit RA5 se detecta en 0. Si la bandera es 1 lo cual indica que se est
haciendo una lectura normal, esta cambia la bandera a 2 y pone las variables a i, j a 255 y k a
1, las cuales posteriormente se utilizan para el direccionamiento, y si la bandera es igual a 2
lo que indica que esta haciendo una reproduccin inversa, esta cambia la bandera a 1
inicializa las variables sube el chip-select, inicializa la memoria de manera de lectura
secuencial y realiza la lectura normal de la memoria.
else if (PORTAbits.RA5==0){
delayzz();
if (ban==1){
i=255;
j=255;
k=1;
ban=2;
//LATCbits.LATC2 = 1;
//memoryread();
}
else if (ban==2){
i=0;
j=0;
ban=1;
LATCbits.LATC2 = 1;
memoryread();
}
}
15
else if (ban==2){
LATCbits.LATC2 = 0;
SSPBUF=0b00000011;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=k;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=j;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=i;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=0b11111111;
while(SSPSTATbits.BF==0);
D=SSPBUF;
LATCbits.LATC2 = 1;
i--;
LATCbits.LATC2 = 0;
SSPBUF=0b00000011;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=k;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=j;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=i;
while(SSPSTATbits.BF==0);
vaciar=SSPBUF;
SSPBUF=0b11111111;
while(SSPSTATbits.BF==0);
E=SSPBUF;
LATCbits.LATC2 = 1;
i--;
LATD=D;
LATE=E;
if (i<0){
i=255;
j--;
if (j<0){
j=255;
k--;
16
if (k<0){
i=255;
j=255;
k=1;
}
}
}
}
4. Pruebas y Verificaciones
En la siguiente imagen se puede ver la seal original sin aplicar el volumen, la seal 1 es la
seal de salida, la seal 2 es el seal de entrada. Como se aprecia ambas estn a la misma
escala de voltaje(2V), y aproximadamente tienen el mismo voltaje de salida:
17
Descenso de volumen:
Aumento de volumen:
Como se explic anteriormente todas estas salidas se reproducen de manera cclica es decir
se recuperan de la memoria ram directamente, ya que para la prctica se dise de esa
manera.
Aumento de Frecuencia
De la misma manera se aument la frecuencia al doble, cabe recalcar que la frecuencia
original era de 10kHz
18
Despus de aumentar la frecuencia al doble se obtuvo lo siguiente
Disminucin de Frecuencia
5. Preguntas.
Conteste a las siguientes preguntas:
Debido a que el cdigo se lo realizo en un solo programa se carg un solo valor para la frecuencia
de muestreo el cual es 10Khz y se lo obtiene en el pin RC0, debido a que el cdigo se implement
en un solo programa fue muy complicado alcanzar ms frecuencia de muestreo, 10Khz fue lo
mximo a lo que se lleg, se puede notar la frecuencia en la siguiente imagen.
19
2. Que sucede si el audio se submuestrea? Qu se escuchara a la salida del sistema ?
Debido a que la seal de ingreso est compuesta de varias seales de distintas frecuencias
debido a esto se deben filtrar las frecuencias altas para as evitar el aliasing cuando se
muestree la seal. Aunque la calidad del sonido en el parlante disminuye debido a que el
filtro elimina las frecuencias altas.
La frecuencia de muestreo es de 4Khz debido a que el audio con que el que se trabaja es la
voz, la cual esta en entre frecuencias de 0 a 4Khz aproximadamente.
5. Porque es importante que la velocidad de muestreo sea la misma que la velocidad a la que
se reconstruye la seal a partir de las muestras? Que sucede si son diferentes?
Porque si leen los datos a la misma velocidad de muestreo se tendr la misma seal, mientras
que al aumentar o disminuir la velocidad de muestreo los tiempos de lectura entre cada dato
cambia haciendo que la seal se adelante o retrase en frecuencia, haciendo que la seal
suene ms rpida o ms lenta la seal.
Esto es debido a que el ADC del Pic solo soporta voltajes positivos y que estn entre los
valores de 0- 5 voltios, si se ingresa mas que eso la seal se satura obteniendo en la DAC una
seal muy diferente a la ingresada.
Una de las ms importantes es sin duda la velocidad a la que trabaja ya que gracias a ella se
puede acceder a los datos de manera eficiente sobre todo cuando se trabaja con audio.
Otro detalle importante es la capacidad de almacenamiento de la memoria, porque la para
audio la 23LC1024 se queda corta debido que nos permite almacenar cercar de 2s de audio.
La robustez de la misma ya que con facilidad se puede hacer cortocircuitos haciendo que la
memoria deje de funcionar.
20
Conclusiones y Recomendaciones.
Bibliografa.
21