TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: alraid en 21 de Enero de 2013, 08:45:33

Título: [Solucionado] problema de rango de voltage en convertidor ADC
Publicado por: alraid en 21 de Enero de 2013, 08:45:33
hola foreros,

estoy haciendo mi proyecto final de carrera que consiste en disenyar e implementar un medidor de campo magnético con un sensor para despues tratar la señal en un PIC 16F876 y mostrar el resultado por una pantalla LCD. El programa ya lo tengo hecho y siulado por Proteus funciona perfectamente pero a la hora de montarlo es donde surgio el problema.

El rango de la señal que entro al PIC para la conversión A/D por la entrada analógica es de 0 a 5 Voltios, que es el voltage con el que alimento el PIC. El caso es que a la hora de representar el resultado por la pantalla LCD no me calcula valores más altos de 4 Voltios ni más pequeños de 1 Voltio, como si el rango del PIC fuera de 1 a 4 Voltios en vez de 0 a 5. A partir del valor equivalente a 4 Voltios ya no me da más resultado aunque le introduzca al PIC en la entrada analógica un valor de 4,5.

Como en la silución por proteus sale perfecta y como en la entrada analógica realmente entran valores de 0 a 5 Voltios creo que es un problema del propio PIC y me tiene bastante desconcertado.

Muchas gracias
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: RALF2 en 21 de Enero de 2013, 09:00:32
Alraid!
Eso pudiera pasar si la impedancia del elemento que estas conectando a la entrada del adc es muy alta, creo que el fabricante del pic recomienda que esta sea menor de 10Kohm.
Prueba utilizando un potenciometro de 5 o 10Kohm, como divisor de tension y nos comentas  :mrgreen:

Saludos
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: ppyote en 21 de Enero de 2013, 10:41:05
Usas un amplificador operacional como etapa amplificadora?
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: alraid en 22 de Enero de 2013, 07:02:43
Sí ppyote. Utilizo un amplificador operacional para adaptar mi señal al rango del PIC. Concretramente una etapa amplificadora restadora de ganancia 1.

Ralf2 viendo tu comentario he calculado con un tester la resistència que provoca esa etapa i es de 5,5kohms. Luego he quitado un condensador cerámico de 100nF que tenia en paralelo entre la salida del operacional y la entrada del PIC que tenía colocado para acabar de filtrar la señal pero aún así el problema persiste.
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: ppyote en 22 de Enero de 2013, 07:48:11
Mide la salida de la etapa amplificadora puesto que podía ser problema de esta. Podría ser  que estas teniendo problemas con el offset del amplificador operacional, a mi me pasó lo mismo ya que del amplificador sólo me cubría el rango de 1v y 4v 
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: RALF2 en 22 de Enero de 2013, 08:32:33
Alraid si conectas directamente los 5V de la alimentacion del pic a la entrada del adc no te aparecen los 5V en la lcd?
Haz probado con otro pic?
En caso tal que hallas hechos todas esas pruebas y verificado los voltajes con un tester, entonces podrias colocar el hardware y el software que hiciste para verlo?

Saludos
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: alraid en 22 de Enero de 2013, 08:46:51
la salida de voltage del operacional es la correcta de 0 a 5V. Mañana probarén conectar directamente 5 Voltios por la entrada analògica sin pasar por la etapa amplificadora haber que pasa. Si persiste el problema mañana os cuelgo el codigo de programa.

Gràcias por vuestro interés.
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: flacoclau en 22 de Enero de 2013, 15:29:44
Me parece que el término que quiso utilizar ppyote es "Swing" y es el rango de tensión que puede cubrir la salida del operacional de acuerdo a la alimentación. Generalmente un operacional alimentado con 5V no llega a esta tensión a la salida debido a cuestiones de los transistores de salida, hay sin embargo un tipo de operacional que se denomina "Rail to rail" el cual puede llevar la tensión de salida a valores muy próximos a los de alimentación. Yo generalmente utilizo los LM358 (Dual AO) que es una especie de semi rail to rail, ya que su valor mínimo llega muy próximo a los 0V, pero no así a la tensión superior. También tiene estas características el LM324 (quad AO).

