Problema SD.begin per datalogger

Buongiorno,

Innanzitutto scusate per la lunghezza del messaggio ma vorrei descrivere bene il mio problema per evitare dubbi. Sto cercando di realizzare un datalogger con Arduino e la cosa è da molto che va avanti causa numerosi incidenti di percorso. Comunque poco a poco sto risolvendo questi problemi se non fosse che oggi ne è saltato fouri uno che davvero non riesco a superare. Prima del codice vi spiego brevemente lo scopo: vorrei che arduino leggesse, ogni mezz’ora, due sensori (temperatura, celle di carico) e salvasse i file su una SD. Inoltre mi piacerebbe mettere un led per segnalare sia quando arduino sta facendo i rilevamente, in modo da non estrarre la sd in quel momento, sia quando la sd non è presente ad esempio per il download dei dati. Ho visto che sulla libreria SD esiste l’apposita SD.begin che dà false in caso di assenza di sd e ho pensato di utilizzarla in questo modo:

#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 3 //definisce il pin del termometro
OneWire ourWire(ONE_WIRE_BUS);
DallasTemperature sensors(&ourWire);

int sensorPin1 = A1, sensorPin2 = A2;  //analogici celle di carico 
int sleep1=1, sleep2=2;  //digitali dello sleep 
int redLed=5;
const int chipSelect = 10; //per la SD
File ArduBeeNo; //indirizzo del file

void setup() 
{
  pinMode(sleep1, OUTPUT);  //setta i pin degli sleep in OUTPUT
  pinMode(sleep2, OUTPUT);
  
  pinMode(10, OUTPUT); //per la SD
  
  pinMode(redLed, OUTPUT); //setta i pin per i led
  digitalWrite(redLed, LOW);
  
  SD.begin(chipSelect);
  
  delay(100);
}

void loop() 
{
  char time[21];
 
  while(!SD.begin()) //verifica che ci sia la SD
  {
    digitalWrite(redLed, HIGH); //accendi il led rosso
    delay(1000);
  }
  
  digitalWrite(redLed, LOW); //spegni il led rosso

  if (flag()==1) // se siamo sulla mezz'ora
  {
    digitalWrite(redLed, HIGH); //accende il led rosso
    ArduBeeNo=SD.open("ArduBeeNo.csv", FILE_WRITE); //apre il file 
    getTime(time);
    ArduBeeNo.print(time); //scrive l'ora
    ArduBeeNo.print(";"); 
    ArduBeeNo.print(getWeight()); //scrive il peso
    ArduBeeNo.print(";");
    ArduBeeNo.println(getTemperature()); //scrive la temperatura
    ArduBeeNo.close(); //chiude il file
    digitalWrite(redLed, LOW);
  }
    
  delay(1000);
}

Il codice è un estratto solo di main e loop, ci sono altre funzioni ma intevengono solo in fase di rilevamento, il mio problema invece è che il led rimane acceso sempre, in poche parole non riesce ad uscire dal ciclo while di verifica della SD. Premetto che:

  1. da istruzioni di datalogger (la mia è adafruit) ho appunto messo il pin CS sul 10 e nn sul 4;
  2. la SD funziona benissimo usando la scheda con lo sketch di esempio;
  3. per quanto ne sappia nessuno dei sensori/led attaccati interferisce con la SD poichè ho lasciato libero i pin 10,11,12,12 e anche il 4 per sicurezza.

Se qualcuno mi riuscisse ad aiutare, gliene sarei infinitamente grato :slight_smile:

  while(!SD.begin()) //verifica che ci sia la SD
  {
    digitalWrite(redLed, HIGH); //accendi il led rosso
    delay(1000);
  }

Queste istruzioni chiamano continuamente SD.begin per cui finché lui dà risposta negativa, il programma non uscirà da lì.
Mettici un if, in alternativa, per cui chiami la SD.begin, se restituisce true entri in un blocco di codice che accende il LED, scrive il log, poi lo spenge.

Non credo di aver capito bene, provo a spiegarmi.. forse ho capito male ma quello che lei dice essere quello che non dovrebbe succedere è esattamente quello che voglio; ossia che finchè la SD è assente il programma rimanga in quel ciclo e tenga acceso il led (questo è dovuto al fatto che quando estraggo la SD per il downloadg il programma non prosegua alla scrittura nel caso fosse il momento, ma aspettasse "morto" in quel ciclo). La mia domanda era proprio perchè, pur essendo presente la SD, la funzione SD.begin non ritorni TRUE e il programma avanzi regolarmente con il loop?

Chiedo scusa se sbaglio io, ma non risco a capire perchè un if sia logicamente diverso da un while, in teoria in entrambi i casi il programma dovrebbe andare avanti in caso di TRUE solo che nel mio caso ciò che rigira ogni volta è un ciclo while, mentre mettendo l'if a riciclare sarebbe tutta la parte loop.

Oggi ho provato anche con l'if, come mi aspettavo non cambia assolutamente nulla... come non funzionava col while non va con l'if... Quello che davvero non capisco è come mai, anche commentando tutto e tenendo praticamente solo le istruzioni strettamente necessarie alla SD, non giri lo stesso. Eppure il writeRead di esempio (che al netto di altre funzioni è identico al mio) gira benissimo...

const int chipSelect = 10; //per la SD

no, il 10 è dedicato all'ethernet (W5100), il 4 è l'SD ti rinvio a questa discussione hai lo stesso problema

ciao

Come detto in precedenza, io ho il datalogger shield Adafruit, non l'ethernet... Di conseguenza il pin giusto è il 10 nel mio caso e ciò è confermato sia dal fatto che fuori da questo dannatissimo programma la SD funziona benissimo, sia da ciò che recita testualmente la pagina Adafruit:

// change this (il pin in qestione) to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8

Il mio problema non è legato al funzionamento della SD in sè come ho visto in molti altri post. Nel mio caso la SD funziona benissimo, leggo, scrivo, non ha problemi di formattazione, ha tutti i pin al loro posto. Poi provo ad usarla con questo programma e non va... ho provato anche a commentare tutti i frammenti di codice che interessano altri pin (gli sleep degli amplificatori, il led, il termometro) ma nulla. Non è razionale questa cosa :frowning:

Hai ragione avevi detto che è il pin 10 :smiley: , non conosco quella scheda, se lo confermi tu va benissimo.
Ho confuso il tuo post con un conflitto eth e sd … sorry

Mi sono picchiato molto con la sd su letture e scritture quindi ti passo qualche pezzo che puoi testare
Io farei così:
innanzi tutto metterei il pin 10 in HIGH nel setup e Inizializzerei la scheda con altre istruzioni le quali non mi hanno mai dato problemi

#include <SPI.h>
#include <SD.h>

#define DEBUG_SD 1  // 0 per non stampare i debug
unsigned long previousMillis_f = 0;    
byte err_sd=1;
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

void setup() 
{
  delay(1000);
  Serial.begin(9600);//debug
  
  pinMode(10, OUTPUT); 
  digitalWrite(10, 1);
  sd_init();
}

creati una funzione di inizializzazione della SD contenente le istruzioni separata dal setup, perchè avrai la possibilità di richiamarla quando ti serve. Ad esempio quando arduino è in running ed estrai la SD al suo reinserimento la SD non risponde più e sei costretto a resettare per tornare ad avviare il setup e inizializzare.

void sd_init() 
{   
  err_sd=0;
  if (!card.init(SPI_FULL_SPEED, 10)) err_sd=1; // <<<<<< pin 10 nel tuo caso
  if (!volume.init(&card)) err_sd=1;
  if (!root.openRoot(&volume)) err_sd=1;
  
  #if DEBUG_SD 
  if (err_sd==0) 
  Serial.println("inizializzazione SD completata.");//debug  
  else //debug
  Serial.println("inizializzazione SD fallita.");//debug
  #endif
}

Qui puoi ottenere 3 tipi di errore sulla sd uno dei 3 è proprio la presenza della SD nello slot non mi ricodo quale però

ora non ti resta che aggiungere nel loop un po’ di controlli con un millis() ogni tot (ad esempio 500 ms) se la scheda è presente
esempio:

void loop() 
{
   if(millis() - previousMillis_f > 500)  {   
        previousMillis_f = millis();
        verify_sd(); 
  }     
 } 


void verify_sd() 
{  
  if (!volume.init(&card)) 
  { 
    #if DEBUG_SD 
     Serial.print("ERRORE SD Card. Ripristino in corso ...");
    #endif
     digitalWrite(5,1); //led errore acceso
     err_sd=1;
     file.close(); 
     root.close(); 
     sd_init();  // qui tento l'inizializzazione, perchè se l'hai estratta dovrà essere ripristinato (ti evita il reset)
   } 
     else
     { 
      
       digitalWrite(5,0); //led errore spento
       err_sd=0;
     } 
}

