Autor Tema: ADC mas interrupción para dsPIC  (Leído 4313 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado pool_guita

  • PIC10
  • *
  • Mensajes: 2
ADC mas interrupción para dsPIC
« 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...

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: ADC mas interrupción para dsPIC
« Respuesta #1 en: 25 de Julio de 2007, 02:00:58 »
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.

Desconectado pool_guita

  • PIC10
  • *
  • Mensajes: 2
Re: ADC mas interrupción para dsPIC
« Respuesta #2 en: 25 de Julio de 2007, 13:15:41 »
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