Autor Tema: Seguimiento a los Voltajes de I/O de un trafo  (Leído 7959 veces)

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

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Seguimiento a los Voltajes de I/O de un trafo
« en: 05 de Abril de 2008, 15:13:40 »
saludos amigos, pues surgido el problema de golpe inductivo me he puesto a observar las movidas que va tener un trafo, para ello he diseñado un circuito, tanto para leer la tensión AC del primario y del secundario (este ya casi como fuente), estoy usando un PIC16F88, aquí mi esquema:



mido la tensión con las entradas analógicas AN0 y AN1, y me ha dado estos resultados, decir que todavia no he colocado el divisor para el secundario del trafo, osea en mi prueba le colocaba a VCC y a GND, el de 220AC si estaba conectado, estos son los datos que he sacado, previamente el código que he escrito:

Código: [Seleccionar]
#fuses INTRC_IO,NOWDT,PUT,PROTECT,NOLVP,NOBROWNOUT,MCLR,NODEBUG,NOFCMEN,NOIESO
#use delay(internal=8000000)
#use rs232(baud=9600,bits=8,parity=N,xmit=PIN_B5,rcv=PIN_B2)
#use fast_io(a)
#use fast_io(b)

int count=0,seg=0,seg2=0,min=0,value1,value2;
int1 get_dato=0;

#INT_TIMER0
void tmr0_isr()
{
   set_timer0(5);
   count++;
   if(count==125)
   {
      seg++;
      seg2++;
      if(seg==5)
      {
         output_toggle(PIN_B0);
         seg=0;
      }
      if(seg2==60)
      {
         min++;
         if(min==5)
         {
            get_dato=1;
            min=0;
         }
         seg2=0;
      }
      count=0;
   }
}

#INT_RDA
void rda_isr()
{

}

void capturar()
{
   SET_ADC_CHANNEL(0);
   value1=READ_ADC();
   delay_us(20);                 // retardo para el muestreo
   SET_ADC_CHANNEL(1);
   value2=READ_ADC();
   delay_us(20);
   printf("\r\nIN value %u\r\n",value1);
   printf("OUT value %u\r\n",value2);
}

void main()
{
   setup_oscillator(OSC_8MHZ);
   SETUP_ADC(ADC_CLOCK_INTERNAL);
   SETUP_ADC_PORTS(sAN0 | sAN1);
   SETUP_TIMER_0(RTCC_INTERNAL | RTCC_DIV_64);
   set_timer0(5);
   set_tris_a(255);
   set_tris_b(0xfc);
   output_b(0);
   output_a(0);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   printf("HOLA\r\n");
   output_high(PIN_B0);
   while(true)
   {
      if(get_dato)
      {
         get_dato=0;
         delay_ms(30);
         capturar();
      }
   }
}

lo que hace el programa es capturar datos de voltaje cada 5 minutos, y he visto algunos problemas, creo que seá necesario colocarle VREF+. nose si el retardo para el muestreo esta bien ubicado

aca los datos que he leido:

Código: [Seleccionar]
HOLA   
IN value 98           //  Entrada AN0 conectado correctamente
OUT value 141       //  entrada AN1 conectado a vcc , el valor deberia ser 255?? porque no use referencias
IN value 97           
OUT value 140             
IN value 36           // entrada AN0 conectado correctamente
OUT value 0          // entrada AN1 conectado a GND, porque bajo el valor de AN0 si no se ha modificado la conexion ahí??
IN value 35           
OUT value 0           
IN value 36           
OUT value 0           
IN value 35           
OUT value 0           
IN value 35           
OUT value 0           
IN value 36           
OUT value 0           
IN value 36           
OUT value 0           
IN value 36           
OUT value 0           
IN value 36           
OUT value 0           
IN value 36           
OUT value 0           
IN value 36           
OUT value 0           
IN value 35           
OUT value 0           
IN value 36           
OUT value 0
IN value 36
OUT value 0
IN value 35
OUT value 0
IN value 35
OUT value 0
IN value 36
OUT value 0
IN value 36
OUT value 0
IN value 36
OUT value 0
IN value 97            // AN0 concetado como antes
OUT value 140        // otra vez AN1 conectado a Vcc
IN value 98
OUT value 141
IN value 96
OUT value 140
IN value 99
OUT value 142
IN value 98
OUT value 141

y pues he visto esas variaciones, que no me explico que puede ser.

