Lettura file da SD e stampa su Display

Salve a tutti,

Ho appena costruito una pista per Slot Car e volevo ampliare il plastico con un piccolo Display I2C 16x2 su quale viene segnato il tempo dell'ultimo giro ed il tempo migliore effettuato. Poi salvare su microSD il giro record che verrà richiamato al prossimo avvio della pista.
Il mio problema stà nel fatto che riesco a salvare su microSD il file "bestlap.txt" con tutti i giri migliori, ma non riesco a richiamare l'ultimo valore della lista all'interno del ".txt" per visualizzarla su Display.
Ho già dato un'occhiata nel forum... per esempio questo " Lettura file su SD card e inserimento su stringa - Software - Arduino Forum ", ma non riesco ad incastrarlo nel mio sketch...
Grazie in anticipo,

Fede.

Ecco lo Sketch:

// Timer per Slot Car a corsia singola
// con salvataggio Record su SD

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h> Includere per registrazione file 

File file; // Denominazione per registrazione file

//variables
const byte lightPin = 0;  
const byte speakerPin = 9;
int lightSensor = 0;
unsigned long lapMillis = 0;
unsigned long startMillis = millis();
unsigned long bestMillis = 9999999;
float lapTime = 0.00;
float bestLap = 0.00;
boolean firstTrigger = true;
boolean newBest = false;

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
    // Lettura Tempo Record
      !SD.begin(53); 
      file = SD.open("bestlap.txt", FILE_READ);

      lcd.begin();
      lcd.setCursor(0, 0);
      lcd.print("Migliore:       ");
      lcd.setCursor(0, 1);
      
      lcd.print(bestLap.);
      file.close();
      delay(5000);

          
    
    
    
    // lcd.begin();
    lcd.setCursor(0, 0);
    lcd.print("Pronti!         ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    Serial.begin(9600); 
    pinMode(speakerPin, OUTPUT);
    digitalWrite(speakerPin, LOW);
}

void loop()
{

//Lettura fotoresisteza
lightSensor = analogRead(lightPin);


  //Se l'auto è stata rivelata
  if(lightSensor < analogRead(1)){
  
    
    //Determinazione del giro in millisecondi
    lapMillis = millis() - startMillis;
    startMillis = millis();
    
    lapTime = lapMillis / 1000.00;
    
    //Stampa su display al passaggio su fotocellula
    if (firstTrigger == true){
      lcd.setCursor(0, 0);
      lcd.print("Partenza!       ");
    }
    
    //stampa su display se non ancora passato su fotocellula
    if (firstTrigger != true){
      Serial.print("lapTime: ");
      Serial.println(lapTime);
      Serial.print("lapMillis: ");
      Serial.println(lapMillis);
      //Stampa il tempo sul giro
      lcd.setCursor(0, 0);
      lcd.print("Last: ");
      lcd.print(lapTime);
      lcd.print("       ");   
    }
   
        
    //Se l'ultimo giro è migliore dell'ultimo giro
    if(lapMillis < bestMillis && firstTrigger != true)
    {
      bestMillis = lapMillis;
      bestLap = lapTime;
      Serial.print("bestLap: ");
      Serial.println(bestLap);
      //print best lap time
      lcd.setCursor(0, 1);
      lcd.print("Best: ");
      lcd.print(bestLap);
      lcd.print("      ");
      newBest = true;
    }
    
    //Suono Piezo e Lampeggio Led
    if(newBest == true)
    {
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);    
      newBest = false;

      // Salvataggio Tempo Record
      !SD.begin(53); 
      file = SD.open("bestlap.txt", FILE_WRITE);
      file.println(bestLap);
      file.close();
  
    } 
    else
    {
      digitalWrite(speakerPin, HIGH);
      delay(150);
      digitalWrite(speakerPin, LOW);
    }
    
    firstTrigger = false;
    Serial.println("----------------"); 

}
}

Ciao Docsavage,

