[RISOLTO]Salvare lo stato di un pulsante nel SD.

Salve, come posso salvare lo stato di un pulsante nel SD per settarlo all'accensione di arduino?

Dovrai creare un file su SD, scrivergli dentro lo stato del pulsante, esempio un byte che vale 1 o 0, all'accensione di arduino leggere il valore da file. Negli esempi della libreria è mostrato come fare un write e un read su file.
Devo dire che hai a disposizione la eeprom, e per il tuo scopo vedrei meglio salvare e leggere un byte su eeprom, un SD dovrebbe essere usata per salvare qualcosa di più pesante di un singolo byte.

Buongiorno la scelta di usare la SD e perché sto usando una MKR1400 .

Visto che usi quella scheda che non ha ne EEPROm ne supporto per SD, se devi acquisare qualcosa acquista una EEPROM I2C che dovrebbe essere più economico e pratico anche da gestire.

O prima prova QUESTA libreria, non avendo una MKR non so dirti se funzioni, ma un tentativo "a costo zero" puoi farlo, tanto più che devi salvare solo pochi bit...

Grazie sempre per i suggerimenti che date ,
ma visto che per il progettino che sto realizzando
devo per forza utilizzare la SD per impostare delle
credenziali direttamente sulla scheda .
Spiego meglio a cosa mi serve :

Se accendo una luce e manca la corrente elettrica,
vorrei che ricordasse lo stato al momento dello spegnimento.

>WinGamesyun: Scusa ma hai visto la libreria che ti ha suggerito docdoc ? Simula una EEPROM sul SAMD21 quindi ... perché ti ostini a voler usare un supporto che NON è certo adatto per memorizzare lo "stato" di un pulsante ? ? ? :o

Devi memorizzare parecchie altre informazioni? Devi fare "data logging" ? Altrimenti .. che c'entra la SD ? ? ?

Guglielmo

docdoc:
O prima prova QUESTA libreria, non avendo una MKR non so dirti se funzioni, ma un tentativo "a costo zero" puoi farlo, tanto più che devi salvare solo pochi bit...

Sto provando gli esempi di questa libreria ma funziona solo uno , non riesco a trovare un'altra libreria simile .

... a te serve solo di provare EmulateEEPROM (... che son convinto che funzioni), con quello fai tutto (... devi memorizzare UN byte ...).

Guglielmo

P.S.: Ovviamente, occhio, parlaimo della Flash e NON di una vera EEPROM, quindi ... vita media 10'000 scritture, dopo possono cominciare i problemi ... ::slight_smile:

... mi correggo, ancora più semplice, per quello che devi fare tu, è l'esempio "FlashStoreAndRetrieve.ino", in cui memorizza e rilegge un numero intero (int).

Guglielmo

P.S.: Altra cosa ... occhio perché la EEPROM emulata si cancella ogni volta che riprogrammi la scheda con l'IDE, quindi, NON sperare di mettere un valore, caricare un nuovo programma e trovare il valore ancora li!

Vorrei fare una cose del genere ,
se controllo nel scheda il file si modifica ma non si imposta il digitalWrite (6,....); al riavvio.

[code]
#include <SD.h>
#include <Wire.h>
#include <SPI.h>
char ultimo[5];
File stato;
void setup() {
  Serial.begin(9600);
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");

    stato = SD.open("stato.txt");

    if (stato)
    {
      Serial.println("stato.txt:");
      byte i = 0;

      while (stato.available() && i < 32)//modificato  con 32 caratteri
      {
        char letto = (stato.read());
        Serial.print(letto);
        ultimo[i++] = letto;
      }
      Serial.print(ultimo);
      pinMode(5, INPUT);
      pinMode(3, INPUT);
      pinMode(6, OUTPUT);
      stato.close();
     
      if ( ultimo == "HIGH") {
        digitalWrite(6, HIGH);

      }
      else if (ultimo == "LOW") {
        digitalWrite(6, LOW);


      }
    }
  }
  Serial.println("fine setup ");
  delay(5000);
}

void loop() {
  if (digitalRead(3) == HIGH) {
    SD.begin();
    SD.remove("stato.txt");
    stato = SD.open("stato.txt", FILE_WRITE);
    Serial.println("Writing to LOW.txt...");
    stato.print("LOW");
    delay(50);
    stato.close();
    Serial.println(ultimo);
    Serial.println(stato);
    delay(5000);

  }
  else if (digitalRead(5) == HIGH) {
    SD.begin();
    SD.remove("stato.txt");
    stato = SD.open("stato.txt", FILE_WRITE);
    Serial.print("Writing to HIGH.txt...");
    stato.print("HIGH");
    delay(50);
    stato.close();
    Serial.println("done.");
    delay(2000);

  } else {
    Serial.println ("esco");
    delay(2000);
  }

}

[/code]

Ma lo hai guardato bene il tuo programma?

La prima if() ("if (!SD.begin(4))") cosa esegue se la condizione è vera, e cosa se è falsa?

Hai ragione ho estratto il pezzo di codice dal
Programma che sto facendo
Per fare prove ,
ora capisco perché non funziona la seriale nel setup

