[RIS] Salvare sulla memoria di Arduino alcuni parametri fatti variare da seriale

Ciao a tutti ragazzi. Sono nuovo del forum. Sto cercando da molto tempo una soluzione a questo problema girando in questo forum e per internet, ma non ho trovato ancora nulla. Speriamo di riuscire a risolverlo tutti insieme così almeno lasciamo qualcosa di chiaro a tutta la comunità.
Allora iniziamo, il mio problema è questo: ho creato un piccolo programma, caricato sulla memoria di Arduino, che mi fa accendere e spegnere un led con un tempo di delay che può variare a causa di una variabile, posto il codice così ci capiamo:

int ledPin = 13; // the number of the LED pin
int val_memorizzato;

void setup() {
Serial.begin(9600); // set serial speed
pinMode(ledPin, OUTPUT); // set LED as output
digitalWrite(ledPin, LOW); //turn off LED
}

void loop(){
int val = Serial.read() - '0'; // deduct ascii value of '0' to find numeric value of sent number

if (val == 1) // test for command 1 then turn on LED
{ 
val_memorizzato = val_memorizzato +100;
//Serial.println("LED on");
}
  else if (val == 2) // test for command 0 then turn off LED
  {
   //Serial.println("LED OFF");
   val_memorizzato = val_memorizzato -100;
  }

if (val_memorizzato >0)
{
digitalWrite(ledPin, HIGH); // turn on LED
delay (val_memorizzato);
digitalWrite(ledPin, LOW);
delay (val_memorizzato);
}
  else if(val_memorizzato <=0)
  {
    digitalWrite(ledPin, LOW);
  }
//Serial.println(val);
//Serial.flush(); // clear serial port
}

ho voluto mettere la variabile "val_memorizzato" perchè questa deve cambiare tramite un interfaccia grafica creata con Visual basic, ovvero schiaccio il bottone 1 su visual basic, viene mandato il valore tramite seriale ad Arduino e se il valore è 1 aumenta la variabile di 100, se il valore è 2 diminuisce la variabile di -100, posto anche qui il codice di visual basic:

Imports System.IO
Imports System.IO.Ports
Imports System.Threading

Public Class Form1
    Shared _continue As Boolean
    Shared _serialPort As SerialPort

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        SerialPort1.Close()
        SerialPort1.PortName = "com15" 'change com port to match your Arduino port
        SerialPort1.BaudRate = 9600
        SerialPort1.DataBits = 8
        SerialPort1.Parity = Parity.None
        SerialPort1.StopBits = StopBits.One
        SerialPort1.Handshake = Handshake.None
        SerialPort1.Encoding = System.Text.Encoding.Default 'very important!
    End Sub


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        SerialPort1.Open()
        SerialPort1.Write("1")
        SerialPort1.Close()
    End Sub


    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        SerialPort1.Open()
        SerialPort1.Write("2")
        SerialPort1.Close()
    End Sub
End Class

Fin qui tutto funziona egregiamente, arduino interagisce col pc.
Il problema è che quando stacco la porta usb dal computer per alimentare Arduino con un alimentazione esterna non fa più nulla, è come se la variabile "val_memorizzato" non fosse stata memorizzata sulla memoria di Arduino, ma in una memoria volatile.
Come faccio a salvarla sulla memoria in modo tale che quando stacco Arduino continui a funzionare con il valore precedentemente passato tramite seriale?
Spero di aver dato quante più informazioni possibili (forse anche troppe :)). Un ringraziamento anticipato a tutti quelli che vorranno partecipare a questo post.

hermit274:
Ciao a tutti ragazzi. Sono nuovo del forum.

Benvenuto.

1° consiglio. Usa gli appositi tag per inserire il codice, altrimenti non si legge nulla.
Quando sei a scrivere il tuo messaggio, premi l'icona "#" per far apparire i tag entro cui mettere il codice.

è come se la variabile "val_memorizzato" non fosse stata memorizzata sulla memoria di Arduino, ma in una memoria volatile.

Perché è così. Tutti i dati elaborati in fase di esecuzione "vivono" in una RAM, memoria volatile che perde il suo valore una volta tolta l'allimentazione.

Come faccio a salvarla sulla memoria in modo tale che quando stacco Arduino continui a funzionare con il valore precedentemente passato tramite seriale?

