Arduino se reinicia bastante y/o hace lo que quiere

Hola, estoy haciendo un trabajo de bachillerato para el instituto con arduino, y tengo un problema que no entiendo porque me pasa.

Os explico, usaba arduino uno con la ethernet shield, porque el trabajo es un control de acceso rfid en que las llaves autorizadas estan guardadas en una base de datos mysql. La cosa es que cuando detecta una llave, se conecta a la base de datos, comprueba si esta la llave guardada, si no lo está, guarda un registro con la fecha y el uid y no abre la puerta. Si la llave está registrada, recupera el nombre de la persona de esa llave y lo guarda en una variable y pasa al siguiente nivel, que es comprobar si la llave esta activa o no, si no lo está no abre la puerta, y guarda un registro con el uid, el nombre y la fecha, Si está activa esa llave, abre la puerta y crea un registro con el uid, el nombre y la fecha.

Pues la cosa es que yo iba haciendo el codigo poco a poco, e iba probando que todo funcionase correctamente. Todo funcionaba genial, pero al terminar todo el codigo con todos los registros a la base de datos, cuando lo subía a arduino, no funcionaba, los leds parpadeanan como les daba la gana, y si llegaba a funcionar, cuando acercaba una llave, arduino se reiniciaba sin mas. Lo curioso es que solo comentando por ejemplo que si la llave no esta activada, no guarde un registro, funciona genial. Pero a la que lo descomento, otra vez. Pero no solo con esa, sino que mientras comente algo de insertar algo a la base de datos, ya funciona perfecto todo lo demas. Cualquier cosa, solo que comente la consulta que hace para recuperar el nombre, ya me funciona. Y no puedo borrar nada, porque me interesa todos los casos en que guarda datos a la base de datos. Pensaba que sería por la ram o la memoria, asi que compre la mega, pero sigue pasando mas o menos lo mismo... No entiendo porque, si el ide de arduino me lo compila sin ningun tipo de problema. Como dato curioso, sin mas el router de movistar, se queda sin conexion, solo pasa a veces cuando ardiuno va loco, pero tengo que reiniciar router etc. El sketch me consume un 9% de memoria de la mega, asi que no entiendo donde esta el problema.

Ahora mismo no estoy en casa y no puedo subir el codigo, pero luego lo subo. Lo publico ya, a ver si alguien tiene idea y le ha pasado algo parecido.

muchas gracias!!

#include <SPI.h>
#include "Ethernet.h" 
#include <MFRC522.h>      
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
#include <MySQL_Encrypt_Sha1.h>
#include <MySQL_Packet.h>         // Librerias

#define rele 4
#define RST_PIN  8    //Pin 9 para el reset del RC522
#define SS_PIN  9   //Pin 10 para el SS (SDA) del RC522
#define led_green 7    // Pin del led verde
#define led_red 6    // Pin del led rojo
char query[80];
boolean siquehayuid = false;
boolean estaactivat = false;
char* nom;


MFRC522 mfrc522(SS_PIN, RST_PIN); //Creamos el objeto para el RC522
String valordeluid;   //Donde se guardará el valor del UID
byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };   // MAC ethernet shield en HEX
IPAddress server_ip(****);   // Dirección IP servidor mysql
EthernetClient client;    // Declaramos ethernet como cliente
MySQL_Connection conn((Client *) &client);    // Declaramos mysql connector como cliente
char user[] = "****";    // Usuario de la base de datos
char password[] = "***";     // Password de la base de datos
boolean connectedfail = false;    // Variable para anular el loop si no conecta con la base de datos


void setup() {
SPI.begin();
mfrc522.PCD_Init(); // Iniciamos  el MFRC522
pinMode(led_green, OUTPUT);   // Declaramos el pin del led verde como salida
pinMode(rele, OUTPUT);
pinMode(led_red, OUTPUT);   // Declaramos el pin del led rojo como salida
digitalWrite(led_green, HIGH);    // Empezamos encendiendo el led verde para indicar que arduino esta inicializandose 
digitalWrite(led_red, HIGH);    // Empezamos encendiendo el led rojo para indicar que arduino esta inicializandose 
Ethernet.begin(mac_addr);   // Inicializamos la shield ethernet con la mac anteriormente introducida en HEX
if (conn.connect(server_ip, 3306, user, password)) {    // Conexión con la base de datos que devuelve true si se ha conectado o false si no
  digitalWrite(led_red, LOW);   // Si se ha conectado, apagamos el led rojo y dejamos encendido el verde
  delay(2000);
  digitalWrite(led_green, LOW);
    } else {
  digitalWrite(led_green, LOW);   // Si no se ha conectado, apagamos el led verde y dejamos únicamente el led rojo
  connectedfail = true;   // Cambiamos de estado la variable para anular el loop si no establece conexión con la database
  }
conn.close();   // Cerramos en cualquiera de los casos la conexión con la database si la había
}





void loop() {
row_values *row = NULL;
  while (connectedfail == true){    // Si no ha conectado con la base de datos, este while hará que no se ejecute el codigo que haya después de este while, es decir, no funcionara el lector rfid, porque no se ha conectado con ninguna database
    return;   // Comando para volver al principio del loop
  }

if (mfrc522.PICC_IsNewCardPresent()) {
    if ( mfrc522.PICC_ReadCardSerial()) {
      String UsuariActual[mfrc522.uid.size];
      for (byte i = 0; i < mfrc522.uid.size; i++) {
      UsuariActual[i] = mfrc522.uid.uidByte[i];      
        }
        
       for (byte i = 0; i < mfrc522.uid.size; i++) {
       valordeluid = valordeluid + UsuariActual[i];
        }
        comprobarsihay();
        if (siquehayuid == true) {
          recuperarnom();
          comprobarsiestaactivat();
          if (estaactivat == true) {
            registresi();
            obralaporta();
            estaactivat = false;
          } else {
            registredeentradanoactivat();
            obralaporta();
          }
          siquehayuid = false;
          nom = "";
        } else {
          registre();
          noobrislaporta();
        }
        valordeluid = ""; 
        mfrc522.PICC_HaltA();
    }
  }
}


void obralaporta() {
digitalWrite(rele, HIGH);
digitalWrite(led_green, HIGH);
delay(2500);
digitalWrite(rele, LOW);
digitalWrite(led_green, LOW);
}

void noobrislaporta() {
  digitalWrite(led_red, HIGH);
  delay(500);
  digitalWrite(led_red, LOW);
  delay(500);
  digitalWrite(led_red, HIGH);
  delay(500);
  digitalWrite(led_red, LOW);
  delay(500);
  digitalWrite(led_red, HIGH);
  delay(500);
  digitalWrite(led_red, LOW);
}

void recuperarnom() {
row_values *row = NULL;
if (conn.connect(server_ip, 3306, user, password)) {
MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
sprintf(query, "SELECT Nom FROM u861701900_ardu.claus WHERE UID = '%s';", valordeluid.c_str());
cur_mem->execute(query);
  column_names *columns = cur_mem->get_columns();
  row = cur_mem->get_next_row();
  if (row != NULL) {
    nom = row->values[0];
    Serial.println(nom);
  }
conn.close();
delete cur_mem;
}
} 

void registresi(){
  if (conn.connect(server_ip, 3306, user, password)) {
      MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
      sprintf(query, "SET time_zone = 'Europe/Madrid'; INSERT INTO u861701900_ardu.registre (UID, Nom, Data_i_hora, Activat) VALUES ('%s', '%s', NOW(), 'Si')", valordeluid.c_str(), nom);
      cur_mem->execute(query);
      delete cur_mem;
      conn.close();
  }
}


  void registredeentradanoactivat() { 
        if (conn.connect(server_ip, 3306, user, password)) {
        MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
        sprintf(query, "SET time_zone = 'Europe/Madrid'; INSERT INTO u861701900_ardu.registre (UID, Nom, Data_i_hora, Activat) VALUES ('%s', '%s', NOW(), 'No');", valordeluid.c_str(), nom);
        if (cur_mem->execute(query)) {
          delete cur_mem;
          conn.close();
      } 
    }
} 


        void registre() { 
        if (conn.connect(server_ip, 3306, user, password)) {
        MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
        sprintf(query, "SET time_zone = 'Europe/Madrid'; INSERT INTO u861701900_ardu.registre (UID, Data_i_hora) VALUES ('%s', NOW());", valordeluid.c_str());
        cur_mem->execute(query);
        delete cur_mem;
        conn.close();
      
    }
}


void comprobarsiestaactivat() {
  row_values *row = NULL;
  if (conn.connect(server_ip, 3306, user, password)) {
    MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
    sprintf(query, "SELECT UID, Activat FROM u861701900_ardu.claus WHERE UID = '%s' AND Activat = 'Si';", valordeluid.c_str());
    if (cur_mem->execute(query)) {
      column_names *columns = cur_mem->get_columns();
      row = cur_mem->get_next_row();
      if (row != NULL) {
        estaactivat = true;
      } 
      if (row == NULL) {
        estaactivat = false;
      }
    }
    conn.close();
    delete cur_mem;
  }
}

void comprobarsihay() {
  row_values *row = NULL;
  if (conn.connect(server_ip, 3306, user, password)) {
    MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
    sprintf(query, "SELECT UID FROM u861701900_ardu.claus WHERE UID = '%s'", valordeluid.c_str());
    if (cur_mem->execute(query)) {
      column_names *columns = cur_mem->get_columns();
      row = cur_mem->get_next_row();
      if (row != NULL) {
        siquehayuid = true;
      }
    }
    conn.close();
    delete cur_mem;
  }  
}

Por qué no nos pegas el resultado de la compilación, memoria RAM usada y memoria Flash?

SEguramente te estas quedando sin ram mientras se ejecuta el código.

Existe un programa llamado MemoryFree Library

Que te permitirá saber en que momento entras en problemas.

surbyte:
Por qué no nos pegas el resultado de la compilación, memoria RAM usada y memoria Flash?

SEguramente te estas quedando sin ram mientras se ejecuta el código.

Existe un programa llamado MemoryFree Library

Que te permitirá saber en que momento entras en problemas.

¡Gracias por tu respuesta! Sí, a continuación estará el resultado de la compilación, la memoria RAM restante cada vez que se ejecuta una consulta a la base de datos. La memoria Flash, no sé como consultarla, he buscado en internet, pero me aparecen páginas tipo “Utiliza SRAM, en vez de la Flash…”.

En el registro de RAM, se puede ver como después de recuperar el nombre del propietario de la tarjeta, se ha reiniciado Arduino, ya que vuelve a mostrar la cantidad de RAM en el setup.

En referencia al código, ¿estaría bien esta manera de programarlo? ¿O sería mejor iniciar la conexión con la base de datos al leer la tarjeta, y cerrarla una vez ya hechas todas las consultas? En vez de abrir y cerrar la conexión constantemente…

Este es el registro de RAM:

RAM en el setup 6041
RAM despues de leer la tarjeta rfid 6017
RAM despues de comprobar si existe el uid 5876
RAM despues de recuperar el nombre del propietario de la tarjeta 5875
RAM en el setup 6041    <------- Aquí se ha reiniciado --------

Este el resultado de la compilación:

El Sketch usa 24864 bytes (9%) del espacio de almacenamiento de programa. El máximo es 253952 bytes.
Las variables Globales usan 2017 bytes (24%) de la memoria dinámica, dejando 6175 bytes para las variables locales. El máximo es 8192 bytes.

¡Muchas gracias!

Vaya no parece que sea RAM tu problema, en todo momento tienes un buen margen.

No te diré nada que no sepas pero... empieza a aislar el culpable

void recuperarnom() {
  row_values *row = NULL;
  if (conn.connect(server_ip, 3306, user, password)) {
      MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
      sprintf(query, "SELECT Nom FROM u861701900_ardu.claus WHERE UID = '%s';", valordeluid.c_str());
      cur_mem->execute(query);
        column_names *columns = cur_mem->get_columns();
        row = cur_mem->get_next_row();
        if (row != NULL) {
          nom = row->values[0];
          Serial.println(nom);
        }
      conn.close();
      delete cur_mem;
  }
}

Esta es la rutina del problema, verifica hasta donde llega paso a paso colocando carteles en el monitor serie

NOTA: Veo que hay mucho manejo de punteros y son siempre los responsables de estos Rompederos de cabeza. No subestimes ninguno. mira bien si estan bien terminados. Son delicados.

No entiendo que son los punteros, si te refieres a la variable “char* nom;”, no tengo ni idea porque se le pone el *, pero buscando documentación de la librería MySQL connect, he visto que lo ponían, y si no lo ponía, no me compilaba.

He hecho lo que me has dicho, pero sucede una cosa muy curiosa. No llega a ejecutar nada de recuperarnom(), justo antes del if (siquehayuid == true), y el comprobarsihay(), lo ejecuta entero, porque he puesto un print entre el if este y el comprobarsihay(). Dejo el código con los prints + el monitor serie. ¡Gracias!

Información monitor serie:

RAM en el setup 5505
RAM despues de leer la tarjeta rfid 5481
RAM despues de comprobar si existe el uid 5346
if siquehayuid == true
RAM en el setup 5505

Código arduino:

comprobarsihay();
Serial.print("RAM despues de comprobar si existe el uid ");
Serial.println(freeMemory());   
Serial.println("if siquehayuid == true");  [b]<---------- Aquí se reinicia ------[/b]
  if (siquehayuid == true) {
    Serial.println("Justo antes de empezar recuperarnom()");
    recuperarnom();

Entonces se cuelga en

void comprobarsihay() {

porque lo otro es una simple variable boolean que no puede generar jamás un reinicio.

Aumenta el tamaño de query de 80 a 100 a ver si te estas quedando corto por poco.

char query[80];

por

char query[100];