Go Down

Topic: Salvare lo stato di un pulsante nel SD. (Read 2316 times) previous topic - next topic

WinGamesyun

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

torn24

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.

WinGamesyun

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

fabpolli

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.

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...
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

WinGamesyun

#5
Dec 03, 2019, 01:55 pm Last Edit: Dec 03, 2019, 02:03 pm by WinGamesyun
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.





gpb01

>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
Search is Your friend ... or I am Your enemy !

WinGamesyun

#7
Dec 03, 2019, 02:41 pm Last Edit: Dec 03, 2019, 02:43 pm by WinGamesyun
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 .

gpb01

#8
Dec 03, 2019, 02:51 pm Last Edit: Dec 03, 2019, 02:54 pm by gpb01
... 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 ... ::)
Search is Your friend ... or I am Your enemy !

gpb01

#9
Dec 03, 2019, 02:58 pm Last Edit: Dec 03, 2019, 03:00 pm by gpb01
... 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!
Search is Your friend ... or I am Your enemy !

WinGamesyun

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

Code: [Select]
[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]

docdoc

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?
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

WinGamesyun

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

WinGamesyun

Corretto ma secondo me e totalmente sbagliato
Code: [Select]
[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]

docdoc

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:

Code: [Select]
    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:

Code: [Select]
    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:

Code: [Select]
    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:

Code: [Select]
    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():

Code: [Select]
    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):

Code: [Select]
#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);
  }
}
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

Go Up