istruzione per leggere il file

if(file.open(&root, "miofile.ini", O_READ))  
  {

istruzione per scrivere su file

file.open(&root, "miofile.ini", O_TRUNC | O_WRITE);

hai una variabile di controllo err_sd pubblica, quindi la puoi usare per bloccare i processi se ti serve in caso di errore
Questi sono i passi che avevo fatto e funzionanti, spero di non aver dimenticato nulla

ciao

WOW! grazie!! :slight_smile: premetto che dovrò vedermi per bene le istruzioni perchè non mi sono di così facile comprensione però almeno ora ho qualcosa su cui poter lavorare ed è un'ottima cosa. Riguardo alla sua esperienza, può succedere che una funzione giri in un programma e nn in un altro?(per esempio per possibili incompatibilità tra librerie o altre funzioni... non so se sono cose possibili e la sto buttando lì visto che io conosco solo alcune cose fondamentali del C e stop.. ) oppure deve esserci un errore nel modo che faccio io di utilizzarle? Lo chiedo perchè ora è anche una questione di curiosità, vorrei capire perchè il metodo "standard" non funziona in questo caso...

la tua domanda

La mia domanda era proprio perchè, pur essendo presente la SD, la funzione SD.begin non ritorni TRUE e il programma avanzi regolarmente con il loop?

ti ho spiegato perchè la scheda sd non funziona più nel post precedente una volta che l’hai tolta devi rifare la procedura di inizializzazione quando la rimetti … sta a te fare in modo che arduino si accorga della sua assenza o presenza … e’ importante che non venga estratta mentre scrive ovvero con file.open in write rovini il file system e devi riformattarla, se sta leggendo poco importa.

può succedere che una funzione giri in un programma e nn in un altro?(per esempio per possibili incompatibilità tra librerie o altre funzioni…

si, può succedere che 2 librerie siano state create da due utenti diversi per due scopi ben diversi, poi arriva un terzo utente che nel suo progetto le vuole usare entrambe e nasce il problema, ad esempio la libreria <IRremote.h> non va daccordo con <RTC.h> semplicemente perchè entrambe usano lo stesso timer, ci si arma di pazienza e si vanno a modificare per farle coesistere.
Io non so dirti se quella sfilza di librerie che usi hanno qualche conflitto tra loro, il tuo post era rivolto ad un problema con la SD.

Puoi anche non stavolgere il tuo lavoro ignorando le porzioni di codice che ho scritto prima, ricordati solo di fare in modo che quando arduino non vede più la SD di fargli fare tutta la procedura di inizializzazione come se facessi un reset della scheda.
Per completezza ti ricordo che la funzione Setup() viene eseguita una sola volta all’avvio di arduino in modo automatico, mentre il loop() è un ciclo infinito tutte le altre funzioni raccolte tra parentesi graffe vengono richiamate dal tuo sketch

Ps non darci del Lei ci fai sentire vecchi ahahahahhahaha

ciao

Ok ora penso di aver capito dove almeno potrebbe esserci l'errore. Sono consapevole che il mio sketch può essere un po' incasinato ma credo sia il minimo indispensabile per fare ciò che mi serve, e se mi dici che effettivamente può esserci incompatibilità può darsi che della decina di di librerie che uso succeda questo. Inoltre credo di aver capito che il mio errore di fondo consistesse nell'interpretare la SD.begin come anche una specie di verifica dell'assenza. In effetti leggendo dalla pagina su arduino.cc dice che fa anche questo, ma a questo punto penso che più che altro sia una cosa secondaria rispetto all'inizializzazione in sè. Quindi vedrò di cercare l'istruzione apposita per la verifica della SD in modo da evitare di estrarre la scheda in fase di scrittura, ora non mi resta che sbatterci su la testa! :slight_smile: Nel frattempo grazie per le preziose informazioni!

Riguardo al "lei"... si tratta di esperienza personale: milito in diversi forum e mentre spesso ci si dà del tu tranquillamente, in altri casi si trova gente che si offende :~ quindi per evitare malintesi, essendo agli inizi su questo forum, evito di "espormi" da subito. So che sembra patetico ma dopo aver sentito cose tipo "Non è che se siamo su un forum online allora siamo tutti amici d'infanzia..." preferisco evitare altre paternali versione 2.0 XD