If-Switch-Array-Millis-For

quindi e' piu' un discorso stilistico e cmq con entrambi si fa tutto.

ma sul mio caso specifico come ragionare ?

stavo pensando di creare una variabile con millis che conta fino a 15sec, e poi i 3 case settati su 5-10-15

Certo ad una variabile assegni il valore di millis e poi nel case a seconda del valore esegui quello che vuoi...

il case non può lavorare con range di valori, ma solo con uguaglianze.
dal punto di vista assembly in oltre è leggermente più efficiente, soprattutto se non si usa il break.

Beh prima del case fà un controllo... ed assegna alle variabili un valore 0-1-2 ma a questo punto diventerebbe stupido, è verò me ne ero scordato... usa gli If consecutivi :slight_smile:

grazie, delle risposte,
sto' lavorando sulla creazione della data, giorno mese anno

mi potete tradurre in italiano questo comando:

long minutes  = time / MINS;    time -= minutes  * MINS;

nella variabile time ci sono i secondi, ma il resto e' una lingua che non parlo :slight_smile:

credevo fosse stato facile aggiungere la data ad un orologio :slight_smile:

ho iniziato a fare questo discorso:
1 ora = 60min
1 giorno = 24 ore
1 mese = ????????

se i mesi erano tutti di 30 giorni sarebbe stato facile, come si risolve ?

c'e' una libreria per la gestione della data ? tipo calendario ?

Intanto mettila così:

long minutes  = time / MINS;
time = time - (minutes  * MINS);

Dichiara minutes di tipo long che contiene i minuti come risultato di time/MINS
Poi da time sottrae il valore di minutes*MINS, che equivale a lasciare in time la parte decimale.

Cioè, mi spiego:
siccome minutes è un intero di tipo lungo, conterrà solo la parte intera della divisione.
Dopodiché da time verrà levata la parte intera, per lasciare solo i decimali. Come? Togliendo minutes*MINS.
E' una forma di conversione dalle date o dagli orari in formato decimale verso il formato temporale oo:mm:ss

ora e' molto piu' chiaro :slight_smile:

per il resto che fo ? mi compro un RTC ? non ci sono librerie che fungono da calendario ?

Testato:
credevo fosse stato facile aggiungere la data ad un orologio :slight_smile:

ho iniziato a fare questo discorso:
1 ora = 60min
1 giorno = 24 ore
1 mese = ????????

se i mesi erano tutti di 30 giorni sarebbe stato facile, come si risolve ?

c'e' una libreria per la gestione della data ? tipo calendario ?

Semplicemente ti fai un array con i giorni dei mesi:
mesi={31,28,31... ecc..}
Per i bisestili, li calcoli semplicemente ed aggiungi 1 giorno a febbraio nel caso di anno bisestile.

boolean bistestile(int anno) {
  if (((anno % 4) ==0) && ((anno % 100) != 0) or ((anno % 400) ==0)) {
    return true;
  } else {
    return false;
  }
}

La differenza tra IF e Switch case é anche che nelle IF puoi controllare piú condizioni e concatenarle in modo AND oppure OR.
Percui puoi usare Switch-case solo in particolari casi e non al posto del IF.
Ciao Uwe

quante cose da imparare :slight_smile:

il mio bell'orologio usa un array per passare avanti l'orario, io ne ho aggiunto un altro per la data, funziona, bravo mi sono detto.
prima di affrontare la questione dei mesi usando la strada spianata da Leo volevo creare l'IF per mandare a video 3 sec l'orario e 3 sec la data.

Debbo usare il blink without delay mi sono detto, lo modifico ed all'aspetto sembra gradevole.
Col cavolo che funziona,
Come si fa la copia di un array ?

  // IF senza delay per alternare Ora/Data
   
   if (millis() - previousMillis > interval) 
   {
    previousMillis = millis();
    
      if (alterna == ClockArray)
      alterna = DateArray;
    else
      alterna = ClockArray;
      
     // Display.
    DisplayNumberString( alterna );
    }

Gli array non puoi copiarli assegnando un array ad un altro array (credo non esistano metodi). Devi copiare i suoi elementi nell'array contenitore.

non funziona ancora

Vado a mangiare, magari a pancia piena penso meglio :slight_smile:

// IF senza delay per alternare Ora/Data
  int AlternaArray[6]={0,0,0,0,0,0};
  
   if (millis() - previousMillis > interval) 
   {
    previousMillis = millis();
    
      if (AlternaArray == ClockArray)
       {
       AlternaArray[6];
  DateArray[0] = upperDays;
  DateArray[1] = lowerDays;
  DateArray[2] = upperMonths;
  DateArray[3] = lowerMonths;
  DateArray[4] = upperYears;
  DateArray[5] = lowerYears;
  }
    else
     {
     AlternaArray[6];
       ClockArray[0] = upperHours;
  ClockArray[1] = lowerHours;
  ClockArray[2] = upperMins;
  ClockArray[3] = lowerMins;
  ClockArray[4] = upperSeconds;
  ClockArray[5] = lowerSeconds;
  
  
     // Display.
    DisplayNumberString( AlternaArray );
   }
}
}

allora, ci sono un pò di errori di base.
Se usi il nome di un array SENZA graffe, non stai utilizzando o confrontando TUTTI i suoi valori, ma l'indirizzo di memoria in cui è posizionato l'array (leggiti qualcosa sui puntatori in caso)

