Dubbio su ciclo for+millis()+array

Buongiorno a tutti,

vi spiego la mia esigenza: ho un sensore SHT31 al quale faccio leggere la temperatura e vorrei poi che ogni tot tempo, ad esempio ogni 3 ore, la lettura venga memorizzata.

Ho pensato di usare millis() per determinare l'intervallo di tempo a me utile e un ciclo for per reiterare le letture 8 volte (3hx8=24h/1day) ed infine un array nel quale memorizzare i dati.

Il codice è questo:

#include "cactus_io_SHT31.h"
cactus_io_SHT31 sht31;
float statTemp[7];
unsigned long tempo = 0;

void setup() {
  
  Serial.begin(9600);
  
  if (!sht31.begin()) { 
  Serial.println("Count not find sensor. Check wiring and I2C address"); 
  while(1) delay(1); 
 } 
}

void loop() {
  
  float t = sht31.getTemperature_C();

if ((millis() - tempo) > 5000) {
   for (int i = 0; i < 7; i++){
     statTemp[i] = t;
   }  
tempo = millis();
}
Serial.println(t);
Serial.print(statTemp[0]);
Serial.print(",");
Serial.print(statTemp[1]);
Serial.print(",");
Serial.print(statTemp[2]);
Serial.print(",");
Serial.print(statTemp[3]);
Serial.print(",");
Serial.print(statTemp[4]);
Serial.print(",");
Serial.print(statTemp[5]);
Serial.print(",");
Serial.print(statTemp[6]);
Serial.print(",");
Serial.println(statTemp[7]);
}

L'array non si popola, perchè?

Grazie

Ovvero, cosa ti scrive?

Serial.println(t) mostra il valore corrente della temp. in modo corretto,

poi l'array si comporta in maniera strana, faccio un esempio:

20.1 // stampa valore t
20.1,20.1,20.1,20.1,20.1,20.1,20.1,0.0 // contenuto array

Esattamente quello che fa il programma
Ogni 5 secondi con un ciclo for aggiorna 7 elementi di matrice con una (1) sola lettura

Ciao, il comportamento è esattamente quello che deve fare dal tuo codice "ERRATO".

Tu leggi la temperatura di continuo e ogni 5 secondi, inseristi in tutti gli elementi dell'array l'ultimo valore letto, ché è uguale per tutti gli elementi.

Altro particolare un array dichiarato array[7], contiene elementi da 0 a 6 sette elementi, quindi il settimo elemento array[7] che tu tenti di usare "non esiste";

