# Duda: ADC a 10 bits con Pic18f4550 trabajando a 48MHz



## Jesus Medina (Ago 24, 2011)

Primero que todo, hola a todos en el foro, y gracias en especial a Moyano y Meta que por lo que veo son muy activos y han apoyado a muchos por aquí y a mi también porque he aprendido bastante leyéndolos.

Les cuento que gracias a lo que he leido por aquí y en otros foros ya pude hacer una aplicación sencilla para comunicarme por usb con el pic18F4550 y Matlab, también lo intenté recientemente con VC#2008  y 2010 express, sin embargo con estos no he tenido éxito aún.

Bueno ahora les comento mi duda y agradezco de antemano su apoyo:
Actualmente en un pequeño proyecto quiero recibir la señal analógica proveniente de un sensor laser (mide distancia) en el pic18F4550 y la envío a la pc para graficar los datos. El problema está en los datos analógicos que recibo, varían bastante aunque el sensor permanezca fijo. Probé en lugar del sensor con un potenciómetro para simular la señal analógica y aún así aunque no gire la perilla del potenciómetro la señal oscila mucho (por ejemplo para un valor alrededor de 750 los valores parecen ir + - 5, cambiando constantemente). 
Me interesa que la señal analógica sea estable para que la gráfica que obtenga represente con mayor precisión las distancias.
Lo que les pido es que me digan por favor si estoy configurando mal el ADC por el asunto del tiempo de adquisición. Acá les dejo el programa con el que leo dos señales analógicas y otras dos digitales, el programa está en CCS.


```
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN,MCLR
#device ADC=10    //ADC a 10 bits
#define ADC_ADFM_RIGHT 0x80 // esto lo tomé de este Foro (vean la pág 17)
#define ADC_ACQT_20TAD 0x38 // esto lo tomé de este Foro (vean la pág 17)

#use delay(clock=48000000)
#define LCD_DATA_PORT getenv("SFR:PORTB")
#include <lcd.c>                        
#define USB_HID_DEVICE     FALSE         
#define USB_EP1_TX_ENABLE  USB_ENABLE_BULK    
#define USB_EP1_RX_ENABLE  USB_ENABLE_BULK    
#define USB_EP1_TX_SIZE    10               
#define USB_EP1_RX_SIZE    10               

#include <pic18_usb.h>             
#include "usb_desc_scope.h"      
#include <usb.c>                    

int8 dato[10];
unsigned int16 entrada;

void main(void) {

   lcd_init();    
   usb_init();   
   usb_task(); 
   usb_wait_for_enumeration();    

   TRISA  = 0x0F;                               // Se declara el puerto A0, A1, A2, A3 como entradas
   
   setup_adc_ports(AN0_TO_AN1|VSS_VDD);     
   setup_adc(ADC_CLOCK_DIV_64 || ADC_ACQT_20TAD || ADC_ADFM_RIGHT );

     
   while (TRUE)
   {
      if(usb_enumerated())                      // si el Pic está configurado via USB
      {
         if (usb_kbhit(1))                      // si el endpoint de salida contiene datos del host
         {
            usb_get_packet(1, dato, 10);        // Se recibe el paquete del EP1
            
            if (dato[6]==1){
               output_high(PIN_A4);
               lcd_gotoxy(1,2);              
               printf(lcd_putc,"mot ON ");}    
            else{
               output_low(PIN_A4);
               lcd_gotoxy(1,2);              
               printf(lcd_putc,"mot OFF");}    
            if (dato[7]==1){
               output_high(PIN_A5);
               lcd_gotoxy(9,2);              
               printf(lcd_putc,"luz ON ");}    
            else{
               output_low(PIN_A5);
               lcd_gotoxy(9,2);              
               printf(lcd_putc,"luz OFF");}    
         }
         set_adc_channel(0);                
         delay_us(20);
         entrada=read_adc();
         dato[0]= make8(entrada,0);
         dato[1]= make8(entrada,1);         
         lcd_gotoxy(1,1);  
         printf(lcd_putc,"CH0:%4lu",entrada); 
         
         set_adc_channel(1);           
         delay_us(20);
         entrada=read_adc();
         dato[2]= make8(entrada,0);
         dato[3]= make8(entrada,1);
         lcd_gotoxy(9,1);    
         printf(lcd_putc,"CH1:%4lu",entrada);    
         
         if (input(PIN_A2)==0)          
            dato[4]=1;                     
         else                                 
            dato[4]=0;
         
         if (input(PIN_A3)==1)          
            dato[5]=1;                     
         else                                 
            dato[5]=0;        
         
         usb_put_packet(1, dato, 10, USB_DTS_TOGGLE); // Se envía el paquete del EP1 al PC
                  
       }
    }
}
```


