Hola, tengo una estructura de código tipo:
if{ }
else{ if{} else { if{} else {} }
No es un tema de condición ni de acciónes porque lo he testeado con cosas muy simples, pero el caso es que el último else deja mi programa en estado catatónico simplemente por su existencia (lo quito y todo va bien) definitivamente es algo muy raro que puede deberse a algún error mío (muy probable) o a una cuestión de lenguaje arduino que me lleva a la siguiente pregunta:
¿Existe algún límite al anidamiento de condicionales en arduino?
Si pones el código completa quizás te podamos ayudar.
Si lo que quieres en evaluar una sola variable, quizas prueba con switch.
Te falta una } al final
if{ }
else{ if{} else { if{} else {} } }
Muchas gracias Ignorante, Kike y jordi, este es el código que no funciona:
Code: [Select]
if (estadoNivelAgua == HIGH) {
Serial.println("lleno");
elnivel = 2;
}
else {
estadoNivelAgua=digitalRead(nivelmedioPIN);
if (estadoNivelAgua == HIGH) {
Serial.println("mitad.");
elnivel = 1;
}
else{
estadoNivelAgua=digitalRead(nivelreservaPIN);
if (estadoNivelAgua == HIGH) {
Serial.println("reserva.");
elnivel = 0;
}
else{
if (estadoNivelAgua == LOW) {
Serial.println("vacío.");
}
}
}
}
Este si funciona, ponga lo que ponga en el último else así como si lo dejo vacío sin contenido:
Code: [Select]
if (estadoNivelAgua == HIGH) {
Serial.println("lleno");
elnivel = 2;
}
else {
estadoNivelAgua=digitalRead(nivelmedioPIN);
if (estadoNivelAgua == HIGH) {
Serial.println("mitad.");
elnivel = 1;
}
else{
estadoNivelAgua=digitalRead(nivelreservaPIN);
if (estadoNivelAgua == HIGH) {
Serial.println("reserva.");
elnivel = 0;
}
}
}
El código total es muy extenso y en muchas partes las instrucciónes direccionan posiciones de memoria, no se si arduino asigna la memoria por bloques contiguos o de que manera, pero me planteo la posibilidad de que mi arduino tenga algún sector dañado (pura especulación). Me queda poco espacio de memoria pero algo queda (10%) y también aprovecho a preguntar a la gente con experiencia si es posible que arduino cuando está cerca del límite de memoria es normal que de problemas. En mi caso concreto también influye un módulo de temperatura 18b20 junto una pantalla OLED 128x64 de 4 pines que me han generado una catarata de problemas al trabajar conjuntamente, por lo que he tenido que rehacer el código evitando librerías y trabajando mas cerca del hardware con las posiciones de memoria. Esto último sin lugar a dudas tiene algo que ver con varios de los problemas que experimento, incluido el de este post con el else. A cada rato incluso las instrucciónes mas inocuas producen un bloqueo y debo ir con pies de plomo cambiándolas de sitio o reescribiéndolas de otra manera para no perder funcionalidad.
No descarto que sea problema de memoria. Las cadenas de los Serial.print() consumen memoria RAM. Para evitar ese uso de RAM puedes usar la macro F(). En lugar de:
Serial.println("lleno");
Pones:
Serial.println(F("lleno"));
Eso hace que tarde un poquito más en mostrar la cadena "lleno" (no lo vas a notar) pero no consume RAM. El fragmento de código que has puesto quedaría tal que así:
if (estadoNivelAgua == HIGH) {
Serial.println(F("lleno"));
elnivel = 2;
}
else {
estadoNivelAgua=digitalRead(nivelmedioPIN);
if (estadoNivelAgua == HIGH) {
Serial.println(F("mitad."));
elnivel = 1;
}
else{
estadoNivelAgua=digitalRead(nivelreservaPIN);
if (estadoNivelAgua == HIGH) {
Serial.println(F("reserva."));
elnivel = 0;
}
else{
if (estadoNivelAgua == LOW) {
Serial.println(F("vacío."));
}
}
}
}
Prueba a usar la macro F() en más sitios y verás cómo te queda más RAM libre.
Nota: al ponerlo no te olvides abrir y cerrar paréntesis.
En primer lugar gracias IAbsoluto (perdona por poner tu nombre así sino queda horrible la frase). Sobre el puerto serie la verdad que solo está para realizar trazas de control y cuando el código esté completo desparecerán esas instrucciones. Gracias por la sugerencia de la macro, la tendré en cuenta. No doy con la clave sobre la inestabilidad en mi código, puede que sea porque uso un arduino-chan, puede que sea mi desconocimiento de la arquitectura arduino y su compilador que me lleva a cometer errores de bulto o puede que la ensalada de cables encima de mi protoboard esté causando estragos. La cuestión que ya tengo código funcional y aunque casi me ponen el chaleco todo va bien, pero entre nosotros mi código parece un cuadro de Pollock, horroroso, la única ventaja que le encuentro es que si algun día alguien le quiere hacer ingeniería inversa se va a terminar pegando dos tiros. Gracias de nuevo.
Prueba a usar la macro F() en todo Serial.print() que puedas. Lo de que tienes un 10% de memoria libre supone unos 200 bytes en un Arduino UNO y unos 800 en un MEGA. Esa es la memoria que se supone que queda disponible para la pila y el heap.
La pila es la memoria que se usa para guardar las variables locales y direcciones de retorno cada vez que se llama a una función. Cierto es que una vez terminada la función la memoria "apilada" se libera. Pero como tengas una función que llama a una función, que a su vez llama a otra función, que llama... pues eso, que la pila va creciendo y creciendo hasta que te quedas sin memoria. Por otro lado está el heap. En el heap se guardan los objetos que se crean dinámicamente. No sé si tú creas dinámicamente algo, pero puede que sí lo hagan las librerías que usas.
Si estás usando un Arduino UNO (o algo con igual RAM) los 200 bytes los puedes consumir rápidamente. Y un efecto típico de quedarse sin RAM es que Arduino se queda "colgado" sin más. A mí me ha pasado precisamente por tener mucho texto con Serial.print() sin usar "la macro".
Ten en cuenta que la RAM que te indica que se está usando (el 90%) se refiere a variables u objetos globales o estáticos (todo aquello que se defina fuera de las funciones o que en su definición tenga la directiva static) así como todas las cadenas que no estén definidas con la macro F(), y cuando digo todas son todas, no importa si la cadena está definida dentro o fuera de una función. Toda variable u objeto que esté definido dentro de una función no "se cuenta" en ese 90% (las cadenas no son realmente una variable ni un objeto).
Una última cosa. Las vatiables tipo String usan memoria del heap para guardar el texto. Y esa memoria no está contabilizada en el 90% de memoria que te dice que está usando. Y por cada variable de tipo String también se "gasta" memoria global (contabilizada en el 90%) si la has definido fuera de las funciones o como static y de la pila (la del 10%) si son variables locales (definidas dentro de una función). Sí, las String son muy "guais" y muy "caras".
Así que insisto en que uses la macro F() siempre que puedas y sobre todo si tu programa es muy grande y tu Arduino es cortito de memoria ;).
Nota: el coste en memoria de las cadenas no sólo es el del "texto" en sí, también hay que tener en cuenta si se están usando variables con ese texto.
Gracias IAbsoluto, muy buena información. Uso un nano y no tengo un uso abusivo de datos estructurados ni tengo exceso de librerías, pero si es verdad que hago un uso importante de las interrupciones, que no se como funcionarán en arduino pero supongo que guardará el contexto y cargará la subrutina, incorporando a la pila una dirección de memoria para retomar el flujo del programa, también es verdad que no tengo recursividad al uso pero si tengo un encadenamiento de funciones importante. Está claro que todo suma, de todos modos sigue siendo un misterio que si en una instrucción pongo display.println("BATERIA: ") no funciona el programa y si pongo display.println("BAT: ") sí funciona, incluso cuando luego agrego mas instrucciones del mismo tipo con diferentes tamaños, me parece que el error tira mas a expediente X que a desbordamiento. Y como este ejemplo muchos mas. De momento el código funciona y lo puedo mostrar, eso sí lo maquillaré un poco porque está muy feo y trataré de meter el arduino en una cajita para que nadie le respire arriba. Seguire todos tus consejos cuando haga una segunda versión del programa y siempre que no me explote el prototipo. Gracias