ciclo for senza delay

Buongiorno a tutti.
Come al solito sono a richiedervi aiuto circa una funzione (distanza)che legge i dati da un sensore di e vorrei che mi salvasse il dato nello array ad intervalli regolari ma senza usare il delay.
Attualmente il codice è perfettamente funzionante ma vorrei fosse libero da vincoli temporali quando entra nel ciclo for
Come posso risolvere?
Grazie a tutti in anticipo

void distanza()
       {   
     for(int i = 0; i < arraysize; i++)
    {                                                    //array pointers go from 0 to 4
        read_sensor();
        rangevalue[i] = cm;
    
           Serial.print("i, value   ");
           Serial.print(i);
           Serial.print(" ,  ");
           Serial.print(rangevalue[i]);
           Serial.println();
      
      delay(3000);  //intervallo tra una lettura e l altra che vorrei rimuovere 
     }  
    
    Serial.print("valori non ordinati ");
    printArray(rangevalue, arraysize);
    Serial.println();
    isort(rangevalue, arraysize);
    Serial.print("valori ordinati ");
    printArray(rangevalue, arraysize);
    Serial.println();
     
  
   // now show the median range  
     int midpoint = arraysize/2;    //midpoint of the array is the medain value in a sorted array
       //note that for an array of 5, the midpoint is element 2, as the first element is element 0
      Serial.print("valore mediano ");
      Serial.print(rangevalue[midpoint]);
      Serial.println();  
     
    if 
      (rangevalue[midpoint] < 60 && rangevalue[midpoint] != 0  ) 
      {
      digitalWrite(led, HIGH);
      digitalWrite(RELE1, LOW);
      Serial.println("pompa accesa");
    }
    else if (rangevalue[midpoint] > 180)
    { digitalWrite(led, LOW);
     digitalWrite(RELE1, HIGH);
      Serial.println("pompa spenta");
    }
  }
   
  void read_sensor(){
    
    sensor1 = pulseIn(pwPin1, HIGH);
    cm = sensor1/58;
  }
  
  //*********************************************************************************
  // funzione per salvare i valori di lettura  in ordine crescente
  void isort(int *a, int n)//  *a is an array pointer function
  {
   for (int i = 1; i < n; ++i)
   {
     int j = a[i];
     int k;
     for (k = i - 1; (k >= 0) && (j < a[k]); k--)
     {
       a[k + 1] = a[k];
     }
     a[k + 1] = j;
   }
  }
  //***********************************************************************************
  //funzione per stampare i dati nell array
  void printArray(int *a, int n)
  {
   
   for (int i = 0; i < n; i++)
   {
     Serial.print(a[i], DEC);
     Serial.print(' ');
   }
   
   Serial.println();
  }

Devi cambiare la struttura del programma e rivederla con l'uso di millis(), per capire le basi con cui si usa millis() consiglio prima la lettura di QUESTO post esplicativo, dopo di che lo studio di come si usa la funzione millis(), prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... alla fine il tutto dovrebbe essere più chiaro :slight_smile:
In pratica non ha senso eliminare il delay e restare comunque intrappolati dentro al for in attesa che tuti i valori vengano letti, se vuoi tenere suddivise le funzioni di "acquisizione valori" e "stampa valori acquisiti" devi adattare il loop in modo da usare una macchina a stati finiti (cerca sul forum ci sono millemila discussioni a riguardo) in modo che sei in uno stato finché tutti i valori sono stati acquisiti (con i giusti intervalli di tempo) e solo allora passi allo stato di "stampa valori aquisiti" per poi tornare allo stato precedente

grazie per i preziosi consigli.

Saluti Fabio

Devi trasformare il for in un if: finché i<arraysize, ogni volta che millis() aumenta di 3000ms rispetto alla lettura precedente, legge il sensore.