Nuevamente muchas gracias a todos y sigan adelante con este foro, porque está buenísimo.


----------



## cosmefulanito04 (Ago 26, 2011)

Es normal esa variacion, fijate que mientras mayor sea la resolucion de tu ADC, mas va a bailar el valor que lea.

Por ej. si tenes 5V de tension de referencia => 5V/1024niveles=4mv/nivel (aprox.)

Si no tenes una buena proteccion contra ruidos, vas a tener ese problema.

Una solucion por soft sencilla, seria la de hacer un filtro pasa bajos usando promedios moviles, mientras mas muestras hagas mas estable sera la medicion, pero mas lenta sera la reaccion.


----------



## R-Mario (Ago 26, 2011)

A mi me funciono eso de sacar varias muestras y promediar, pero si se vuelve mucho mas lento y tarda en responder a los cambios brusco, y si quieres que el sistema responda rapido, entonces eso del promediado no sirve, estas trabajando a moustrosos 48Mhz posiblemente el pic genere mucho ruido, en los avr hay una opcion de detener el oscilador "entrar en modo Idle" momentaneamente mientras se realiza una conversion, esto minimiza al maximo el ruido, y bueno todas las demas chacharas relacionadas a los ADC como los filtros pasa bajas, conexiones estrella, conectar lo mas cerca posible, toma en cuenta que 10 bits por aprox sucesivas a 48 Mhz es mucho para un micro que no es su funcion principal, podrias probar a usar un adc externo de calidad, de la programacion siento no ayudar hace rato que no regreso con los pics


----------



## Jesus Medina (Ago 27, 2011)

Estimados Cosmefulanito04 y Dseda86, muchas gracias por responder a mi pregunta. Les cuento que he seguido con las pruebas y es verdad, la variación sigue presente. Lo que pasa es que no había trabajado con ADC a 10 bits, solo a 8 bits y por eso no pensé que se notara mucho la variación de voltaje.
En este proyectito me interesa mucho la resolución, ya que el sensor laser que estoy probando tiene una resolución de 10mV/mm de distancia. con el ADC a 8 bits  me falta precisión y con el ADC a 10 bits estoy bien porque la resolución 1 bit equivale aproxidamente a 4.8mV y por lo tanto es esta forma si sería capaz de saber la variación de distancia por milímetro.
La idea que me dan sobre promediar valores está muy buena, se me había ocurrido ya pero ahora que ustedes dos lo mencionan parece ser que es una práctica común hacer esto. Bueno, lo que me interesa mucho más es probar con la otra idea que me dio cada uno de ustedes, por un lado eso de hacer una protección contra ruidos y la otra de utilizar un buen conversor ADC externo. Les comento que mi perfil es más de ingeniería mecánica así que no tengo idea de como se haría un filtro para disminuir el ruido de la señal analógica antes de que entre al microcontrolador, así que agradeceré mucho su ayuda con alguna idea para esto. También les pido por favor que me orienten sobre un buen conversor ADC externo porque no he usado ninguno. Tengo un libro de microntroladores de Palacios, Remiro y López de la editorial RA-MA donde hablan sobre el convertidor ADC PFC8591, ¿es buen convertidor o me siguieren otro?
De antemano gracias y un saludo.


----------



## R-Mario (Ago 27, 2011)

Puff convertidores hay un "titipuchal" jejej pero seria bueno que empezaras en Analog Device, son de los mejores fabricando conversores, hay nomas date una vuelta para que veas, puedes buscarlos por caracteristicas, http://www.analog.com/en/analog-to-digital-converters/products/index.html

De lo del filtro, por ejemplo en el PIC trae una patita que debe decir  Avdd ahi se conecta la tension de alimentacion del convertidor y generalmente se conecta un capacitor hacia tierra y una bobina desde Vcc, busca sobre filtros LC, y para la entrada analogica la que vienen desde el transductor, no se las cualidades de transductor pero prueba a utilizar un amplificador operacional con ganancia unitaria "probablemente la entrada analogica del PIC carga mucho la salida del transductor, por eso la variacion" , ya sabes aumentamos la corriente pero mantenemos el mismo voltaje, si esto va a  ser algo semi o profesional, busca sobre amplificadores operacionale como por ejemplo los INA101 etc,


