Problema con contapezzi

Ciao a tutti.Ho un Poblema con questo sketch, in pratica quando azzero il contatore mi cancella solo la cifra che incrementa al posto dello 0. Per farvi capire: se incremento sino a 12 dopo il reset visualizzero 02.Come posso risolverlo?E' possibile inoltre tenere in memoria il numero a cui sono arrivato senza perderlo ogni volta che stacco l'alimentazione?

 #include <LiquidCrystal.h>
    int in=8;
    int in2=7;


    int a = 0;
    int b = 0;
    int c= 0;
    int d = 0;

    LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

    void setup() {
      pinMode(in,INPUT);
      lcd.begin(16, 2);
      lcd.print(" xxxxxxxxxxxxxxxx. ");
      delay(3000); lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("xxxxxxxxxxxxx");
      lcd.setCursor(0, 1);
      lcd.print("Pz=");


void loop() {

  c=digitalRead(in);
  if ( c== 1){b=b+1; delay(500);}
  d=digitalRead(in2);
  if ( d== 1){a=a+1;delay(500);}
   if (( c ==1) & ( d==1)){a=0; b=0; delay(500);}
 
  lcd.setCursor(4, 1);
  lcd.print(a);
  lcd.setCursor(14, 1); 
  lcd.print(b); 
  }

se stami un numero a una cifra devi stampare anche un spazio prima.
Ciao Uwe

come faccio a stamapre uno spazio?

rocco8383:
come faccio a stamapre uno spazio?

Devi modificare lo sketch.
Invece di stampare le variabili così come sono, devi fare un controllo e gestire l'output.

Ricordati che un display LCD mantiene i dati sulle celle che non riaggiorni per cui se scrivi 10 in posizione (0,0) e poi ci riscrivi 5, resta a video "50" perché lo zero non è stato sovrascritto da nulla.

per stampare uno spazio è sufficiente fare

lcd.print (" ");

altrimenti un modo che ti può evita controlli ma magari rende meno efficiente lo sketch è scrivere 3-4 caratteri vuoti e poi riposizionare il cursore alla posizione di prima.

Per salvare i valori c'è la libreria EEPROM. Quando lanci lo sketch leggi se c'è qualcosa in memoria, e salvi alla fine di ogni loop. Attenzione che non so se ci sono dei limiti al numero di volte che puoi salvare sulla EEPROM.. :roll_eyes:

Grazie per l'aiuto mi metto subito all'opera

Ho ancora qualche problema...non mi salva il valore nella eeprom e non riesco ad azzerare tutte le cifre del contatore

#include <EEPROM.h>

#include <LiquidCrystal.h>

int in=8;
int in2=7;


int a = 0;
int b = 0;
int c= 0;
int d = 0;


LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  pinMode(in,INPUT);
  lcd.begin(16, 2);
  lcd.print(" Rocco8383. ");
  delay(3000); 
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Rocco8383");
  lcd.setCursor(0, 1);
  lcd.print("PZ:");

}

void loop() {

  EEPROM.read (a );
    c=digitalRead(in);
  if ( c== 1){
    b=b+1; 
    delay(500);
  }
  d=digitalRead(in2);
  if ( d== 1){
    a=a+1;
    delay(500);
  }
  if (( c ==1) & ( d==1)){
    a=0;  
    delay(500);
  }
  


  lcd.setCursor(3, 1);
  lcd.print(a);
  EEPROM.write (a, a);
 
   

}