Y tambien, como tengo convertido a valor digital, se que debo multiplicarlo o dividirlo por un factor para tener el valor leido, osea 220AC ó 222, etc. Que debo considerar para ese factor??

bueno seguiré probando, muchas gracias por la ayuda
.

Desconectado Tho0oR

  • PIC10
  • *
  • Mensajes: 18
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #1 en: 22 de Abril de 2008, 17:45:07 »
Buenaaas!!

A tu pregunta final no puedo contestarte porque tampco se me ocurre nada. Yo estoy haciendo algo similar. Mi programa lee la tension mediante el CAD de un potenciometro (divisor de tension) colocado en RA0. (0 a 5V) y lo displaya en un LCD. Ahora, tengo que llevar ese dato a un PC mediante un RS232.

tengo la parte del codigo que displaya y todo perfecto. Solo me queda la parte de cada "x" tiempo, capturar ese valory enviarselo al PC. Creo que esa parte la entiendes tu. Me podrias ayudar algo?

Trabajo con el CCsC para programa, con el MPlab para el debugger y grabar el programa y el ISIS para simular.

Un saludoo amigo!!

(te pongo mi codigo hasta ahora)
//=================================================================================================
//    Nombre:  Tho0oR                                     Fecha: 22/04/2008       
//=================================================================================================
//    Titulo del programa: El programa mide la tension que cae en el divisor de tension
//                       RA0, la visualiza en un LCD y la envia por el puerto RS232                       
//   ----------------------------------------------------------------------------------------------
//    Descricion: Mostrar en la pantalla LCD el valor de la tension que pasa por la resistencia RA0
//__________________________________________________________________________________________________             
//    Microcontrolador: PIC 16F877            Complilador: CCS 4.23
//    Entorno IDE: MPLAB v8.00                SIMULADOR: Proteus 7.1 SP4       
//    Tarjeta de aplicacion: Picdem 2 Plus    Debugger:  Icd2                 
//==================================================================================================
//   Conexiones: A1-> E           
//               A2-> RW         
//               A3-> RS     
//               D0 -> D4       
//               D1 -> D5           
//               D2 -> D6
//               D3 -> D7
//   Notas: Para una mayor precision el voltaje viene con 4 decimales (5.0068V es el max.)
//==================================================================================================
#include<16f877.h>
#device ADC=10                                  //10 bits de precision en el ADC
#use delay (clock=4000000)                      //Modo del oscilador
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,NOLVP,PUT   
#include<LCD_flexible.c>
#use fast_io(A)

//--------------Configuracion del RS232------------------
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use fast_io(C)

//----------------Programa principal----------------

void main()
{

unsigned long bat;
float volt;                                    //declaramos la variable "volt" tipo float(decimales)
setup_adc(adc_clock_internal);
setup_adc_ports(AN0);                                 // AN0 como canal analogico
lcd_init();
set_tris_a (0b00000001);                              // puerto RA0 como entrada resto salida
set_tris_c(0b10111111);                               //RC7-Rx entrada, RC6-Tx salida
do{
    set_adc_channel(0);                               //comienzo de la medicion
    delay_ms(50);
    bat=read_adc();                                   // mide el voltage aplicado a AN0
    volt=bat/204.600;                               //factor de correcion para que el valor en
    lcd_gotoxy(1,1);                                  //pantalla sea el mismo que la tension aplicada en
    printf(lcd_putc,"Tension=%1.4f V",volt);          //patilla RA0/AN0
 }while(TRUE);

}

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #2 en: 22 de Abril de 2008, 20:09:25 »
Hola.

Pues normalmente se debe esperar un tiempo minimo para la adquisicion del dato analogico.
Código: [Seleccionar]
set_adc_channel(0);
delay_us(20);
value1 = read_adc();

Siempre es bueno tener aislada la parte digital de la de potencia, asi que yo pondria un transformador para captar el voltaje y, aprovechando que el tiempo de adquisicion no parece ser un problema, calcularia en el pic el valor de una manera algebraica.

Si se quiere hacer seguimiento a la senal AC ... seria mejor usar un dsPIC, ya que cobra importancia el tiempo de muestreo.
El papel lo aguanta todo

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #3 en: 23 de Abril de 2008, 14:24:39 »
Para enviar los datos cada determinado tiempo y no afectar el proceso usaria una interrupcion de un timer (Los calculos es en osc = XT).
Código: [Seleccionar]
#int_TIMER0 //T_base = 256 * 4 / 4M = 256uS                                                                     
void  TIMER0_isr(void)
{
  ++C_Ints;
   if(C_Ints>=10)
    {
    time+=0.01024;
    B_Int=1;   
    C_Ints=0;
    }
}

