Voltímetro con el ADC del PIC

Estado
Cerrado para nuevas respuestas.
RA0_RA1_ANALOG ya no se acepta en el compilador, o si se acepta es solo para compatibilidad.

Adjunto acá las definiciones correctas del propio compilador, encontradas en "16F877A.h", línea 258:
Código:
#define NO_ANALOGS                           7    // None
#define ALL_ANALOG                           0    // A0 A1 A2 A3 A5 E0 E1 E2 
#define AN0_AN1_AN2_AN4_AN5_AN6_AN7_VSS_VREF 1    // A0 A1 A2 A5 E0 E1 E2 VRefh=A3     
#define AN0_AN1_AN2_AN3_AN4                  2    // A0 A1 A2 A3 A5          
#define AN0_AN1_AN2_AN4_VSS_VREF             3    // A0 A1 A2 A4 VRefh=A3              
#define AN0_AN1_AN3                          4    // A0 A1 A3
#define AN0_AN1_VSS_VREF                     5    // A0 A1 VRefh=A3
#define AN0_AN1_AN4_AN5_AN6_AN7_VREF_VREF 0x08    // A0 A1 A5 E0 E1 E2 VRefh=A3 VRefl=A2     
#define AN0_AN1_AN2_AN3_AN4_AN5           0x09    // A0 A1 A2 A3 A5 E0        
#define AN0_AN1_AN2_AN4_AN5_VSS_VREF      0x0A    // A0 A1 A2 A5 E0 VRefh=A3           
#define AN0_AN1_AN4_AN5_VREF_VREF         0x0B    // A0 A1 A5 E0 VRefh=A3 VRefl=A2           
#define AN0_AN1_AN4_VREF_VREF             0x0C    // A0 A1 A4 VRefh=A3 VRefl=A2              
#define AN0_AN1_VREF_VREF                 0x0D    // A0 A1 VRefh=A3 VRefl=A2
#define AN0                               0x0E    // A0
#define AN0_VREF_VREF                     0x0F    // A0 VRefh=A3 VRefl=A2
 
ok man gracias pucha que esta informacion es valiosa y es siempre bueno contar con un foro tan buena onda con este.gracias

pero como haria la poner en setup_adc_ports(AN0_AN1);
set_adc_channel(0);
set_adc_channel(1);
i cimo lo hariap ta que pueda reconocer las entradas analogicas
 
Última edición por un moderador:
Este pic permite solamente 1 o 3 entradas al mismo tiempo, así que creo que la que te vendría mejor sería AN0_AN1_AN3, que te va a permitir usar AN0 y AN1, aunque te va a habilitar también AN3.

Con respecto a la lectura, es simple:

setup_adc_ports(); -> Configura el/los puertos análogos a utilizar.
setup_adc(); -> Configura la velocidad de muestreo, en base a la velocidad del cristal elegida.

Estas dos funciones son llamadas, normalmente, una sola vez al principio del código.

Después están las siguientes:

set_adc_channel(); -> Elije el canal análogo a leer; En caso de usar AN0, AN1 y AN3, los canales serían 0, 1 y 3.
read_adc(); -> Lee un valor análogo del canal elegido anteriormente.

Estas últimas dos se usan cada vez que se quiera leer un valor análogo o cambiar el canal a leer; pero hay que tener en cuenta que la lectura análoga o el cambio de canal requiere un tiempo, por lo tanto, si se van a registrar lecturas seguidas se debe poner un delay entre lectura y lectura de unos 20uS, y entre cambio de canal y lectura de unos 100uS (que alguien me corrija si el tiempo que elegí no es correcto).

De modo que si quisiera leer 500 valores del puerto análogo, sería así:
Código:
   set_adc_channel(0);
   delay_us(100);
   for(i=0;i<500;i++)
   {
      temporal = read_adc();
      delay_us(20);
   }
 
gracias estuve un poco ocupado estos dias hasta ayer que me desocupe y pude recien revisar mi proyecto hice las modificaciones que indicaste y si logre hacer que funcione mas la otra entrada analogica pra hacer que este voltimetro pueda trabajar en una fuente simetrica y quiesiera hacer hacer mas un amperimetro dc para no desperdiciar la an3.como es que lo hacia tendria que conseguir un trandustor de corriente a a voltaje o hay alguna otra forma de hacer lo posible.

y si no fuese asi tendria que mandar a tierra an3 y no es nesesario gtacias por las respuestas que pudieran dar
 
Para el amperímetro tendrías que poner una resistencia de bajo valor (cuanto más bajo mejor), en serie con la salida de la fuente y medir la caída de tensión en esa resistencia, luego con ley de Ohm calculas la corriente que circula por esa resistencia, que, al estar en serie, va a ser igual a la corriente total que circula por el circuito. Tenes que tener en cuenta que si la fuente es de 3A por esa resistencia podrían llegar a circular 3A y si es de 10A, van a circular 10A, por ende, tiene que ser una resistencia de potencia. En cuanto al valor, cuanto más bajo mejor va a ser, una resistencia de 0,1 ohm, o 0,01 ohm va a andar bien, tendrías que ver la caída de tensión generada y la resolución del ADC del pic.
Ejemplo: Si la resistencia es de 0,1 ohm, y la corriente máxima de la fuente es de 3A, tendrías que poner una resistencia de 1W para que no se queme, y tener en cuenta que el PIC tendría que leer una tensión comprendida entre 0 y 0,3V (o poner un amplificador operacional y aumentarla para tener una mejor resolución).
 
ok man gracia voy a hacer las cosas que me recomiendas. una cosa mas man al mometo de poner el voltimetro uso eltransformador de la fuente simetrica todo va vine con la parte positiva pero cuando conecto la parte negativa medir el lcd se pone cono en cuadro y la razon es que estoy poniendo los 2 terminales del voltimetro a tierra como haria para usar solamente el transformador de la fuente simewtrica o nesesariamente tendria que construir transformador solo para el voltimetro gracias por las respuestas que me puieran dar.
 
No se si entendí bien, pero, primero que nada, el PIC solamente mide tensiones positivas con respecto a su GND, por lo tanto, si queres medir una tensión negativa, primero vas a tener que hacerla positiva y después medirla con el PIC. Segundo, si medis directamente desde el transformador, vas a tener media señal senoidal, dado que vas a obtener el semiciclo positivo de la señal y el otro lo vas a perder; tendrías que rectificarla antes y con respecto a la alimentación del micro, tienen que ser 5V de corriente continua. Volviendo al primer punto, las mediciones que el PIC haga, van a depender de su GND.

En caso de querer usar una referencia de tensión diferente a <+5V - GND>, tendrías que usar otra configuración del ADC, como por ejemplo: AN0_AN1_AN4_VREF_VREF que configura A0, A1 y A4 como entradas análogas, A3 como referencia de tensión positiva y A2 como referencia de tensión negativa (Ver mensaje #41), y de esta manera podés modificar la resolución o la polaridad del ADC (ver características eléctricas del micro en su datasheet). Te recomiendo no superar la tensión de alimentación en los pines de referencia para no quemar el micro.
 
Brother podrías explicarme un poco mas del voltaje de referencia?
creo es lo único que no me queda, ahora ya que intente usar una fuente externa para alimentar solo el voltímetro y medir la tensión negativa en mi fuente simétrica y no dio buenos resultados. Ah una cosa más, ¿como puedo hacer que la lectura del pic sea mas estable? cuando pongo por ejemplo una batería de 9v el voltímetro oscila de 8.77v a 9.21v, no se queda en un valor fijo, ¿debería de aumentar el tiempo de lectura o que debería de hacer?
 
Última edición por un moderador:
Bueno, primero partamos de una base: El pic puede leer una tensión que oscile entre la tensión de alimentación negativa (0V) y la tensión de alimentación positiva (comúnmente, 5V). Obteniendo como respuesta un valor comprendido entre 0 y 255 para el ADC de 8 bits, y entre 0 y 1023 para el ADC de 10 bits, proporcional a la tensión medida.

El voltaje de referencia sirve para obtener una resolución mayor cuando se lee una tensión que tiene una variación menos brusca que [VCC - GND (comúnmente, 5V)]. Por ejemplo: Si tenemos un sensor que emite una tensión, proporcional a la medición, que está entre los 0,5V y los 2V, se puede bajar la tensión de referencia al mínimo (2,5V según la hoja de datos), para que los "pasos" sean más chicos y el mismo tenga más precisión.

Con respecto a la variación del ADC, es muy probablemente debido al ruido, podrías probar poniendo una resistencia en PULL-DOWN y ver si la medición se estabiliza, o sino realizar un promedio de mediciones; por ejemplo: se toman 100 mediciones en un segundo, se las suma, luego se las divide por 100 y el valor obtenido debe ser la tensión medida.
 
Hola manes, no entiendo eso de resistencia PULL-DOWN es distinto de las resistencias PULL-UP y como haría para hacer el promedio que dices



ya hice la modificación a mi proyecto y le puse el amplificador inversor para hacer la medición y funciona pero ahora como hago para que pueda visualizar la medida del amperímetro aquí pongo algunas fotos del proyecto



aquí pongo el código del proyecto y podrían decirme como hago para las tiempos de lectura y cambio de canal en en adc del pic
Código:
while (true)
   {
   //
   //medida de la entrada positiva
   set_adc_channel(0);
   valor = read_adc();
   delay_us(50);
   voltaje=(valor*50/930);
   lcd_gotoxy(1,1);
   printf(lcd_putc,"%04.2f P ",voltaje);
   delay_ms(100);
   //
   //medida de la entrada negativa
   set_adc_channel(1);
   val = read_adc();
   delay_us(150);
   volt=(val*5/930);
   lcd_gotoxy(8,1);
   printf(lcd_putc,"%04.2f N ",volt);
   delay_ms(100);
   //
   //medica de corriente de entrada positiva
   set_adc_channel(2);
   valor1 = read_adc();
   delay_us(50);
   voltaje1=(valor*50/930);
   amp1=(voltaje1/0.1)
   lcd_gotoxy(1,2);
   printf(lcd_putc,"%04.2f A ",amp1);
   delay_ms(100);
   //
   //medida de corriente de la entrada negativa
   set_adc_channel(3);
   val1 = read_adc();
   delay_us(50);
   volt1=(val1*50/930);
   amp2=(volt1/0.1)
   lcd_gotoxy(8,2);
   printf(lcd_putc,"%04.2f A ",amp2);
   delay_ms(100);
   }
  
}

