Componentes armónicas de corriente con PIC18F4550

Hola a todos, estoy desarrollando un analizador de componentes armónicas con un PIC18F4550 en el cual he implementado la FFT y una especie de osciloscopio que permite graficar las formas de onda en una GLCD de 128x64. La idea es que en conjunto mejoremos lo que ya está hecho y agreguemos nuevas funcionalidades. Quien se anima?

Les dejo el link del video que he subido a la red:





Saludos a todos.
 
Hola Dirac,

Felicidades por este proyecto! Yo hace un mes que me estoy peleando para coger una señal sinusoidal (de un osciloscopio, de momento) y a través del ADC guardarla y hacer la FFT. Pero no me sale bien, no se si hago mal la adquisición de datos, o el procesado de la FFT.

Yo trabajo con un dsPIC30F6013A y tu una 18F4550, ya se que trabajan un poco diferente, pero me puedes echar una mano?

A continuación te mando la configuración del ADC:

Código:
void ADCInit (){
 // 1 Configure the A/D Module
 
	ADPCFG = 0xFFF7; // primer poso tots els canals a 1 excepte el 3, Digital mode 1111 1111 1111 0111 // v
	ADCON1bits.ASAM = 1; // Sampling begins immediately after last conversion completes. SAMP bit is auto set.
	ADCON1bits.SSRC = 7; // 7=111 Internal counter ends sampling and starts conversion 2=010 General purpose Timer3 compare ends sampling and starts conversion //Timer 3 estableix el temps de mostreig
	ADCON1bits.FORM = 2; // 11 Signal fractional, 10 Fractional, 01 Signed integer, 00 Integer

	ADCON2bits.SMPI = 15; // Interrupció després de 16 mostres en el buffer

	ADCON3bits.ADCS=63;// Tad = Tcy*(ADCS+1)/2 = 50ns*(63+1)/2 = 1.6usec Sample time = 15Tad, Tad = internal Tcy/2
	ADCHS = 0x0003; // Connecta RB3/AN3 al canal CH0 d'entrada

	ADCSSL = 0 ; //Ja ho controlo amb el CH0SA



    //Clear the A/D interrupt flag bit
    IFS0bits.ADIF = 0; //

    //Set the A/D interrupt enable bit
    IEC0bits.ADIE = 1;       
    ADCON1bits.ADON = 1;  //Turn on the A/D converter //This is typically done after configuring other registers//  A/D converter module is operating

	flagDada = 0;
}

La interrupción del ADC es la siguiente:

Código:
void __attribute__ ((__interrupt__, no_auto_psv)) _ADCInterrupt(void)
{
	//AD Conversion complete interrupt handler 

	FlagADC = 1;
	IFS0bits.ADIF = 0; // Clear ADC Interrupt Flag

	ADResult_3 = ADCBUF3; // Get the conversion result. Només vull del canal 0, sortida 3. 
	if(m<FFT_BLOCK_LENGTH){ //si encara no he agafat tots els punts
		//guardo
		sigCmpx[m].real = ADResult_3;
		m++;	
	}
	if(m==FFT_BLOCK_LENGTH){		//ja he omplert tot el sigComx
		flagDada = 1; //ja puc fer la FFT

	}
}

Por otro lado, al main tengo un MotorFFT que me calcula la FFT si el flagDada vale 1 (o sea si tengo el número de datos que quiero).

Código:
void FFTMotor(){
	fractional *p_real = &sigCmpx[0].real ;
	fractcomplex *p_cmpx = &sigCmpx[0] ;
	in = 0;
	if(ADCReturnFlagADC() == 1) // agafo dades
	{
	//	sigCmpx[inde].real = ADCBUF3;	// Load the DAC buffer with data
	//	inde++;
	//	sprintf(uTxt, "\r\n sigCmpx %d \r\n", sigCmpx[inde].real);
	//	putsUART1((unsigned int *)uTxt);
		ADCBaixaFlagADC();
	}
//	if(inde == FFT_BLOCK_LENGTH){ //si ja tinc totes les dades faig la FFT
	if(ADCReturnFlagDada()==1){
		for (in = 0; in < FFT_BLOCK_LENGTH; in++){
			sprintf(uTxt, "\r\n sigCmpx %d \r\n", sigCmpx[in].real);
			putsUART1((unsigned int *)uTxt);
		}
		
		#ifndef FFTTWIDCOEFFS_IN_PROGMEM					// Generate TwiddleFactor Coefficients 
			TwidFactorInit (LOG2_BLOCK_LENGTH, &twiddleFactors[0], 0);	// We need to do this only once at start-up 
		#endif
	
		for ( in = 0; in < FFT_BLOCK_LENGTH; in++ )// 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. 
			*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[(FFT_BLOCK_LENGTH/2)-1].real ;	// Set up pointers to convert real array 
		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 ( in = FFT_BLOCK_LENGTH; in > 0; in-- ) // 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 
		}
	
		// Perform FFT operation 
		#ifndef FFTTWIDCOEFFS_IN_PROGMEM
			FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], &twiddleFactors[0], COEFFS_IN_DATA);
		#else
			FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));
		#endif
	
		// 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);
	
		// 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);
		inde = 0; // torno a posar l'index del buffer a 0. I tornem a començar
	}
}

Mi duda es donde tengo que guardar las muestras de entrada, si dentro la interrupción del ADC (como está declarado ahora) o puedo hacerlo desde el Motor de la FFT. Entiendo que si lo hago dentro del FFTMotor, igual me pierdo algunas muestras... ¿es así?

Por otro lado, yo meto una señal de 1khz, de 1 voltio de pico, y con un offset de 1v. Y si quiero mostrar por la uart "peakfrequency" me da siempre 0. Alguna sugerencia?

Muchas gracias por tu atención!
 
Atrás
Arriba