sì, l'intento è quello di registrare nella SD il tempo assoluto più veloce.
Ho notato che nello sketch c'è un "errore" nel salvataggio dei dati, ossia vengono salvati tutti i giri veloci in ordine cronologico, ma al momento del riavvio, se io leggo l'ultimo valore, sarà il giro più veloce effettuato nella sessione precedente e non quello assoluto.
Dovrei quindi fare in modo che il software vada a leggere il contenuto del file ad ogni loop e confronti il valore. Se il miglior tempo è superiore a quanto scritto nel file, non succede nulla; altrimenti, sovrascrive il file con il nuovo tempo migliore. Tutto questo nel blocco blocco IF.
Il mio problema è che non ho capito come si fa ad andare a leggere il contenuto del file *.txt e farlo apparire all'inizio di ogni riavvio.
Anche perché non posso fare confronti tra i tempi se non riesco a leggere quello salvato.
Grazie,

Fede.

Io farei in modo che nel file ci sia sempre una sola riga:

  • all'avvio leggi quella singola riga, sarà il tempo migliore, e lo tieni in memoria.
  • alla fine di ogni gara, se è stato registrato un tempo migliore, lo scrivi nel file (sovrascrivendo il vecchio) e lo aggiorni anche in memoria.

Fine.

Beh... si... :confused:

Io ho usato questo approccio da niubbo...

// Timer per Slot Car a corsia singola
// con salvataggio Record su SD

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h> // Includere per registrazione file 

File file;      // Denominazione per registrazione file

//variabili
const byte lightPin = 0;  
const byte speakerPin = 9;
int lightSensor = 0;
unsigned long lapMillis = 0;
unsigned long startMillis = millis();
unsigned long bestMillis = 9999999;
float lapTime = 0.00;
float bestLap = 0.00;
boolean firstTrigger = true;
boolean newBest = false;


LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
    
   // Lettura Tempo Record
      !SD.begin(53); 
      file = SD.open("bestlap.txt", FILE_READ);

      lcd.begin();
      lcd.setCursor(0, 0);
      lcd.print("Migliore:       ");
      lcd.setCursor(0, 1);
      
      lcd.write(file.read());
      file.close();
      delay(5000);

          
    
    
    
 // lcd.begin();
    lcd.setCursor(0, 0);
    lcd.print("Pronti...       ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    Serial.begin(9600); 
    pinMode(speakerPin, OUTPUT);
    digitalWrite(speakerPin, LOW);
}

void loop()
{

//Lettura fotoresisteza
  lightSensor = analogRead(lightPin);
 

  //Se l'auto è stata rivelata
    if(lightSensor < analogRead(1)){
  
    
  //Determinazione del giro in millisecondi
    lapMillis = millis() - startMillis;
    startMillis = millis();
    
    lapTime = lapMillis / 1000.00;
    
  //Stampa su display al passaggio su fotocellula
    if (firstTrigger == true){
      lcd.setCursor(0, 0);
      lcd.print("Via!            ");
    }
    
    //stampa su display se non ancora passato su fotocellula
      if (firstTrigger != true){
      Serial.print("lapTime: ");
      Serial.println(lapTime);
      Serial.print("lapMillis: ");
      Serial.println(lapMillis);
      
      //Stampa il tempo sul giro
        lcd.setCursor(0, 0);
        lcd.print("Last: ");
        lcd.print(lapTime);
        lcd.print("       ");   
    }
   
        
  //Se l'ultimo giro è migliore del penultimo giro
    if(lapMillis < bestMillis && firstTrigger != true)
    {
      bestMillis = lapMillis;
      bestLap = lapTime;
      Serial.print("bestLap: ");
      Serial.println(bestLap);
      //print best lap time
      lcd.setCursor(0, 1);
      lcd.print("Best: ");
      lcd.print(bestLap);
      lcd.print("      ");
      newBest = true;
    
    //Eliminazione Vecchio Tempo Record
      !SD.begin(53); 
      SD.remove("bestlap.txt");
      file.close();

    //Salvataggio Nuovo Tempo Record
      !SD.begin(53); 
      file = SD.open("bestlap.txt", FILE_WRITE);
      file.println(bestLap);
      file.close();
    
    
    
    
    }
    
  //Suono Piezo e Lampeggio Led
    if(newBest == true)
    {
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);    
      newBest = false;

    } 
    else
    {
      digitalWrite(speakerPin, HIGH);
      delay(150);
      digitalWrite(speakerPin, LOW);
    }
    
    firstTrigger = false;
    Serial.println("----------------"); 

}
}