Corretto ma secondo me e totalmente sbagliato

[code]
#include <SD.h>
#include <Wire.h>
#include <SPI.h>
char ultimo[5];
File stato;
void setup() {
  Serial.begin(9600);
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
 while (1);
    }
    stato = SD.open("stato.txt");

    if (stato)
    {
      Serial.println("stato.txt:");
      byte i = 0;

      while (stato.available() && i < 32)//modificato  con 32 caratteri
      {
        char letto = (stato.read());
        Serial.print(letto);
        ultimo[i++] = letto;
      }
      Serial.print(ultimo);
      pinMode(5, INPUT);
      pinMode(3, INPUT);
      pinMode(6, OUTPUT);
      stato.close();
     
      if ( ultimo == "HIGH") {
        digitalWrite(6, HIGH);

      }
      else if (ultimo == "LOW") {
        digitalWrite(6, LOW);


      }
    }
  
  Serial.println("fine setup ");
  delay(5000);
}

void loop() {
  if (digitalRead(3) == HIGH) {
    SD.begin();
    SD.remove("stato.txt");
    stato = SD.open("stato.txt", FILE_WRITE);
    Serial.println("Writing to LOW.txt...");
    stato.print("LOW");
    delay(50);
    stato.close();
    Serial.println(ultimo);
    Serial.println(stato);
    delay(5000);

  }
  else if (digitalRead(5) == HIGH) {
    SD.begin();
    SD.remove("stato.txt");
    stato = SD.open("stato.txt", FILE_WRITE);
    Serial.print("Writing to HIGH.txt...");
    stato.print("HIGH");
    delay(50);
    stato.close();
    Serial.println("done.");
    delay(2000);

  } else {
    Serial.println ("esco");
    delay(2000);
  }

}

[/code]

Ok, quella parte ora è a posto, ma scusa, non basta mica dire "secondo me e totalmente sbagliato", spiega bene cosa intendi, ossia cosa è "sbagliato"?

In questi casi oltre a descrivere esattamente cosa hai fatto, cosa vedi sulla seriale, e cosa ti aspettavi di vedere, postare anche un copia/incolla del serial monitor può aiutarci a capiremeglio e quindi aiutarti, non ti pare?

In pratica vedo che tu dentro al file "stato.txt" scrivi una stringa che sarà "HIGH" o "LOW", e quando la leggi consideri solo i primi 32 caratteri al massimo.

Beh intanto questo limite di 32 caratteri forse lo hai messo per qualcosa che hai in mente in futuro (se usi la funzone available te lo dice la libreria SD se il file è finito), perché nel caso attuale non hai questa necessità , ma diciamo che funziona lo stesso, quindi puoi anche lasciarlo.

Poi le istruzioni "pinMode" ti conviene generalmente metterle all'inizio del setup().

Tu in questo modo accumuli nella variabile "ultimo" i byte letti dal file:

    while (stato.available() && i < 32)//modificato  con 32 caratteri
    {
      char letto = (stato.read());
      Serial.print(letto);
      ultimo[i++] = letto;
    }
    Serial.print(ultimo);
    stato.close();

Bene, visto che stai leggendo singoli byte, intanto nel while() puoi togliere la Serial.print(letto) visto che lo fai già alla fine. Poi però tu non stai considerando il fatto che le "stringhe C" usate da Arduino devono contenere un "terminatore" ossia un byte a zero.

Se tu leggi dalla SD i quattro caratteri "HIGH" (visto che tu scrivi solo quelli), nella variabile ultimo[] avrai i primi 4 byte con quei caratteri, ma non essendoci alcun terminatore, sulla seriale rischi di vedere HIGH seguito da una serie di caratteri casuali.
Quindi devi sempre aggiungerlo tu, ad esempio puoi rivedere quel ciclo in modo più ottimizzato:

    while (stato.available() && i < 32)//modificato  con 32 caratteri
    {
      ultimo[i++] = stato.read();
    }
    ultimo[i] = 0; // Terminatore di stringa
    stato.close();
    Serial.print(ultimo);

Passiamo al riconoscimento della stringa:

    if ( ultimo == "HIGH") {
      digitalWrite(6, HIGH);
    }
    else if (ultimo == "LOW") {
      digitalWrite(6, LOW);
    }

Le "stringhe C" non si possono confrontare con "==", devi usare la funzione strcmp() (sempre a patto che abbiano il terminatore di cui sopra) che restituisce zero se le stringhe sono uguali:

    if ( strcmp(ultimo,"HIGH") == 0) {
      digitalWrite(6, HIGH);
    }
    else if ( strcmp(ultimo,"LOW") == 0 ) {
      digitalWrite(6, LOW);
    }

Detto questo, se dal file leggi sempre o HIGH o LOW puoi evitare la seconda, inutile if():

    if ( strcmp(ultimo,"HIGH") == 0)
      digitalWrite(6, HIGH);
    else 
      digitalWrite(6, LOW);

Ma se devi solo salvare lo stato di un pin, fai prima a scrivere solo un carattere invece di una stringa, magari "0" per LOW e "1" per HIGH (potresti anche usare un byte, dove quindi potresti memorizzare fino ad 8 bit/pin, ma per ora lasciamo stare).
Infine non hai bisogno di fare remove() del file perché la FILE_WRITE se il file esiste lo sovrascrive.

Quindi puoi fare qualcosa di più semplice come questo (anche se il codice non l'ho provato, mi raccomando, provalo e cerca di capire cosa ho fatto, e possibilmente aggiungi i commenti nel codice per descrivere i vari passi poi postalo qui così ti dico se hai colto esattamente le modifiche):

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

#define PULSANTE_ON 5
#define PULSANTE_OFF 3
#define LED 6

File stato;

void setup() {
  Serial.begin(9600);
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }

  pinMode(PULSANTE_ON , INPUT);
  pinMode(PULSANTE_OFF , INPUT);
  pinMode(LED, OUTPUT);

  stato = SD.open("stato.txt");
  if (stato)
  {
    byte ultimo = stato.read();
    stato.close();
    Serial.print("stato.txt: ultimo=");
    Serial.println(ultimo);
    digitalWrite(6, ultimo);
  }
  Serial.println("fine setup ");
  delay(5000);
}

void loop() {
  ultimo = -1;
  if (digitalRead(PULSANTE_OFF) == HIGH)
    ultimo = 0;
  else if (digitalRead(PULSANTE_ON) == HIGH) {
    ultimo = 1;
  if (ultimo != -1)
  {
    stato = SD.open("stato.txt", FILE_WRITE);
    Serial.print("Scrivo lo stato: ");
    Serial.println(stato);
    stato.write(ultimo);
    delay(50);
    stato.close();
    delay(5000);
  }
}

docdoc:
...

Le "stringhe C" non si possono confrontare con "==", devi usare la funzione strcmp() (sempre a patto che abbiano il terminatore di cui sopra) che restituisce zero se le stringhe sono uguali:

quello OP è da maggio , o forse giugno, che ha sempre lo stesso problema (in varie salse), che fa sempre gli stessi errori e ignora sempre gli stessi consigli
forse sarebbe il caso di fare un colpo di mano, uno di noi si offre per dargli la pappa fatta e morta li....

però, attenzione, bisogna mettergliela sotto il naso, che a dirgli che è a due post di distanza non la trova:

Standardoil:
beh, è qualche giorno che abbiamo pubblicato, prorpio per questo OP, più versioni di funzioni che leggono da file variabili intere e/o stringhe, un "minimo" di ricerca ed attenzione........

ai tempi non mi aspettavo di venir ringraziato, questo no, ma che almeno lo OP cercasse... questo sì

avrebbe trovato questo:

Standardoil:
Che poi la scelta è facile: leggere, leggere sempre, anche di fronte all'evidenza.......

(se mi vedete confuso, avete ragione)

vorrei allacciarmi ad una discussione recente, su leggere un int da file

che sarebbe stato, allora, la soluzione ai problemi che ha ancora

se ti puo' consolare è stato proprio cercando di capire come aiutare lo OP che abbiamo trovato quello

ed è li che abbiamo capito che nonostante i tuoi titoli un po' "fantasiosi" col SW te la cavi bene

quasi meglio di Fabio :slight_smile:

Buona sera sto provando il codice postato da >Docdoc< .

[code]
#include <SD.h>
#include <Wire.h>
#include <SPI.h>

#define PULSANTE_ON 5
#define PULSANTE_OFF 3
#define LED 6
//int ultimo; //ho provato  cosi.
//char ultimo;
File stato;

void setup() {
   Serial.begin(9600);
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }

  pinMode(PULSANTE_ON , INPUT);
  pinMode(PULSANTE_OFF , INPUT);
  pinMode(LED, OUTPUT);

  stato = SD.open("stato.txt");
  if (stato)
  {
    byte ultimo = stato.read();
    stato.close();
    Serial.print("stato.txt: ultimo=");
    Serial.println(ultimo);
    digitalWrite(6, ultimo);
  }
  Serial.println("fine setup ");
  delay(1000);
}

void loop() {
  ultimo = -1;//           mi da errore 'ultimo' su questa riga di codice 
  if (digitalRead(PULSANTE_OFF) == HIGH)
    ultimo = 0;
  else if (digitalRead(PULSANTE_ON) == HIGH) {
    ultimo = 1;
    if (ultimo != -1)
    {
      stato = SD.open("stato.txt", FILE_WRITE);
      Serial.print("Scrivo lo stato: ");
      Serial.println(stato);
      stato.write(ultimo);
      delay(50);
      stato.close();
      delay(1000);
    }
  }
}

[/code]
ho commentato la riga che mi da errore ho provato a inizializzare >int ultimo;
funziona ma sulla sd mi stampa dopo la scritta caratteri strani .


sulla seriale invece mi stampa solo stato 1, anche se premo l'altro pulsante.

Provando ho risolto la scrittura dei simboli strani nel sd cambiando Write con print,
ora devo capire perchè funziona solo il pulsante di ON e non funziona la seriale nel setup.

Mi dite sempre che devo leggere bene il codice ma secondo voi questo codice perché non funziona?