Pages: [1]   Go Down
Author Topic: [RIS] Salvare sulla memoria di Arduino alcuni parametri fatti variare da seriale  (Read 1795 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:

Code:
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:

Code:
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 smiley). Un ringraziamento anticipato a tutti quelli che vorranno partecipare a questo post.
« Last Edit: November 22, 2012, 12:58:09 pm by hermit274 » Logged

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 327
Posts: 22662
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Quote
è 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.

Quote
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:
http://www.arduino.cc/en/Reference/EEPROM
Ricordati che la EEPROM regge solo 100.000 riscritture, quindi che non sia un accesso frenetico a questa memoria altrimenti la rovina rapidamente
Logged


Offline Offline
Jr. Member
**
Karma: 0
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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:
Code:
#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...
Logged

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 327
Posts: 22662
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Code:
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:
Code:
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.
Logged


Battipaglia (SA)
Offline Offline
Jr. Member
**
Karma: 0
Posts: 70
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 327
Posts: 22662
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Offline Offline
Jr. Member
**
Karma: 0
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 ;-) grazie mille davvero!
Logged

Battipaglia (SA)
Offline Offline
Jr. Member
**
Karma: 0
Posts: 70
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 327
Posts: 22662
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Offline Offline
Edison Member
*
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Per dati multibyte c'è sempre la EEPROMWriteAnything... (anche se a dire il vero non l'ho mai usata  smiley-eek-blue )
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
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...
Code:
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?
Logged

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 327
Posts: 22662
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Offline Offline
Jr. Member
**
Karma: 0
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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) smiley-wink grazie mille ragazzi!!!!

Code:
#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);
  }

}
Logged

Offline Offline
Edison Member
*
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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  smiley-lol
Logged

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 327
Posts: 22662
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@hermit:
Bravo, mi fa piacere.  smiley-wink
Logged


Pages: [1]   Go Up
Jump to: