Follow along with the video below to see how to install our site as a web app on your home screen.
Nota: This feature currently requires accessing the site using the built-in Safari browser.
- Si se trata de una señal de baja frecuencia cuyo espectro llega como maximo a 1kHz si.Yo tambien tengo duda de eso, si deseo muestrear una señal de 1khz debo hacer interrupcion cada 1/2000hz para cumplir on teorema de nyquist no?
Son muy pocas muestras, aunque todo depende de para queres usarlas.mi duda surge cuando lleno mi buffer de 16 muestras y le quiero aplicar la fft cada 200ms,es buena idea?
#define FOSC 10000000
#define PLL 8
//#define FCY FOSC*PLL/4
#define NUMSAMP 256
#define SAMPLINGRATE 8000
#define SAMPCOUNT (20000000/SAMPLINGRATE)+1
void ADCInit (){
//ADCON1 Register
//Set up A/D conversrion results to be read in 1.15 fractional number format.
//All other bits to their default state
ADCON1bits.FORM = 2; // 11 Signal fractional, 10 Fractional, 01 Signed integer, 00 Integer
ADCON1bits.SSRC = 2; //Use Timer3 to provide sampling time
ADCON1bits.ASAM = 1; // Auto-Sample Start Mode. Allows the ADC to schedule sample/conversion sequences with no intervention by the user or other devices resources
//ADCON2 Register
ADCON2bits.SMPI = 0;// interrupció x cada mostra/conversio
//ADCON3 = 0x1F02; // SAMC = 11111 (31Tad) i ADCS = 2 => Tad = Tcy*(2+1)/2
// Dades per una Fs = 8KHz
ADCON3bits.ADCS = 63; // Tad = Tcy(ADCS+1)/2 = 1.6usec
TMR3 = 0x0000;
PR3 = SAMPCOUNT; // Load Period value SAMPCOUNT = (Fcy/Fs)+1 (ho he vist algun lloc amb -1)
//IFS0bits.T3IF: Timer3 Interrupt Flag Status bit
//1 = Interrupt request has occurred
//0 = Interrupt request has not occurred
IFS0bits.T3IF = 0;
//IEC0bits.T3IE: Timer3 Interrupt Enable bit
//1 = Interrupt request enabled
//0 = Interrupt request not enabled
IEC0bits.T3IE = 0;
//Set up A/D Channel Select Register to convert AN3 on Mux A input
ADCHS = 0x0003;
//ADCSSL Register
//Channel Scanning is disabled. All bits left to their default state
ADCSSL = 0x0000;
//ADPCFG Register
//Set up channels AN3 as analog input and configure rest as digital
ADPCFG = 0xFFFF;
ADPCFGbits.PCFG3 = 0;
//Clear the A/D interrupt flag bit
IFS0bits.ADIF = 0;
//Set the A/D interrupt enable bit
IEC0bits.ADIE = 1;
//Turn on the A/D converter
//This is typically done after configuring other registers
ADCON1bits.ADON = 1;
//Start Timer 3
//T3CONbits.TON: Timer On Control bit
//1 = Starts the timer
//0 = Stops the timer
T3CONbits.TON = 1;
CountSamples = 0;
}
void __attribute__ ((__interrupt__, no_auto_psv)) _ADCInterrupt(void)
{
// int i;
fractional aux;
//Clear the Timer3 Interrupt Flag
IFS0bits.T3IF = 0;
//Clear the A/D Interrupt flag bit or else the CPU will
//keep vectoring back to the ISR
IFS0bits.ADIF = 0;
inputSignal[CountSamples] = ADCBUF0; // mentrestant...
//sigCmpx[CountSamples].real = ADCBUF0; // mentrestant...
CountSamples++;
if (CountSamples >= FFT_BLOCK_LENGTH){
ADCFFTMoveSamples(); // moc les mostres del buffer aux al buffer sigCmpx.
doFilterFlag = 1; // CountSamples >= 256, ja ho tinc tot
CountSamples = 0;
}
}
void ADCFFTMoveSamples(){
int i;
for (i = 0; i < FFT_BLOCK_LENGTH; i++){
sigCmpx[i].real = inputSignal[i]; //inicialitzo a 0
sigCmpx[i].imag = 0; //inicialitzo a 0
}
}
char FFTMotor(){
int i = 0;
fractional *p_real = &sigCmpx[0].real ; // posa al punter p_real l'@de memòria on es troba sigCmpx[0].real
fractcomplex *p_cmpx = &sigCmpx[0] ; // posa al punter p_cmpx l'@de memòria on es troba sigCmpx[0]
char flagAuxCaiguda =0;
//******* paro la interrupció
IEC0bits.ADIE = 0; //paro la interrupció per fer la FFT
//*****baixo flags
ThereIsARockFlag = 0;
doFilterFlag = 0;
sprintf(uTxt, "\r\n 1 Inici FFT \r\n");
putsUART1((unsigned int *)uTxt);
for ( i = 0; i < FFT_BLOCK_LENGTH; i++ )/* The FFT function requires input data */
{ /* to be in the fractional fixed-point range [-0.5, +0.5]*/
*p_real = *p_real >>1 ; /* So, we shift all data samples by 1 bit to the right. */
//En teoria això divieix per 2? el valor de la variable que apunta p_real. Perquè la variable va de [+1, -1], l'ADC ja l'agafa tipus fractional, per tant divideix x 2.
*p_real++; /* Should you desire to optimize this process, perform */
} /* data scaling when first obtaining the time samples */
/* Or within the BitReverseComplex function source code */
// p_real = &sigCmpx[127].real posa a p_real l'@ de memòria de sigCmpx[127].real
p_real = &sigCmpx[(FFT_BLOCK_LENGTH/2)-1].real ; /* Set up pointers to convert real array */
// p_cmpx = &sigCmpx[255] posa a p_cmpx l'@ de memòria de sigCmpx[255]
p_cmpx = &sigCmpx[FFT_BLOCK_LENGTH-1] ; /* to a complex array. The input array initially has all */
/* the real input samples followed by a series of zeros */
for ( i = FFT_BLOCK_LENGTH; i > 0; i-- ) /* Convert the Real input sample array */
{ /* to a Complex input sample array */
(*p_cmpx).real = (*p_real--); /* We will simpy zero out the imaginary */
(*p_cmpx--).imag = 0x0000; /* part of each data sample */
}
FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));
// Store output samples in bit-reversed order of their addresses
BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]);
// Compute the square magnitude of the complex FFT output array so we have a Real output vetor
SquareMagnitudeCplx(FFT_BLOCK_LENGTH, &sigCmpx[0], &sigCmpx[0].real);
// Find the frequency Bin ( = index into the sigCmpx[] array) that has the largest energy
// i.e., the largest spectral component
VectorMax(FFT_BLOCK_LENGTH/2, &sigCmpx[0].real, &peakFrequencyBin);
sprintf(uTxt, "\r\n BIN: %d \r\n",peakFrequencyBin );
putsUART1((unsigned int *)uTxt);
// Compute the frequency (in Hz) of the largest spectral component
peakFrequency = peakFrequencyBin*(SAMPLING_RATE/FFT_BLOCK_LENGTH);
sprintf(uTxt, "\r\n Frequencia de Pic: %ld \r\n", peakFrequency);
putsUART1((unsigned int *)uTxt);
sprintf(uTxt, "\r\n Fi FFT \r\n");
putsUART1((unsigned int *)uTxt);
//
flagAuxCaiguda = FFTDecide();
ADCEnableConversion ();
IEC0bits.ADIE = 1;
return flagAuxCaiguda;
}