Autor Tema: Problemas con el ADC en dsPIC 30f6014A  (Leído 4338 veces)

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

Desconectado donroyaline

  • PIC10
  • *
  • Mensajes: 1
Problemas con el ADC en dsPIC 30f6014A
« en: 22 de Julio de 2009, 11:12:18 »

Hola,

Estoy probando  la board dsPICDEM Starter Demo Board V2, me gustaría usar el potenciometro analogo ( conectado al canal analogo AN2 / RB2 de la tarjeta) como mi entrada analogica. Quiero muestrear este canal multiples veces. Quiero utilizar el comparador del timer3 como señal de evento externo para activar el ADC y muestrear a la mayor velocidad posible 16 veces  cada 500 Hz y obtener la media de estos valores.

Estoy usando un oscilador externo que opera a 7.3728 MHz con  PLLx16, con lo q puedo obtener 29.4 MIPS => Tcy = 33.9ns
si configuro el prescaler del timer3 1:8 y PR3 = 7370;

El periodo del timer3 sería = 33.9ns * 8 * 7370 = 0.0020 s = 2ms ( 500 Hz)

En teoría estos serian los calculos, pero quiero probar la frecuencia del timer utilizando la interrupcion del ADC para encender y apagar una salida digital, (RD6), pero al medir la frecuencia con el osciloscopio obtengo 15.62 Hz.

La verdad no he podido identificar el error, alguien me puede ayudar dandole un vistazo al codigo, la verdad lo agradecería mucho.

Este es el codigo:

*****
DSPIC 30F6014A, 5V
Oscilador externo a 7.3728 MHz,  conectado entre osc1 - osc2.
*******

/*********************************************************************/
// Config directive to set configuration bits

_FOSC(CSW_FSCM_OFF & XT_PLL16); // Cristal externo via PLL 16x de 7.3728 MHz
                        // = 7.3728e+6*16/4 = 29.4 MIPS(Fcy)
                        // Tiempo de instrucción (Tcy)= 33.9 nanosegundos
_FWDT(WDT_OFF);               // Apaga el timer del watchdog
_FBORPOR(MCLR_EN & PWRT_OFF);   //Habilita el pin de reset maestro MCLR y apaga los
                                                 //power-up timers.
_FGS(CODE_PROT_OFF);            //Deshabilita la proteccion de codigo

//---------------------------------------------------------------------
// List interrupt and subroutine prototypes here

void InitADC12(void);
void SetupPorts(void);
void __attribute__((__interrupt__)) _ADCInterrupt(void);

// Variables

unsigned int ADCValue;
int count;
volatile unsigned int *ADC16Ptr;

//---------------------------------------------------------------------


int main(void)
{
 
 InitADC12();
 SetupPorts();
 PORTDbits.RD6 = 1;  // inicializa led en 1   

 while(1)                     
   {
   asm("clrwdt");   // espera un bucle infinito

         }

}                               // end main

/*******************************************************************
      Configuracion registros ADC:
      1. 1 canal de conversion (RB2/AN2)
      2. Automatic Sample start
      3. Timer3 trigger (2mS)
      4. Automatic Stop Sampling and start converting
      5. 16 muestras por interrupcion

                                             
*********************************************************************/
void InitADC12(void)
{

// Registro ADCON1
    // Configurar A/D para muestreo automatico.

   ADCON1bits.ASAM = 1;
    // Timer 3 establece el tiempo de muestreo
   ADCON1bits.SSRC = 2;
    // Formato de numero = 1.15 fraccional
   ADCON1bits.FORM = 3;
   
// Registro ADCON2
    //Interrupcion despues de 16 muestras en el buffer
    ADCON2bits.SMPI = 15;


// Registro ADCON3
   // Deseamos una tasa de muestreo de 500 Hz.
   // Tiempo total de conversion = 1/fs = 1/500 = 2ms
   // A 29.4 MIPS, Tcy = 33.9ns = tiempo de instruccion
   // Tad > 667ns (Para temperaturas de -40°C a 125°C )
    // Se configura la fs por medio del Timer3 y Tad usando los bits ADCS<5:0>
    // Primero se configura el Timer del AD al maximo valor posible: ADCS = 63.
   ADCON3bits.ADCS = 63;
    // Tad = Tcy*(ADCS+1)/2 = 33.9ns *(63+1)/2 = 1.0848 us
    // El convertidor se toma 14 * Tad periodos para cada muestra

// Configuracion Timer3
   // Ahora se configura Timer3 para que finalice cada 2ms
   // provocando que el modulo termine el muestreo e inicie la conversion
   // Calculo del prescaler y del periodo de interrupcion:
   // Periodo3 = Tcy * prescaler = 33.9ns * 256 = 8678.4 ns; este es el periodo al usar prescaler de 256
   // Periodo interrupcion = Periodo3 * PR3 = 2ms
   // de donde PR3 = 2ms/ 8.6784 ms = 231, para un periodo aproximado de
   // interrupcion de 0.0020047 ms (equivalente de 499 Hz)
   // Inicializacion del timer3
   TMR3 = 0x0000;
   // Configuracion prescaler timer3
   // T3CONbits.TCKPS = 255;
   // Periodo de interrupcion
   //PR3 = //1842;
   PR3 = 7370;
   IFS0bits.T3IF = 0;
    IEC0bits.T3IE = 0;
   
//Registro ADCHS
    //Conecta RB2/AN2 al canal CH0 de entrada.
    ADCHS = 0x0002;

// Registro ADCSSL
    // Escaneo de canales deshabilitado.
    ADCSSL = 0x0000;

// Registro ADPCFG
    //Configura todo el puerto B como digital y RB2 como analago.
   ADPCFG = 0xFFFB;
   
//Limpia el flag de interrupcion de A/D
    IFS0bits.ADIF = 0;

//Pone en set el bit de interrupcion
    IEC0bits.ADIE = 1;

//Inicia el convertidor AD
//NOrmalmente se hace despues de configurar los otros registros.
    ADCON1bits.ADON = 1;

//Inicia Timer3
      T3CON = 0x8010;      // Inicio de timer3, ajuste de prescaler 1:8

}

void __attribute__((interrupt, no_auto_psv)) _ADCInterrupt(void)
{
     //Esta sería mi rutina normal

              //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;
            //   ADCValue = 0; // clear value
            //   ADC16Ptr = &ADCBUF0; // initialize ADCBUF pointer
             //   for (count = 0; count < 16; count++) // average the 16 ADC value
           //   ADCValue = ADCValue + *ADC16Ptr++;
           //   ADCValue = ADCValue >> 4;

// Rutina de prueba para visualizar frecuencias
      IFS0bits.T3IF = 0; // borramos flag de interrupcion
      IFS0bits.ADIF = 0;
      if(PORTDbits.RD6 == 1)
         PORTDbits.RD6 = 0;
      else
         PORTDbits.RD6 = 1;

}

// Inicializa puertos

void SetupPorts(void)
{
PORTD = 0;
TRISD = 0xFF0F;            // RD7 a RD4 como salidas
}

Agradezco si me pueden dar una luz sobre lo que me esta pasando.

Gracias.

Desconectado juanjo328

  • PIC10
  • *
  • Mensajes: 1
Re: Problemas con el ADC en dsPIC 30f6014A
« Respuesta #1 en: 12 de Noviembre de 2009, 09:06:34 »
El problema esta en el tiempo del Timer3, 2ms son para un solo canal, tu estas escaneando 16 por lo que 16 x 2= 32ms   por eso el toggle es de 16Hz aproximadamente, el timer marca el momento en el que se realiza la conversion pero estas convirtiendo 16 canales, divide el tiempo del timer entre 16 y tendras los 500 hz.


 

anything