El valor "time" es en funcion del desborde del TIMER0. El programa principal seria el siguiente:
Código: [Seleccionar]
void main()
{
  printf("%cADQ. M.L.O\r\n",0x0c);
  printf("tiempo   voltaje\r\n\r\n");
  lcd_init();
 
  setup_adc(ADC_CLOCK_DIV_16);
  setup_adc_ports(AN0);
  setup_timer_0(RTCC_8_BIT|RTCC_DIV_4|RTCC_INTERNAL);// RTCC_DIV_128 -> 256uS * 4 = 1.024 mS
  enable_interrupts(INT_TIMER0);
  enable_interrupts(GLOBAL);
 
  while(true)
  {
    set_adc_channel(0);
    delay_us(10);
    lcd_gotoxy(1,1);
    printf(lcd_putc,"V:%e  ",0.00491245 * filtro(0));
    lcd_gotoxy(1,2);
    printf(lcd_putc,"%lu  ",filtro(0));
   
    if(B_Int==1)
    {
     set_adc_channel(0);
     delay_us(10);
     printf("%f    %e\r\n", time, 0.00491245 * filtro(0));
     B_Int=0;
    }
  }
}

la funcion filtro() es un moving average de 100 datos:
Código: [Seleccionar]
int16 filtro (int chan)
{
 int16 valor[100]="\0"
 unsigned int32 sld=0;
 float res=0;
 int i=0,j=0;
   
   set_adc_channel(chan);
   for (i=0;i<=99;++i)
   {
    delay_us(10);
    valor[i] = read_adc();
   }

   for (j=0;j<=99;j++)
   {
   sld += valor[j];
   }
   res = sld/100;

 return res;
}

De esta manera envio el dato cada 0.01024 seg (se puede aproximar a 0.01 seg) mientras que en la LCD despliego el valor mas rapido (valor digital y analogico).

Un saludo.
El papel lo aguanta todo

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #4 en: 23 de Abril de 2008, 14:29:07 »
uupssssss!!!!!! :mrgreen:

es:

Código: [Seleccionar]
setup_timer_0(RTCC_8_BIT|RTCC_DIV_4|RTCC_INTERNAL);// RTCC_DIV_4 -> 256uS * 4 = 1.024 mS

Si no, no darian los calculos!!!!! :-)
El papel lo aguanta todo

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #5 en: 25 de Abril de 2008, 23:05:07 »
en cuanto a mi codigo creo q si esto es lo correcto:

set_adc_channel(0);
delay_us(20);
value1 = read_adc();

pues despues de seleccionar el canal al parecer ya se adquiere el dato y esta listo para ser leido, por eso el retardo despues de seleccionar el canal, y pues es muy comprensible en cuando se utiliza varios canales, pero si solo se usa un canal pues seria medio "raro" q se seleccione todo el tiempo el canal para leer el mismo canal, y pues nose ahi uno piensa q el retardo va despues del read_adc()

bueno cosas q se van descubriendo :mrgreen:

sobre el factor, hice una pequeña regra de 3 :D con un valor convertido a digital y leido con el mutimetro
digamos:
1 digital     ->  X
189 digital  ->  19.3 Vdc (valores leidos de mi lectura digital y mi multimetro respectivamente)

y de ahi tengo el factor :mrgreen: nose si esta bien o tan preciso, pero creo eso ya se puede afinar con un potenciometro en la resistencia q lee el valor analogico. y bueno no necesitaba mucha presición en cuanto a esto, y pues a funcionado bien nomas :mrgreen:

un saludo
.

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #6 en: 26 de Abril de 2008, 13:31:20 »
Pues, tengo entendido que se debe esperar un tiempo despues de seleccionar el canal, para que el condensador de "HOLD" se cargue completamente y de esa manera obtener el valor preciso del voltaje (el calculo del tiempo esta en el datasheet en la seccion del modulo ADC), por eso yo siempre coloco un delay de tiempo para luego leer el dato. Otra manera es testear la bandera de conversion en los registros del ADC (ADCON1 y ADCON2), y leer el dato cuando la bandera se dispare.

Para convertir el dato a analogico depende de la resolucion y el voltaje de referencia.
Resolucion = Vref / 2n