----------



## cosmefulanito04 (Ago 27, 2011)

Antes de cambiar el ADC, tene en cuenta esto:

- Tu ADC tiene mayor resolucion que tu sensor, osea que el bit menos significativo (LBS) puede valer cualquier cosa, osea que tu lectura deberia empezar con el 2 bit menos significativo.

- ¿Es necesario trabajar a 48MHz? a mayor frecuencia de trabajo mas ruido generas, con lo cual deberias tratar de trabajar con la menor frecuencia posible sin afectar tus mediciones. ¿Cual el tiempo maximo entre medicion y medicion?

Por otro lado, seguramente el ADC no trabaje a 48MHz, sino que el core del PIC lo haga a esa frecuencia y los puertos y demas perifericos lo hagan a una fraccion de esa frecuencia.

- ¿Con que tension de fuente estas trabajando?, a mayor tension tambien mayor sera el rango de inmunidad de ruido, osea un uC que trabaje con 3,3v sera mas propenso a ruidos que otro que trabaje a 5v. Algunos uC como los Atmega te permiten trabajar con un amplio rango de tensiones, deberias fijarte que dice la hoja de datos de tu uC.

- ¿Colocaste los capacitores de desacople? el uC deberia tener bien cerca un capacitor que vaya de Vcc a GND y como dijieron arriba el propio ADC tambien debe tener su propio capacitor.

Esas son las cosas que deberias verificar antes de cambiar tu ADC, hace mas incapie en el tema de los capacitores y las frecuencias de trabajo, por ultimo tene en cuenta que el LSB puede tomar cualquier valor ya que tu sensor tiene una menor resolucion.


----------



## Jesus Medina (Ago 27, 2011)

Pues nuevamente muchas gracias a ustedes Dseda86 y cosmefulanito04, son muy amables por ayudarme con tanta información, voy a leer atentamente la información que amablemente me proporcionaste Dseda86 y también buscaré lo que me comentas de los filtros LC.
Lo que me comentas cosmefulanito04, sobre considerar el segundo bit como el menos significativo me parece una idea excelente, muy lógica, haré las mediciones y veré si considerando esto obtengo una buena correlación entre los valores del adc y la distancia medida. Sobre la alimentación del Pic te comento que esta a 5V, sí puse al menos un capacitor de desacoplo en la alimentación del pic (el cap es de 100nF, ¿esta bien o necesito más capacitancia?), pero no puse ninguna en el adc, ¿cómo hago esto?, es decir, el sensor es de tipo industrial y recibe una alimentación de 24VCD a partir de una fuente dedicada sólo para eso y está configurado para que la salida analógica sea voltaje el cual varía de 0 a 10V, como voy a leer distancias menores a 3m el voltaje máximo que leerá el adc es de 3V y así no supera los 5V con los que trabaja el pic.
Seguiré intentando con las ideas e información que me dieron, les comentaré después mis avances, saludos.


----------



## YORDYTO (May 17, 2012)

parcero ya hice que me reconociera mi tarjeta de adquisición de datos como usb , pero no he podido comunicarla con el matlab ,no se como hacer para conectar las dos, le agradecería si me adjuntara pantallazos , o me escribiera o subiera un video de como hacerlo


----------



## fernandotapia (Oct 31, 2012)

Que tal amigos perdonen que me meta en sus conversaciones pero keria preguntarle a Ajna como hacer para sacar un cierto numero de muestras una conversion AD y despues promediarlas. Sucede que estoy haciendo una bascula con un 18f4550 pero a la hora de la conversion y mostrarla en una LCD es muy inestable y mi margen de error no puede ser tan alto. Se realizar y he hecho para otros proyectos una ADC pero nunca he hecho esto de sacar un promedio de las muestras. 

Te agradeceria que me orientaras un poco compañero xq no he encontrado info en la web sobre esto y soy relativamente nuevo programando, me gusta mucho pero esto me urge para un proyecto proximo a entregar. Muchas gracias por tus comentarios y sugerencias. Por cierto mi programa es en CCS.


----------



## foso (Oct 31, 2012)