Intanto penso che
if (( c ==1) & ( d==1)){
se intendi un AND logico allora devi scrivere && altrimenti fai un AND di bit

poi non riesco a capire:
lcd.print(a);
EEPROM.write (a, a);

se a è il valore da scrivere, allora la write su eprom scrive il valore in celle diverse a seconda del valore stesso.
Il comando write ha 2 parametri, uno il byte da scrivere e l'altro in quale posizione, partendo da zero.
Non mi sembra abbia un senso scrivere (a,a), vuol dire se a=3, scrivi 3 in cella 3, se a=5 scrivi 5 in cella 5, etc.
Visto che posizione cella=valore che senso ha?

Un consiglio. Io faccio una fatica bestia a capire il tuo codice perchè i nomi delle tue variabili a,b,c,d non danno nessuna informazione.
a sarebbe il numero pezzi? chiamalo "npzz" ad esempio.

Come ha già detto nid69ita, devi usare un indirizzo per salvare il valore.
Poi è inutile leggere i valori dalla EEPROM nel loop, fallo prima del setup! Tanto a te serve leggere il valore salvato solo se l'arduino si è resettato o spento....
è sufficiente fare

const byte indirizzo=1
int variabile=EEPROM.read(indirizzo);
void setup()
.....
void loop()
....
EEPROM.write(indirizzo,variabile)

E ricorda che la EEPROM ha un ciclo di vita finito, ovvero puoi scrivere una cella di memoria solo un tot di volte (mi sembra 100.000)

nid69ita:
E ricorda che la EEPROM ha un ciclo di vita finito, ovvero puoi scrivere una cella di memoria solo un tot di volte (mi sembra 100.000)

Per evitare di friggere la stessa cella 100'000 volte conviene utilizzare un algoritmo di Wear leveling.
L'atmel propone un application note sull'argomento --> http://www.atmel.com/Images/doc2526.pdf
insieme al codice

/******************************************************/
/* AVR101 "High endurance EEPROM storage"             */
/*                                                    */
/* Filename: High_Endurance_EEPROM.c                  */
/* Date: 2002.08.15                                   */
/* Author: jllassen                                   */
/*                                                    */
/* Modified: 2003.10.06 (raapeland)                   */
/*                                                    */
/* Compiler: IAR EWAVR 2.26C                          */
/******************************************************/

#include <iom16.h>

/******************************************************/
/* Define the number of levels in the buffer, */
/* - eight levels will guarantee 800k writing onf the parameter */
/******************************************************/
#define EE_PARAM_BUFFER_SIZE  8
#define EE_STATUS_BUFFER_SIZE  EE_PARAM_BUFFER_SIZE

/******************************************************/
/* List of parameters */
/******************************************************/
#define EE_PARAM_1  0
#define EE_PARAM_2 (EE_PARAM_1 + EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
//#define EE_PARAM_3 (EE_PARAM_2 + EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)  ... and so forth

/******************************************************/
/* prototyping of functions used*/
/******************************************************/
void findCurrentEepromAddr( unsigned int *EeBufPtr );
char EeReadBuffer( unsigned int address );
void EeWriteBuffer( unsigned char parameter, unsigned int *address, unsigned char data );

/******************************************************/
/* Global variables:                                  */
/* Initialize the parameter buffer pointers to be able to resume at the right location.*/
/******************************************************/
unsigned int EeBufPtrParam1 = EE_PARAM_1; 
unsigned int EeBufPtrParam2 = EE_PARAM_2; 

void findCurrentEepromAddr( unsigned int *EeBufPtr )
{
  unsigned char temp;
  unsigned int EeBufEnd;

  *EeBufPtr += EE_PARAM_BUFFER_SIZE;              // Point the the status buffer
  EeBufEnd = *EeBufPtr + EE_STATUS_BUFFER_SIZE;   // The first address outside the buffer

  /* Identify the last writen element of the status buffer */
  do{
    if( *EeBufPtr == EeBufEnd )
      break;
    temp = EeReadBuffer( (*EeBufPtr)++ );
  }while ( EeReadBuffer( *EeBufPtr ) == temp +1 );

  *EeBufPtr -=  (EE_PARAM_BUFFER_SIZE + 1);       // Point to the last used element of the parameter buffer
}

char EeReadBuffer( unsigned int address )
{
  while(EECR & (1<<EEWE));
  EEAR = address;
  EECR |= (1<<EERE);
  return EEDR;
}  

void EeWriteBuffer( unsigned char parameter, unsigned int *address, unsigned char data )
{
  unsigned char EeOldStatusValue;

  /* Store the old status value and move pointer to the next element in the buffer */
  EeOldStatusValue = EeReadBuffer( *address + EE_PARAM_BUFFER_SIZE);
  (*address)++;
  if( *address == parameter + EE_PARAM_BUFFER_SIZE )
  {
    *address = parameter;
  }
  
  // If self-programming is used in the application, insert code here to wait for any
  // self-programming operations to finish before writing to the EEPROM.
  // Also make sure that interrupts are disabled during EEPROM write if interrupts
  // are used in the application, otherwise the 4-cycle limit could be exceeded.

  /* Update the parameter in the EEPROM buffer */
  while(EECR & (1<<EEWE));
  EEAR = *address;
  EEDR = data;
  EECR |= (1<<EEMWE);
  EECR |= (1<<EEWE);

  /* Update the status buffer */
  while(EECR & (1<<EEWE));
  EEAR = *address + EE_PARAM_BUFFER_SIZE;
  EEDR = EeOldStatusValue + 1;
  EECR |= (1<<EEMWE);
  EECR |= (1<<EEWE);
}

/* Appliction main routine - to show how the EEPROM buffers are used */
void main ( void )
{
  unsigned char counter;

  findCurrentEepromAddr( &EeBufPtrParam1 );
  findCurrentEepromAddr( &EeBufPtrParam2 );
  
  for( counter = 0 ; counter < 50; counter++)
  {
    EeWriteBuffer( EE_PARAM_1, &EeBufPtrParam1, counter );
    EeWriteBuffer( EE_PARAM_2, &EeBufPtrParam2, counter*2 );
  }
}

C'è qualcosa anche nel Playground del sito.

Allora con questo sketch penso di essere vicino alla soluzione.Non riesco però ad azzerare tutto il contatore ma solo la cifra di partenza.

 #include <LiquidCrystal.h>
    #include <EEPROM.h>       
    int addr_a = 0;                 
    int addr_b = 1;                


    int in=8;
    int in2=7;


    int a = 0;
    int b = 0;
    int c= 0;
    int d = 0;

    LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

    void setup() {
      pinMode(in,INPUT);
      pinMode(13,OUTPUT);
      digitalWrite(13,HIGH);
      lcd.begin(16, 2);
      lcd.print(" xxxxxxxx");
      delay(3000); lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Valori:");
      lcd.setCursor(0, 1);
      lcd.print("P1=");
      lcd.setCursor(10, 1);
      lcd.print("P2=");
      a = EEPROM.read(addr_a);          // leggo i valori a salvati nella precedente "sessione di lavoro"
      b=  EEPROM.read(addr_b);          // leggo i valori b salvati nella precedente "sessione di lavoro"
    }

    void loop() {

      c=digitalRead(in);
      if ( c== 1){b=b+1; EEPROM.write(addr_b, b); delay(500); }
      d=digitalRead(in2);
      if ( d== 1){a=a+1; EEPROM.write(addr_a, a);delay(500);}
      if (( c ==1) & ( d==1)){a=0; b=0; delay(500);EEPROM.write(addr_b, b);EEPROM.write(addr_a, a);}

     
      lcd.setCursor(4, 1);
      lcd.print(a);
      lcd.setCursor(14, 1); 
      lcd.print(b); 
     
    }

Prova così.
Avevi dimenticato di mettere l'ingresso 2 in INPUT col pinmode.

......

Non puoi registrare un contatore maggiore di 255 (un byte) [Thanks Leo]
Devi aggiungere del codice se vuoi registrare un dato su più celle nella eeprom.

EDIT: Ho trovato questo topic interessante con un bel codice pronto per scrivere unsigned long (http://arduino.cc/forum/index.php/topic,45220.0.html)
integrandolo col tuo programma diventa:

#include <LiquidCrystal.h>
#include <EEPROM.h>       

#define PINLED 13
#define INGRESSO1 8
#define INGRESSO2 7

int addr_a = 0; // 0,1,2,3                
int addr_b = 4; // 4,5,6,7               

unsigned long count_a = 0; // Valore massimo 4 miliardi 294...
unsigned long count_b = 0; // Valore massimo 4 miliardi 294...

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  pinMode(INGRESSO1,INPUT);
  pinMode(INGRESSO2,INPUT);
  pinMode(PINLED,OUTPUT);
  digitalWrite(PINLED,HIGH);

  lcd.begin(16, 2);
  lcd.print(" xxxxxxxx");
  delay(3000); 
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Valori:");
  lcd.setCursor(0, 1);
  lcd.print("P1=");
  lcd.setCursor(10, 1);
  lcd.print("P2=");

  count_a = EEPROM_readlong(addr_a);          // leggo i valori a salvati nella precedente "sessione di lavoro"
  count_b = EEPROM_readlong(addr_b);          // leggo i valori b salvati nella precedente "sessione di lavoro"
}

void loop() {
  byte c = digitalRead(INGRESSO1);
  byte d = digitalRead(INGRESSO2);
  delay(10); // debounce

  if (c == HIGH){
    count_b++; 
    EEPROM_writelong(addr_b, count_b); 
    delay(500); 
  }

  if (d == HIGH){
    count_a++; 
    EEPROM_writelong(addr_a, count_a);
    delay(500);
  }

  if ((c == HIGH) && (d == HIGH)){
    count_a = 0; 
    count_b = 0; 
    delay(500);
    EEPROM_writelong(addr_b, count_b);
    EEPROM_writelong(addr_a, count_a);
  }

  lcd.setCursor(4, 1);
  lcd.print(count_a);
  lcd.setCursor(14, 1); 
  lcd.print(count_b); 
}

 // read double word from EEPROM, give starting address
  unsigned long EEPROM_readlong(int address) {
  //use word read function for reading upper part
  unsigned long dword = EEPROM_readint(address);
  //shift read word up
  dword = dword << 16;
  // read lower word from EEPROM and OR it into double word
  dword = dword | EEPROM_readint(address+2);
  return dword;
}

//write word to EEPROM
  void EEPROM_writeint(int address, int value) {
  EEPROM.write(address,highByte(value));
  EEPROM.write(address+1 ,lowByte(value));
}
  
  //write long integer into EEPROM
  void EEPROM_writelong(int address, unsigned long value) {
  //truncate upper part and write lower part into EEPROM
  EEPROM_writeint(address+2, word(value));
  //shift upper part down
  value = value >> 16;
  //truncate and write
  EEPROM_writeint(address, word(value));
}

unsigned int EEPROM_readint(int address) {
  unsigned int word = word(EEPROM.read(address), EEPROM.read(address+1));
  return word;
}

PaoloP:
Non puoi registrare un contatore maggiore di 256 (un byte)

Ad esser precisi, 255.
256 è il numero di valori diversi che un byte può tenere, valori che vanno da 0 a 255.

Adesso manca solo l'algoritmo di wear leveling e potresti andare avanti per 6'400'000 scritture.
Con una scrittura al secondo la EEPROM durerebbe poco più di 2 anni.

Tempo fa avevo scritto qualcosa di simile.
In pratica facevo così.

Formattavo la EEPROM con una serie di byte standard (esempio $AA).
Ogni blocco di dati iniziava con un byte diverso da $AA, ovviamente. Siccome memorizzavo degli orari e delle letture, era facile avere un byte diverso da $FF dato che un'ora al max arriva a $17 (23d). Ogni volta che scrivevo un blocco di dati, incrementavo il puntatore all'indirizzo del blocco corrente.

In caso di riavvio, controllavo se la prima cella era diversa da $AA, segno che la EEPROM era già stata formattata e che quindi non era il primo avvio. A questo punto partiva un loop che mi "saltava" a blocchi attraverso la EEPROM finché non trovava una cella contenente appunto $AA e quello era l'indirizzo del 1° blocco libero disponibile.

E' ovvio che se io non svuotavo la EEPROM prima di averla riempita, il contatore ripartiva da 0, sovrascrivendomi i dati in fondo. Per ovviare a questo avevo messo un led di avviso per informarmi che i blocchi stavano per terminare.

Con lo sketch di PAOLOP(grazie) ho più cifrea disposizione ma quando resetto azzera solo la prima cifra.Con lo sketch da te modificato quante volte potrò scrivere l'eeprom?

rocco8383:
Con lo sketch di PAOLOP(grazie) ho più cifrea disposizione ma quando resetto azzera solo la prima cifra.Con lo sketch da te modificato quante volte potrò scrivere l'eeprom?

Dipende da quante scritture fai e da quanto è grosso il tuo blocco di dati.
Ipotizziamo un blocco di 4 byte e 1 scrittura al secondo.
1K di EEPROM sono 1024 byte, quindi hai 1024/4=256 blocchi.
100.000 scritture per 256 blocchi, sono 256.000.000 blocchi. Scrivendone 1 al secondo bruci la EEPROM in 296 giorni.

rocco8383:
Con lo sketch di PAOLOP(grazie) ho più cifre disposizione ma quando resetto azzera solo la prima cifra.

#include <LiquidCrystal.h>
#include <EEPROM.h>       

#define PINLED 13
#define INGRESSO1 8
#define INGRESSO2 7

int addr_a = 0; // 0,1,2,3                
int addr_b = 4; // 4,5,6,7               

unsigned long count_a = 0; // Valore massimo 4 miliardi 294...
unsigned long count_b = 0; // Valore massimo 4 miliardi 294...

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  pinMode(INGRESSO1,INPUT);
  pinMode(INGRESSO2,INPUT);
  pinMode(PINLED,OUTPUT);
  digitalWrite(PINLED,HIGH);

  lcd.begin(16, 2);
  lcd.print(" xxxxxxxx");
  delay(3000); 
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Valori:");
  lcd.setCursor(0, 1);
  lcd.print("P1=");
  lcd.setCursor(10, 1);
  lcd.print("P2=");

  count_a = EEPROM_readlong(addr_a);          // leggo i valori a salvati nella precedente "sessione di lavoro"
  count_b = EEPROM_readlong(addr_b);          // leggo i valori b salvati nella precedente "sessione di lavoro"
}

void loop() {
  byte c = digitalRead(INGRESSO1);
  byte d = digitalRead(INGRESSO2);
  delay(10); // debounce

  if (c == HIGH){
    count_b++; 
    EEPROM_writelong(addr_b, count_b); 
    delay(500); 
  }

  if (d == HIGH){
    count_a++; 
    EEPROM_writelong(addr_a, count_a);
    delay(500);
  }

  if ((c == HIGH) && (d == HIGH)){
    count_a = 0; 
    count_b = 0; 
    delay(500);
    EEPROM_writelong(addr_b, count_b);
    EEPROM_writelong(addr_a, count_a);

    lcd.setCursor(4, 1);
    lcd.print("  ");
    lcd.setCursor(14, 1); 
    lcd.print("  "); 
  }

  lcd.setCursor(4, 1);
  lcd.print(count_a);
  lcd.setCursor(14, 1); 
  lcd.print(count_b); 
}

// read double word from EEPROM, give starting address
unsigned long EEPROM_readlong(int address) {
  //use word read function for reading upper part
  unsigned long dword = EEPROM_readint(address);
  //shift read word up
  dword = dword << 16;
  // read lower word from EEPROM and OR it into double word
  dword = dword | EEPROM_readint(address+2);
  return dword;
}

//write word to EEPROM
void EEPROM_writeint(int address, int value) {
  EEPROM.write(address,highByte(value));
  EEPROM.write(address+1 ,lowByte(value));
}