Ad ogni nuovo tempo record il file *.txt viene eliminato e sostituito con un nuovo file. Il problema ora è che sul display non mi vengono visualizzate correttamente le cifre .
Per esempio, se il giro più veloce è stato di 38.72 secondi, ad ogni riavvio vedrò apparire sul display solo la prima cifra. Ossia 3...

Allora...

aggiungendo questo:

 while (file.available()) {
      lcd.write(file.read());
      }

il tempo viene visualizzato correttamente.
Ma è normale che mi appaiano 2 strani caratteri dopo la cifra? :frowning:

Fede_ITA:
se il giro più veloce è stato di 38.72 secondi, ad ogni riavvio vedrò apparire sul display solo la prima cifra. Ossia 3...

Provo a buttarti giù l'idea, se fai una funzioncina del genere?

String leggiRecord(String fileName) {
  File fh = SD.open(fileName);
  if (fh) {
    char buf[64] = "";
    int chPos = 0;
    while(fh.available())
    {
      char ch = fh.read();
      if(chPos < 64) {
        buf[chPos++] = ch;
        buf[chPos] = 0;
      }
    }
    fh.close();
    return String(netBuffer);
  }
}

Fede_ITA:
il tempo viene visualizzato correttamente.
Ma è normale che mi appaiano 2 strani caratteri dopo la cifra? :frowning:

Se nel file hai scritto anche i fine riga (CR e LF, o \r \n o 0x0D 0x0A) si.
O non li scrivi, o devi leggere tutto fino al primo \r (nella funzioncina di esempio che ti ho scritto, devi fare break dal while se il carattere letto è '\r').

Uhm...

Ho provato ad inserire il codice che mi hai passato apportando le modifiche del caso... ma proprio non ci arrivo.

Posta tutto il tuo codice, inclusa la nuova funzione, e vediamo..

Ecco...

// Timer per Slot Car a corsia singola
// con salvataggio Record su SD

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h> // Includere per registrazione file 

File file;      // Denominazione per registrazione file

//variabili
const byte lightPin = 0;  
const byte speakerPin = 9;
int lightSensor = 0;
unsigned long lapMillis = 0;
unsigned long startMillis = millis();
unsigned long bestMillis = 9999999;
float lapTime = 0.00;
float bestLap = 0.00;
boolean firstTrigger = true;
boolean newBest = false;


LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
    
   // Lettura Tempo Record
      !SD.begin(53); 
 /*   file = SD.open("bestlap.txt", FILE_READ);

      lcd.begin();
      
      lcd.setCursor(0, 0);
      lcd.print(" Rally          ");
      lcd.setCursor(0, 1);
      lcd.print("       Speedway ");
      delay(5000);
      
      lcd.setCursor(0, 0);
      lcd.print("Migliore:       ");
      lcd.setCursor(0, 1);
      lcd.print("                ");
      lcd.setCursor(11, 1);
      while (file.available()) {
      lcd.write(file.read());
      }
      file.close();
 */   
    
    String leggiRecord(String bestlap.txt) {
  file = SD.open("bestlap.txt", FILE_READ);
  if (file) {
    char buf[64] = "";
    int chPos = 0;
    while(file.available())
    {
      char ch = file.read();
      if(chPos < 64) {
        buf[chPos++] = ch;
        buf[chPos] = 0;
      }
    }
    file.close();
    return String(netBuffer);
  }
}
    
    
    delay(5000);

 // lcd.begin();
    lcd.setCursor(0, 0);
    lcd.print("Pronti...       ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    Serial.begin(9600); 
    pinMode(speakerPin, OUTPUT);
    digitalWrite(speakerPin, LOW);
}

void loop()
{

//Lettura fotoresisteza
  lightSensor = analogRead(lightPin);
 

  //Se l'auto è stata rivelata
    if(lightSensor < analogRead(1)){
  
    
  //Determinazione del giro in millisecondi
    lapMillis = millis() - startMillis;
    startMillis = millis();
    
    lapTime = lapMillis / 1000.00;
    
  //Stampa su display al passaggio su fotocellula
    if (firstTrigger == true){
      lcd.setCursor(0, 0);
      lcd.print("Via!            ");
    }
    
    //stampa su display se non ancora passato su fotocellula
      if (firstTrigger != true){
      Serial.print("lapTime: ");
      Serial.println(lapTime);
      Serial.print("lapMillis: ");
      Serial.println(lapMillis);
      
      //Stampa il tempo sul giro
        lcd.setCursor(0, 0);
        lcd.print("Last: ");
        lcd.print(lapTime);
        lcd.print("       ");   
    }
    
  //Se l'ultimo giro è migliore del penultimo giro
    if(lapMillis < bestMillis && firstTrigger != true)
    {
      bestMillis = lapMillis;
      bestLap = lapTime;
      Serial.print("bestLap: ");
      Serial.println(bestLap);
      //print best lap time
      lcd.setCursor(0, 1);
      lcd.print("Best: ");
      lcd.print(bestLap);
      lcd.print("      ");
      newBest = true;
    
    //Eliminazione Vecchio Tempo Record
      !SD.begin(53); 
      SD.remove("bestlap.txt");
      file.close();

    //Salvataggio Nuovo Tempo Record
      !SD.begin(53); 
      file = SD.open("bestlap.txt", FILE_WRITE);
      file.println(bestLap);
      file.close();
    
    
    
    
    }
    
  //Suono Piezo e Lampeggio Led
    if(newBest == true)
    {
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);    
      newBest = false;

    } 
    else
    {
      digitalWrite(speakerPin, HIGH);
      delay(150);
      digitalWrite(speakerPin, LOW);
    }
    
    firstTrigger = false;
    Serial.println("----------------"); 

}
}

e tanti messaggi di errore...

Visto e considerato la mia scarsa conoscenza in ambito di programmazione, è chiaro che il mio approccio è del tutto sbagliato.
A questo punto dovrei dare al valore contenuto nel file un nome, per poter poi confrontarlo con la variabile "bestLap".

Ehm... La leggiRecord() è una funzione, mica puoi metterla così! :o

La definizione della funzione messa FUORI dalle setup() e loop(), e solo RICHIAMATA dentro a setup!
E poi non si richiama così ("leggiRecord(String bestlap.txt)"???)...
E poi hai commentato persino l'inizializzazione dell'lcd...
E poi perché il "!" in "!SD.begin()"???
E poi non è mica necessario fare SD.bgin() ad ogni uso della SD...

Insomma penso/temo che ci sia qualche base di C che ti manca...

La funzione che ti ho scritto al volo ti restituisce una stringa, che poi TU devi usare per mostrarla sul display e, probabilmente, convertirla in float per poterla poi confrontare con il tempo rilevato successivamente...

Vabbé prova intanto a mettere questo, è incompleto e non l'ho potuto verificare (non sono a casa) ma alcune cosette ho iniziato ad aggiustartele, dovrebbe almeno girare e poi vedi tu come sistemarlo e cosa farci con la variabile "record". Ovviamente non basta fare copia/incolla di vari esempi trovati in rete (e neanche del codice che ti ho fatto io), devi prima CAPIRE cosa stai facendo e cosa significano certe istruzioni... :wink:

// Timer per Slot Car a corsia singola
// con salvataggio Record su SD

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h> // Includere per registrazione file 

File file;      // Denominazione per registrazione file

//variabili
const byte lightPin = 0;  
const byte speakerPin = 9;
int lightSensor = 0;
unsigned long lapMillis = 0;
unsigned long startMillis = millis();
unsigned long bestMillis = 9999999;
float lapTime = 0.00;
float bestLap = 0.00;
boolean firstTrigger = true;
boolean newBest = false;

#define FILE_RECORD "bestlap.txt"
String record = "";

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
	SD.begin(53); 

	// Lettura Tempo Record
    record = leggiRecord(FILE_RECORD);

	lcd.begin();

	lcd.setCursor(0, 0);
	lcd.print(" Rally          ");
	lcd.setCursor(0, 1);
	lcd.print("       Speedway ");
	delay(5000);

	lcd.setCursor(0, 0);
	lcd.print("Migliore:       ");
	lcd.setCursor(0, 1);
	lcd.print("                ");
	lcd.setCursor(11, 1);
	lcd.print(record);
    
    delay(5000);

    lcd.setCursor(0, 0);
    lcd.print("Pronti...       ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    Serial.begin(9600); 
    pinMode(speakerPin, OUTPUT);
    digitalWrite(speakerPin, LOW);
}

void loop()
{

  //Lettura fotoresisteza
  lightSensor = analogRead(lightPin);
 

  //Se l'auto è stata rivelata
  if(lightSensor < analogRead(1)){
	  //Determinazione del giro in millisecondi
		lapMillis = millis() - startMillis;
		startMillis = millis();
		
		lapTime = lapMillis / 1000.00;
		
	  //Stampa su display al passaggio su fotocellula
		if (firstTrigger == true){
		  lcd.setCursor(0, 0);
		  lcd.print("Via!            ");
		}
		
		//stampa su display se non ancora passato su fotocellula
		  if (firstTrigger != true){
		  Serial.print("lapTime: ");
		  Serial.println(lapTime);
		  Serial.print("lapMillis: ");
		  Serial.println(lapMillis);
		  
		  //Stampa il tempo sul giro
			lcd.setCursor(0, 0);
			lcd.print("Last: ");
			lcd.print(lapTime);
			lcd.print("       ");   
		}
		
	  //Se l'ultimo giro è migliore del penultimo giro
		if(lapMillis < bestMillis && firstTrigger != true)
		{
		  bestMillis = lapMillis;
		  bestLap = lapTime;
		  Serial.print("bestLap: ");
		  Serial.println(bestLap);
		  //print best lap time
		  lcd.setCursor(0, 1);
		  lcd.print("Best: ");
		  lcd.print(bestLap);
		  lcd.print("      ");
		  newBest = true;
		
		//Salvataggio Nuovo Tempo Record
			salvaRecord(FILE_RECORD);
		}
		
	  //Suono Piezo e Lampeggio Led
		if(newBest == true)
		{
		  digitalWrite(speakerPin, HIGH);
		  delay(25);
		  digitalWrite(speakerPin, LOW);
		  delay(25);
		  digitalWrite(speakerPin, HIGH);
		  delay(25);
		  digitalWrite(speakerPin, LOW);
		  delay(25);
		  digitalWrite(speakerPin, HIGH);
		  delay(25);
		  digitalWrite(speakerPin, LOW);
		  delay(25);
		  digitalWrite(speakerPin, HIGH);
		  delay(25);
		  digitalWrite(speakerPin, LOW);    
		  newBest = false;

		} 
		else
		{
		  digitalWrite(speakerPin, HIGH);
		  delay(150);
		  digitalWrite(speakerPin, LOW);
		}
		
		firstTrigger = false;
		Serial.println("----------------"); 

  }
}

String leggiRecord(String nomeFile) {
  file = SD.open(nomeFile, FILE_READ);
  if (file) {
    char buf[64] = "";
    int chPos = 0;
    while(file.available())
    {
      char ch = file.read();
      if(chPos < 64) {
        buf[chPos++] = ch;
        buf[chPos] = 0;
      }
    }
    file.close();
    return String(netBuffer);
  }
}

void salvaRecord(String nomeFile) {
	//Eliminazione Vecchio Tempo Record
	SD.remove(nomeFile);
	//Salvataggio Nuovo Tempo Record
	file = SD.open(nomeFile, FILE_WRITE);
	file.print(bestLap);
	file.close();
}

Guarda...

Ti ringrazio, ma davvero, non sono proprio in grado di comprendere ciò che hai scritto... mi sono imbarcato in qualcosa che va al di là delle mie attuali conoscenze.

Tranquillo, siamo tutti qui per imparare, io per primo. Tu inizia a provare quel codice, cerca di capire come è fatto e come ho cambiato alcune cose (ad esempio sulla SD non scrivo con println() ma con print() così non hai più i caratteri \r \n), se qualcosa non riesci a capirla o a farla, chiedi pure!!!

Non ho idea di come si gestiscono le funzioni e le stringhe... è la prima volta che ho la necessità di farne uso. Stavo leggendo proprio ora un tutorial, ma haimè faccio fatica a venirne a capo.
Ho visto che hai aggiunto la stringa "record" per poterla richiamare quando ce n'è bisogno e ridefinito in FILE_RECORD il file "bestlap.txt". Ho anche capito che cosa vuol dire il pacchetto di istruzioni che mi hai passato all'inizio (richiami solo il numero di caratteri che compongono il file stesso e gli dà un nome, così da poter essere anch'egli richiamato al bisogno).
Purtoppo non conosco tutte le istruzioni e quindi mi trovo ad un punto morto.

Va bene, ma come ti ho detto, non preoccuparti, tu fai prove, vedi che succede, e poi se ti serve qualche aiuto scrivi qui!

In ogni caso inizia con un tutorial di base sulla programmazione come QUESTO (dell'ottimo sito Alfieri) o un testo in PDF come QUESTO. Ma di risorse in rete ce ne sono tantissime...

Allora...

grazie ai suggerimenti sono arrivato qui. Putroppo ho bisogno ancora dell'Oracolo per correggere gli errori...

// Timer per Slot Car a corsia singola
// con salvataggio Record su SD

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h> // Includere per registrazione file

File file;      // Denominazione per registrazione file

//variabili
const byte lightPin = 0; 
const byte speakerPin = 9;
int lightSensor = 0;
unsigned long lapMillis = 0;
unsigned long startMillis = millis();
unsigned long bestMillis = 9999999;
float lapTime = 0.00;
float bestLap = 0.00;
boolean firstTrigger = true;
boolean newBest = false;

#define FILE_RECORD "bestlap.txt"
String record = "";

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
  SD.begin(53);

  // Lettura Tempo Record
    record = leggiRecord(FILE_RECORD);

  lcd.begin();

  lcd.setCursor(0, 0);
  lcd.print(" Rally          ");
  lcd.setCursor(0, 1);
  lcd.print("       Speedway ");
  delay(5000);

  lcd.setCursor(0, 0);
  lcd.print("Migliore:       ");
  lcd.setCursor(0, 1);
  lcd.print("                ");
  lcd.setCursor(11, 1);
  lcd.print(record);
   
    delay(5000);

    lcd.setCursor(0, 0);
    lcd.print("Pronti...       ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    Serial.begin(9600);
    pinMode(speakerPin, OUTPUT);
    digitalWrite(speakerPin, LOW);
}

void loop()
{

  //Lettura fotoresisteza
  lightSensor = analogRead(lightPin);
 

  //Se l'auto è stata rivelata
  if(lightSensor < analogRead(1)){
    //Determinazione del giro in millisecondi
    lapMillis = millis() - startMillis;
    startMillis = millis();
    
    lapTime = lapMillis / 1000.00;
    
    //Stampa su display al passaggio su fotocellula
    if (firstTrigger == true){
      lcd.setCursor(0, 0);
      lcd.print("Via!            ");
    }
    
    //stampa su display se non ancora passato su fotocellula
      if (firstTrigger != true){
      Serial.print("lapTime: ");
      Serial.println(lapTime);
      Serial.print("lapMillis: ");
      Serial.println(lapMillis);
     
      //Stampa il tempo sul giro
      lcd.setCursor(0, 0);
      lcd.print("Last: ");
      lcd.print(lapTime);
      lcd.print("       ");   
    }
    
    //Se l'ultimo giro è migliore del penultimo giro
    if(lapMillis < bestMillis && firstTrigger != true)
    {
      bestMillis = lapMillis;
      bestLap = lapTime;
      Serial.print("bestLap: ");
      Serial.println(bestLap);
      //print best lap time
      lcd.setCursor(0, 1);
      lcd.print("Best: ");
      lcd.print(bestLap);
      lcd.print("      ");
      newBest = true;
    
    //Salvataggio Nuovo Tempo Record
      salvaRecord(FILE_RECORD);
    }
    
    //Suono Piezo e Lampeggio Led
    if(newBest == true)
    {
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);
      delay(25);
      digitalWrite(speakerPin, HIGH);
      delay(25);
      digitalWrite(speakerPin, LOW);   
      newBest = false;

    }
    else
    {
      digitalWrite(speakerPin, HIGH);
      delay(150);
      digitalWrite(speakerPin, LOW);
    }
    
    firstTrigger = false;
    Serial.println("----------------");

  }
}

String leggiRecord(String vecchioRecord) {
  file = SD.open("bestlap.txt", FILE_READ);
  if (file) {
    char buf[64] = "";
    int chPos = 0;
    while(file.available())
    {
      char ch = file.read();
      if(chPos < 64) {
        buf[chPos++] = ch;
        buf[chPos] = 0;
      }
    }
    file.close();
    return String(record);
  }
}

void salvaRecord(String nuovoRecord) {
  //Eliminazione Vecchio Tempo Record
  SD.remove("bestlap.txt");
  //Salvataggio Nuovo Tempo Record
  file = SD.open("bestlap.txt", FILE_WRITE);
  file.print(bestLap);
  file.close();
}

Manca l'IF per capire se il nuovoRecord sostituirà vecchioRecord... comunque sia, ora ho il file salvato su SD che con la versione a stringhe non avevo.
Ora però, sul display, quando è il momento di visualizzare in tempo registrato su file, appiono solo simboli indecifrabili.
Credo che il problema risieda qui...

if (file) {
    char buf[64] = "";
    int chPos = 0;
    while(file.available())
    {
      char ch = file.read();
      if(chPos < 64) {
        buf[chPos++] = ch;
        buf[chPos] = 0;
      }
    }

Fede_ITA:
Manca l'IF per capire se il nuovoRecord sostituirà vecchioRecord...

Prova questo:

    //Salvataggio Nuovo Tempo Record?
	  char buf[20];
	  sprintf(buf, "%2d.%02d", (int)bestLap, (int)(bestLap*100.0)%100);
	  String newLap = String(buf);
  	  if ( newLap < bestLap) 
		salvaRecord(FILE_RECORD, bestLap);

Ora però, sul display, quando è il momento di visualizzare in tempo registrato su file, appiono solo simboli indecifrabili.
Credo che il problema risieda qui...

Per capire cosa fa un programma Arduino, e quindi fare il "debugging" ossia cercare di capire cosa non va e perché, si usa in genere scrivere sulla seriale, per visualizzare informazioni sul monitor seriale.
Prova a mettere qualche riga Serial.print() in giro e poi fai partire il programma con il Monitor Seriale attivo (impostato alla stessa velocità che hai nella Serial.begin()), ad esempio:

  Serial.begin(9600);
  // Lettura Tempo Record
  record = leggiRecord(FILE_RECORD);
  Serial.print("record=");
  Serial.println(record);

e vedi cosa succede. Se leggi il valore giusto, allora devi proseguire nel flusso aggiungendo altri Serial.print per mostrare sul monitor cosa sta facendo il programma e cosa sta leggendo o scrivendo. Purtroppo questa fase non è descrivibile, dipende dal programma e da cosa stai cercando di fare, per cui ti consiglio di sperimentare in questo senso (fa parte dell'"addestramento" alla programmazione e DEVI farlo tu!).

Grazie per la dritta! provo subito!

Niente da fare...

ma, leggendo in giro, ho trovato la funzione ".toFloat()".
Posso usare questa funzione per tradurre la stringa salvata nel file .txt in un valore numerico da confrontare con gli altri?

Grazie per la pazienza, sono di coccio ma non mi arrendo!

Fede.

Fede_ITA:
Niente da fare...

Scusa ma "niente da fare" cosa significa? Hai visualizzato correttamente il valore letto dal file? Hai aggiunto altri Serial.print() per capire il programma cosa fa e quali valori legge o imposta? E qual è il risultato di questi tuoi test, ossia cos'è che secondo te continua a non andare?

ma, leggendo in giro, ho trovato la funzione ".toFloat()".
Posso usare questa funzione per tradurre la stringa salvata nel file .txt in un valore numerico da confrontare con gli altri?

Il confronto te l'ho abbozzato io, non ne hai bisogno almeno per ora, visto che lo fai confrontando le due stringhe come vedi nella if(), e funziona a patto che abbiano lo stesso numero di caratteri.
Altrimenti devi o aggiungere zeri iniziali, o si, convertire le stringhe in float e confrontare il valore float.
Ma ti serve veramente questa "complicazione" (che non è complessa, ma se hai poca dimestichezza col linguaggio temo lo sia, almeno per ora)?

Grazie per la pazienza, sono di coccio ma non mi arrendo!

Fai bene a non arrenderti, tutto serve per imparare.
Ma dai sempre tutte le informazioni, non dire solo "niente da fare" :wink: anche perché non penso tu vada dal meccanico dicendo "la macchina non va bene" senza spiegare cosa hai visto/sentito e magari le prove che hai già fatto, non ti pare?