aquí están las imágenes del voltímetro en el proteus



como haría par que me para ver en la pantalla del lcd uA, mA, A seria usando el if y else , como mas o menos lo haría alguna ayuda para eso manes que es lo que tendría que aumentar en las instrucciones del pic



y como hago con los tiempos de lectura del canal y del cambio para el otro canal cuanto tiempo mas de retardo tengo que dar por que en proteus aparece mensajes diciéndome que no le da suficiente tiempo para la lectura y cambio de canal sera por eso que oscila la lectura del lcd cuando mido una batería de 9v como dije mas arriba



vi en alguna pagina donde hay un voltímetro ,amperímetro y termómetro que además cuando hay corte el lcd parpadea y aparece en la pantalla ¡CORTE¡ hasta que se soluciones el problema como se pude hacer eso alguien tiene una idea
 

Adjuntos

  • resultados.rar
    375.3 KB · Visitas: 245
  • Dibujo.PNG
    Dibujo.PNG
    13.7 KB · Visitas: 115
  • Dibujo2.PNG
    Dibujo2.PNG
    29.8 KB · Visitas: 223
  • Dibujo3.PNG
    Dibujo3.PNG
    15.2 KB · Visitas: 123
Última edición por un moderador:
Entre cambio de canal y lectura tenes que esperar unos 100uS.
Esto:
Código:
set_adc_channel(3);
val1 = read_adc();

Debería cambiarse por esto:
Código:
set_adc_channel(3);
delay_us(100);
val1 = read_adc();
delay_us(50);

Por supuesto que estos cambios deben realizarse para los 3 canales. En tu caso, yo crearía una función [int LeerCanal(int Canal);] que se ocupe de seleccionar el canal y realizar la lectura, para reducir instrucciones en el programa, y para que la escritura de código sea más veloz.

Código:
int LeerCanal(unsigned int Canal)
{
    if(Canal > 3) //Verificamos que el número de canal sea válido
        return 0;
    set_adc_channel(Canal);
    delay_us(100);
    int a = read_adc();
    delay_us(50);
    return a;
}

Con respecto a lo de "Corte", es sencillo, está vinculado directamente al amperímetro. Un corte se detecta cuando una corriente demasiado alta está circulando por el circuito. Por ende, si en la medición del ADC nos devuelve 3A y nuestro circuito no soporta más que eso, lo que se hace normalmente es reducir la tensión o bloquear el circuito, dado que se llegó al máximo de corriente establecida.

Olvidé agregar sobre mA, uA y A: Es algo medio rebuscado de hacer en un PIC, sobre todo en CCS, dado que la presición decimal de los PIC no es de más de 2 decimales (que alguien me corrija si no estoy en lo correcto), y porque CCS, en mi opinión, tiene bastantes fallas en la parte aritmética (entre otras). De todas formas, tenés dos maneras de realizarlo, la primera es usar directamente la medición del ADC, la cual es un entero de 10 bits (aunque se almacene en una variable de 16 bits), e ir verificando con bloques [if] si es menor a tal valor o si está comprendido entre tal y tal valor.
La segunda opción, es más sencilla de realizar a simple vista, pero está el problema de la precisión. Consiste en pasar el valor a corriente y después realizar la misma verificación con los bloques [if], con la única diferencia que en lugar de verificar un valor que, a simple vista, no parece una corriente, estarías verificando para 1A o menos de 1mA.

* Pull-down: Es una resistencia conectada a masa, cuya función es hacer que la señal nunca quede flotando (alta impedancia), sino que en el caso de que la señal flote, quedaría conectada a masa. En este caso, la resistencia en PULL-DOWN lo que haría es generar una corriente -que circularía desde la fuente de la medición hacia masa- para estabilizar la medición, hay que tener en cuenta que debe ser una resistencia alta para no alterar la medición.
Son iguales que las PULL-UP, solamente que en lugar de estar conectado a VCC van conectadas a GND.
 
Última edición:
estube modificando el codigo del programa e hice que a 1.6A en el lcd apareca alto para el canal 2 esta bien trabaj bien pero para el canal 2 oscila de la lectura a a alto como hago para solucionar eso
ademas quisiera una referencia al poner %04.00f este pude cambiar por %d o %s o %LuB como es que se diferencian de estos al momento de los digitos



mas tarde colgare el cosigo y la simulacion en proteus estoy un poco ocupado estunsian pata mi examen
 
Última edición:
Aquí pongo el código del programa, y no entiendo porque aparece ese problema en el canal 3
Debiera de ser como el canal 2. Alguien que me saque de la duda que estoy haciendo mal
Se inicia la LCD

Código:
lcd_init();
   lcd_gotoxy(4,1);
   lcd_putc("Iniciando");
   delay_ms(2000);
   lcd_gotoxy(3,2);
   lcd_putc("PABLO OJEDA");
   delay_ms(1000);
   lcd_putc("\f");
   lcd_gotoxy(2,1);
   lcd_putc("VOLTIMETRO DC");
   delay_ms(1000);
    lcd_putc("\n");
   lcd_gotoxy(2,2);
   lcd_putc("AMP1      AMP2");
   delay_ms(1000);
   //
   while (true)
   {
   //
   //medida de la entrada positiva
   set_adc_channel(0);
   delay_us(100);
   valor = read_adc();
   delay_us(50);
   voltaje=(valor*50/1024);
   lcd_gotoxy(1,1);
   printf(lcd_putc,"%04.2f P ",voltaje);
   delay_ms(100);
   //
   //medida de la entrada negativa
   set_adc_channel(1);
   delay_us(200);
   val = read_adc();
   delay_us(50);
   volt=(val*50/1024);
   lcd_gotoxy(9,1);
   printf(lcd_putc,"%04.2f N ",volt);
   delay_ms(100);
   //
   //medica de corriente de entrada positiva
   set_adc_channel(2);
   delay_us(300);
   valor1 = read_adc();
   delay_us(50);
   voltaje1=(valor1*5/1024);
   amp1=(voltaje1);
   lcd_gotoxy(2,2);
   if(amp1<=1.6)
   printf(lcd_putc,"%04.2f A ",amp1);
   if(amp1>1.6)
   lcd_gotoxy(1,2);
   printf(lcd_putc," !ALTO! ");
   delay_ms(100);
   //
   //medida de corriente de la entrada negativa
   set_adc_channel(3);
   delay_us(400);
   val1 = read_adc();
   delay_us(50);
   volt1=(val1*5/1024);
   amp2=(volt1);
   lcd_gotoxy(10,2);
   if(amp2<=1.6)
   printf(lcd_putc,"%04.2f A ",amp2);
   if(amp2>1.6)
   lcd_gotoxy(9,2);
   printf(lcd_putc," !ALTO! ");
   delay_ms(100);
}
 }
Aquí pongo la simulación en proteus del voltimetro y otra es la simulacio para los opams que configuracion me recomineda la de amplificador inversor o la no inversora.
Busque el amplificador no inversor tiene problemas con las respuestas en frecuencia, pero la frecuencia siempre va a ser de 60 hz. No creo que tenga problemas, o uso el amplificador inversor para desarrollar el proyecto.
Gracias por las respuestas que puedan brindarme



