Problema con función de busqueda en tarjeta microSD

Buenas tardes compañeros.

Como ya comenté en algún post anterior, estoy trabajando en mi trabajo fin de grado con arduino entre otras cosas. Me he propuesto en una de las fases de mi proyecto usar un shield ethernet v2 con el chip w5500. Con el pretendo generar una conectividad entre mi equipo y una red interna, pero antes prefiero avanzar en el uso de el lector de microSD que lleva incorporado.

Mi idea es hacer una llamada la la tarjeta microSD, en la cual tendré dos archivos txt. Uno de ellos será para generar registros en tiempo y hora de los usos de la máquina que tengo en mente, y el otro será una base de datos de usuarios que pueden acceder a la máquina. Esta segunda es la que me preocupa.

Tengo un teclado 4x4 conectado a arduino MEGA y un código para introducir contraseña. Mi idea es que esa contraseña, en vez de validarla por arduino, busque en la base de datos el número introducido (de 4 dígitos numéricos) y devuelva el nombre de la persona y un valor positivo (en el caso de ser correcto el número). El usar estos 4 dígitos para abrir o cerrar la entrada al sistema de dicha persona no me preocupa, lo que me preocupa es saber hacer una búsqueda por las más de 200 o 300 filas que habrá comparando cada valor hasta dar con el código completo.

Para ello he pensado que si por ejemplo introduzco 1234 como el código de 4 dígitos, sabiendo que los códigos estaran ordenados de menor a mayor, haré una búsqueda de cada fila en la columna 1 de los que coincidan con el valor 1, y si es correcto, pasar a la columna 2 para saber si coincide con el valor 2. Así sucesivamente hasta que sea capaz de encontrar los 4 valores correctos y me devuelva el nombre de la persona que esta en el archivo txt tras los 4 dígitos.

He buscado por internet y he encontrados muchas maneras de hacer cosas parecidas, pero la mayoría no me funcionan. No se si existirá una función en la librería SD.h que sea buscar o comparar, y tampoco se como hacer que avance la búsqueda de fila en fila o de columna en columna.

Obviamente entiendo que es con un bucle for, while etc, mi problema no reside ahí, está en que no conozco bien de que funciones puedo tirar. Entiendo que lo haré con un char[4] comparando cada valor, pero me cuesta avanzar.

[u]Espero que algún compañero sepa orientarme, muchas gracias a todos y un saludo.[/u]

niconetti: lo que me preocupa es saber hacer una búsqueda por las más de 200 o 300 filas que habrá comparando cada valor hasta dar con el código completo.

Para ello he pensado que si por ejemplo introduzco 1234 como el código de 4 dígitos, sabiendo que los códigos estaran ordenados de menor a mayor, haré una búsqueda de cada fila en la columna 1 de los que coincidan con el valor 1, y si es correcto, pasar a la columna 2 para saber si coincide con el valor 2. Así sucesivamente hasta que sea capaz de encontrar los 4 valores correctos y me devuelva el nombre de la persona que esta en el archivo txt tras los 4 dígitos.

Si la lista es inalterable en el Arduino, eso sería posible. Si todos los registros tuvieran una longitud (en bytes) fija y constante; todavía mejor.

Tu método de búsqueda agilizaría un poco el proceso, pero sigue siendo búsqueda secuencial al final, así que la ganancia es poca. Si la lista estuviera completamente ordenada, y los registros fueran de longitud constante, se podría aprovechar una característica importante de los archivos en la librería: acceso aleatorio. De esta forma se podría ejecutar el algoritmo de búsqueda binaria, el cuál reduce drásticamente el tiempo de este proceso aún para 300 registros.

Segun tu método, una persona tiene entonces 300 posibilidades mas de encontrar un número de acceso que no es el suyo? O sea.. como vas a discernir entre su código de acceso y el de otra persona? si yo voy, en lugar de tener 1/10000 = 0.0001 posiblidades tendre 300/10000 = 0.03 posibilidades, mejoró 300 veces sus posibilidades. 3 en 100.