Donde n es el numero de bits. Por ejemplo, para 5 voltios de Vref y 8 bits, la resolucion es de 19.61x10-3, por lo que el valor analogico sera:

V = 0.01961 x Vd

Donde Vd es el voltaje digital, entre 0 y 255.

Que, en ultimas, es una regla de tres!!!!  :mrgreen: .

Si solo se va usar un canal, claro... basta con seleccionar una vez el canal de adquisicion, pero, es mejor tener la funcion de adquisicion para varios canales..... en esa funcion lo que hago es un promedio de 100 medidas para que sea estable (filtro moving average), porque el valor simple del read_adc() es muuuuuy inestable  :D (en los ultimos 2 bits) y eso afecta la medida.
El papel lo aguanta todo

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #7 en: 27 de Abril de 2008, 13:51:33 »
ok, gracias por la respuesta, como no tenia q tener tanta presición, ni me había preocuapdo de ese problema, pero en futuras en las q si tenga que tener bastante presisción, hare lo que mencionas

gracias
.

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #8 en: 29 de Abril de 2008, 16:46:42 »
Para mi un gustazo enoooooormeeee poder ayudar!!!!!!!!  :-/

Saludos
El papel lo aguanta todo

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #9 en: 30 de Abril de 2008, 16:54:12 »
 :mrgreen:
.

Desconectado scientist

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 999
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #10 en: 09 de Mayo de 2008, 22:04:00 »
aprovecho este hilo para hacer una pregunta, es un programa que estoy haciendo, con al adc, y es que estoy utilizando el voltaje de referencia, pero sucede algo muy extraño, el voltaje de referencia lo pongo a 2.5v, y el dato del adc lo proyecto en un lcd, cuando pongo un potenciomentro en a0, voy midiendo este dato, lo que no entiendo es que cuando voy variando el voltaje en a0 deja de medir exactamente pasando el valor de .28v a .80v no varia el dato de duty, que tengo puesto en el programa, alguien me podria decir la barbaridad que estoy cometiendo, no logro visualizar cual es

Código: [Seleccionar]
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
 #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use standard_io(b)
#use standard_io(c)

 

#include "LCD.C"
long duty;
int contRTCC=0;
int grados_temperatura;
int1 flag=0;
int1 flag_extern=0;

#int_ext
void int_extern(){

flag_extern=1;

}

#int_rtcc
void interruption(){
set_timer0(61);
++contRTCC;
if(contRTCC==10){
contRTCC=0;
flag=1;
}

}
 
void toma_adc(void){
set_adc_channel(0);
delay_ms(1);
duty= read_adc();
delay_ms(1);
grados_temperatura = (int) ((duty * 156) / 1024);


}

void main()
{

   setup_adc_ports(RA0_RA1_ANALOG_RA3_REF);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DIV_BY_1,0x50,1);
   setup_comparator(NC_NC_NC_NC);
   
   setup_ccp1(CCP_PWM);
   
   enable_interrupts(int_rtcc);
   enable_interrupts(global);
   
   set_tris_a(0x0B);
    lcd_init();
   // TODO: USER CODE!!
   
   
 
   do{
   toma_adc();
   output_b(duty);
   set_pwm1_duty(duty);
   
   if(flag==1){
 
        //cursor para escribir mensaje
      printf(lcd_putc,"Temp=%lx",duty) ;   //muestra por pantalla el mensaje
   
   delay_us(100);
   
   
     
   flag=0;
   }
    }while(true);

}

no entiendo por que no varia el adc en ese rango de voltaje, gracias de antemano,por favor chequen si esta bien mi
setup_adc_ports(RA0_RA1_ANALOG_RA3_REF);
poniendo en a3 los 2.5 volts, y la entrada analogica en a0
NO le digas a DIOS que tienes un gran problema, dile a tu problema que tienes un GRAN DIOS!!
Alma mia y castillo mio, mi Dios en quien yo confiare....

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #11 en: 09 de Mayo de 2008, 23:07:31 »
scientist, he descubierto varias cosillas que aunque no sean las causantes de tu problema, no favorecen al funcionamiento del ADC.