Salva i dati nella EEPROM interna:

Ricordati che la EEPROM regge solo 100.000 riscritture, quindi che non sia un accesso frenetico a questa memoria altrimenti la rovina rapidamente

Grazie leo72 per la risposta fulminea. Cercherò di seguire i tuoi consigli per quanto riguarda i tag :slight_smile:

Sulla pagina che mi hai indicato tu c'è esattamente quello che volevo. Poi non penso che farò un accesso per 100.000 volte. Si tratterà di modificare il codice solo una dozzina di volte.
Quello che interessa a me è scrivere sulla EEPROM e ho trovato tra gli esempi questo:

#include <EEPROM.h>

void setup()
{
  for (int i = 0; i < 512; i++)
    EEPROM.write(i, i);
}

void loop()
{
}

dove la funzione EEPROM.write ha una sintassi del genere EEPROM.write(address, value), dove:
address: the location to write to, starting from 0 (int)
value: the value to write, from 0 to 255 (byte)

Allora, a quanto capisco il mio value è la mia variabile val_memorizzato. E l'Address??che posizione deve avere?Non ne ho la minima idea...

Per "address" devi mettere un valore da 0 a 1023 (dato che l'Atmega328 ha 1024 byte di EEPROM).
Ricordati solo che tu mi pare utilizzi un tipo "int" per val_memorizzato, per cui hai bisogno di 2 celle di EEPROM per salvarlo.
Devi dividerlo in 2 byte usando le funzioni lowByte e highByte.
Esempio:

EEPROM.write(0, highByte(val_memorizzato));
EEPROM,write(1, lowByte(val_memorizzato));

Per ricomporlo fai una semplice moltiplicazione per 256 del byte alto e poi ci sommi il byte basso:

val_memorizzato = (EEPROM.read(0) * 256) + EEPROM.read(1);

L'accesso a cui mi riferisco sono le SCRITTURE in EEPROM. Oltre 100.000 la memoria si corrompe.

Ciao, stavo scrivendo la stessa risposta di leo che è arrivato prima. Per rimporre l'int a partire dai due bytes è possibile anche utilizzare la word (magari un po' più leggibile).

Ciao.
Vittorio.

vittorio68:
Ciao, stavo scrivendo la stessa risposta di leo che è arrivato prima. Per rimporre l'int a partire dai due bytes è possibile anche utilizzare la word (magari un po' più leggibile).

Ciao.
Vittorio.

In Arduino il tipo "word" altro non è che un alias per unsigned int. All'atto pratico non cambia nulla se il dato memorizzato rappresenta un "int" o un "unsigned int". L'interpretazione del dato viene da come è stato scritto il programma e da che tipo di "contenitore" è stato usato, ma in EEPROM vengono scritti i singoli byte.

Casomai si poteva ricostruire il dato usando gli spostamenti dei bit (<<), per rendere l'operazione più veloce ma non l'ho proposta apposta perché non so il livello di conoscenza di hermit. La moltiplicazione fa la stessa cosa ed è più comprensibile per chi non ha molta dimestichezza con l'informatica.

ah meno male che mi hai detto che gli int sono a due byte altrimenti avrei scritto direttamente il valore sulla eeprom... ok ragazzi! per adesso grazie per l'aiuto appena torno a casa mi metto un pò a smanettare e vediamo se il problema si risolve :wink: grazie mille davvero!

Scusa, leo, forse sono stato poco chiaro. Io non dicevo di utilizzare il tipo "word" ma la funzione di conversione word. Cioè:

byte h = 2;
byte l = 1;
int X = word(h, l);
// X = 513

Ciao.
Vittorio.

vittorio68:
Scusa, leo, forse sono stato poco chiaro. Io non dicevo di utilizzare il tipo "word" ma la funzione di conversione word. Cioè:

byte h = 2;
byte l = 1;
int X = word(h, l);
// X = 513

Ciao.
Vittorio.

Ops.
Avevo frainteso che ti riferissi alla funzione. Me n'ero dimenticato perché non la uso mai.

Per dati multibyte c'è sempre la EEPROMWriteAnything... (anche se a dire il vero non l'ho mai usata :fearful: )

ok ragazzi ci siamo quasi. ho inserito il codice che mi ha consigliato leo72 nel mio controllo if, ovvero

if (val == 1) // test for command 1 then turn on LED
{ 
val_memorizzato = val_memorizzato +100;
EEPROM.write(0, highByte(val_memorizzato));
EEPROM.write(1, lowByte(val_memorizzato));
//Serial.println("LED on");
}
  else if (val == 2) // test for command 0 then turn off LED
  {
   //Serial.println("LED OFF");
   val_memorizzato = val_memorizzato -100;
   EEPROM.write(0, highByte(val_memorizzato));
   EEPROM.write(1, lowByte(val_memorizzato));
  }

in questo modo ogni volta che viene data un informazione via seriale, questa viene opportunamente salvata nella EEPROM.
Adesso volevo chiedervi nel momento in cui faccio lampeggiare i led devo richiamare ogni volta la variabile dalla EEPROM?? Mi spiego meglio con il codice...

val_memorizzato = (EEPROM.read(0) * 256) + EEPROM.read(1);
if (val_memorizzato >0)
{
digitalWrite(ledPin, HIGH); // turn on LED
delay (val_memorizzato);
digitalWrite(ledPin, LOW);
delay (val_memorizzato);
}
  else if(val_memorizzato <=0)
  {
    digitalWrite(ledPin, LOW);
  }

in questo modo ogni volta che Arduino ripete la mia void loop legge sempre dalla EEPROM...è giusto? forse secondo me non è la soluzione ideale, perchè in questo modo è costretto a leggere sempre dalla memoria...consigli?

E' ovvio che tu non debba leggere sempre da EEPROM.
Lo fai solo 1 volta, all'avvio del programma, quindi inserisci un controllo nel setup().

Potresti anche mettere 1 terzo carattere di controllo. Leggi quello, se non è quello che ti aspetti, significa che in EEPROM non è stato mai salvato nulla per cui: 1) scrivi il carattere di controllo; 2) assegni alla tua variabile un valore di default; 3) lo salvi anche in EEPROM. Altrimenti carichi il valore memorizzato.

yeeeeaaaaa!!!funzionaaaaa!!! grazie mille leo72!!! Magari posto il codice completo che ho utilizzato in modo che magari possa essere utile in futuro a qualcuno (il codice di visual basic è rimasto tale e quale, basta vedere all'inizio del post) :wink: grazie mille ragazzi!!!!

#include <EEPROM.h>
int ledPin = 13; // the number of the LED pin
int val_memorizzato=0;
int modifica=0;

void setup() {
Serial.begin(9600); // set serial speed
pinMode(ledPin, OUTPUT); // set LED as output
digitalWrite(ledPin, LOW); //turn off LED
modifica = (EEPROM.read(0) * 256) + EEPROM.read(1);
}


void loop(){
int val = Serial.read() - '0';

if (val == 1) // test for command 1 then turn on LED
{ 
val_memorizzato = val_memorizzato +100;
EEPROM.write(0, highByte(val_memorizzato));
EEPROM.write(1, lowByte(val_memorizzato));
modifica = (EEPROM.read(0) * 256) + EEPROM.read(1);
//Serial.println("LED on");
}
  else if (val == 2) // test for command 0 then turn off LED
  {
   //Serial.println("LED OFF");
   val_memorizzato = val_memorizzato -100;
   EEPROM.write(0, highByte(val_memorizzato));
   EEPROM.write(1, lowByte(val_memorizzato));
   modifica = (EEPROM.read(0) * 256) + EEPROM.read(1);
  }

if (modifica >0)
{
digitalWrite(ledPin, HIGH); // turn on LED
delay (modifica);
digitalWrite(ledPin, LOW);
delay (modifica);
}
  else if(modifica <=0)
  {
    digitalWrite(ledPin, LOW);
  }

}

Bene, ora che dal punto di vista funzionale hai trovato la soluzione, puoi dedicarti a rendere il codice leggibile. Inizia dall'indentazione (CTRL+T nell'IDE ti dà una mano), poi dai alle variabili dei nomi che ne rispecchino il più possibile la funzione all'interno del codice.

Il grillo parlante scass...zi ha parlato XD

@hermit:
Bravo, mi fa piacere. :wink: