Problema con medida de tensión en batería ácido plomo.

Hola, escribo por primera vez en el foro, por tanto, un saludo a todos.

Mi problema es el siguiente:
He hecho una máquina de estados con Arduino UNO, que utilizo para arrancar un motor diésel, en función de la tensión de la batería y usando un switch/case. Arduino se alimenta con una batería de 12 V (ácido-plomo) y ésta es la tensión que debo leer. (no alimento Arduino directamente con 12V lo he reducido a 5V con un regulador)

Para medir dicha tensión utilizo un divisor con R1=10k y R2=5K que trabaja con un rango de voltaje de 0 a 16 V y que leo con la entrada analógica a través de una función auxiliar que pongo a continuación, a la que llamo en el programa principal.

float getTENSION(){
float t3=analogRead(0);           //Lectura de tensión
t3 = ((15.3*float(t3))/1024.0);
 return t3; 
}

Y en el programa principal a la función la llamo de la siguiente forma:

case 3:  // lectura continua de tensión a motor parado
 lcd.setCursor(0,0);
  lcd.print("AUTOMATICO");
   lcd.clear();
while(V > 12.38){
float V=getTENSION();

   lcd.setCursor(0,1);
   lcd.print("TENSION: ");
      lcd.print(V);
      lcd.print(" V   ");
           delay(300);
           if (V <= 12.38){
            pasoEstado=4;
            break; 
           }
}

(El If no afecta, pues el while debería hacer que pase al estado 4 directamente que es el estado de arranque).

Si leo la tensión de una fuente de alimentación independiente, la medida es correcta, pero cuando leo la tensión de la batería con que alimento al Arduino la medida es de 15.3 V, por tanto 1024 valores para una tensión de 12.36 aproximadamente (medida con multímetro) lo cual no está bien. He probado a medir la tensión que tiene en la entrada analógica con el multímetro, y mide 3.36, lo que esta dentro de lo normal. Por algún motivo el programa no interpreta bien los valores analógicos cundo mido únicamente con la batería.

A modo de información decir, que todas las masas están unidas.

Espero no haberos aturullado y me podáis echar una mano.

Perdón, se me olvido decir que si el sketch lo pruebo en otro Arduino sin máquina de estados, con el programa solo y visualizo la tensión con en monitor serie, me da una medida correcta.

//-- No se que hay antes...
case 3: 
  lcd.setCursor(0,0);
  lcd.print("AUTOMATICO");
  lcd.clear();
  while(V > 12.38)  // 1) Variable V usada.
  {
    float V=getTENSION(); // 2) Variable V declarada.
    lcd.setCursor(0,1);
    lcd.print("TENSION: ");
    lcd.print(V);
    lcd.print(" V   ");
    delay(300);
    if (V <= 12.38)
    {
       pasoEstado=4;
       break;
    }
//-- No se que hay despues...

¿Has definido la variable global V antes como float? Y declaras una variable local V dentro. Eso puede dar problemas. Declara una variable global Vbat, donde guardes siempre la tensión de la bateria y usala siempre para ello, no declares otra variable local para ello.

Si, declaré la variable V como local en la cabecera.
Antes del case 3 hay un 'case' para inicialización, un 'case' selector de manual/automático, y después hay un 'case' de calentamiento, otro de arranque y otro de lectura de tensión con el motor arrancado. La cuestión es que mide bien una fuente externa pero no la propia batería. Gracias.

Me equivoque, la variable 'V' la declare como local y como global. He cambiado a variable solo global. Y nada, sigo intentando...

La única forma que hace funcionar el sistema, leyendo una fuente externa, es declarando la variable local y globalmente. He probado de todas las maneras, pero cuando mido la batería (12.36 V) mide 15.3 V (1024 valores) no está bien.

Comprueba las masas, y un esquema no vendría nada mal.

Bueno, no has leído las normas del foro. Todo bien posteado, usando códigos y tags como dicen las normas pero PACIALIZASTE el código.
Yo no veo todo el código asi que no puedo darte una impresión de que ocurre.
De lo que has mostrado corrijo algunas cosas sutiles que no afectan en nada lo que hace tu código tal como está.
Solo corrijo que no es 1024 el factor de división ya que si lo fuera y tu analogRead(A0) lee 1023 o sea 5V luego del divisor de tensión que obviamente tienes, entonces tendrias 1023/1024 que es > 1. Explicado porque no va 1024
Luego definir float t3 = analogRead(0) y luego volver a ponerle float es un desperdicio.
Si quieres se lo pones ahora a mi corrección. Yo he visto que el compilador lo hace bien.

float getTENSION(){
 float t3 = (15.3 * analogRead(A0)/1023.0);
 return t3; 
}

Veamos tu divisor resistivo. Dices usar 5K y 10K
Supongo y espero que 5K sean 5K y no 4k7 pero sigamos.
Vout = 5K/)10+5)K * 16V = 5.33 V dime como has hecho las cuentas? hasta 16V no puedes medir.
Veamos si 15.3 esta bien

Vout = 5/15* 15.3 = debe darme 5V y me da 5.1V MAL de nuevo

Al revés... tu divisor es ese, pero esta mal el cálculo
La tensión máxima para 5V es Vmax = 15K/5K *5 = 15V y no 15.3V ya es un cambio.