questo, a differenza di una copia, fa si che se ad uno dei due array vengono modificati dei valori, anche l'altro array avrà i valori modificati, perchè in realtà sono due "etichette" agli stessi dati, ovvero un'insieme di bit nella ram :slight_smile:

quindi dire:

 if (alterna == ClockArray)

equivale a dire: l'array alterna, ha (o meglio punta) lo stesso indirizzo di memoria dell'array ClockArray? sintatticamente è corretto da fare

alterna = DateArray;

vuol dire, ora alterna dovrebbe puntare all'indirizzo della prima cella di DateArray, e anche questo è corretto (ricorda che modificando alterna, anche i valori contenuti in DateArray risulteranno modificati e viceversa)

Quindi cosa c'è di sbagliato?
molto probabilmente hai dichiarato alterna come un array. gli array sono dei puntatori alla prima cella di memoria di una serie di celle di memoria nella ram (l'array dal punto di vista fisico, appunto). Cambiare questo indirizzo senza prima lanciare una free() su quella zona di memoria vuol dire che finchè il programma è in esecuzione o non termina la visibilità della variabile (savo malloc manuale ma è un'altra storia), quell'aria di memoria viene considerata "in uso" e non può essere riassegnata, è un errore di programmazione. La zona di memoria si dice garbage, e quando il garbage riempie tutta la ram sia il programma, che il sistema operativo possono crashare.
Dunque per evitare problemi, gli array hanno l'indirizzo puntato costante, se non erro. Quindi dobbiamo usare un puntatore.
alterna sarà un puntatore alla prima cella dell'array:

int *alterna;

l'if e l'assegnazione rimangono uguali, persino il display:

if (alterna == ClockArray)
      alterna = DateArray;
    else
      alterna = ClockArray;
// Display.
    DisplayNumberString( alterna );

come puoi vedere un puntatore può essere tranquillamente sostituito ad un array, l'unica differenza è che l'array si prende da solo una zona memoria, mentre col puntatore devi allocarla manualmente con una malloc(), ma in questo caso non serve perchè usi delle aree di memoria già allicate dai 2 array

spero sia chiaro e che la storia sull'indirizzo dell'array costante sia corretta, perchè non sono affatto sicuro :slight_smile:

tutto qui ?
mi mancava un asterisco ? :slight_smile:

grazie, avevo notato in altri codici quell'asterisco, credevo avesse il significato di carattere jolly :slight_smile:

funziona alla grande, il codice finale e' questo, lo posto per chi si imbattesse in questa discussione:

  // serve per cambio Ora/Data
  long previousMillis = 0;
  long interval = 3000; 
  int *alterna;
  // IF senza delay per alternare Ora/Data
   
   if (millis() - previousMillis > interval) 
   {
    previousMillis = millis();
    
      if (alterna == ClockArray)
      alterna = DateArray;
    else
      alterna = ClockArray;
      
     // Display.
    DisplayNumberString( alterna );
    }

ora devo affrontare la questone dellla gestione del mese, nel frattempo vi chiedo, il problema di overflow del millis, oltre a tutte le funzioni dell'orologio sara' presente anche su questa previousmillis che uso per lo switch, che succede dopo 2 mesi non switchera' piu' tra data e ora ?

Certamente.

ma allora mi chiedo, se millis e' una funzione, ed anche importante e molto usata, perche' non viene aggiornata in modo da gestire automaticamente questo problema ?

Chiedilo agli sviluppatori di Arduino :stuck_out_tongue:

guardate che funziona lo stesso, credo :slight_smile:

millis() - previousMillis > interval

dove interval è una costante, ricordate che sia millis() che previousMillis sono unsigned, quindi NON assumono valori negativi.

lavoriamo con valori da 0 a 63 (6bit), con 64 che è l'overflow, quindi a 64 si ritorna a 0

se previusMillis vale 50, il timer si resetta(a 0), abbiamo:
0 - 50, ovvero -50? no! non ci sono numeri negativi! lavoriamo a bit

000000 -
110010 =
001110 ovvero 14... e guarda caso, è proprio il tempo trascorso tra 50 e 0... 50+14=64, ovvero overflow e si riparte da 0

quindi l'overflow non è gestito da arduino perchè fondamentalmete non necessario. Certo, se parti da 50, si resetta, e ritorni a 50 il tempo trascorso è pari a 0. Quindi in realtà questa cosa ti permette di avere SEMPRE un valore di massimo tempo pari alla grandezza della variabile (pensa sewnza questo trucco cosa succede a 2 secondi dall'overflow... al massimo hai 2 secondi di autonomia!)

Puoi usare un trucco per andare oltre: ogni volta che millis si riazzera, aumenti una variabile. A questo punto il massimo valore memorizzabile è (valori unsigned long)*(valori variabile). con un int mi sa che arrivi tranquillamente fino a fine del sole :slight_smile:
ovviamente quando salvi un tempo, non prendi più solo la millis, ma ti salvi anche il numero di reset attuali. A questo punto si complica un poco la matematica: al valore 14 che prima abbiamo trovato, devi aggiungere il valore massimo dell'overflow moltiplicato per il numero di reset di differenza -1. Dato che è un valore non memorizzabile in una variabile standard, è un poco difficile da computare ma credo tu abbia capito cosa intendo, e spero non ti debba mai inbattere in calcoli del genere (che poi in realtà noi tra giorni, mesi e anni bisestili complichiamo la storia mooooolto di più) :slight_smile: