dubbio Setup()

Buongiorno devo fare una cosa stupida.
Devo scrivere uno sketch che ogni volta che viene acceso un dispositivo verifica se è stato acceso N volte; se non è stato acceso N volte fa una serie di azioni se è già stato acceso N volte fa lampeggiare i LED e scrive
sulla seriale versione demo terminata.

/*
    Lampeggio
 Accende il LED1 per un secondo, poi lo spegne per un secondo, ripetendo queste fasi.
 Accende il LED2 per un secondo, poi lo spegne per un secondo, ripetendo queste fasi.
 
 Questo codice è di dominio pubblico.
 */

//  I Pin 23,24 hanno un LED connesso.

int led1 = A0;
int led2 = A1;

int demoCountSw = 0;
//  La routine di setup viene eseguita una volta che viene premuto il pulsante di Reset
void setup() {                
  //  Inizializza i pin digitali come uscite.
  Serial.begin(9600);
  pinMode(led1, OUTPUT); 
  pinMode(led2, OUTPUT);
  if (demoCountSw < 1000){
    loop();  
    demoCountSw++;
  }
  else
    Serial.print("FW expired DEMO version");
  digitalWrite(led1, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led1, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led2, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led2, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
  delay(1000);                //  Attendi 1 secondo
}

//  La routine di Loop viene eseguito per sempre
void loop() {
  Serial.println("Esegui...");
}

può andare bene?
Mi servirebbe sapere in qual caso viene eseguito il setup()
Altro dubbio ogni volta che riaccendo la mia scheda demoCountSw va a 0 o tiene memoria di quante volte è stata già accesa la scheda?
Grazie

Per conservare i dati anche dopo aver spento l’Arduino devi salvarli sulla EEPROM. C’è la lib apposita per leggere e scrivere i dati in EEPROM:
http://arduino.cc/en/Reference/EEPROM

Il setup() viene eseguito, dopo l’accensione dell’Arduino, solo 1 volta. Quella che viene eseguito all’infinito è la funzione loop().
Il tuo uso del setup() è errato, stai sbagliando logica di utilizzo dei controlli- Questo in particolare non va bene:

if (demoCountSw < 1000){
    loop();  
    demoCountSw++;
  }
  else
    Serial.print("FW expired DEMO version");

Inverti il check, ossia

void setup() {
  ...
  if (demoCountSw >= 1000){
    Serial.print("FW expired DEMO version");
    lampeggio infinito)
  }
}

void loop() {
  ...
}

In questo modo proseguirà verso il loop in automatico.

leo72:
Per conservare i dati anche dopo aver spento l’Arduino devi salvarli sulla EEPROM. C’è la lib apposita per leggere e scrivere i dati in EEPROM:
http://arduino.cc/en/Reference/EEPROM

Il setup() viene eseguito, dopo l’accensione dell’Arduino, solo 1 volta. Quella che viene eseguito all’infinito è la funzione loop().
Il tuo uso del setup() è errato, stai sbagliando logica di utilizzo dei controlli- Questo in particolare non va bene:

if (demoCountSw < 1000){

loop();  
   demoCountSw++;
 }
 else
   Serial.print(“FW expired DEMO version”);




Inverti il check, ossia 


void setup() {
 …
 if (demoCountSw >= 1000){
   Serial.print(“FW expired DEMO version”);
   lampeggio infinito)
 }
}

void loop() {
 …
}



In questo modo proseguirà verso il loop in automatico.

qui la variabile la modifico nel loop incrementandola e memorizzandola con la funzione write() della libreria eeprom?
EEPROM.write(address, value)
così ?

/*
    Lampeggio
 Accende il LED1 per un secondo, poi lo spegne per un secondo, ripetendo queste fasi.
 Accende il LED2 per un secondo, poi lo spegne per un secondo, ripetendo queste fasi.
 
 Questo codice è di dominio pubblico.
 */

//  I Pin 23,24 hanno un LED connesso.

int led1 = A0;
int led2 = A1;

int demoCountSw = 0;
//  La routine di setup viene eseguita una volta che viene premuto il pulsante di Reset o che viene accesa la scheda
void setup() {                
  //  Inizializza i pin digitali come uscite.
  Serial.begin(9600);
  pinMode(led1, OUTPUT); 
  pinMode(led2, OUTPUT);
  if (demoCountSw >= 1000){
    Serial.print("FW expired DEMO version");
  digitalWrite(led1, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led1, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led2, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led2, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
  delay(1000);                //  Attendi 1 secondo
  }

//  La routine di Loop viene eseguita x sempre
void loop() {

  Serial.println("Esegui...");
  EEPROM.write(0000, demoCountSw); 
}

Intanto non hai messo la lettura del valore da EEPROM, da assegnare a demoCount. E poi metterei la scrittura sempre nel setup(), non nel loop().

Altra cosa, prendi il blocco di codice che fa lampeggiare il led ed infilalo in una funzione esterna al setup, che richiami da lì. Così il codice è più pulito.

Ah, altra cosa. Devi prevedere un sistema di "avvio", nel senso che il programma deve capire che è stato avviato per la prima volta. Non puoi basarti sul fatto che la EEPROM abbia di default il valore 0. Io generalmente uso una cella di EEPROM in cui scrivo un byte il cui valore è diverso sia da $00 che da $FF (non sto a spiegarti il motivo). Se non trovo quel valore in una determinata cella, capisco che ho avviato per la prima volta la EEPROM e quindi: 1) scrivo quel valore; 2) formatto (ossia inserisco il valore o i valori di partenza dei dati che registrerò in memoria) una o più locazioni addizionali.

Quando avvii il setup devi: 1) leggere la cella di controllo 2) se la cella contiene il carattere di controllo, andare al punto 5) 3) se non la contiene, scrivere il carattere di controllo 4) scrivere in un'altra cella (anche attigua) il valore iniziale del contatore. Proseguire al punto 5) 5) leggere il valore del contatore 6) incrementarlo 7) salvarlo 8) confrontarlo col numero max ammesso e poi prendere la decisione

leo72: Intanto non hai messo la lettura del valore da EEPROM, da assegnare a demoCount. E poi metterei la scrittura sempre nel setup(), non nel loop().

Altra cosa, prendi il blocco di codice che fa lampeggiare il led ed infilalo in una funzione esterna al setup, che richiami da lì. Così il codice è più pulito.

Ah, altra cosa. Devi prevedere un sistema di "avvio", nel senso che il programma deve capire che è stato avviato per la prima volta. Non puoi basarti sul fatto che la EEPROM abbia di default il valore 0. Io generalmente uso una cella di EEPROM in cui scrivo un byte il cui valore è diverso sia da $00 che da $FF (non sto a spiegarti il motivo). Se non trovo quel valore in una determinata cella, capisco che ho avviato per la prima volta la EEPROM e quindi: 1) scrivo quel valore; 2) formatto (ossia inserisco il valore o i valori di partenza dei dati che registrerò in memoria) una o più locazioni addizionali.

Quando avvii il setup devi: 1) leggere la cella di controllo 2) se la cella contiene il carattere di controllo, andare al punto 5) 3) se non la contiene, scrivere il carattere di controllo 4) scrivere in un'altra cella (anche attigua) il valore iniziale del contatore. Proseguire al punto 5) 5) leggere il valore del contatore 6) incrementarlo 7) salvarlo 8) confrontarlo col numero max ammesso e poi prendere la decisione

Si infatti la lettura l'avevo prevista appena avevo postato la mia risposta... però non ho capito che intendi di capire l'avvio quindi non utilizzo 00 nè FF all'inizio ma dove dovrei metterlo dentro al setup? o fuori da tutto? scusa l'ignoranza Leo per la scrittura della EEPROM devo scrivere EEPROM.write(08,demoCountSw++); così? Grazie

Capire il primo avvio. Ecco perché ti dico di usare una cella solo per scrivere il carattere di controllo. Una specie di firma digitale: se c'è il valore registrato nella cella successiva è valido, se non c'è la memoria va azzerata, indipendentemente da cosa contiene.

leo72:
Capire il primo avvio.
Ecco perché ti dico di usare una cella solo per scrivere il carattere di controllo. Una specie di firma digitale: se c’è il valore registrato nella cella successiva è valido, se non c’è la memoria va azzerata, indipendentemente da cosa contiene.

#include <EEPROM.h>

/*
    Lampeggio
 Accende il LED1 per un secondo, poi lo spegne per un secondo, ripetendo queste fasi.
 Accende il LED2 per un secondo, poi lo spegne per un secondo, ripetendo queste fasi.
 
 Questo codice è di dominio pubblico.
 */

//  I Pin 23,24 hanno un LED connesso.

int led1 = A0;
int led2 = A1;

  
EEPROM.write(0234, 28); // mi da errore qui  error: expected constructor, destructor, or type conversion before '.' token

int demoCountSw = 0;

//  La routine di setup viene eseguita una volta che viene premuto il pulsante di Reset o che viene accesa la scheda
void setup() {  
  //  Inizializza i pin digitali come uscite.
  Serial.begin(9600);
  pinMode(led1, OUTPUT); 
  pinMode(led2, OUTPUT);
  demoCountSw = EEPROM.read(demoCountSw);
  if (demoCountSw >= 1000){
    Serial.print("FW expired DEMO version");
    lampeggio();
  }
  else
    EEPROM.write(0326,demoCountSw++);
}
//  La routine di Loop viene eseguita x sempre
void loop() {
  Serial.println("Esegui..."); 
}

void lampeggio(){  
  digitalWrite(led1, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led1, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led2, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
  delay(1000);                //  Attendi 1 secondo
  digitalWrite(led2, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
  delay(1000); 
}

Leo provo a postarti il codice errato …sembra come se non posso scrivere niente sulla EEPROM fuori dal setup ? …io non ho capito dove piazzare la tua sequenza di azioni da fare …tipo scrivere un valore su una cella della EEPROM x fare il controllo deve stare dentro al setup ? da come mi dicevi io avevo capito che doveva stare fuori dal Setup però a quanto pare non funziona…nemmeno compila :frowning:

Io vorrei solo tenere conto di quante volte ho acceso la scheda dove sta il micro …e se ho superato tot accensioni mi deve dare che è una DEMO altrimenti deve fare quello che sta nel loop

Scritto in pseudo codice :grin: la funzione la chiami nel setup.

void CheckEeprom() {
 --> legge dalla posizione x della eeprom
 --> se il valore letto è diverso da yy
      --> resetta tutto
      --> altrimenti continua 
 demoCountSw = EEPROM.read(0); // Legge dalla cella con indirizzo 0
   if (demoCountSw >= 1000){
     Serial.print("FW expired DEMO version");
     lampeggio();
   }
   else
     EEPROM.write(0,demoCountSw++); // Scrive nella cella con indirizzo 0
}

Attento che read e write scrivono e leggono byte dove puoi memorizzare al massimo il valore 255. Per scrivere interi vedi qui --> http://forum.arduino.cc/index.php/topic,37470.0.html

PaoloP:
Scritto in pseudo codice :grin:
la funzione la chiami nel setup.

void CheckEeprom() {

→ legge dalla posizione x della eeprom
→ se il valore letto è diverso da yy
    → resetta tutto
    → altrimenti continua
demoCountSw = EEPROM.read(0); // Legge dalla cella con indirizzo 0
  if (demoCountSw >= 1000){
    Serial.print(“FW expired DEMO version”);
    lampeggio();
  }
  else
    EEPROM.write(0,demoCountSw++); // Scrive nella cella con indirizzo 0
}




Attento che read e write scrivono e leggono byte dove puoi memorizzare al massimo il valore 255.
Per scrivere interi vedi qui --> http://forum.arduino.cc/index.php/topic,37470.0.html

Paolo se ho capito bene questa mi controlla fino a 255? giusto? …ma perché mi dici per gli interi devo guardare li? cmq GRAZIE
vediamo se ho capito bene scusa ma il primo valore nelle EEPROM non è stato settato da nessuna parte? cioè in EEPROM(0) quando leggo cosa trovo ? 0 in integer ? la prima volta che faccio demoCountSw = EEPROM.read(0);

Non so come escano di fabbrica le EEPROM.
Potresti trovare FF, 00 o un valore a caso.

Per inizializzare la EEPROM devi crearti uno sketch minimale che scriva in una data locazione un determinato valore, lo carichi e lo esegui.
Poi carichi lo sketch definitivo.

PaoloP: Non so come escano di fabbrica le EEPROM. Potresti trovare FF, 00 o un valore a caso.

Per inizializzare la EEPROM devi crearti uno sketch minimale che scriva in una data locazione un determinato valore, lo carichi e lo esegui. Poi carichi lo sketch definitivo.

cioè dovrei fare uno sketch in cui nel setup scrivo EEPROM.write(0,0); così mi inizializza la cella 0 della EEPROM al valore 0 :) tutto qui...o ho sbagliato? questo ovviamente lo carico solo all'inizio prima dell'altro buono che mi hai consigliato.

Esatto.

Problema: contare quante volte è stata spenta e riaccesa la mia scheda se maggiore di 1000 stop se minore di 1000 esegui il loop

Risoluzione

Carico inizialmente una volta per tutte lo sketch che imposta la cella 0 a 0

#include <EEPROM.h>

void setup()  
{
  EEPROM.write(0,0);
}
void loop(){
}

Carico il codice che verifica se la cella 0 contiene un valore (“byte particolare”) > o < di 1000

#include <EEPROM.h>
#include <Wire.h>

int Led1 = A0;
int Led2 = A1;

int demoCountSw;

int addressTuner;  //  Indirizzo Tuner
int addressDem;    //  Indirizzo Demodulatore

//  Questa funzione scriverà 2 byte interi nella EEPROM all'indirizzo e all'indirizzo + 1 specificati.
//  p_address è il parametro dell'indirizzo mentre p_value è un valore che può arrivare a 1024
//  viene spezzettato in due byte (255) e moltiplicato per il byte FF successivamente vengono scritti i due byte 
//  nell'indirizzo p_address e p_address+1

void EEPROMWriteInt(int p_address, int p_value)
{
  byte lowByte = ((p_value >> 0) & 0xFF);
  byte highByte = ((p_value >> 8) & 0xFF);

  EEPROM.write(p_address, lowByte);
  EEPROM.write(p_address + 1, highByte);
}

//  Questa funzione leggerà 2 byte interi della EEPROM all'indirizzo e all'indirizzo + 1 specificati.
//  p_address è il parametro dell'indirizzo
//  vengono letti i due byte
//  viene restituito il byte meno significativo moltiplicato per FF e il più significativo moltiplicato x FF00

unsigned int EEPROMReadInt(int p_address)
{
  byte lowByte = EEPROM.read(p_address);
  byte highByte = EEPROM.read(p_address + 1);

  return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}

//  Questa funzione verifica se l'HW è stato spento per più di 1000 volte nel caso manda un messaggio di Warning e STOP  
//  Altrimenti continua con l'esecuzione del loop

void CheckEeprom() {

  //  Legge dalla posizione x della EEPROM
  //  Se il valore letto è diverso da 255
  //  Messaggio e Lampeggia
  //  Altrimenti esegue il Loop

  demoCountSw = EEPROMReadInt(0);    //  Lettura dalla cella con indirizzo 0
  if (demoCountSw >= 1000){
    Serial.print("FW EXPIRED DEMO VERSION");
    lampeggio();
  }
  else
    EEPROMWriteInt(0,demoCountSw++); //  Scrive nella cella con indirizzo 0
}
void lampeggio(){ 
  for( ; ; ){ 
    digitalWrite(Led1, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
    delay(1000);                //  Attendi 1 secondo
    digitalWrite(Led1, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
    delay(1000);                //  Attendi 1 secondo
    digitalWrite(Led2, HIGH);   //  Accendi il LED1 (Livello di tensione HIGH)
    delay(1000);                //  Attendi 1 secondo
    digitalWrite(Led2, LOW);    //  Spegni il LED1 (Livello di tensione LOW)
    delay(1000); 
  }
}
void setup()  
{
  Serial.begin(9600);  //  Apriamo la comunicazione Seriale.
  Wire.begin();        //  Apriamo la comunicazione I2C.
  CheckEeprom();       //  Richiamiamo la funzione verifica.
}

void loop()  //  Esegui
{
  Serial.println("Esegui...");
  Wire.beginTransmission(addressDem);
  Wire.beginTransmission(addressTuner);
}

P.S. nel loop dovrei configurare DEMODULATOR e TUNER con I2C.
Può andare la verifica di quante volte è stata spenta e riaccesa la mia scheda?

Gli interi usano 2 byte. Nello sketch per inizializzare la memoria devi mettere:

void setup()  
{
  EEPROM.write(0,0); // Primo byte
  EEPROM.write(1,0); // Secondo byte
}

PaoloP: Gli interi usano 2 byte. Nello sketch per inizializzare la memoria devi mettere:

void setup()  
{
  EEPROM.write(0,0); // Primo byte
  EEPROM.write(1,0); // Secondo byte
}

Giusto :astonished: svista mia Grazie.

Potresti aggiungere:

if (demoCountSw = 0) Serial.println(F("PRIMA ACCENSIONE"));
 else {
  Serial.print(F("Questa scheda è stata accesa "));
  Serial.print(demoCountSw);
  Serial.println(F(" volte."));
  }

Per tutte le scritte statiche usa la funzione F(). Risparmi memoria.

Per comunicare con l'I2C con dei demodulatore e tuner devo conoscere il protocollo o me lo posso anche inventare?? Per la comunicazione I2C ho visto la Libreria wire.h, è quella giusta?

Per l'I2C devi usare la libreria wire. Per parlare con loro devi conoscere il loro protocollo di trasmissione. Di solito li trovi nei datasheet.

PaoloP: Potresti aggiungere:

if (demoCountSw = 0) Serial.println(F("PRIMA ACCENSIONE"));
 else {
  Serial.print(F("Questa scheda è stata accesa "));
  Serial.print(demoCountSw);
  Serial.println(F(" volte."));
  }

Per tutte le scritte statiche usa la funzione F(). Risparmi memoria.

scusa Paolo questa scrittura statica la devo fare nel setup o su check eeprom quella funzione che controlla la prima celle della EEPROM

Lollo, il metodo da te scelto, quello cioè di usare 2 sketch distinti, uno per scrivere a 0 la EEPROM e uno che è il programma che la usa, funziona ma è inefficiente. Funziona in questo caso perché devi impostare a 0 un contatore, ma come faresti se dovessi distribuire un progetto in cui nella EEPROM va scritto il valore letto da un sensore ambientale? Mica puoi metterci un valore predefinito tu, oppure mica potresti chiedere all'utente di fare la doppia scrittura: ci sarebbe qualcuno che potrebbe non farla (fatica, fraintendimento). Ed il tuo sketch non funzionerebbe.

Col metodo che ti avevo descritto io fai tutto dallo stesso programma. Quella che vai a cercare in una cella predeterminata è una specie di firma digitale che informa il tuo programma che l'utente lo ha già eseguito almeno una volta.

http://www.leonardomiliani.com/2012/micrologio-un-micro-orologio-con-un-atmega328p/ Scaricati il pacchetto del mio Micrologio e guarda la funzione loadDefaults() che chiamo dal setup(). Cerca qui sul forum anche il mio progetto del sensore di fughe di gas. C'è nel suo firmware lo stesso identico sistema.

@Paolo: una EEPROM nuova ha le celle con lo stesso valore di default delle Flash, ossia $FF. Anche avrdude, se gli fai fare l'erase della Flash o della Eeprom, scrive $FF.