Voltímetro con el ADC del PIC

Estado
Cerrado para nuevas respuestas.
Lo que debe quedar claro es que no vas a obtener el valor real en toda la escala y si vas a poder informar sobre esa tensión final.

Y empeorás un poco la calidad de la medición aumentando el error de cuantización en una cuenta.

Por ej es como los multímetros y su fondo de escala, los que tienen por decir algo... 2000 cuentas, solo son capaces de medir hasta 1999 antes de pasar a otra escala, es decir a fondo de escala te informa por ej. 1,999 v.
OK. Ahora si ya me quedó algo más claro lo que mencionas.
Sin embargo, no se nota mucho la variación, sino hasta que se llega al máximo.
Ahí es cuando yo quería ver el mismo voltaje máximo de la lectura.

Realicé unas pruebas en físico y las lecturas obtenidas con el divisor 1024 no fueron cercanas al voltaje de entrada que se estaba midiendo. (Estableciendo un máximo de 10 V.)
Variando el voltaje de entrada, desde 0 a 5 V, el valor más próximo comparando la lectura con un multímetro Fluke, siempre fue con el divisor 1023. :rolleyes:

Anteriormente ya había realizado este tipo de prueba, y por ese motivo siempre me convenció más dividir entre 1023.
Sea o no sea lo adecuado, lo interesante es que el resultado se aproxima más al esperado.

Dejo 4 fotos.
 

Adjuntos

Si te interesa más obtener el valor límite, puedes modificar el cálculo así:

delta = 20 V / 1024; // 2^10 bits del ADC

y luego, en la lectura de los valores:

Vadc = delta * (ADC()+1);

Con esto, al llegar ADC() a 1023, y sumarle 1, permitimos que con delta lleguemos a un valor de Vadc igual al máximo.

Pero... el problema se traslada al 0: nos dará que siempre hay un valor de unos mV.

Hay otras formas de hacerlo, pero según la documentación, estos chip tienen un error de 1/2 LSB (el bit menos significativo). Según la función de transferencia, si el valor de paso es 1 LSb = Vref/1024, el paso a 1023 se produce en el momento que la tensión esté entre el valor de 1023 LSb a 1023.5 LSb.

Eso quiere decir que el valor de 1023, realmente no indica que Vadc ha llegado a Vref, sino al valor anterior. Si Vadc = Vref, sigue mostrando 1023.

Eso quiere decir que el ADC nunca nos dará un valor 1024. Es entonces una convención nuestra el decidir que 1023 realmente indica que hemos llegado a Vref.
 
Última edición:
Lindo multímetro... (y).

Si entendí bien, mediste en todo el rango y siempre daba más cercano usando el factor de 1023, ¿cómo es la tensión de referencia? (tal vez esté un poco desplazada).

como modifico el código para que mida con coma?
¿Cuánto sería el valor máximo que pensas medir?, ¿40V?

Si es así, tenés dos formas:

1- Usar flotantes como venías haciendo y simplemente a la hora de imprimir el resultado se agregan esos dos decimales.

2- Usar "unsigned long int" para trabajar con decimales fijos, entonces solo se modifica esto:

Código:
voltaje = (valor_adc * 40*100) / 1024;
Pero como ahora trabajas con enteros, se puede usar desplazamientos en vez de divisiones y el uC "sufre" menos:

Código:
voltaje = (valor_adc*40*100);
voltaje=(voltaje>>10);
Ese (voltaje>>10) equivale a dividir por 1024, pero al uC le resulta mucho más sencillo hacerlo. Como resultado te quedará un número de este tipo, ej:

valor_adc=100 => voltaje=390 => será equivalente a 3,90v
valor_adc=500 => voltaje=1953 => será equivalente a 19,53v
... etc
 
Última edición:
Si te interesa más obtener el valor límite, puedes modificar el cálculo así:

delta = 20 V / 1024; // 2^10 bits del ADC

y luego, en la lectura de los valores:

Vadc = delta * (ADC()+1);

Con esto, al llegar ADC() a 1023, y sumarle 1, permitimos que con delta lleguemos a un valor de Vadc igual al máximo.

Pero... el problema se traslada al 0: nos dará que siempre hay un valor de unos mV.
Algo similar ocurre con el divisor 1024, también quedan algunos milivoltios en vez del 0.

Si entendí bien, mediste en todo el rango y siempre daba más cercano usando el factor de 1023, ¿cómo es la tensión de referencia? (tal vez esté un poco desplazada).
Utilicé la siguiente configuración:

ADCON1:
Bit 7 ADFM: A/D Conversion Result Format Select bit
1 = Right justified <--- Esta selección.
0 = Left justified

Bit 5 VCFG1: Voltage Reference bit
1 = VREF- pin
0 = VSS <--- Esta selección.

Bit 4 VCFG0: Voltage Reference bit
1 = VREF+ pin
0 = VDD <--- Esta selección.

Entonces viene quedando como VRef = VSS_VDD (Rango: 0V a 5V)
De esta forma en el PIC, no se usan los pines VRef- y VRef+ utilizando me supongo, una referencia interna y quedan disponibles éstos pines como otras entradas análogas.
Gracias. :)
 
Utilicé la siguiente configuración:

ADCON1:
Bit 7 ADFM: A/D Conversion Result Format Select bit
1 = Right justified <--- Esta selección.
0 = Left justified

Bit 5 VCFG1: Voltage Reference bit
1 = VREF- pin
0 = VSS <--- Esta selección.

Bit 4 VCFG0: Voltage Reference bit
1 = VREF+ pin
0 = VDD <--- Esta selección.
Es decir, usás referencia interna que suele ser muy mala en todos los uC (para aclarar), o por lo menos en los AVR dejan mucho que desear.

¿La tensión en Vdd es 5,01v?
 
Es decir, usás referencia interna que suele ser muy mala en todos los uC (para aclarar), o por lo menos en los AVR dejan mucho que desear.
Así es. También utilicé referencia externa, pero el resultado fue el mismo porque la fórmula toma como base 10.0V.
Entonces vRef lo tenía que poner en 5V para que realizara la lectura correctamente sin que me diera el resultado máximo antes de llegar a 10V en la entrada.
¿La tensión en Vdd es 5,01v?
Si. El microcontrolador tiene un regulador 7805 y el multímetro mide 5.01V.
Para el voltaje a medir, usé una fuente variable.
 
esto es mas difícil de lo que pensé la verdad que la tienen clara! estoy tratando de medir con coma con los 3 dígitos pero no se que pasa!
En la línea 40 tienes
PHP:
      voltaje *= 350;               // Voltaje requerido
Si voltaje (que contiene al principio el valor del ADC), tiene un valor, por ejemplo, de 1023, quedaría

voltaje = 1023 * 350 = 358 050

y esa cifra... no cabe en 16 bits, que es como lo que tienes definida la variable voltaje.

Yo lo haría así:
PHP:
    unsigned int16 voltaje;

        ....

    voltaje   = read_adc();    // leer valor del ADC
    voltaje  *= 35;        // escalado según Vref
    voltaje >>=  8;        // ajuste
    voltaje  *=  5;
    voltaje >>=  1;
 
Última edición:
Así es. También utilicé referencia externa, pero el resultado fue el mismo porque la fórmula toma como base 10.0V.
Entonces vRef lo tenía que poner en 5V para que realizara la lectura correctamente sin que me diera el resultado máximo antes de llegar a 10V en la entrada.

Si. El microcontrolador tiene un regulador 7805 y el multímetro mide 5.01V.
Para el voltaje a medir, usé una fuente variable.
Perfecto, entonces si usamos las mediciones como referencia, en realidad está mal usar 5v como Vref y deberías usar 5,01v, como consecuencia de eso, el valor arrojado en la medición de 2,506v usando 1024 es más cercano que el valor arrojado por 1023.

Es decir, para aislarnos de las cuentas sería más útil conocer el nivel que lee el ADC, de no equivocarme debe ser cercano a 513 cuentas.

En base a eso:

[LATEX]V_{in}=\frac{5,01v.513cuentas}{1024cuentas}=2,509...v[/LATEX]

[LATEX]V_{in}=\frac{5,01v.513cuentas}{1023cuentas}=2,512...v[/LATEX]

Si me baso en tus resultados, la lectura del ADC pareciera que dá 509, ¿podrías confirmar eso?
 
Última edición:
Perfecto, entonces si usamos las mediciones como referencia, en realidad está mal usar 5v como Vref y deberías usar 5,01v, como consecuencia de eso, el valor arrojado en la medición de 2,506v usando 1024 es más cercano que el valor arrojado por 1023.

Es decir, para aislarnos de las cuentas sería más útil conocer el nivel que lee el ADC, de no equivocarme debe ser cercano a 513 cuentas.

En base a eso:

[LATEX]V_{in}=\frac{5,01v.513cuentas}{1024cuentas}=2,509...v[/LATEX]

[LATEX]V_{in}=\frac{5,01v.513cuentas}{1023cuentas}=2,512...v[/LATEX]

Si me baso en tus resultados, la lectura del ADC pareciera que dá 509, ¿podrías confirmar eso?
OK. Bueno, la tensión de referencia al ser interna, entonces ya queda en 5.01V.
Ahora tomando como base una lectura de 5V máximo, la fórmula la realicé así:
voltaje = (5.01 * valor_adc / 1024);

El resultado para 2.5V fue: ADC = 511 y V = 2.500
Y para 5.0V fue: ADC = 1022 y V = 5.000

De esta forma ahora los resultados si fueron certeros.
¿Entonces está bien sumar el 0.01 en la fórmula? Pues así fue como funcionó bien.
Así también se obtuvo 0 en la lectura con 0V en la entrada.
 

Adjuntos

¿Entonces está bien sumar el 0.01 en la fórmula? Pues así fue como funcionó bien.
Si, pensá que el ADC no distingue la tensión que le metés, él solo compara la tensión de entrada contra la Vref/1024. Claro que uno nunca se toma ese trabajo de calibrar esa tensión con un buen instrumento y en realidad lo que si debería hacer es propagar los errores del 7805 y los del ADC en la medición final, de esta forma te cubrís.

Sobre el 0v, deberías haberlo obtenido en las dos mediciones previas independientemente del factor que uses (ya sea 1024, 1023 o 5v, 5,01v), es posbile que el nivel del ADC no llegara a la cuenta 0 y por eso te arrojaba un valor mayor. Hay que tener en cuenta que no siempre las mediciones son repetibles.
 
Última edición:
Si, pensá que el ADC no distingue la tensión que le metés, él solo compara la tensión de entrada contra la Vref/1024. Claro que uno nunca se toma ese trabajo de calibrar esa tensión con un buen instrumento y en realidad lo que si debería hacer es propagar los errores del 7805 y los del ADC en la medición final, de esta forma te cubrís.


Don Cosme, pues muchas gracias por la explicación, igualmente a Joaquín.
Ahora con esta información ya tendré en cuenta este importante detalle.

Saludos.
 
O sea... que estás intentando leer el ADC sin haber esperado el tiempo suficiente a que terminara de hacer la conversión...

Debes hacer una espera, mirando por el bit que indica final de conversión.
 
Estado
Cerrado para nuevas respuestas.

Temas similares

Arriba