Los conversores A/D de aproximaciones sucesivas no son los mas precisos. Si querés precisión, ni lo dudes --------> Sigma-Delta. 

Ahora si queres aprovechar el conversor del microcontrolador te recomiendo algunas cosas:

1) Filtro pasa-bajo o pasa-banda analógico apropiado que deje pasar la señal de interés.

2) Lo más cercano que puedas a la entrada analógica del microcontrolador poner un pasa-bajos de 1 polo (resistor-capacitor) sintonizado a algunos MHz ( ej: 1MHz o 3MHz). Esto es para filtrar ondas de radio.

3) Si la aplicación lo permite, mientras esté muestreando el ADC del microcontrolador deja el CPU en modo SLEEP (bajo consumo) y si es posible sin sacar señales por ninguno de los pines ( ej: PWMs son las mas ruidosas).

4) Si la aplicación lo permite y el CPU trabaja a suficiente velocidad hacer filtrado digital. Lo más sencillo es tomar cierta cantidad de muestras y promediar.


----------



## fernandotapia (Nov 1, 2012)

Muchas gracias por tu comentario amigo foso, mira el filtro ya lo tengo contemplado solo q*ue* aun no lo implemento ya que no cuento con un osciloscopio para determinar la frecuencia de corte. Ahora, el circuito *qu*edara expuesto a motores trifasicos y eso me preocupa por el ruido, que frecuencia me recomendarías manejar sabiendo que *e*stare manejando mV (máximo hasta 24  mV)a la entrada del filtro. Yo había contemplado un filtro paso bajos de segundo orden. 

En cuanto a la salida de los pines necesito sacar dos señales del puerto B, pero son digitales, no necesito un PWM. Sin embargo esas señales dependen de la conversión ADC, crees que el pic las pueda procesar bien? trabajo a 4Mz.

Por ultimo, y como les comente, no tengo mucha idea de como haces una conversión que tome cierto numero de muestras y que después las promedie, tendrás algún código que me puedas mostrar para darme una idea por favor?

De nuevo muchas gracias compañero.


----------



## Chico3001 (Nov 1, 2012)

La promediacion es simple

1.- Asignas un area en memoria para guardar tus datos,y que sea en multiplos de 2 (2, 4, 8, 16 localidades etc)
2.- Tomas las x lecturas necesarias para llenar tu tabla
3.- Sumas todas las lecturas y finalmente recorres a la izquierda el resultado para hacer la division. Si tu tabla fue de 2 localidades recorres una vez, si fue de 4 recorres 2 veces y asi sucesivamente
4.- Tienes 2 opciones: volver a llenar la tabla desde el inicio y repetir desde el punto 2, o asignar punteros e ir actualizando los valores mas viejos de la tabla con nuevas lecturas, este ultimo metodo es mas rapido a la hora de tomar lecturas por que no tienes que esperar las x conversiones de nuevo, pero requiere mas programacion para mantener los punteros alineados y que no se salgan de la tabla


----------



## foso (Nov 1, 2012)

fernandotapia dijo:


> Muchas gracias por tu comentario amigo foso, mira el filtro ya lo tengo contemplado solo q*ue* aun no lo implemento ya que no cuento con un osciloscopio para determinar la frecuencia de corte. Ahora, el circuito *qu*edara expuesto a motores trifasicos y eso me preocupa por el ruido, que frecuencia me recomendarías manejar sabiendo que *e*stare manejando mV (máximo hasta 24  mV)a la entrada del filtro. Yo había contemplado un filtro paso bajos de segundo orden.
> 
> En cuanto a la salida de los pines necesito sacar dos señales del puerto B, pero son digitales, no necesito un PWM. Sin embargo esas señales dependen de la conversión ADC, crees que el pic las pueda procesar bien? trabajo a 4Mz.
> 
> ...



Preguntas que frecuencias recomiendo manejar ??? eso depende de tu señal. ¿Qué frecuencia tiene la señal que vas a medir? o es continua ?? Si estás en el orden de 24 mV te recomiendo amplificar un poco.

El promedio lo tenés que hacer vos. No lo hace automático el ADC. Simplemente tomas varias muestras guardando su valor en memoria y luego hacés un promedio. O sea, tomas una muestra y la guardas en memoria, tomas la segunda muestra y la guardas en otra posicion de memoria, etc. Luego haces promedio. Tenés que tener en cuenta que en el período que tomas estas muestras tu señal no varíe mucho.


----------