void distanza
 {

 if ((millis() - iMillis1) > 30000)
    {  lettura=read_sensor();
       rangevalue[i++] = lettura;
     
       iMillis1 = millis();
 
      if(i>=4){
         // eseguo la stampa dei risultati
          Serial.print("i, value   ");
        Serial.print(i);
        Serial.print(" ,  ");
        Serial.print(rangevalue[i]);
        Serial.println();
         
         i=0; // Torno al primo elemento
     
    }
  
  }

ho provato qualcosa del genere ma mi ritorna un errore nella compilazione:

exit status 1
void value not ignored as it ought to be

Spero di aver centrato il consiglio di ragionare a stati......

O l'errore è nella println senza ninete da stampare o altrove nel programma.
Per il ragionamento a stati non è quello che hai implementato tu, funziona come vuoi (ovvero stampare solo alla fine delle 4 letture) ma non è una macchina a stati finiti, un piccolo esempio potrebbe essere:

void loop()
{
  switch(stato_programma)
  {
     case LETTURA:
       leggi_sensori();
     break;
     case STAMPA:
       stampa_valori();
       stato_programma = LETTURA;
     break;

  }
}

Mancano le parentesi in void distanza

Vero, non avevo notato, anche se provando a me da un errore differente in quel caso, bho???
Comunque ho visto che quando entri in stampa dei valori in realtà stampi un solo valore e tra l'altro stampi un valore successivo a tutti quelli letti, se l'array è definito più grande stampi un valore a caso, se l'array è definito preciso di 4 elementi stampi un valore ancora più a caso :slight_smile: li devi per forza fare un ciclo che usi un altro indice oppure se vuoi usare i devi azzerare prima e dopo aver stampato i valori

Il codice in origine è questo e funziona perfettamente anche se è bloccante quando entra nel for.

void distanza()
  {
  
    
      for (int i = 0; i < arraysize; i++)
      { //array pointers go from 0 to 4
        read_sensor();
  
        rangevalue[i] = cm;
  
        Serial.print("i, value   ");
        Serial.print(i);
        Serial.print(" ,  ");
        Serial.print(rangevalue[i]);
        Serial.println();
  
        delay(3000);  //wait between analog samples
      }

ho trovato un esempio nel forum che utilizza con successo la formula con millis ma non riesco ad implementarlo…

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
     }
}

non capisco dove sbaglio

Ps per Datman: nel codice originale le parentesi sono inserite
per Fabpolli : println serve per lasciare una riga vuota

Se nel codice originale ci sono le parentesi non è li l'errore come da me ipotizzato, posta tutto il codice altrimenti è impossibile aiutarti.
Il codice che hai scritto (tolti gli errori) funziona, tranne la parte di stampa dei valori ma li è semplice da sistemare.

Di seguito il codice completo funzionante ma con il ciclo for :

//lettura sensore di livello con mediana

# define RELEVASCA 3
const int pwPin1 = 6; //pin 6 su arduino pwm
long sensor1, cm;
//variables needed to store values
int arraysize = 5;  //quantity of values to find the median (sample size). Needs to be an odd number
int rangevalue[] = {0, 0, 0, 0, 0};    //declare an array to store the samples. not necessary to zero the array values here, it just makes the code clearer

unsigned long iMillis1 = 0;
unsigned long TempoON1 = 300000;//esegue le letture ogni 5 minuti

void setup() {

  pinMode(RELEVASCA, OUTPUT);
  digitalWrite(RELEVASCA, HIGH);
  printArray(rangevalue, arraysize);
  Serial.begin(9600);
  Serial.println( "Sensore Ultrasuoni: ");
}

void loop() {
  if ((millis() - iMillis1) > TempoON1)
  {
    distanza ();
    iMillis1 = millis();
  }
}
//end of loop

void distanza()
{
  for (int i = 0; i < arraysize; i++) //array pointers go from 0 to 4
  { 
    read_sensor();
   rangevalue[i] = cm;
   
   Serial.print("i, value   ");
    Serial.print(i);
    Serial.print(" ,  ");
    Serial.print(rangevalue[i]);
    Serial.println();

    delay(3000);  //wait between analog samples
  }

  Serial.print("valori non ordinati ");
  printArray(rangevalue, arraysize);
  Serial.println();
  isort(rangevalue, arraysize);
  Serial.print("valori ordinati ");
  printArray(rangevalue, arraysize);
  Serial.println();

  // now show the median range
  int midpoint = arraysize / 2;  //midpoint of the array is the medain value in a sorted array
  //note that for an array of 5, the midpoint is element 2, as the first element is element 0
  Serial.print("valore mediano ");
  Serial.print(rangevalue[midpoint]);
  Serial.println();

  if (rangevalue[midpoint] < 60 && rangevalue[midpoint] != 0  )
  {
    digitalWrite(RELEVASCA, LOW);
    Serial.println("pompa accesa");
  }
  else if (rangevalue[midpoint] > 180)
  {
    digitalWrite(RELEVASCA, HIGH);
    Serial.println("pompa spenta");
  }
  if (rangevalue[midpoint] < 180 && rangevalue[midpoint] > 60 )
  {
    Serial.println("range corretto");
  }
}

void read_sensor() {

  sensor1 = pulseIn(pwPin1, HIGH);
  cm = sensor1 / 58;
}

//*********************************************************************************
// funzione per salvare i valori di lettura  in ordine crescente
void isort(int *a, int n)
//  *a is an array pointer function
{
  for (int i = 1; i < n; ++i)
  {
    int j = a[i];
    int k;
    for (k = i - 1; (k >= 0) && (j < a[k]); k--)
    {
      a[k + 1] = a[k];
    }
    a[k + 1] = j;
  }
}
//***********************************************************************************
//funzione  per stampare i valori dell'array
void printArray(int *a, int n)
{
  for (int i = 0; i < n; i++)
  {
    Serial.print(a[i], DEC);
    Serial.print(' ');
  }
  Serial.println();
}

qui invece quello che vorrei utilizzare senza il ciclo for ma mi compila con errore:

{ lettura = read_sensor();

^

exit status 1
void value not ignored as it ought to be

lettura sensore livello senza ciclo for
# define RELEVASCA 3
const int pwPin1 = 6; //pin 6 su arduino pwm
long sensor1, cm;
int  lettura;
int i = 0;
//variables needed to store values
int arraysize = 5;  //quantity of values to find the median (sample size). Needs to be an odd number
int rangevalue[] = {0, 0, 0, 0, 0};    //declare an array to store the samples. not necessary to zero the array values here, it just makes the code clearer

unsigned long iMillis1 = 0;
unsigned long TempoON1 = 300000;

void setup() {

  pinMode(RELEVASCA, OUTPUT);
  digitalWrite(RELEVASCA, HIGH);
  printArray(rangevalue, arraysize);
  Serial.begin(9600);
  Serial.println( "Sensore Livello: ");
}

void loop() {

  distanza ();

}
//end of loop




void distanza()
{
  if ((millis() - iMillis1) > 30000)
  { lettura = read_sensor();
    rangevalue[i++] = lettura;
    rangevalue[i] = cm;
    iMillis1 = millis();

    if (i >= 4) {
      // eseguo la stampa dei risultati
      Serial.print("i, value   ");
      Serial.print(i);
      Serial.print(" ,  ");
      Serial.print(rangevalue[i]);
      Serial.println();

      i = 0; // Torno al primo elemento

    }

    Serial.print("valori non ordinati ");
    printArray(rangevalue, arraysize);
    Serial.println();
    isort(rangevalue, arraysize);
    Serial.print("valori ordinati ");
    printArray(rangevalue, arraysize);
    Serial.println();


    // now show the median range
    int midpoint = arraysize / 2;  //midpoint of the array is the medain value in a sorted array
    //note that for an array of 5, the midpoint is element 2, as the first element is element 0
    Serial.print("valore mediano ");
    Serial.print(rangevalue[midpoint]);
    Serial.println();

    if
    (rangevalue[midpoint] < 60 && rangevalue[midpoint] != 0  )
    {
      digitalWrite(RELEVASCA, LOW);
      Serial.println("pompa accesa");
    }
    else if (rangevalue[midpoint] > 180)
    {
      digitalWrite(RELEVASCA, HIGH);
      Serial.println("pompa spenta");
    }
    if (rangevalue[midpoint] < 180 && rangevalue[midpoint] > 60 )
    {
      Serial.println("range corretto");
    }
  }

}

void read_sensor() {

  sensor1 = pulseIn(pwPin1, HIGH);
  cm = sensor1 / 58;
}

//*********************************************************************************
// funzione per salvare i valori di lettura  in ordine crescente
void isort(int *a, int n)
//  *a is an array pointer function
{
  for (int i = 1; i < n; ++i)
  {
    int j = a[i];
    int k;
    for (k = i - 1; (k >= 0) && (j < a[k]); k--)
    {
      a[k + 1] = a[k];
    }
    a[k + 1] = j;
  }
}
//***********************************************************************************
//function to print array values
void printArray(int *a, int n)
{
  for (int i = 0; i < n; i++)
  {
    Serial.print(a[i], DEC);
    Serial.print(' ');
  }
  Serial.println();
}

Non riesco a capire dove sbaglio
grazie

E te credo che non funziona, la funzione read_sensor() è di tipo void ovvero non restituisce nessun dato tu vorresti assegnare un valore ritornato dalla funzione ad una varibile di tipo int e chiaro che il compilatore s'inalbera, a questo punto o usi cm che è già globale o cambi la funzione in modo che essa ritorni un valore di tipo int

Ovvero nel primo tuo codice hai tutte variabili globali, che "sporchi" nella funzione
Se invece la funzione deve essere una scatola chiusa allora:

...
lettura=read_sensor(pwPin1);
...
long read_sensor(byte p_Pin) 
{ long xsensor,xcm;
  xsensor = pulseIn(p_Pin, HIGH);
  xcm = xsensor / 58;
  return xcm;
}

P.S const int pwPin1 = 6; metti const byte pwPin1 = 6;

Scusate la mia assenza ma ho passato una intera domenica a combattere con il simulatore Tinkercad che mi ha deluso profondamente: per semplificare la cosa e testare il codice ho simulato la lettura analogica di un potenziometro inserendo il codice seguente; bene dopo migliaia di prove non ottenevo dal monitor seriale le letture volute. Non ancora ho capito il perchè.

Alla fine ho smontato l’arduino e il sensore da dove era installato e tutto funziona perfettamente!!! Peccato perchè un simulatore sarebbe stato uno strumento veramente valido.

Ritengo di postare questo codice affinchè possa servire d’aiuto, dato che ho avuto difficoltà a trovare esempi funzionanti a riguardo.

Ogni spunto per il miglioramento è sempre ben accetto.

//
//Lettura di un valore analogico, ordinamento dei valori, calcolo della mediana
//con valori salvati in un array, senza utilizzare il ciclo for (bloccante) ma con millis
//In questo modo si possono effettuare letture ad intervalli lunghi senza bloccare 
//il codice nell'intervallo tra le misurazioni. 

int anPin = 0;
int t; //  VARIABILI GLOBALI
int z=0; 
unsigned long tempo=0;  
//variables needed to store values
int arraysize = 5;  //quantity of values to find the median (sample size). Needs to be an odd number
int rangevalue[] = {0, 0, 0, 0, 0};    //declare an array to store the samples. not necessary to zero the array values here, it just makes the code clearer
//*********************************************************************************************
void setup()
{

 //This opens up a serial connection to shoot the results back to the PC console
 Serial.begin(9600);
 printArray(rangevalue, arraysize);  
 delay(1000);        //wait a while to open serial monitor window

}
//********************************************************************************
void loop()
{

 pinMode(anPin, INPUT);

  if ((millis() - tempo) > (1000)) {
     
     t=analogRead(anPin);
          Serial.print(t);
     Serial.print(" ");
    
          rangevalue[z++] =t;
     tempo = millis();

     if(z>=5){               
         // eseguo la stampa dei risultati
   Serial.println();
   Serial.println();
    Serial.print("unsorted ");
  printArray(rangevalue, arraysize);
  Serial.println();
  isort(rangevalue, arraysize);
  Serial.print("sorted ");
  printArray(rangevalue, arraysize);
  Serial.println();
   // now show the median range  
   int midpoint = arraysize/2;    //midpoint of the array is the medain value in a sorted array
     //note that for an array of 5, the midpoint is element 2, as the first element is element 0
    Serial.print("median range value ");
    Serial.print(rangevalue[midpoint]);
    Serial.println();  
    Serial.println();  
    z=0;} // Torno al primo elemento      
 }
 }   //end of loop

//***********************************************************************************
//function to print array values
void printArray(int *a, int n)
{ 
 for (int i = 0; i < n; i++)
 {
   Serial.print(a[i], DEC);
   Serial.print(' ');
 }
 Serial.println();
}
//***********************************************************************************
//function to print array values
void isort(int *a, int n)
{
 for (int i = 1; i < n; ++i)
 {
   int j = a[i];
   int k;
   for (k = i - 1; (k >= 0) && (j < a[k]); k--)
   {
     a[k + 1] = a[k];
   }
   a[k + 1] = j;
 }
}

Igor e fabpolli grazie per i preziosi consigli, ne farò tesoro.