Lo que me extraña es que el rango sea tan corto, en una de esas todo sea cuestion de programación o de algún error de diseño.
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: KALLITOS en 22 de Enero de 2013, 16:01:09
Verifica en el seteo del micro y los pines de voltaje de referencia.
por alli podria estar el problema.

saludos.
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: soymoe en 22 de Enero de 2013, 16:06:34
anda por parte, saca la etapa de acondicionamiento de señal y reemplazala por un divisor de tension para obtener todo el rango de tensiones de 0 a 5v y verifica que funcione la rutina de conversion.
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: ppyote en 22 de Enero de 2013, 16:20:51
Cita de: flacoclau link=topic=39996.m :lol:sg333054#msg333054 date=1358879384
Me parece que el término que quiso utilizar ppyote es "Swing" y es el rango de tensión que puede cubrir la salida del operacional de acuerdo a la alimentación. Generalmente un operacional alimentado con 5V no llega a esta tensión a la salida debido a cuestiones de los transistores de salida, hay sin embargo un tipo de operacional que se denomina "Rail to rail" el cual puede llevar la tensión de salida a valores muy próximos a los de alimentación. Yo generalmente utilizo los LM358 (Dual AO) que es una especie de semi rail to rail, ya que su valor mínimo llega muy próximo a los 0V, pero no así a la tensión superior. También tiene estas características el LM324 (quad AO).

Lo que me extraña es que el rango sea tan corto, en una de esas todo sea cuestion de programación o de algún error de diseño.

a eso precisamente me refería, pero por no enrollarme escribiendo y editando con el móvil lo he dejado así
gracias por una mejor explicación flacoclau
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: RALF2 en 22 de Enero de 2013, 16:50:02
alraid
Lo que indican los amigos sobre las limitaciones del op amp son correctas el operacional tiene unos voltajes de saturacion que limitan el maximo voltaje de salida y el minimo de estos, como sabes, por eso no tendras los 5V a la salida si los almentas con 5V, ni 0V,  a menos que sean del tipo rail to rail, creo  :mrgreen:

Aqui (http://www.swarthmore.edu/NatSci/echeeve1/Ref/SingleSupply/SingleSupply.html), puedes ver un ejemplo   :mrgreen:

No obstante como te indique arriba y como los compañeros señalan, elimina la etapa acondicionadora y metele 5V directo o por un divisor de tension al pic debes leer 5V en la lcd, sino saca por la lcd tambien el valor del adc que deberia ser 1023 si operas a 10bits o 255 si operas a 8 bits.
Haber si el problema esta en otra parte y si tienes un pic de sobra prueba tambien con el.

Saludos
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: alraid en 23 de Enero de 2013, 08:06:43
Gràcias a todos por las respuestas pero acabo de probar de alimenar directamente la entrada analógica con 5V sin la etapa amplificadora y el problema persiste, aunque le entre 5V el PIC ve 4V. Además el problema de swing ja lo tuve en su momento y por eso alimento el operacional com -8V y 8V.

Despues de la prueba de hoy de conectar directamente 5V y que no funcione veo que el problema es del PIC o de la programación. Os dejo el codigo del programa.

#include <16f876.h>                                                           
#device adc=10                                                                 
#FUSES XT,NOWDT                                                               
#use delay (clock=2000000)                                                   
#include <lcd420.c>                                                           

                                                                             
   float b;                                                                   
   float valor;                                                               
   float G=1.0;                                                               
   int8 unitat=1;                                                             
   short n=0;                                                                 
                                                                             
////////////////////////////////////////////////////////////////////////////////
//                         Funciones del programa                                    //
////////////////////////////////////////////////////////////////////////////////
                                                                             
void menu2()                                                                 
{                                                                             
    printf(lcd_putc, "1-GAUSS  2-TESLA\n");                                   
    printf(lcd_putc, "3-VOLT   4-ANT\n");                                     
}                                                                             
                                                                             
void menu1()                                                                 
{                                                                             
   printf(lcd_putc, "1-MESURA\n");                                           
   printf(lcd_putc, "2-UNITATS  3-SEG\n");                                   
}                                                                             
                                                                             
void menu3()                                                                 
{                                                                               
   printf(lcd_putc, "1-GUANY    3-ANT\n");                                   
   printf(lcd_putc, "\n");                                                   
}                                                                             
                                                                             
void ant4()                                                                   
{                                                                             
   printf(lcd_putc, "\n           4-ANT");                                   
}                                                                             
                                                                             
void menys()                                                                 
{                                                                                 
 printf(lcd_putc, "\fG=%01.2f  4-ANT" , G);                                   
 printf(lcd_putc, "\n1:- 2:0.1 3:0.01");                                     
 delay_ms(250);                                                               
}                                                                             
                                                                             
void mes()                                                                   
{                                                                             
 printf(lcd_putc, "\fG=%01.2f  4-ANT\n" , G);                                 
 printf(lcd_putc, "1:+ 2:0.1 3:0.01\n");                                     
 delay_ms(250);                                                               
}                                                                             
                                                                             
////////////////////////////////////////////////////////////////////////////////
//                      Función principal del programa                             //
////////////////////////////////////////////////////////////////////////////////
//                                                                                               //
////////////////////////////////////////////////////////////////////////////////
//                      Inicialización del programa                                   //
////////////////////////////////////////////////////////////////////////////////
                                                                             
void main() {                                                                 
                                                                             
   setup_adc_ports(all_analog);                                               
   setup_adc(ADC_CLOCK_INTERNAL);                                             
   lcd_init();                                                               
   printf(lcd_putc, "   BENVINGUTS\n");                                       
   delay_ms(2000);                                                             
   printf(lcd_putc, "\f");                                                                                       
   printf(lcd_putc, "   GAUSSIMETRE\n");                                     
   printf(lcd_putc, "     DIGITAL");                                         
   delay_ms(2000);                                                           
   inici:                                                                     
   printf(lcd_putc, "\f");                                                   
                                                                             
  for (;;)                                                                   
  {                                                                           
  menu1();                                                                                       
                                                                             
///////////////////////////////////////////////////////////////////////////////
//                      Programa para la  medida                                  //
////////////////////////////////////////////////////////////////////////////////
      if(input(pin_c0)==0)                                                   
         {                                                                   
         while (input(pin_c0)==0)                                             
            {                                                                 
            menu1();                                                                                 
            }                                                                 
           while (input(pin_c3)==1)                                           
               {                                                                             
               set_adc_channel(0);                                           
               valor=read_adc();                                             
               delay_ms(20);                                                 
               set_adc_channel(1);                                           
               b=read_adc();                                                 
               delay_ms(20);                                                 
               b=2.0*b/1024.0;                                               
               valor=(5.0*valor/1024.0);                                     
                                                                             
                  if (input(pin_c4)==1)                                       
                     {                                                       
                     if (unitat==1)                                           
                        {                                                     
                        valor=((G*200.0*valor)-(b*500));                     
                        printf(lcd_putc, "\f  %04.2f Gauss", valor);         
                        ant4();                                               
                        delay_ms(250);                                       
                        }                                                     
                     else if (unitat==3)                                     
                        {                                                     
                        printf(lcd_putc, "\f   %01.2f Volts", valor);         
                        ant4();                                               
                        delay_ms(250);                                       
                        }                                                     
                     else if (unitat==2)                                     
                        {                                                     
                        valor=((G*200.0*valor)-(b*500));                         
                        valor=valor*0.1;                                     
                        printf(lcd_putc, "\f  %04.2f mTeslas", valor);       
                        ant4();                                               
                        delay_ms(250);                                       
                        }                                                     
                     }                                                       
                  else if (input(pin_c4)==0)                                 
                     {                                                       
                     if(unitat==1)                                           
                        {                                                     
                        valor=((G*1000.0*valor)-(b*2500.0));                 
                        printf(lcd_putc, "\f  %04.2f Gauss", valor);                                                                             
                        ant4();                                                 
                        delay_ms(250);                                       
                        }                                                     
                     else if (unitat==3)                                     
                        {                                                     
                        printf(lcd_putc, "\f   %01.2f Volts", valor);         
                        ant4();                                               
                        delay_ms(250);                                       
                        }                                                     
                     else if (unitat==2)                                     
                        {                                                     
                        valor=((G*1000.0*valor)-(b*2500.0));                 
                        valor=valor*0.1;                                     
                        printf(lcd_putc, "\f  %04.2f mTeslas", valor);       
                        ant4();                                               
                        delay_ms(250);                                       
                        }                                                     
                     }                                                       
               }                                                             
      goto inici;                                                             
         }                                                                   
                                                                             
///////////////////////////////////////////////////////////////////////////////
//                   Programa para el cambio de unidades                      //
////////////////////////////////////////////////////////////////////////////////
      if(input(pin_c1)==0)                                                   
         {                                                                   
         while (input(pin_c1)==0)                                             
            {                                                                 
            menu1();                                                         
            }                                                                 
         printf(lcd_putc, "\f");                                               
            for(;;)                                                           
               {                                                             
               menu2();                                                       
                  if(input(pin_c0)==0)                                       
                     {                                                             
                       while (input(pin_c0)==0)                               
                        {                                                     
                        menu2();                                             
                        }                                                     
                                                                             
                     printf(lcd_putc, "\f");                                 
                     unitat=1;                                               
                     printf(lcd_putc, "  MESURA GAUSS\n");                   
                     delay_ms(1000);                                         
                     goto inici;                                             
                     }                                                       
                  if(input(pin_c1)==0)                                       
                     {                                                       
                     while (input(pin_c1)==0)                                 
                        {                                                     
                        menu2();                                             
                        }                                                     
                     printf(lcd_putc, "\f");                                 
                     unitat=2;                                               
                     printf(lcd_putc, "  MESURA TESLAS\n");                   
                     delay_ms(1000);                                         
                     goto inici;                                             
                     }                                                       
                  if(input(pin_c2)==0)                                       
                     {                                                       
                     while (input(pin_c2)==0)                                 
                        {                                                     
                        menu2();                                             
                        }                                                     
                     printf(lcd_putc, "\f");                                 
                     unitat=3;                                               
                     printf(lcd_putc, "  MESURA VOLTS\n");                   
                     delay_ms(1000);                                           
                     goto inici;                                             
                     }                                                       
                  if(input(pin_c3)==0)                                       
                     {                                                       
                     goto inici;                                             
                     }                                                       
               }                                                             
         }                                                                   
                                                                             
///////////////////////////////////////////////////////////////////////////////
//                   Programa para la variación de la ganancia                //
////////////////////////////////////////////////////////////////////////////////
      if(input(pin_c2)==0)                                                   
         {                                                                   
         while (input(pin_c2)==0)                                             
                  {                                                           
                  menu1();                                                   
                  }                                                           
         printf(lcd_putc, "\f");                                             
          for(;;)                                                             
            {                                                                 
            menu3();                                                         
            if(input(pin_c0)==0)                                             
               {                                                             
               while (input(pin_c0)==0)                                       
                  {                                                           
                  menu3();                                                   
                  }                                                           
               tornar:                                                       
               printf(lcd_putc, "\f");                                       
                  if(n==0)                                                   
                  {                                                           
                     for(;;)                                                 
                     {                                                       
                     mes();                                                   
                        if (input(pin_c0)==0)                                 
                        {                                                     
                           while (input(pin_c0)==0)                           
                           {                                                 
                           mes();                                             
                           }                                                 
                        n=1;                                                 
                        goto tornar;                                         
                        }                                                     
                        else if (input(pin_c1)==0)                           
                        {                                                     
                           while (input(pin_c1)==0)                           
                           {                                                 
                           mes();                                             
                           }                                                 
                        G=G+0.1;                                             
                        goto tornar;                                         
                        }                                                     
                        else if (input(pin_c2)==0)                           
                        {                                                     
                           while (input(pin_c2)==0)                           
                           {                                                 
                           mes();                                             
                           }                                                 
                        G=G+0.01;                                             
                        goto tornar;                                         
                        }                                                     
                        else if (input(pin_c3)==0)                           
                        {                                                     
                           while (input(pin_c3)==0)                           
                           {                                                 
                           mes();                                             
                           }                                                 
                        goto inici;      &n
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: MGLSOFT en 23 de Enero de 2013, 08:26:50
Me parece (confirmarlo antes) que All_Analogs ()  habilita las dos Referencias también, es decir, que en ref+ deberías conectarle 5V y en ref- deberías conectarle gnd.
Ese puede ser tu problema...
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: AngelGris en 23 de Enero de 2013, 10:03:20
  Yo creo que All_ANALOG dejaba todos como entradas analógicas pero utilizaba las referencias internas. He visto que cuando hace la selección de canal no espera el tiempo prudencial para hacer la lectura. Tal vez sea ese el error.

  En su código veo esto....

Código: C
  1. set_adc_channel(0);                                            
  2. valor=read_adc();                                              
  3. delay_ms(20);                                                  
  4. set_adc_channel(1);                                            
  5. b=read_adc();

  Y la espera debería estar entre la selección del canal "set_adc_channel(xxxx)" y la lecutra "x=read_adc()"
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: alraid en 23 de Enero de 2013, 11:04:35
MGLSOFT, probaré en vez de activar todas las entradas analógicas con All_analog() probaré sólo activar la entrada analógica de RA0 y RA1 que son las únicas que necesito. También aumentaré el tiempo que te refieres AngelGris, pondré delay_ms(100);

Lo pruebo y os cuento
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: AngelGris en 23 de Enero de 2013, 11:54:08
No pasa por aumentar el tiempo que ya tienes puesto, sino por cambiarlo de lugar. La idea es que sea assí...

Código: C
  1. set_adc_channel(0);
  2. delay_ms(2);
  3. variable = read_adc();
  4. set_adc_channel(1);
  5. delay_ms(2);
  6. variable = read_adc();
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: MGLSOFT en 23 de Enero de 2013, 12:02:17
Es para darle tiempo de estabilización al canal analógico elegido...
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: RALF2 en 23 de Enero de 2013, 13:12:11
Ves alraid un pequeño problema de tiempos por eso era necesario que colocoaras el programa.
Haz como dice AngelGris y de seguro resuelves el 1er problema, te queda luego el del op amp  :D

Saludos
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: alraid en 25 de Enero de 2013, 07:55:31
Señores, problema solucionado. cambiando la configuración analógica de All_analogs() por la configuración setup_adc(AN0_AN1_VREF_VREF) o setup_adc(AN0_AN1_AN3) (lo he probado con las dos configuraciones) ya me abarca todo el rango que tiene que abarcar el PIC. Por lo que supongo que era problema de la configuración analógica o de las referencias que cogía con esta configuración.

Muchas gracias a todos, quizas no me habéis ayudado directamente con el problema pero con vuestros comentarios me habéis ayudado a "rodear" el problema y localizarlo. Finalmente el problema no era la etapa amplificadora sino problema de programa. Gracias a todos.

Cuando lo tenga definitivamente acabado preguntaré al tutor si puedo colgarlo en el foro de proyectos para enseñarlo. Lo tengo que preguntar porque como es un proyecto para la universidad en que he tenido que firmar un papel que no haya problemas de confidencialidad.

Gracias de nuevo soys unos cracs
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: MGLSOFT en 25 de Enero de 2013, 08:08:27
Me alegro que pudieras solucionarlo.
Deberías ponerle al tema (Solucionado) en el nombre del POST, así saben que ya hubo solución...
Título: Re: problema de rango de voltage en convertidor ADC
Publicado por: KALLITOS en 25 de Enero de 2013, 14:01:34
Verifica en el seteo del micro y los pines de voltaje de referencia.
por alli podria estar el problema.

saludos.

Hay que leer todas los aportes  ;-), que bueno que encontraras la solución.