1) No setes constantemente el canal del ADC si vas a usar siempre el mismo. Coloca la instrucción set_adc_channel al comienzo de la aplicación y asi te evitas tener que esperar ese ms antes de la medición.
2) No hace falta esperar despues de la medicion, la función read_adc() termina cuando devuelve el valor convertido asi que quedate tranquilo que cuando el código continua, el valor ya esta guardado en el registro duty.
3) No utilizes el reloj interno del ADC si tu PIC tiene una frecuencia de reloj mayor a 1 MHz o bien si tu conversion no es realizada en modo Sleep porque el ADC sale fuera de sus especificaciones de precisión. Calcula cual de las opciones de reloj te convienen en base a obtener el menor tiempo de conversión posible, pero sin descender por debajo del TAD minimo.
4) Define mediante el preprocesador #ADC = 10 que el ADC guarde el valor convertido en formato de 10 bits, de lo contrario no podás utilizarlo para tu PWM sin antes realizarle un desplazamiento de bits.
5) Tienes una incoherencia en el código, pues quieres sacar los datos de 16 bits por el puerto b siendo este de 8 lineas. O conviertes la variable duty a un valor de 8 bits o lo envias en dos tandas.

De paso habria que ver como conectas el pote a la entrada del ADC, conectarlos directamente no te asegura la conversión, sobre todo si este es de un valor ohmico importante.

MLO, no entiendo que quisiste decir con que el valor obtenido con read_adc() es muy inestable en los 2 bits menos significativos. El conversor siempre convierte con una precisión de +-1LSb o menos, asi que el hecho de que tengas una inexactitud de +-2 LSb es una cuestión de mala implementación de la conversión por SW o de un mal diseño del HW. No creo que la función read_adc por si sola haga perder exactitud, sino ya estoy tirando el CCS por la ventana  :mrgreen: :mrgreen:. Bueno, en realidad a mi nunca me ha pasado y no creo que se hallan mandado semejante bug los chicos de CCS.

Un saludo a todos.

"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #12 en: 09 de Mayo de 2008, 23:48:05 »
El error no es del CCS (en C18 pasaba lo mismo).

Es mas o menos asi: cuando conecto un trimer como divisor de tension al AN0 y  hago la conversion (supongamos que hallan 2.5v y estoy trabajando a 10 bits) con el read_adc() y coloco el valor en una LCD, el valor mostrado no es 512, si no que se observa 5xx (donde xx es un salto de valores, cambian mucho y no se ven bien, sobre todo las unidades!!!). Por eso digo que es inestable. Coloque sequidores de tension y nada :? . No se si influya los voltajes de referencia (por lo general tomo los de Vdd y Vss)???? sera eso????? Por eso lo que hago es un promedio de unos 100 datos para que el valor leido si se quede en un valor estable (pero pierdo tiempo....valioso recurso).

Citar
3) No utilizes el reloj interno del ADC si tu PIC tiene una frecuencia de reloj mayor a 1 MHz o bien si tu conversion no es realizada en modo Sleep porque el ADC sale fuera de sus especificaciones de precisión. Calcula cual de las opciones de reloj te convienen en base a obtener el menor tiempo de conversión posible, pero sin descender por debajo del TAD minimo.
Yo utilizo una configuracion XT y coloco setup_adc(ADC_CLOCK_INTERNAL);, sera que eso influye????

Que me recomiendas?

Saludos
El papel lo aguanta todo

Desconectado scientist

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 999
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #13 en: 10 de Mayo de 2008, 01:36:59 »
ok, gracias Gonzalo_BlackHawk habia unos errores que no habia corregido, volviendo a tu comentario, que debo de poner en el reloj de el adc? debo de utilizar adc_clock_div_8 si utilizo un cristal de 4 mhz?
gracias por la pronta respuesta
NO le digas a DIOS que tienes un gran problema, dile a tu problema que tienes un GRAN DIOS!!
Alma mia y castillo mio, mi Dios en quien yo confiare....

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Seguimiento a los Voltajes de I/O de un trafo
« Respuesta #14 en: 10 de Mayo de 2008, 07:42:49 »
Antes que nada, me corrijo a mi mismo, cuando uno obtiene aleatoriedad en los 2 bits menos significativos tiene una inexactitud máxima de +-4LSb, y no de -+2LSb como habia dicho en mi otro mensaje, eso me pasa por escribir rápido  :mrgreen: :mrgreen: :mrgreen:

MLO, si realmente en tu ADC no puedes obtener mejor exactitud que las centenas entonces estas teniendo graves problemas con la adquisición de datos. Bien, como ya he dicho anteriormente, este error puede ser por una mala implementación de la toma de datos por SW, en general le podes errar definiendo mal la frecuencia de oscilacion o bien no realizando el código según el procedimiento recomendado, sobre todo esta ultima equivocación se comete cuando se multiplexan los canales de lectura del ADC o bien se intentan tomar muestras seguidas en el mismo canal.  Bien, el oscilador RC interno tiene dos problemas a saber: Tiene un periodo de 4 us, en realidad oscila entre 2 y 6 us, y por lo tanto no se rige bajo un frecuencia exacta y es un reloj relativamente lento sabiendo que con el reloj del PIC podemos obtener tiempos menores al us (por mas que violemos las especificaciones del ADC convirtiendo a estos periodos, sin embargo los he utilizadon en ciertos casos cuando necesite sacrificar bits de precision por un muestreo mas rápido) El otro problema es que no debe utilizarse si el PIC esta funcionando a frecuencias mayores de 1 MHz, nunca he leido porque, debe ser que existen ciertos circuitos en el ADC que siempre funcionan regidos bajo el reloj de cristal y el oscilador RC comienza a tener una deriva en su frecuencia respecto a la de estos circuitos, falseando la medición. Entonces me dirán ahora que el oscilador RC es una porqueria y que para que lo pusieron ahi, pues bien, el oscilador RC se utiliza para convertir con el ADC mientras el PIC esta durmiendo, es un método que yo utilizo bastante y con la que se obtiene la mayor precisión posible con el ADC del PIC. Aquí expongo el código para ese método, obviamente habra que realizar las correciones correspondientes para utilizarlo con nuestro circuito:

Código: [Seleccionar]
// En la carga inicial del PIC colocamos:
   setup_adc_ports(AN0);
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(0);

  // Luego para cada conversión ejecutamos el código asi:
   disable_interrupts(GLOBAL);
   enable_interrupts(INT_AD);
   clear_interrupt(INT_AD);
   read_adc(ADC_START_ONLY);
   sleep();
   delay_cycles(1);
   Valor = read_adc(ADC_READ_ONLY);
   disable_interrupts(INT_AD);
   enable_interrupts(GLOBAL);

Bien, algunas herramientas que puedes implementar bajo SW y que no agregan precisión a la lectura pero si estabilidad en la misma (obviamente sacrificando muestreos) son el MA (moving average, el promediar valores por asi decirlo) y los filtros digitales FIR o IIR (En general con un filtro FIR pasabajos de primer orden es suficiente). No se confundan, estos metodos solo deben ser aplicados cuando ya hemos optimizado al máximo el HW acondicionador de la señal y el SW y la variación aleatoria es inherente a la función matemática generadora de la señal.

Aunque tu código este realmente mal y el método que utilizes sea incorrecto (no digo que sea lo que estas haciendo MLO, solo estoy suponiendo el peor de los casos  :)) es muy raro que esto te produzca semejante variación en los valores de lectura del ADc, por lo que yo supongo que estas errando en el HW, un tema que es demasiado extenso para tratar en este post, además de que estoy algo apurado y quiero tocar la pregunta de scientist. Será para el proximo mensaje :-)

Scientist, no hay un prescalador definido para una frecuencia de reloj determinado, en general hay que tratar de obtener el menor tiempo de muestreo sin descender por el valor de TAD minimo que especifica Microchip (esto si quieres obtener una resolución igual a la fundamental del ADC). El valor de TAD minimo depende del PIC que estes utilizando, en general para la linea de 16F y la serie estandar C de Microchip, es de 1.6 us. Ah, me olvidaba, el TAD es el tiempo que se utiliza como referencia en los ADC y se denomina como el tiempo de conversión requerido para un bit. Supongamos este valor y ahora
veamos todas las opciones que tienes:

2 x Tosc (adc_clock_div_2) = 2 x (1/ 4 . 10^6 Hz) = 500 ns = VIOLA EL TAD MINIMO, NO UTILIZAR
8 x Tosc (adc_clock_div_8) = 8 x (1/ 4 . 10^6 Hz) = 2 us
32 x Tosc (adc_clock_div_32) = 32 x (1/ 4 . 10^6 Hz) = 8 us
Oscilador RC (adc_clock_internal) = 2 a 6 us = NO UTILIZAR EN ESTE CASO

Utiliza el adc_clock_div_8 para un tiempo de muestreo minimo pero recuerda revisar primero el datasheet de tu PIC para verificar los valores minimos de TAD. Espero haber sido claro con mis explicaciones.

Nos estamos escribiendo.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."