tu ecuación entonces será.

float t3 = (15.0 * (float) analogRead(A0)/1023.0);  // Agregué el typecast float

prueba ahi.

Adjunto el esquema eléctrico. La instalación llegara como mucho a 14V. El divisor lo calcule bien en un principio pero la desesperación me hizo cambiarlo infinitas veces (pero siempre R1 =10K y R2 =5K, siendo R2 la resistencia entre Arduino y GND ), en principio de esta forma mide la tensión de una fuente regulable con bastante precisión, no me importa que el error sea aparente, lo que me preocupa es que no mida la tensión de la batería, o mejor dicho que mida el máximo valor cuando la lectura del polímetro es de 3.36 v mas-menos. Aún así gracias por la rapidez de la respuesta.

plano.pdf (23.8 KB)

Adjunto el código, falta hacer una limpieza, pues se hace pesado de leer.
Del 'case 3' hacia abajo hay cosas que corregir, pero el sistema probado con un motor real va bien (calienta, arranca con hall, para, lee nivel de depósito y temperatura del radiador) aunque no en función de la tensión que es lo interesante.

Proyecto_final.ino (17.3 KB)

Y no dijiste nada de mi sugerencia?

Veo 2 errores.

  1. Nunca lees el valor de V o al menos debiar fijarlo en 0.0 de este modo cuando lo defines
float V = 0.0;

Luego en tu case

case 3:  // lectura continua de tensión a motor parado
        lcd.setCursor(0,0);
        lcd.print("AUTOMATICO");
        lcd.clear();
        while (V < 16.0){ // esto debe ser 16.0 no 16. Nunca compares float como enteros.
              V = getTENSION();
              lcd.setCursor(0,1);
              lcd.print("TENSION: ");
              lcd.print(V);
              lcd.print(" V   ");
              delay(300);
              if (V <= 11.0){
                  pasoEstado = 4;
                  break;
              }   
        }

Perdona surbyte, estoy corrigiendo lo que me comentaste, no lo pase por alto. En cuanto tenga un descanso doy una respuesta. No se si está bien hecho, pero como has podido comprobar, el while está para que se mantenga leyendo y la única manera de salir sea la comparación condicional, cuando he declarado la variable 'V' como global (solo), sale del bucle aún teniendo una tensión mayor a la de while y eso me pareció raro. Sigo con ello...

Con las reformas propuestas en el foro, y midiendo con una fuente de laboratorio regulada Arduino mide:

Tensión de fuente Medida de Arduino
9.1 V 14.12 V
9.7 V 14.99 V
10 V 15.0 V

Con la batería Arduino mide 15.0 V

He probado alimentando Arduino con la fuente regulada y midiendo su tensión, y mide correctamente.
La conclusión que saco es que de software va bien, probare a leer tensión con un operacional como seguidor. También revisare de nuevo la masas como dijo victorjam.

Kinojp:
Con las reformas propuestas en el foro, y midiendo con una fuente de laboratorio regulada Arduino mide:

Tensión de fuente Medida de Arduino
9.1 V 14.12 V
9.7 V 14.99 V
10 V 15.0 V

Con la batería Arduino mide 15.0 V

while (V < 16.0){

Esto es incoherente con lo que muestras hace un momento.
nunca sale como condición a no ser que sea menor que 11.0
Entonces porque no preguntar por mayor que 11.0? Todo el tiempo
Igualmente algo que no me convence es que tu sistema se queda clavado ahi en ese loop

Lo mantengo parado en ese loop para que solo lea tensión y que únicamente salga si la tensión de la batería cae por debajo de un cierto valor (he puesto 11 pero suele ser 12.35 V). Cuando sale es porque hay que cargar batería y por tanto arranca el motor. Respecto al while, fuerzo a que se mantenga en el todo el tiempo diciendo que V<16, tensión a la que nunca llegara la batería.

Lo curioso es que todo funciona OK si lo conecto a una fuente independiente, simulando la batería de ácido plomo.

Bien. Esta claro que tu problema no es el código al que le hemos dedicado mucho tiempo sino porque funciona bien con fuente externa y no lo hace cuando usas la batería.

Veamos usas la batería para alimentar el arduino y a la vez la mides. En principio esta bien.
Usas NEGATIVO a GND, tu divisor resistivo para medir la tensión, la pregunta es:
Por donde tienes un blucle o lazo tal que hace que mida mal?
Dificil responderte desde acá pero ese es el problema.

Sería bueno que indicaras con un esquema manuscrito si quieres que comprendamos mejor todo.. tal vez al hacerlo veas el error. Eso a mi me funciona.
Cada vez que le explico a alguien mas surge la respuesta!

No he podido contestar antes. He decidido volver a mecanizar el circuito impreso que gestiona el sistema, pero esta vez lo he fragmentado, para poder localizar errores. En principio el -BAT está unido a GND de Arduino, he probado a tomar una referencia de cero absoluto poniendo -BAT a una pica de tierra y nada. No he dicho que estoy usando una placa china, pero he probado con una original y tampoco.

Cuando tenga en nuevo circuito montado, lo colgare y comentare los resultados.