//write long integer into EEPROM
void EEPROM_writelong(int address, unsigned long value) {
  //truncate upper part and write lower part into EEPROM
  EEPROM_writeint(address+2, word(value));
  //shift upper part down
  value = value >> 16;
  //truncate and write
  EEPROM_writeint(address, word(value));
}

unsigned int EEPROM_readint(int address) {
  unsigned int word = word(EEPROM.read(address), EEPROM.read(address+1));
  return word;
}

Ho aggiunti la scrittura di 2 spazi bianchi quando si resetta.
Se prevedi cifre più lunghe aumenta il numero degli spazi ma attenzione a non andare oltre lo schermo altrimenti i numeri non si capiscono perche taglierebbe le cifre.

Per risolvere il problema protesti prendere una EEPROM i2c (http://www.robot-italy.com/it/24lc256i-i2c-eeprom.html) e quando si esaurisce la cambi.
Naturalmente bisognerebbe rivedere il codice. :grin:
Però si trova molto materiale
--> Arduino Playground - I2CEEPROM24LC512
--> http://www.hobbytronics.co.uk/arduino-external-eeprom
--> Arduino Playground - HomePage
--> GitHub - mikeneiderhauser/I2C-EEPROM-Arduino: Interface Library from Arduino V1.X to Microchip 24LC256 or 24LC512 EEPROM

Ma quando la eeprom si esaurirà come si comporterà il contatore?Leggerà sempre l'ultimo valore che è riuscito a scrivere?