No le vas a agregar un Id al usuario? Y si este fuera el caso, porque no crear 300 archivos, uno por cada usuario (se que es grotesco) y sabras si ingresa o no por el password

Aunque olvida.. porque todo esto esta resuelto. Sigue el consejo de Lucario.

surbyte: Segun tu método, una persona tiene entonces 300 posibilidades mas de encontrar un número de acceso que no es el suyo? No le vas a agregar un Id al usuario? Y si este fuera el caso, porque no crear 300 archivos, uno por cada usuario (se que es grotesco) y sabras si ingresa o no por el password

Perdón si no me he explicado bien, la base de datos contará con unos 300 número de 4 cifras conn sus correspondientes 300 nombres de personas, una persona un código.

Lucario448: Si la lista estuviera completamente ordenada, y los registros fueran de longitud constante, se podría aprovechar una característica importante de los archivos en la librería: acceso aleatorio. De esta forma se podría ejecutar el algoritmo de búsqueda binaria, el cuál reduce drásticamente el tiempo de este proceso aún para 300 registros.

Perfecto, te pongo un extracto de la base de datos que tengo en mente:

0000 Usuario_1 0010 Usuario_2 0020 Usuario_3 . . . . . .

Algo así, con unos 300 nombres y códigos correspondientes. Además en el txt están así ordenados: código - espacio de tabulador - nombre de usuario.

Mi duda es saber como poder buscar por fila y columna cada número, puesto que no conozco dichas funciones en arduino.

Gracias

Buenas de nuevo compañeros. He escrito un poco de código en mi porgrama buscando en otro post que he vito en este foro: https://forum.arduino.cc/index.php?topic=285248.0

he generado el siguiente código:

char Tarjeta[]="1000";
char claveSD[4];

archivo = SD.open("datos.txt", FILE_WRITE);

  if(archivo){ // reviso archivo si está disponible
    int i=0; // variable para almacenar linea en char array
    while(archivo.available()){ // mientras no se haya leído todo el archivo
      char c = archivo.read(); // extrae un caracter de la tarjeta
      while(c != '\n'){ // mientras no encuentre un final de linea
        claveSD[i] = c; // almacena cadena en un char array
        i++;
      }   
  if(claveSD[0]==Tarjeta[0]&&claveSD[1]==Tarjeta[1]&&claveSD[2]==Tarjeta[2]&&claveSD[3]==Tarjeta[3]){
        lcd.println("clave válida"); // acción al encontrar clave
        delay(1000);
        break; // sale del loop
      }
      i= 0; // reinicia variable cuando la linea encontrada no coincide
    }
  }

 lcd.println(Tarjeta);
 lcd.setCursor(0,2);
 lcd.println(claveSD);

He utilizado "Tarjeta" como el código que quiero buscar, más adelante lo cambiaré para que sea el que introduzca por pantalla puesto que tengo ahora mismo todo el programa en sucio y estoy haciendo muchas pruebas.

Por otro lado, claveSD es la lectura que hace de las distintas claves que tengo en la SD, en el archivo datos.txt.

Cuando impirmo por LCD lo resultados me salen cosas raras, y obviamente no me sale el mensaje de clave válida. Concretamente me sale esto:

|500x375

Como podéis ver, arriba tengo el código de Tarjeta seguido de unos caracteres raros, y abajo el código de claveSD que se aprecia que no los lee bien.

A ver si podéis ayudarme. Gracias y un saludo.