Se metto if ((millis() - tempo) > 10800000) { //3h

mi aspetto che i valori dell'array si riempiano uno alla volta ogni 3 ore, e non accade poichè si riempie tutto di botto. Quello che non capisco e se il ciclo foe aspetta il millis() o effettua tutto il ciclo a prescindere...

un modo corretto di procedere sarebbe.

  1. Calcolo un intervallo di tempo con la funzione millis()

  2. Trascorso il tempo entro in un ciclo for() che legge la temperatura, la inserisce in un elemento
    dell'array, e attende un intervallo di tempo per la prossima lettura.

  float t;
  

if ((millis() - tempo) > 50000) {

 
   for (int i = 0; i < 7; i++){
     t = sht31.getTemperature_C();
     statTemp[i] = t;
     delay(10000);//Attende 10 secondi tra una lettura e l'altra
   }  
tempo = millis();
}

Capisco torn24, e se non potessi fermare l'esecuzione del programma con il delay(10000) , non ho scampo, devo abbandonare questa strada?

Adesso è più chiaro cosa vuoi fare, una lettura ogni 3 ore :slight_smile:

Allora non usare un ciclo for(), ma un indice che incrementi ogni volta che passa 3 ore

  float t; // Variabili da dichiarare fuori dal loop() e setup() VARIABILI GLOBALI
  int i=0;// Globale 
  
if ((millis() - tempo) > (3*3600*1000)) {

 
   
     t = sht31.getTemperature_C();
     statTemp[i++] = t;
     
     tempo = millis();

     if(i>=8){
         // eseguo la stampa dei risultati
         Serial.Println(....
         i=0; // Torno al primo elemento
     }
}

Cacchio, che bello! Provo il codice in serata e ti riporto l'esito.

Grazie mille per il tempo dedicatomi

La funzione millis() non è precisa nel calcolo di ore o giorni, si ha un errore notevole "diversi minuti in un ora", quindi valuta se ti va bene un conteggio del tempo molto approssimato, altrimenti devi pensare ad un sistema che usi un RTC come componente aggiuntivo :slight_smile:

dunque sto provando questo codice:

#include "cactus_io_SHT31.h"
cactus_io_SHT31 sht31;

float t;
float statTemp[8];
int i = 0;
unsigned long tempo = 0;


void setup() {

  Serial.begin(9600);

  if (!sht31.begin()) {
    Serial.println("Count not find sensor. Check wiring and I2C address");
    while (1) delay(1);
  }
}

void loop() {

  if ((millis() - tempo) > 5000) {
    t = sht31.getTemperature_C();
    statTemp[i++] = t;
  }
  if (i >= 8) {
    Serial.print(statTemp[0],1);
    Serial.print(",");
    Serial.print(statTemp[1],1);
    Serial.print(",");
    Serial.print(statTemp[2],1);
    Serial.print(",");
    Serial.print(statTemp[3],1);
    Serial.print(",");
    Serial.print(statTemp[4],1);
    Serial.print(",");
    Serial.print(statTemp[5],1);
    Serial.print(",");
    Serial.print(statTemp[6],1);
    Serial.print(",");
    Serial.println(statTemp[7],1);
    i = 0; // Torno al primo elemento
  }

}

ogni 5 secondi stampa qualcosa del genere:

20.3,20.3,20.3,20.3,20.3,20.3,20.3,20.3

siccome la stampa dell'array vorrei stamparla anche prima del suo riempimento, allora ho provato a fare questo:

#include "cactus_io_SHT31.h"
cactus_io_SHT31 sht31;

float t;
float statTemp[8];
int i = 0;
unsigned long tempo = 0;


void setup() {

  Serial.begin(9600);

  if (!sht31.begin()) {
    Serial.println("Count not find sensor. Check wiring and I2C address");
    while (1) delay(1);
  }
}

void loop() {

  if ((millis() - tempo) > 5000) {
    t = sht31.getTemperature_C();
    statTemp[i++] = t;
  }
  if (i >= 8) {
    i = 0; // Torno al primo elemento
  }
  Serial.print(statTemp[0], 1);
  Serial.print(",");
  Serial.print(statTemp[1], 1);
  Serial.print(",");
  Serial.print(statTemp[2], 1);
  Serial.print(",");
  Serial.print(statTemp[3], 1);
  Serial.print(",");
  Serial.print(statTemp[4], 1);
  Serial.print(",");
  Serial.print(statTemp[5], 1);
  Serial.print(",");
  Serial.print(statTemp[6], 1);
  Serial.print(",");
  Serial.println(statTemp[7], 1);
}

la stampa è questa:

per i primi 5 secondi, ottengo giustamente sempre

0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0

poi

20.2,0.0,0.0,0.0,0.0,0.0,0.0,0.0
20.2,20.2,0.0,0.0,0.0,0.0,0.0,0.0
20.2,20.2,20.2,0.0,0.0,0.0,0.0,0.0
20.2,20.2,20.2,20.2,0.0,0.0,0.0,0.0
20.2,20.2,20.2,20.2,20.2,0.0,0.0,0.0
20.2,20.2,20.2,20.2,20.2,20.2,0.0,0.0
20.2,20.2,20.2,20.2,20.2,20.2,20.2,0.0
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2
20.2,20.2,20.2,20.2,20.2,20.2,20.2,20.2

e giusto? Perchè non aspetta 5 secondi prima di riempire il valore successivo dell'array?

Ti racconto il mio segreto per debuggare i problemi del genere:
Mi metto con carta e matita, seguo col dito il programma ed "eseguo" il programma sul block notes.
Quando mi capita di fare una operazione che non era quella che volevo fare: ho trovato il problema

solo per semplificarti un po la vita:

questo pezzo

  Serial.print(statTemp[0], 1);
  Serial.print(",");
  Serial.print(statTemp[1], 1);
  Serial.print(",");
  Serial.print(statTemp[2], 1);
  Serial.print(",");
  Serial.print(statTemp[3], 1);
  Serial.print(",");
  Serial.print(statTemp[4], 1);
  Serial.print(",");
  Serial.print(statTemp[5], 1);
  Serial.print(",");
  Serial.print(statTemp[6], 1);
  Serial.print(",");
  Serial.println(statTemp[7], 1);

lo puoi accorciare con

for (int x = 0 ; x<=6; x++) {
  Serial.print(statTemp[x], 1);
  Serial.print(",");
}
Serial.println(statTemp[7], 1);  //questo fuori dal loop se non vuoi che la stampa finisca con ","

p.s.
controlla la variabile tempo...

e gà la variabile tempo non l'azzeravo....adesso va, però non riesco a svuotare del tutto l'array nell'if relativo al raggiungimento delle 8 letture. Come si fa?

#include "cactus_io_SHT31.h"
cactus_io_SHT31 sht31;

float t;
float statTemp[8];
int i = 0;
unsigned long tempo = 0;


void setup() {

  Serial.begin(9600);

  if (!sht31.begin()) {
    Serial.println("Count not find sensor. Check wiring and I2C address");
    while (1) delay(1);
  }
}

void loop() {

  if ((millis() - tempo) > 5000) {
    t = sht31.getTemperature_C();
    statTemp[i++] = t;
    tempo = millis();
  }
  if (i > 8) {
    i = 0; // Torno al primo elemento
    statTemp[i] = 0; //svuoto l'array
  }
  Serial.print(statTemp[0], 1);
  Serial.print(",");
  Serial.print(statTemp[1], 1);
  Serial.print(",");
  Serial.print(statTemp[2], 1);
  Serial.print(",");
  Serial.print(statTemp[3], 1);
  Serial.print(",");
  Serial.print(statTemp[4], 1);
  Serial.print(",");
  Serial.print(statTemp[5], 1);
  Serial.print(",");
  Serial.print(statTemp[6], 1);
  Serial.print(",");
  Serial.println(statTemp[7], 1);
}

Grazie Patrick_M e Standardoil...

per resettare in un colpo solo tutta l'array usa memset()...dai un occhi QUI

In alternativa una banale
for (byte i=0;i<dimensione_array;i++){array*=0;}*
va benissimo (se non aggrada aggiungere librerie)

Silente:
In alternativa una banale

for (byte i=0;i<dimensione_array;i++){array[i]=0;}

va benissimo (se non aggrada aggiungere librerie)

così si capisce meglio :smiley:

Comunque tutta la parte in cui stampi i valori su seriale la puoi semplificare in:

for (byte i=0;i<7;i++)
{
//Gli array cominciano dall'elemento 0 e finiscono con l'elemento lunghezza-1.
//Stacci attento perché non viene fatto alcun controllo se stai scrivendo/leggendo dentro o fuori dall'array... quindi casino in agguato
Serial.print (nomedell'arraychemomisfugge[i], 1);
if (i+1<7)
{
Serial.print (F(", "));
}
else
{
Serial.println (F('.')):
}
}

non riesco a svuotare del tutto l'array

Non mi sembra necessario che tu debba portare a valore zero gli elementi dell'array.
Quando fai la lettura delle temperature i valori degli elementi saranno sostituiti con i nuovi valori letti.
Quindi secondo me non è necessario "svuotare" l'array...