TODOPIC
Microcontroladores PIC => dsPIC => Mensaje iniciado por: pool_guita en 24 de Julio de 2007, 18:04:25
-
Hola a todos, por favor necesito ayuda de urgencia :-/
Estoy desarrollando un proyecto con un dsPIC30F3014, estoy haciendo un afinador para instrumentos musciales de cuerda, tengo que sacar la transformada de fourier para saber la frecuencia de una señal de entrada analógica, estoy programando en MikroBasic.
EL programa de ejemplo de MikroBasic realiza la FFT casi bien, ya que cuando ingreso valores pares de frecuencia lee bien, pero cuando son impares tengo una falla de 100Hz menos y solo puedo leer frecuencias minimas de 200 Hz y solo en valos fijos por ejemplo 200, 400, 600, etc...
Esto no me sirve para mi proyecto, necesito leer frecuencias bajas desde los 30Hz y con intervalos de 1 en 1, por ejemplo 35, 37,38, etc...
Me sugirieron realizar una interrupción con el Timer, y dentro de la interrupción tomar la lectura del ADC para asi conseguir una mayor cantidad de muestras de la señal. Mi pregunta es como debe hacer la interrupción con el Timer y el ADC para establecer un tiempo diferente de adquisión de datos??
Espero que alguien me pueda ayudar GRACIAS...
-
Hacer una interrupción con el timer que vaya variando su frecuencia es relativamente sencillo. Basta con cargar un valor distinto en el contador del Timer cada vez que entras en la interrupción del mismo.
Lo que quizás no sea tan fácil es saber qué frecuencia quieres testear en cada momento, dado que por tu explicación no queda demasiado claro.
En cualquier caso, si sigues con dudas, pega aquí tu programa e intentamos resolverlas.
-
Grfacias por la respuesta, creo que no estoy siendo clara, por lo que voy a poner el código de mi programa
program FFTTLCD
dim cuerda as integer
dim enter as integer
dim i as integer
dim j as integer
dim abajo as integer
dim cont as integer
dim instru as integer
dim aux3 as integer
dim menu as integer
dim valins as integer
dim valcue as integer
dim valori as string [6]
dim valorc as string [6]
dim Samples as word[256] absolute $0C00 ' Y data space for P30F4013- required by FFT routine
' See datasheet for your dsPIC to see Y data space limits
freq as word ' Auxiliary variables
txt as string[5]
Written as word[64]
valor as string [5]
amplitud as string [17]
sub procedure escribir (dim x, y as integer, dim byref texto as string[20])
Lcd_Cmd (LCD_FIRST_ROW)
Lcd_Cmd (LCD_CURSOR_OFF)
Lcd_Cmd (LCD_SECOND_ROW)
Lcd_Out (x, y, texto)
end sub
sub function leerpe as integer
dim aux as integer
aux = 0
while aux = 0
if Button(PORTD, 2, 50, 1) = 1 then
aux = 1
result = aux
end if
wend
end sub
sub function leerpb as integer
dim aux as integer
aux = 0
while aux = 0
if Button(PORTD, 3, 50, 1) = 1 then
aux = 1
result = aux
end if
wend
end sub
sub function leer2pe as integer
dim aux1 as integer
dim ctrl as integer
ctrl = 0
while ctrl = 0
if Button(PORTD, 2, 50, 1) = 1 then
aux1 = 1
ctrl=1
end if
if Button(PORTD, 3, 50, 1) = 1 then
aux1 = 2
ctrl=1
end if
wend
result =aux1
end sub
sub procedure InitAdc
ADPCFG = 0x00FF ' PORTB is analogue input
ADCHS = 8 ' Connect RBxx/ANxx as CH8 input. RB10 is input pin
ADCSSL = 0 '
ADCON3 = $1E3F ' sample time = 31 Tad. en este registro se encuentra definido el tiempo en el que debe tomar las muestras, esto es lo que necesito modificar
para realizar las lecturas mucho mas rápido para así obtener las muestras en menor tiempo
ADCON2 = 0
ADCON1 = $83E0 ' turn ADC ON, fractional result, internal counter ends conversion
TRISB.8 = 1 ' RB10 as input pin
end sub
sub procedure MainInit
InitAdc
Vector_Set(Written, 64, $FFFF) ' Fill "Written" with $FFFF
IPC0 = IPC0 or $1000 ' Interrupt priority level = 1
IFS0 = IFS0 and $FFF7 ' Clear TMR1IF
IEC0 = IEC0 or $0008 ' Enable Timer1 interrupts
T1CON = $8030 ' Timer1 ON, internal clock FCY, prescaler 1:256
end sub
' Auxiliary function for converting 1.15 radix point to
' IEEE floating point variable (needed for sqrt).
sub function Fract2Float(dim input_ as integer) as float
if (input_ < 0) then
input_ = - input_
end if
result = input_/32768.
end sub
' "Samples" at this moment contains DFT of the signal in the manner Re, Im, Re, Im...
sub procedure WriteData
dim Re, Im, tmpw,
j, k, l, max as word
Rer, Imr, tmpR as float
j = 0 ' If you wan to skip DC component then make j >= 1
k = 0
max = 0
freq = 0 ' Reset current max. frequency for new reading
while k <= 63
Re = Samples[j] ' Real part of DFT sample
inc(j)
Im = Samples[j] ' Imaginary part of DFT sample
inc(j)
Rer = Fract2Float(Re) ' conversion to IEEE floating point
Imr = Fract2Float(Im) ' conversion to IEEE floating point
tmpR = Rer * Rer ' Re^2
Rer = tmpR
tmpR = Imr * Imr ' Im^2
Imr = tmpR
tmpR = sqrt(Rer + Imr) ' Amplitude of current DFT sample
Rer = tmpR*256. ' DFT is scaled down by 1/N, we need to
' take it back in order to have visible
' components on GLCD
Re = Rer
if Re > 63 then
if k = 0 then
Re = 0
else
Re = Written[k-1] ' k = 0? beware of the glitch
end if
end if
if Re > max then ' Find max amplitude
max = Re
freq = k ' This should be the center frequency of the signal
end if
tmpw = Written[k]
inc(k) ' Move current X coordinate
inc(k) ' Draw on each second X coordinate
wend
' Write the frequency of max. sample
freq = freq * 100
WordToStr(freq, txt)
escribir (1,1,txt)
end sub
' Take current sample
sub function ReadAdc as word
ADCON1.1 = 1 ' Start AD conversion
while ADCON1.0 = 0 ' Wait for ADC to finish
nop
wend
result = ADCBUF0 ' Get ADC value
end sub
' Fill "Samples" with input samples in manner Re, Im, Re, Im... where Im = 0
sub procedure SampleInput
dim i as integer
i =0
while i <= 255
Samples = tiempo ' Re
inc(i)
Samples = 0
inc(i) ' Im
wend
' "Samples" now contains 128 pairs of <Re, Im> samples
end sub
sub procedure tiempo org $1A esta es la interrupción con el timer 1 que quiero modificar, lo que quiero hacer es que cada vez que el registro PR1 alcanze
el tiempo
deseado se realize la lectura del ADC para asi obtener las muestras de una señal en un menor tiempo como debo hacer
esto? esta bien?
IFS0 = IFS0 and $FFF7 ' Clear TMR1IF
ReadAdc
end sub
main:
cont = 0
menu = 0
cuerda = 0
instru = 0
valins = 0
valcue = 0
TRISF = 0
TRISD = $000F
PR1 = 2863
Lcd_Init (PORTF, 6, 5, 4, 3, PORTF, 0, 1, 2)
escribir (1, 1, "Bienvenido")
escribir (2, 1, "presione enter")
cont = cont + leerpe
Lcd_Cmd (LCD_CLEAR)
MainInit
while true ' Infinite loop
SampleInput ' Sample input signal
' Perform FFT (DFT), 7 stages, 128 samples of complex pairs
' Twiddle factors are taken from the <TwiddleFactors.dpas> unit
FFT(7, @TwiddleCoeff_128, Samples)
' DFT butterfly algorythm bit-reverses output samples.
' We have to restore them in natural order.
BitReverseComplex(7, Samples)
' Draw DFT samples on GLCD
WriteData
wend
end.
Lo que obtengo con este programa es la lectura de la frecuencia de una señal no menor a 200Hz, lo que necesito es mejorar la resolución y poder leer frecuencias menores como por ejemlo 30Hz, 34Hz, 45Hz, necesito que el programa sea capaz de diferenciar entre frecuencias de diferencia de + o - 1Hz
Espero me puedan ayudar
Gracias de antemano... :P