Si la longitud del dato del nombre no es constante (que ocupe siempre la misma cantidad de bytes), no será posible utilizar búsqueda binaria. Sin embargo ya entiendo tu idea de cómo buscar (y con más razón sabiendo el formato de los datos. Como búsqueda secuencial sería:

const char Tarjeta[]="1000";
char claveSD[5];

archivo = SD.open("datos.txt");

  if (archivo){ // reviso archivo si está disponible

    while (archivo.available()) { // mientras no se haya leído todo el archivo

      archivo.readBytes(claveSD, 4); // Ya que el inicio del registro siempre es la clave, se lee de una vez

      if (!strcmp(Tarjeta, claveSD)) { // Así se comparan cadenas sin tantas operaciones lógicas
        lcd.println("clave valida"); // acción al encontrar clave
        delay(1000);
        break; // sale del loop
      }
      while (archivo.read() != '\n'); // Avanzar al siguiente registro (puede quedarse atrapado si el archivo no termina en línea en blanco)
    }
  archivo.close(); // RECUERDA SIEMPRE CERRAR EL ARCHIVO UNA VEZ QUE HAYAS TERMINADO
  }

 lcd.println(Tarjeta);
 lcd.setCursor(0,2);
 lcd.println(claveSD);

Hay un trabajo hecho por noter justamente para resolver un problema similar de alguien que quería bloquear numeros telefonicos o algo asi. El hizo un sistema de BD que aprovecha sea la EEPROM, sea una EEPROM externa o una SD si mal recuerdo, y permite lo que tu buscas.

Aca tienes tu solución Gestión e indexación de registros de una tabla en SD Es un gran trabajo. Mira a ver si sirve a tus fines.

Lucario448: Sin embargo ya entiendo tu idea de cómo buscar (y con más razón sabiendo el formato de los datos. Como búsqueda secuencial sería:

Perfecto, gracias. Hasta este viernes no podré tener acceso a mi arduino, lo primero que haré sera utilizar el código a ver si consigo que funcione. Además veo que has entendido mi idea: dispongo de un txt con 4 cifras segudido un espacio y de un nombre, por lo que para comparar siempre utilizaré las 4 cifras únicamente.

Por otro lado no entiendo bien cuando me comentas:

Lucario448: Si la longitud del dato del nombre no es constante (que ocupe siempre la misma cantidad de bytes), no será posible utilizar búsqueda binaria.

Al buscar simplemente por las 4 cifras del identificador, entiendo que al estar ya sabiendo en la línea que me sitúo podré mostrar el nombre de esta persona, ¿no? Se que está tras el espacio.

Aunque si solo puedo usar el código aún así sería válido por ahora para mi.

Gracias, estoy deseando probarlo =)

surbyte: Aca tienes tu solución Gestión e indexación de registros de una tabla en SD Es un gran trabajo. Mira a ver si sirve a tus fines.

Gracias, lo miraré

niconetti: Por otro lado no entiendo bien cuando me comentas:

[...]

La búsqueda binaria funciona en listas ordenadas, indexadas y de acceso aleatorio (ej.: vector o "array").

En el caso de una base de datos en un archivo de texto, los índices no se almacenan, se calculan. Para hacer posible dicho cálculo, se requiere de un valor constante, el cual viene siendo la longitud o tamaño de un registro (nótese que hago énfasis en esa palabra, que es la clave para poder realizar la indexación). Si el tamaño del registro no es constante, el acceso a estos no podría ser aleatorio (solo por eso ya perdimos un requisito de la búsqueda binaria) porque eventualmente el "puntero" del archivo se nos desalinia y los registros ya no se leerían correctamente.

Aclarar algunos conceptos: En estructuras de datos informáticos, el opuesto al acceso aleatorio, es el acceso secuencial. Acceso aleatorio es aquel que permite la obtención de un dato en un tiempo relativamente constante, sin importar dónde esté. Acceso secuencial es aquel donde por fuerza se debe acceder a una secuencia de datos para llegar al buscado. El tiempo que tarda es lineal (proporcional a la distancia entre el primero y dicho dato), lo que quiere decir que se puede poner peor si la lista crece.

niconetti: Al buscar simplemente por las 4 cifras del identificador, entiendo que al estar ya sabiendo en la línea que me sitúo podré mostrar el nombre de esta persona, ¿no? Se que está tras el espacio.

De hecho; entonces fue mi error mandar a cerrar el archivo una vez se haya encontrado la clave ::)

Buenos días Lucario448.

He probado el código que me enviaste, y me muestra por pantalla dos números distintos. Si te fijas en la foto que subí, me muestra el 1000 más dos simbolos de 4 rayas, y abajo, me muestra 9000 y 4 símbolos de 4 rayas, una cosa extraña. Voy a investigar que es lo que pasa, pero parece que ahora con socas más coherentes y no lo que me salía antes.

Edito: Esto es lo que me sale:

|500x375

Exactamente no entiendo el porqué de esos símbolos de rayas. A ver si puedes explicarmelos, gracias.

Buenas de nuevo compañeros.

Ante el problema de que no consigo que funcione bien, he hecho una pequeña modificación al código de Lucario448 para ver si el problema reside en que no lee el txt o no compara.

      if (!strcmp(Tarjeta, claveSD)) { // Así se comparan cadenas sin tantas operaciones lógicas
        lcd.println("clave valida"); // acción al encontrar clave
        delay(2000);
        break; // sale del loop
     }else{
        lcd.println(claveSD);
        delay(400);
        lcd.clear();
      }

Como podéis ver, he añadido un else al bucle if para que me vaya dando todos los valores leidos en el txt por pantalla. En este caso lo hace perfectamente, así que deduzco el que el problema reside en que no compara el valor dado (Tarjeta) con el valor leído (claveSD).

Ahora estoy intentando solucionar esto último, a ver si consigo entender porque. Yo creo que tiene que ver con los símbolos que muestra por lcd después de cada número, el que son 4 rayas horizontales, que no entiendo porque salen.

Buenas noticias compañeros, tocando un poco he conseguido que compare y me de el código por correcto, simplemente he hecho esta modificación:

//if (!strcmp(Tarjeta, claveSD)) { // Así se comparan cadenas sin tantas operaciones lógicas
      if(claveSD[0]==Tarjeta[0]&&claveSD[1]==Tarjeta[1]&&claveSD[2]==Tarjeta[2]&&claveSD[3]==Tarjeta[3]){

He cambiado el primer if por el segundo, como tenia anteriormente puesto, y ahora compara. Eso sí, el símbolo raro de 4 rayas horizontales sigue apareciendo, no se porque. Aunque lo que me muestra es clave válida, está seguido por el símbolo ese dos veces, como si el número 1000 de la primera foto que puse fuera.

Que no haya funcionado con strcmp es porque claveSD no tiene espacio para el terminador de cadenas. O el tamaño de ese array se aumenta a 5, o se usa strncmp o memcmp.

Los "simbolos de 4 rayas" son el par de caracteres "\r\n"; por eso usualmente no se ve println en los códigos con LCDs de caracteres. El cambio de línea se hace manualmente con setCursor.

PD: me hice una prueba de búsqueda binaria, la base de datos era un archivo con una lista de un millón (hablo en serio, UN MILLÓN) de personas; preordenda por un identificador irrepetible de 9 dígitos. Cada registro tenía un tamaño constante de 50 bytes, lo que resultó en un archivo de aprox. 48 MB (50 millones de bytes).

Por el poder que le concede el acceso aleatorio y el algoritmo de búsqueda binaria, buscar entre un millón de personas por mucho le toma medio segundo. Si hubiera hecho eso mismo pero de manera secuencial, en el peor caso tardaría 8 minutos (asumiendo una velocidad de lectura de 2000 elementos por segundo)

Lucario448:
Que no haya funcionado con strcmp es porque claveSD no tiene espacio para el terminador de cadenas. O el tamaño de ese array se aumenta a 5, o se usa strncmp o memcmp.

Los “simbolos de 4 rayas” son el par de caracteres “\r\n”; por eso usualmente no se ve println en los códigos con LCDs de caracteres. El cambio de línea se hace manualmente con setCursor.

Muchas gracias por la aclaración sobre los símbolos esos raros que tanto me salen. Entonces para evitaros ¿tengo que cambiar de línea manualmente?

Por otro lado, se que me dijiste lo de strcmp, pero como ayer no pude conectarme estuve probando mi código “definitivo” (aun le queda limpieza y más cosillas por meter), con la comparación de caracteres que te enseñe hace un par de post. Ahora quiero cambiar esa comparación por lo que me has dicho que se que es más efectiva.

  char key = teclado.getKey(); //se guarda en la variable customKey el caracter de la tecla presionada
  lcd.setCursor(0,0); //nos vamos a la columna 0 fila 0
  lcd.print("INTRODUZCA CLAVE");
  //delay(500);
  
  if (key != NO_KEY){               //se evalúa si se presionó una tecla
    codigo[cont]=key;               //se guarda caracter por caracter en el arreglo codigo[]
    // Serial.println(codigo[cont]);         //se imprime en el puerto serie la tecla presionada
    lcd.setCursor(cont,1); //columna avanza fila 1
    lcd.print(codigo[cont]);
    cont=cont+1;                          //incrementamos la variable cont
    if(cont==4){                           //si ya fueron presionadas 4 teclas se evalúa si la contraseña es correcta
      delay(500);

////////////////imprime para PRUEBA
      lcd.clear();
      lcd.println(codigo);
      delay(2000);
//////////////////      

archivo = SD.open("datos2.txt");

if (archivo){ // reviso archivo si está disponible
  
  while (archivo.available()) { // mientras no se haya leído todo el archivo
    
    //archivo.setTimeout(100000);
    archivo.readBytes(claveSD, 4); // Ya que el inicio del registro siempre es la clave, se lee de una vez

      if(claveSD[0]==codigo[0]&&claveSD[1]==codigo[1]&&claveSD[2]==codigo[2]&&claveSD[3]==codigo[3]){  // Así se comparan cadenas

         lcd.println("CLAVE VALIDA"); // acción al encontrar clave
         delay(2000);
         lcd.clear();
         
         lcd.println("BIENVENIDO"); // acción al encontrar clave
         archivo.readBytes(nombre,11);
         lcd.println(nombre);
         delay(2000);
         lcd.clear();
         
         lcd.print(" SENTIDO DEL MOTOR");
         lcd.setCursor(0,2);
         lcd.print("       ----->");
         digitalWrite(L293D1, HIGH);
         digitalWrite(L293D7, HIGH); 
         while(digitalRead(2)==HIGH){
          delay(15);
         }
         digitalWrite(L293D7, LOW);
         lcd.clear();
         
         lcd.print(" SENTIDO DEL MOTOR");
         lcd.setCursor(0,2);
         lcd.print("       <-----");
         digitalWrite(L293D2, HIGH);
         delay(1000);
         while(digitalRead(2)==HIGH){
          delay(15);
         }
         digitalWrite(L293D2, LOW);
         lcd.clear();
        
         lcd.setCursor(0,1); //nos vamos a la columna 0 fila 0
         lcd.print("        FIN");
         delay(1500);
         lcd.clear();
         
         break; // sale del loop
      
         while (archivo.read() != '\n'); // Avanzar al siguiente registro (puede quedarse atrapado si el archivo no termina en línea en blanco) 
      
      } //if de comparación 4 dígitos
  
      else{
        
        lcd.clear();
        lcd.setCursor(0,1); //nos vamos a la columna 0 fila 0
        lcd.print("   CODIGO ERRONEO");
        lcd.setCursor(0,2);
        lcd.print("********************");
        delay(2000);
        lcd.clear();
      
        break; // sale del loop
      
        while (archivo.read() != '\n'); // Avanzar al siguiente registro (puede quedarse atrapado si el archivo no termina en línea en blanco)  
      
      } //else del if de comparación 4 digitos

  } //while lectura de todo el archivo
         
   archivo.close(); // CERRAR EL ARCHIVO UNA VEZ TERMINADO
   cont=0;  //resetear a 0 la variable cont

} //if de archivo disponible
     
 } //if si se han pulsado ya las 4 teclas
 } //if de si no se pulsa ninguna tecla

Esto es más o menos lo que tengo en el loop. Mi problema viene en que no consigo ahora que me recorra el bucle, solo es capaz de leerme el primer dato de mi archivo txt, los demás directamente me salta al else y me muestra el mensaje que tengo escrito de código erróneo.

A ver si me podéis ayudar a encontrar el error, porque no doy con el. Creo que el problema esta en el tema del orden de los bucles if y while, ya he estado comparando con el código anterior que me pasaste y en el podría hacer la búsqueda. La diferencia ahora es que yo meto por teclado el código de 4 cifras y ese es el que tiene que comparar, de ahí que haya cambiado cosas.

Gracias

Ya se el porque del problema que os comenté anteriormente de que siempre se iba a la segunda parte del if, concretamente al else.

Me he dado cuenta añadiendo unas líneas de código para visualizar lo que se lee, que al ir de 4 cifras en 4 cifras el archivo.readBytes(claveSD, 4); cuando lee no solo lee las 4 cifras primeras del archivo, si no también las 4 posteriores y así etc. Por ello cuando llega al final y por ejemplo no ha completado un ciclo entero de 4 cifras, digamos que solo lee 3 cifras en la linea x, pues pasa a la línea x+1 y lee la primera cifra como la 4ª de ciclo de 4 cifras completo.

De ahí que no me valide las posiciones, puesto que aunque todas las líneas empiezan por un código numérico de 4 cifras, a ellas les sigue un nombre que no siempre tiene la misma longitud.

  char key = teclado.getKey(); //se guarda en la variable customKey el caracter de la tecla presionada
  lcd.setCursor(0,0); //nos vamos a la columna 0 fila 0
  lcd.print("INTRODUZCA CLAVE");
  //delay(500);
  
  if (key != NO_KEY){               //se evalúa si se presionó una tecla
    codigo[cont]=key;               //se guarda caracter por caracter en el arreglo codigo[]
    // Serial.println(codigo[cont]);         //se imprime en el puerto serie la tecla presionada
    lcd.setCursor(cont,1); //columna avanza fila 1
    lcd.print(codigo[cont]);
    cont=cont+1;                          //incrementamos la variable cont
    if(cont==4){                           //si ya fueron presionadas 4 teclas se evalúa si la contraseña es correcta
      delay(500);

////////////////imprime para PRUEBA
      lcd.clear();
      lcd.println(codigo);
      delay(2000);
//////////////////      

archivo = SD.open("datos2.txt");

if (archivo){ // reviso archivo si está disponible
  
  while (archivo.available()) { // mientras no se haya leído todo el archivo
    
    //archivo.setTimeout(100000);
    archivo.readBytes(claveSD, 4); // Ya que el inicio del registro siempre es la clave, se lee de una vez

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println(claveSD);
    delay(500);
    
      if (!strcmp(claveSD, codigo)) { // Así se comparan cadenas sin tantas operaciones lógicas. El 4 indica los caracteres a comparar
      //if(claveSD[0]==codigo[0]&&claveSD[1]==codigo[1]&&claveSD[2]==codigo[2]&&claveSD[3]==codigo[3]){
         
         contTrue=contTrue+1;
         
         lcd.println("CLAVE VALIDA"); // acción al encontrar clave
         delay(2000);
         lcd.clear();
         
         lcd.println("BIENVENIDO"); // acción al encontrar clave
         archivo.readBytes(nombre,11);
         lcd.println(nombre);
         delay(2000);
         lcd.clear();
         
         lcd.print(" SENTIDO DEL MOTOR");
         lcd.setCursor(0,2);
         lcd.print("       ----->");
         digitalWrite(L293D1, HIGH);
         digitalWrite(L293D7, HIGH); 
         while(digitalRead(2)==HIGH){
          delay(15);
         }
         digitalWrite(L293D7, LOW);
         lcd.clear();
         
         lcd.print(" SENTIDO DEL MOTOR");
         lcd.setCursor(0,2);
         lcd.print("       <-----");
         digitalWrite(L293D2, HIGH);
         delay(1000);
         while(digitalRead(2)==HIGH){
          delay(15);
         }
         digitalWrite(L293D2, LOW);
         lcd.clear();
        
         lcd.setCursor(0,1); //nos vamos a la columna 0 fila 0
         lcd.print("        FIN");
         delay(1500);
         lcd.clear();
         
         break; // sale del loop  
      
      } //if de comparación 4 dígitos

  } //while lectura de todo el archivo
  
  if (contTrue==0){
        lcd.clear();
        lcd.setCursor(0,1); //nos vamos a la columna 0 fila 0
        lcd.print("   CODIGO ERRONEO");
        lcd.setCursor(0,2);
        lcd.print("********************");
        delay(1000);
        lcd.clear();

        contTrue=0;
  }
      
        //break; // sale del loop
      
        //while (archivo.read() != '\n'); // Avanzar al siguiente registro (puede quedarse atrapado si el archivo no termina en línea en blanco)  
      
      //} //else del if de comparación 4 digitos

while (archivo.read() != '\n'); // Avanzar al siguiente registro (puede quedarse atrapado si el archivo no termina en línea en blanco)  

  //} //while lectura de todo el archivo
         
   archivo.close(); // CERRAR EL ARCHIVO UNA VEZ TERMINADO
   //cont=0;  //resetear a 0 la variable cont

} //if de archivo disponible
     cont=0;  //resetear a 0 la variable cont
 } //if si se han pulsado ya las 4 teclas
 } //if de si no se pulsa ninguna tecla
 } //buble loop

A ver si podéis orientarme como corregir ese error.

Gracias

Veamos si esto funciona:

 char key = teclado.getKey(); //se guarda en la variable customKey el caracter de la tecla presionada
  lcd.setCursor(0,0); //nos vamos a la columna 0 fila 0
  lcd.print("INTRODUZCA CLAVE");
  //delay(500);
  
  if (key != NO_KEY){               //se evalúa si se presionó una tecla
    codigo[cont]=key;               //se guarda caracter por caracter en el arreglo codigo[]
    // Serial.println(codigo[cont]);         //se imprime en el puerto serie la tecla presionada
    lcd.setCursor(cont,1); //columna avanza fila 1
    lcd.print(codigo[cont]);
    cont=cont+1;                          //incrementamos la variable cont
    if(cont==4){                           //si ya fueron presionadas 4 teclas se evalúa si la contraseña es correcta
      delay(500);

////////////////imprime para PRUEBA
      lcd.clear();
      lcd.println(codigo);
      delay(2000);
//////////////////      

archivo = SD.open("datos2.txt");

if (archivo){ // reviso archivo si está disponible
  
  while (archivo.available()) { // mientras no se haya leído todo el archivo
    
    archivo.readBytes(claveSD, 4); // Ya que el inicio del registro siempre es la clave, se lee de una vez

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.println(claveSD);
    delay(500);
    
      if (!strcmp(claveSD, codigo)) { // Así se comparan cadenas sin tantas operaciones lógicas. El 4 indica los caracteres a comparar
         
         contTrue=contTrue+1;
         
         lcd.println("CLAVE VALIDA"); // acción al encontrar clave
         delay(2000);
         lcd.clear();
         
         lcd.println("BIENVENIDO"); // acción al encontrar clave
         archivo.readBytes(nombre,11); // ¿11 es el tamaño máximo?
         lcd.println(nombre);
         delay(2000);
         lcd.clear();
         
         lcd.print(" SENTIDO DEL MOTOR");
         lcd.setCursor(0,2);
         lcd.print("       ----->");
         digitalWrite(L293D1, HIGH);
         digitalWrite(L293D7, HIGH); 
         while(digitalRead(2)==HIGH){
          delay(15);
         }
         digitalWrite(L293D7, LOW);
         lcd.clear();
         
         lcd.print(" SENTIDO DEL MOTOR");
         lcd.setCursor(0,2);
         lcd.print("       <-----");
         digitalWrite(L293D2, HIGH);
         delay(1000);
         while(digitalRead(2)==HIGH){
          delay(15);
         }
         digitalWrite(L293D2, LOW);
         lcd.clear();
        
         lcd.setCursor(0,1); //nos vamos a la columna 0 fila 0
         lcd.print("        FIN");
         delay(1500);
         lcd.clear();
         
         break; // sale del loop  
      
      } //if de comparación 4 dígitos
  while (archivo.read() != '\n');

  } //while lectura de todo el archivo
  
  if (contTrue==0){
        lcd.clear();
        lcd.setCursor(0,1); //nos vamos a la columna 0 fila 0
        lcd.print("   CODIGO ERRONEO");
        lcd.setCursor(0,2);
        lcd.print("********************");
        delay(1000);
        lcd.clear();

        
  }
  contTrue=0;
         
   archivo.close(); // CERRAR EL ARCHIVO UNA VEZ TERMINADO

} //if de archivo disponible
     cont=0;  //resetear a 0 la variable cont
 } //if si se han pulsado ya las 4 teclas
 } //if de si no se pulsa ninguna tecla
 } //buble loop

Solo una pregunta:

archivo.readBytes(nombre,11); // ¿11 es el tamaño máximo?

Si después del nombre no hay más datos, entonces puedes hacer lectura hasta cierto caracter:

nombre[archivo.readBytesUntil('\r', nombre, sizeof(nombre) - 1)] = 0;

Muchas gracias, yo está funcionando. Ahora lo que tengo que hacer es añadir funciones del equipo y depurar lo que e muestra por lcd, básicamente borrar los simbolos de los espacios que aparecen por pantalla. ¿Me comentaste que era haciendo un clear al lcd y luego escribiendo?

Lucario448: Solo una pregunta:

archivo.readBytes(nombre,11); // ¿11 es el tamaño máximo?

Esto lo tenia hecho para probar la lectura del nombre de la persona que acompaña al dígito de 4 números. Al estar en la misma línea pues me lee la continuación. Le metí 11 basicamente para que cupiera todo el nombre.

Lucario448: Si después del nombre no hay más datos, entonces puedes hacer lectura hasta cierto caracter:

nombre[archivo.readBytesUntil('\r', nombre, sizeof(nombre) - 1)] = 0;

Con este código que me comentas sale mejor, el problema es que tendría que tenerlo aumentado hasta el número de bytes máximo del nombre más largo, para que cupieran todos. ¿No se podría hacer hasta que llegara a un espacio?

Gracias

niconetti: Ahora lo que tengo que hacer es añadir funciones del equipo y depurar lo que e muestra por lcd, básicamente borrar los simbolos de los espacios que aparecen por pantalla. ¿Me comentaste que era haciendo un clear al lcd y luego escribiendo?

No recuerdo haber dicho eso, pero sí que no usaras println y que el cambio de línea lo hicieras con setCursor; solo eso.

Esto lo tenia hecho para probar la lectura del nombre de la persona que acompaña al dígito de 4 números. Al estar en la misma línea pues me lee la continuación. Le metí 11 basicamente para que cupiera todo el nombre.

niconetti: el problema es que tendría que tenerlo aumentado hasta el número de bytes máximo del nombre más largo, para que cupieran todos. ¿No se podría hacer hasta que llegara a un espacio?

Vamos a analizar en profundidad esa línea de código:

nombre[archivo.readBytesUntil('\r', nombre, sizeof(nombre) - 1)] = 0;

archivo.readBytesUntil dice: lea bytes/caracteres que se van a guardar en nombre; lea hasta toparse con '\r', o hasta llegar a los sizeof(nombre) - 1 bytes/caracteres.

Definimos '\r' como el terminador de la cadena a leer. Definimos sizeof(nombre) como el tamaño en bytes/caracteres del array nombre.

readBytesUntil retorna un int que representa la cantidad real de bytes/caracteres que fueron leídos; dicho valor se aprovecha para determinar el índice dónde colocar el terminador de cadenas de caracteres (byte con valor cero).