algo mas alguna información sobre como poner o que significa %f,%o3LBU;%s,%d esto para poner en el código al momento de seleccionar escalas en el amperímetro.
 

Adjuntos

  • sim1.rar
    46.4 KB · Visitas: 195
  • sim 2.rar
    13.8 KB · Visitas: 129
Última edición por un moderador:
broders por fa quiero una opinion de ustedes para terminar mi proyecto solo nesesito eso y lo armo ah sigue oscilando la lectura en el lcd a pesar de poner una esistencia en pull dow o sera por que lo tengo armado aun en el protoboard
 
Bueno, mirá, yo de electrónica sé poco, puedo ayudarte en el tema de la programación, pero creo que si pones un capacitor de bajo valor a la entrada del ADC (en lugar de la resistencia), quizas puedas estabilizar mejor la medición, aunque creo que podría retrasarse un poco la actualización de la medición. Quizás con uno de 100nF (realmente no sabría que valor decirte). Si la medición tiene variaciones muy bruscas, (se considera una variación leve [+5; -5] puntos del ADC), es probable que estés configurando mal el oscilador o que el pin de entrada esté "al aire". En ese caso, o bien se reconfigura el oscilador (del ADC), o bien se verifica la conexión. Cabe destacar que si está conectado a un amplificador operacional, es necesario usar capacitores de estabilización, sobre todo si el operacional esta amplificando una señal de baja amplitud.
 
Muchas gracias MVB, io hice el ajuste necesario para hacerme un voltimetro de 0 - 100Vdc.
Les dejo los archivos para Uds del voltimetro, por si acaso qieren hacerle modificaciones o mejor aun implementar ademas un amperimetro.
El extracto contiene:
- Archivo *.bas del programa
- Archivo *.HEX
- Esquematico en ISIS PROTEUS
Nota: el compilador que estoy usando es el PROTON IDE DEVELOPMENT SUITE. Ademas deben tener instalado el MPLAB, por si quieren hacer nuevas modificaciones.
Gracias.

una pregunta amigo, como puedo hacer para medir un voltaje negativo con el pic? tu voltimetro está muy bueno, sin embargo necesito mostrar el voltaje que da una fuente de cd que arroja desde -36v a -1.2 v y de 1.2 a 36v
espero haberme explicado, muchas gracias :apreton:
 
el voltimetro que estoy haciendo mide tensiones negativas indirectamente uisando opams, igual qe tu lo pienso poner en una fuente simetrica que estoy haciendo, para medir una tension negativa pones un opam en configuracion de amplificador inversor despues de la salida del divisor de tension, teoricamente tendriamos que hacer que la ganacia sea 1 para no afectar la lectura pero hay una caida de tension en el opam por eso hay que usarse potenciometros para regular la ganancia para eso mas puse una simulacion en proteus en el mensaje 53 en el archivo rar que dice sim 2 ahi esta las configuraciones pra las entradas



pero el problema de esto es el ruido que hace variar la lacetura por eso estoy preguntando alguna manera de eliminar esto ya sea poniendo capacitoe en paralelo en las entradas del adc
 
Última edición:
manes creo que la unica solucion que encontre para deje de oscilar el voltimetro es un filtro pasa bajos en la entrada del adc y hacer un promedio de las mediciones el problema es que no se como hacer un promedio de ellas con codigo alguien puede darme una ayudas con esto ya hice el pcb tiendo en cuenta todos los detalles que me pusieron enlos post
 
como hacer un promedio de ellas con codigo alguien puede darme una ayudas con esto ya hice el pcb tiendo en cuenta todos los detalles que me pusieron enlos post

Puedes tomar varios samples (por ejemplo 20) del ADC, sumarlos y al final divides entre 20. El resultado es el promedio. Otra es guardar los samples en una array luego según quieras puedes tomar el de mayor valor o el valor que más se repita, etc.
 
Coincido con ByAxel, sino la otra opción es agregar un capacitor de no muy alto valor en la entrada del ADC (.1uF o parecido), para que derive las variaciones de alta frecuencia a masa. De esta manera vas a tener una menor velocidad de respuesta pero también una menor oscilación. De todas formas coincido en que lo mejor en estos casos es hacer un promedio de 15 o 20 muestras para obtener un valor consistente.
 
Estado
Cerrado para nuevas respuestas.
Atrás
Arriba