Strutturare il codice in blocchi funzionali

Salve ragazzi, per un lavoro di tesi che sto realizzando, mi trovo davanti ad un problema. Devo misurare la velocità di due rotori, il primo funziona con dei reed switch ed il secondo con un contatore laser.

Il codice del primo rotore è essenzialmente questo e misura la velocità del vento:

const int reedPin = 3; // pin assegnato al contatto reed


int Statoreed = 0; // variabile per la lettura del contatto
int Statoreed_old = 0; // variabile per evitare doppio conteggio

int Conteggio = 0;// variabile che contiene il conteggio delle pulsazioni
unsigned long int TempoStart = 0; // memorizza i  millisecondi dalla
//prima pulsazione conteggiata

unsigned long int Tempo = 0; // per conteggiare il tempo trascorso dalla prma pulsazione

unsigned long int TempoMax = 2000;// numero di millisecondi (2 seondi)
//per azzerare il conteggio e calcolare la Velocità
// così non si conteggiano brevi folate di vento

void setup() {
  Serial.begin(9600);   //attiva la porta seriale
  pinMode(reedPin, INPUT);// mette in ascolto del reed il pin 2

}

//--------------------------------------------
// loop principale
//--------------------------------------------

void loop()
{
  Statoreed = digitalRead(reedPin); // legge il contatto reed

  if (Statoreed != Statoreed_old) // si verifica se è cambiato
  {
    Statoreed_old = Statoreed;   // se SI si aggiorna lo stato

    if (Statoreed == HIGH)  // si controlla SE è alto ( passaggio magnete)
    {
      if (Conteggio == 0) {
        TempoStart =  millis(); // se E' il primo passaggio
      }
      // si memorizza il tempo di partenza

      Conteggio = Conteggio + 1; // si aggiorna il contatore

      Tempo = ( millis() - TempoStart); // si conteggia il tempo trascorso dallo start conteggio


      if (Tempo >=  TempoMax)   // se il tempo trascorso è maggiore o uguale al tempo impostato
        // si eseguono i calcoli e la stampa della velocità
      {
        
        float deltaTempo = ( Tempo / 1000.0); // si trasforma in secondi

        float pulse =  Conteggio / deltaTempo ;

        float Metris = ( pulse * 0.765 )  + 0.35;
 
        //--------------------------------------
        // stampa i valori sul monitor
        //---------------------------------------
        Serial.print(" m/s = ");
        Serial.print(Metris);
        Serial.print(" pulse = ");
        Serial.println(pulse);

        Conteggio = 0; // azzeriamo il conteggio per nuova lettura
        delay(1000);// attesa per altra lettura
      }
    }
  }

Il secondo codice, conta la velocità di rotazione della turbina:

int half_revolutions = 0;
int rpm = 0;
unsigned long lastmillis = 0;
void setup() {
  Serial.begin(9600);
  attachInterrupt(0, rpm_fan, FALLING);
}
void loop() {
  if (millis() - lastmillis == 1000) { //Uptade every one second, this will be equal to reading frecuency (Hz).
    detachInterrupt(0);//Disable interrupt when calculating
    rpm = half_revolutions * 20; // Convert frecuency to RPM, note: this works for one interruption per full rotation. For tree interrups per full rotation use half_revolutions * 20.
    Serial.print("RPM =\t"); //print the word "RPM" and tab.
    Serial.print(rpm); // print the rpm value.
    Serial.print("\t Hz=\t"); //print the word "Hz".
    Serial.println(half_revolutions); //print revolutions per second or Hz. And print new line or enter.
    half_revolutions = 0; // Restart the RPM counter
    lastmillis = millis(); // Uptade lasmillis
    attachInterrupt(0, rpm_fan, FALLING); //enable interrupt
  }
}
// this code will be executed every time the interrupt 0 (pin2) gets low.
void rpm_fan() {
  half_revolutions++;
}

Utilizzando una guida che ho acquistato, e che consiglio veramente a tutti per la sua completezza, realizzata da Margolis :"Arduino CookBook" spiega come strutturare il codice in blocchi funzionali, ma quando vado a mettere insieme il tutto riesco solo a visualizzare la velocità del vento ma non quella della turbina.

Qualcuno avrebbe qualche tips da darmi?!

Ciao, verificando nei post di presentazione, NON riesco a trovare il tuo :confused: ... pertanto, nel rispetto del regolamento, ti chiedo cortesemente di presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con attenzione il su citato REGOLAMENTO (... che magari, da quando ti sei iscritto, è cambiato) ... Grazie :slight_smile:

Guglielmo

Buonasera Guglielmo ...ho gia scritto una volta il mio post di presentazione, provvedo subito comunque. Non ci metterò troppo :wink:

Fluvius:
Buonasera Guglielmo ...ho gia scritto una volta il mio post di presentazione, provvedo subito comunque. Non ci metterò troppo :wink:

Grazie :slight_smile: ... non so che fine abbia fatto il vecchio ... ::slight_smile:

Guglielmo

Ne ho scritto uno nuovo e più aggiornato a scanso di equivoci.

innanzi tutto lavariabile half_revolution essendo all'interno di una iSR deve essere dichiarata volatile

volatile int half_revolutions = 0;

Altrimenti non funziona
e per il discorso di far lavorare insieme i due sketch, dovresti farci vedere come li hai combinati

Allora, ho apportato la modifica proposta da Brunello e vi posto lo sketch come ho tentato di realizzarlo, ogni critica è ben accetta ...lo sketch che vedete qui è in forma ridotta; altri blocchi funzionali, che misurano potenza generata, direzione del vento e carica della batteria che alimenta lo Yún sono stati omessi; premetto che come diceva il mio prof di informatica:"quando un programma è scritto in modo poco elegante funzionerà in modo disastroso.
Mi rendo conto che ho delle lacune e mi scuso se potranno sembrare eresie.
A voi l'ardua sentenza:

// Laser Instance --------------------------------
// read RPM
volatile int half_revolutions = 0;
int rpm = 0;
unsigned long lastmillis = 0;

//Anemometer Instance ----------------------------

const int reedPin = 3; // pin assegnato al contatto reed

int Statoreed = 0; // variabile per la lettura del contatto
int Statoreed_old = 0; // variabile per evitare doppio conteggio

int Conteggio = 0;// variabile che contiene il conteggio delle pulsazioni
unsigned long int TempoStart = 0; // memorizza i  millisecondi dalla
//prima pulsazione conteggiata

unsigned long int Tempo = 0; // per conteggiare il tempo trascorso dalla prma pulsazione

unsigned long int TempoMax = 2000;// numero di millisecondi (2 seondi)
//per azzerare il conteggio e calcolare la Velocità
// così non si conteggiano brevi folate di vento

void setup()
    {
    Serial.begin(9600);   //attiva la porta seriale
    
    attachInterrupt(0, rpm_fan, FALLING);//interrupt 0 corrisppnde al pin 2

    pinMode(reedPin, INPUT);// mette in ascolto del reed il pin 3
    }

void lasersensor()
{
  if (millis() - lastmillis == 1000) { //Uptade every one second, this will be equal to reading frecuency (Hz).
    detachInterrupt(0);//Disable interrupt when calculating
    rpm = half_revolutions * 20; // Convert frecuency to RPM, note: this works for one interruption per full rotation. For tree interrups per full rotation use half_revolutions * 20.
    Serial.print("RPM =\t"); //print the word "RPM" and tab.
    Serial.print(rpm); // print the rpm value.
    Serial.print("\t Hz=\t"); //print the word "Hz".
    Serial.println(half_revolutions); //print revolutions per second or Hz. And print new line or enter.
    half_revolutions = 0; // Restart the RPM counter
    lastmillis = millis(); // Uptade lasmillis
    attachInterrupt(0, rpm_fan, FALLING); //enable interrupt
  }
}
void rpm_fan() {
  half_revolutions++;
}
    
void loop() 

{ Statoreed = digitalRead(reedPin); // legge il contatto reed

  if (Statoreed != Statoreed_old) // si verifica se è cambiato
  {
    Statoreed_old = Statoreed;   // se SI si aggiorna lo stato
  
   if (Statoreed == HIGH)  // si controlla SE è alto ( passaggio magnete)
    {
      if (Conteggio == 0){ TempoStart =  millis();} // se E' il primo passaggio
                                                 // si memorizza il tempo di partenza
    
      Conteggio = Conteggio + 1; // si aggiorna il contatore      
    
      Tempo = ( millis() - TempoStart); // si conteggia il tempo trascorso dallo start conteggio
    
          
           if (Tempo >=  TempoMax)   // se il tempo trascorso è maggiore o uguale al tempo impostato
                                     // si eseguono i calcoli e la stampa della velocità
          {
         
           float deltaTempo = ( Tempo / 1000.0); // si trasforma in secondi

           float pulse =  Conteggio / deltaTempo ;

           float Metris = ( pulse * 0.765 )  + 0.35;
         
           //--------------------------------------
           // stampa i valori sul monitor
           //---------------------------------------
           Serial.print("Speed m/s = ");
           Serial.println(Metris);
     
           Conteggio = 0; // azzeriamo il conteggio per nuova lettura
           Statoreed = 0;
           Statoreed_old =1;
           Tempo = 0;
           lasersensor();
           delay(2000);// attesa per altra lettura 
                   
          }
    }
  }
}

intanto vedo un paio di cose "strane"
delay(2000);// attesa per altra lettura
Va' tolto e usato un millis() come fai sulla turbina

e questo passaggio da' sicuramente dei problemi
if (millis() - lastmillis == 1000) { //Uptade every one second, .....

Perche' combinato con il precedente delay() sicuramente non viene mai eseguito.
correggilo così

if (millis() - lastmillis > 1000) { //Uptade every one second,

Buondì ...oggi andrò in laboratorio e proverò le modifiche al codice che mi ha suggerito Brunello.

Il codice rivisto e corretto è questo, vediamo cosa succede

void lasersensor()
{
  if (millis() - lastmillis > 1000) { //Uptade every one second, this will be equal to reading frecuency (Hz).
    detachInterrupt(0);//Disable interrupt when calculating
    rpm = half_revolutions * 20; // Convert frecuency to RPM, note: this works for one interruption per full rotation. For tree interrups per full rotation use half_revolutions * 20.
    Serial.print("RPM =\t"); //print the word "RPM" and tab.
    Serial.print(rpm); // print the rpm value.
    Serial.print("\t Hz=\t"); //print the word "Hz".
    Serial.println(half_revolutions); //print revolutions per second or Hz. And print new line or enter.
    half_revolutions = 0; // Restart the RPM counter
    lastmillis = millis(); // Uptade lasmillis
    attachInterrupt(0, rpm_fan, FALLING); //enable interrupt
  }
}
void rpm_fan() {
  half_revolutions++;
}

void loop()

{ Statoreed = digitalRead(reedPin); // legge il contatto reed

  if (Statoreed != Statoreed_old) // si verifica se è cambiato
  {
    Statoreed_old = Statoreed;   // se SI si aggiorna lo stato

    if (Statoreed == HIGH)  // si controlla SE è alto ( passaggio magnete)
    {
      if (Conteggio == 0) {
        TempoStart =  millis(); // se E' il primo passaggio
      }
      // si memorizza il tempo di partenza

      Conteggio = Conteggio + 1; // si aggiorna il contatore

      Tempo = ( millis() - TempoStart); // si conteggia il tempo trascorso dallo start conteggio


      if (Tempo >=  TempoMax)   // se il tempo trascorso è maggiore o uguale al tempo impostato
        // si eseguono i calcoli e la stampa della velocità
      {

        float deltaTempo = ( Tempo / 1000.0); // si trasforma in secondi

        float pulse =  Conteggio / deltaTempo ;

        float Metris = ( pulse * 0.765 )  + 0.35;

        //--------------------------------------
        // stampa i valori sul monitor
        //---------------------------------------
        Serial.print("Speed m/s = ");
        Serial.println(Metris);

        Conteggio = 0; // azzeriamo il conteggio per nuova lettura
        Statoreed = 0;
        Statoreed_old = 1;
        Tempo = 0;
        lasersensor();


      }
    }
  }
}

Grazie Brunello,
Funziona tutto perfettamente.

Adesso provo a caricare tutto lo sketch completo e vedere cosa mi dice.

Dopo diversi tentativi ho risolto il mio problema ...la soluzione è sempre l'algoritmo più semplice.

Premetto che la soluzione di Brunello, che ringrazio per il tentativo, non era fattibile perché: se devo campionare un evento, il tempo deve essere una costante, non può essere minore o maggiore di qualcosa.

La soluzione l'ho trovata grazie al comando attachInterrupt() .

Il processo logico è: Abilita il conteggio => aspetta un tempo definito => disabilita il conteggio

L'attesa del tempo può essere tranquillamente eseguita grazie ad un delay(1000); il quale non inibisce la funzione di counter del comando.

In conclusione utilizzando un sensore laser ed un disco riflettente sono riuscito a misurare la velocità di rotazione di una turbina eolica.

Grazie a tutti per i preziosi consigli

L'attesa del tempo può essere tranquillamente eseguita grazie ad un delay(1000); il quale non inibisce la funzione di counter del comando.

ok, però il counter interferisce sul delay() , visto che quando sei nella ISR la funzione millis() e quindi anche il delay() non si incrementa.
Sono sofismi, ma mettere
delay(1000) oppure if (millis() - lastmillis >= 1000) non cambia molto, a parte che il primo è bloccante

Il delay non è bloccante con attachInterrupt(), perché utilizzando un isr ti consente di avere contemporaneamente un incremento ed un tempo di campionamento ben preciso.

void lasersensor()
{
  pulse = 0;
  attachInterrupt(1, contatore, FALLING);
  delay(1000);
  detachInterrupt(1);
  Serial.print(pulse);
}
void contatore()
{
  pulse++;
}

Ho provato con un oscilloscopio è funziona alla perfezione

Io mi riferivo al fatto che il delay() era bloccante per qualsiasi altra cosa all'interno dello sketch ( la ISR agisce comunque ).