anemomentro e stazione meteo

ciao, non sono riuscito a trovare un esempio di anemometro che faccia al caso mio, quindi prendendo un po di spunti ho provato a farmi un mio codice ma non funziona un granchè :confused:

secondo me dovrebbe fare così:
conta quanti impulsi riceve in 5 secondi, divide per il tempo e moltiplica x 2.4 (un valore che vedo nelle info degli anemometri), il valore che riceve me lo stampa.
solo che rilevo valori sballati... anche a vento costante varia di parecchio il risultato.
può essere colpa del delay? avevo provato a mettere un if con millis ma non funziona.

non ho messo l'interrupt nel setup perchè devo fare altro anche in caso di vento tipo integrarlo con sensore di luminosità che già ho che fà una lettura al minuto.
pensavo di fare così:
ogni minuto legge la lumiosità, e ogni 20 secondi mi misura il vento facendo il conto degli impulsi che riceve in 5 secondi.

ecco il codice che ho fatto:

#define anemometro 2
const int tempomisura = 5;      //secondi di misura
int imp_vento = 0;
float vento = 0.0;

void setup()
{
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
}

void loop()
{

  misurazione();

  Serial.print(vento);       // Km/h
  Serial.print(" km/h - ");
  Serial.print(vento / 3.6); // m/s
  Serial.println(" m/s");

}


void misurazione() {
  imp_vento = 0;
  attachInterrupt(digitalPinToInterrupt(anemometro), controllovento, RISING);
  delay (1000 * tempomisura);
  detachInterrupt(anemometro);
  vento = (float)imp_vento / (float)tempomisura * 2.4;
}


void controllovento() {
  imp_vento ++;
}

Come prima cosa la variabile imp_vento deve essere dichiarata volatile in quanto la modifichi sia dentro l’ISR sia nel resto del codice (in ogni caso le variabili usate nelle ISR è andrebbero sempre dichiarate volatile)
Poi se vuoi mantenere il codice con millis aggancia l’interrupt nel setup, prima di azzerare la variabile che contiene il valore di millis nell’istante in cui inizia la misurazione azzeri anche la variabile, trascorso il tempo fai i calcoli che devi e torni ad azzerare la variabile e memorizzare il nuovo valore di millis.
Visto che hai già un implementazione con millis prova ad adeguarla al suggerimento se vuoi e postare il codice se non funziona

ciao,

se devi verificare degli impulsi in ingresso sicuramente il delay() è da evitare; dovresti usare la funzione millis() per calcolarti il tempo...però quello che sicuramente devi fare, almeno io la vedo così, è determinare delle ISR per impulsi dell'anemometro e dell'altro strumento che hai.
per anemometro...ti crei delle varibili "volatile" dove salvi numero impulsi ed una array dove ti salvi il valore del tempo trascorso tra impulso precedente e quello attuale..quindi alla fine, tra un impulso e l'altro, potresti stamparti la media del tempo nell'array (media della portata) e verificando il tempo più breve avere il picco del flusso d'aria.

spero di essermi spiegato.

grazie ad entrambi per i suggerimenti!
ho provato a riscrivere il codice integrandolo già nel codice del sensore luce (sono separati da una linea commentata)
ho cercato di seguire i vostri suggerimenti applicati alla mia poca conoscenza… scusatemi se ho fatto obbrobri :slight_smile:
ho messo un po di serialprint per capire come si comporta.
sembra che si muova bene ma non si incrementa la variabile imp_vento nonostante il numero 2 nella seriale lo vedo
p.s. il discorso del picco del vento non mi interessa… mi basta un valore abbastanza affidabile per decidere se chiudere o no le finestre

#include <SoftwareSerial.h>
#define RISCRX 6 //pin ricevitore seriale 
#define RISCTX 7 //pin trasmettitore seriale
#define anemometro 2 //pin anemometro
int valori[10];
int vdiviso = 0;
unsigned long intervalloluce = 60000;
unsigned long intervalloanemometro = 6000;
unsigned long previousMillisluce = 0;
unsigned long previousMillisanemometro = 0;
unsigned long currentMillis = 0;
int somma = 0;
int i = 0;
int media = 0;
const int tempomisura = 5000;
volatile int imp_vento = 0;
float vento = 0.0;


SoftwareSerial Serialint(RISCRX, RISCTX); //seriale secondaria

void setup() {

  pinMode(RISCTX, OUTPUT);
  pinMode(RISCRX, INPUT);
  pinMode(2, INPUT_PULLUP);
  Serial.begin(9600);
  Serialint.begin (9600);
  attachInterrupt(anemometro, controllovento, RISING);

}

void loop() {
  currentMillis = millis();

  //-----------------sensore luminosità-------------

  if (currentMillis - previousMillisluce >= intervalloluce) {
    previousMillisluce = currentMillis;
    valori[i] = analogRead(A0);
    Serial.print("valore =");
    Serial.println(valori[i]);
    i++;
    if (i > 9) {
      somma = 0;
      i = 0;
      for (int i = 0; i < 10; i++) {
        somma += valori[i];
        Serial.print("somma =");
        Serial.println(somma);
      }
      media = somma / 10;
      Serial.print("media =");
      Serial.println(media);
      vdiviso = (media / 4);
      Serial.print("dimezzato =");
      Serial.println(vdiviso);
      Serialint.write(vdiviso);
      i = 0;
    }
  }
  //-------------- sensore vento --------------------

  if ((currentMillis - previousMillisanemometro) >= intervalloanemometro) {
    imp_vento = 0;
    Serial.println("1");
    attachInterrupt(digitalPinToInterrupt(anemometro), controllovento, RISING);
    Serial.println("3");
    if (millis() > (previousMillisanemometro + tempomisura)) {
      Serial.println("4");
      Serial.println(imp_vento);
      vento = (float)imp_vento / (float)tempomisura * 2.4;
      Serial.print(vento);       // Km/h
      Serial.print(" km/h - ");
      previousMillisanemometro = currentMillis;
      detachInterrupt(anemometro);
      Serial.println("5");
    }
  }
}

void controllovento() {
  imp_vento ++;
  Serial.println("2");
}

Così come è scritto non può funzionare, detto che non serve il doppio controlli di millis ma se ragioni sul comportamento della procedura hai che, ammettendo che previousMillisanemometro valga zero all'avvio dopo che sono trascorsi 6 secondi, entri nell'if e azzeri la variabile poi controlli se sono trascorsi più di cinque secondi e fai i conti.
Lo schema che devi seguire è:
Nel setup attacchi l'interrupt
Nel loop
Controlli se non sono trascorsi cinque seocndi dall'ultima volta, se no non fai nulla, se si entri e fai i calcoli della media con il valore della variabile incrementata dall'anemometro come primissima cosa, dopodiché la azzeri e assegni a previousMillisanemometro il valore di millis attuale e poi fai ciò che vuoi (stampa su seriale, gestioni varie ecc.)
Ma in nessun caso devi sganciare e riagganciare l'interrupt non ce ne bisogno, se proprio proprio vuoi ottenere la certezza che nel mentre che stai facendo il conto della media l'interrupt non posso incrementar ulteriormente la variabile puoi decidere se disattivare gli interrupt e poi riattivarli (ma te lo sconsiglio, a te non serve in questo caso e per giocare con certe cose occorre studiarle bene e avere una certa esperienza quindi a te impiegare del tempo in tal senso) oppure copiare il valore della variabile in una d'appoggio in modo che sei certo che i conteggi di media verranno effettuati con il valore rilevato nei cinque secondi, assegnare un valore è un operazione atomica che l'interrupt non riesce a sospendere.
Se anche mentre farai i calcoli ecc. l'anemometro incrementerà la variabile poco importa tanto alla fine prima di uscire dall'if la azzeri e riassegni anche previousMillisanemometro e quindi sei a posto.

rieccomi, allora sono andato avanti a step.
prima ho fatto come mi hai detto tu e mi misurava correttamente ogni 6 secondi, ma non era esattamente quello che volevo io, quindi ho aggiunto un if e una variabile di controllo così ogni 6 secondi mi parte il test che dura 4 secondi. poi i tempi nella realtà saranno diversi, ma l’importante è la logica.

mi sono anche permesso di aggiungere una specie di debounce dentro alla void dell’interrupt… ho sbagliato??

quindi se non ho capito male l’interrupt lavora sempre e arduino continua a fare il suo… un po come millis. giusto?

#include <SoftwareSerial.h>
#define RISCRX 6 //pin ricevitore seriale 
#define RISCTX 7 //pin trasmettitore seriale
#define anemometro 2 //pin anemometro
int valori[10];
int vdiviso = 0;
unsigned long intervalloluce = 60000; //millis
unsigned long intervalloanemometro = 6000; //millis
unsigned long previousMillisluce = 0;
unsigned long previousMillisanemometro = 0;
unsigned long startmisuravento = 0;
unsigned long currentMillis = 0;
int somma = 0;
int i = 0;
int media = 0;
const int tempomisura = 4; //in secondi
volatile unsigned long imp_vento = 0;
volatile unsigned long last_micros;
float vento = 0.0;
long debouncing_time = 8; //in millis
int controllo = 0;


SoftwareSerial Serialint(RISCRX, RISCTX); //seriale secondaria

void setup() {

  pinMode(RISCTX, OUTPUT);
  pinMode(RISCRX, INPUT);
  pinMode(2, INPUT_PULLUP);
  Serial.begin(9600);
  Serialint.begin (9600);
  attachInterrupt(digitalPinToInterrupt(anemometro), controllovento, RISING);

}

void loop() {
  currentMillis = millis();

  //-----------------sensore luminosità-------------

  if (currentMillis - previousMillisluce >= intervalloluce) {
    previousMillisluce = currentMillis;
    valori[i] = analogRead(A0);
    Serial.print("valore =");
    Serial.println(valori[i]);
    i++;
    if (i > 9) {
      somma = 0;
      i = 0;
      for (int i = 0; i < 10; i++) {
        somma += valori[i];
        Serial.print("somma =");
        Serial.println(somma);
      }
      media = somma / 10;
      Serial.print("media =");
      Serial.println(media);
      vdiviso = (media / 4);
      Serial.print("dimezzato =");
      Serial.println(vdiviso);
      Serialint.write(vdiviso);
      i = 0;
    }
  }
  //-------------- sensore vento --------------------

  //-----intervallo tra lettura
  if (((currentMillis - previousMillisanemometro) >= intervalloanemometro) and (controllo == 0)) {
    imp_vento = 0;
    controllo = 1;
    Serial.println("start");
    startmisuravento = currentMillis;
  }
  //-----tempo lettura
  if (((currentMillis - startmisuravento) >= (tempomisura * 1000)) and (controllo == 1)) {
    Serial.println("inizio");
    Serial.println(imp_vento);
    vento = (float)imp_vento / (float)tempomisura * 2.4;
    Serial.print(vento);       // Km/h
    Serial.println(" km/h - ");
    previousMillisanemometro = millis() ;
    imp_vento = 0;
    controllo = 0;
    Serial.println("fine");
  }
}

void controllovento()
{
  if ((long)(micros() - last_micros) >= debouncing_time * 1000) {
    imp_vento++;
    Serial.println("2");
    last_micros = micros();
  }
}

Errato …
… le ISR DEVONO essere le più corte e veloci possibili, NON devono introdurre ritardi e NON devono usare altre funzioni che usano gli interrupt come … le funzionio della seriale (Serial), quindi … togli tutta quella roba dalla ISR ed eventualmente, se proprio occorre, nella ISR alzi semplicemente una flag e poi la controlli nel loop() e se attiva fai quello che dovevi fare.

Il debouncing di pulsanti/contatti che attivano ISR va fatto via hardware, NON via software.

Guglielmo

Io piloterei l'interrupt con il sensore; nella funzione dall'interrupt copierei millis() in una variabile volatile e poi, fuori, farei il conto in base ai millisecondi trascorsi tra un impulso e l'altro. Credo che si ottenga una risoluzione molto maggiore, senza salti tra bassi valori.

Dubbio: si può copiare miliis() dall'interno della ISR? Se no, bisogna prima copiare millis().

Datman:
Dubbio: si può copiare miliis() dall'interno della ISR? Se no, bisogna prima copiare millis().

SI, si può copiare ... oltretutto è fermo e non si incrementa :smiley:

Guglielmo

Si si, I serialprint li toglierò! Sono lì solo per capire se mi funziona tutto giusto!

Quindi voi cambiereste la logica?
Invece di contare gli impulsi in tot tempo controllereste il tempo tra un impulso e un altro?

A me non serve una cosa di precisione, mi serve un qualcosa che tenga filtrato i vari picchi, per quello pensavo ad una media in tot secondi.

Altrimenti al primo picco (e magari anche unico) mi si chiuderebbero le finestre.

Durava sei secondi perché hai definito l'intervallo a 6000, e poi ti ostini ad azzerare la variabile imp_vento e ad usare due variabili distinte in modo quantomeno bizzarro.
A questo punto o segui l'idea di Datman oppure prosegui sulla tua strada ma usando un solo if per verificare con millis se sono trascorsi cinque secondi e, al suo interno, fare i conti per la media ecc. azzerare la variabile e prendere l'attuale valore di millis per fare il successivo controllo dopo cinque secondi.
Per il discorso folata improvvisa puoi decidere di chiudere tutto se si sono verificati almeno N eventi consecutivi quindi se arriva una folata e poi il vento cessa non chiudi nulla se il vento è sostenuto per tutte le N misurazioni allora chiudi tutto

Ciao! Ho sistemato il codice ed ora funziona bene. Grazie

Ora vorrei migliorare la lettura della fotoresistenza.
Ho la fotoresistenza standard da “kit Arduino” e l’ho collegata con una resistenza da 10k.
Leggendo vari esempi ho capito che teoricamente andrebbe una resistenza di pari valore, ma il mio intento è riconoscere quando c’è sole pieno e quando è nuvoloso. Non mi interessa sapere quando è buio…
Variando il valore della resistenza posso “alzare il punto zero” in modo di aver più “risoluzione” nella zona che mi interessa?
O c’è qualche altra soluzione?

Ciao, mi ha funzionato tutto perfettamente per una settimana, ora non funziona più la fotoresistenza.
L'avevo messa provvisoriamente all'esterno ed ha preso 2 giorni di pioggia. Può essere saltata per quel motivo?
Gli ho misurato la resistenza e segna 200ohm e Arduino mi legge intorno ai 950... Ogni mezz'ora sale di qualche unità.

P. S. Arduino è all'interno

Ovviamente non è fatta per essere esposta alla pioggia... :frowning:
Prova a farla asciugare al sole...

Ci proverò. Non mi ero preoccupato più di tanto perché è ricoperta di una resina trasparente,pensavo la rendesse impermeabile

ciao, sto notando dei problemi con la parte anemometro.
praticamente 2/3 volte al giorno (apparentemente senza logica) mi rileva una velocità assurda anche in assenza di vento.

così come è impostato l’ho visto arrivare al massimo a 30 con tanto vento, ma a volte mi rileva velocità di 109 , 84… numeri cosi, per poi tornare a 0.

l’unica cosa che mi viene in mente è che potrebbe esserci qualche problema con la funzione millis, ma mi sembra tutto regolare… potete buttarci un occhio voi che siete molto più esperti di me?

grazie

#include <SoftwareSerial.h>
#define RISCRX 6 //pin ricevitore seriale 
#define RISCTX 7 //pin trasmettitore seriale
#define txvento 8//pin seriale vento
#define rxvento 9 //pin seriale vento
#define anemometro 2 //pin anemometro
#define luce A2 //pin sensore luminosità
int valori[10];
int vdiviso = 0;
unsigned long intervalloluce = 60000; //millisecondi
unsigned long intervalloanemometro = 6; //secondi
unsigned long invioventostandard = 120000; //millisecondi
unsigned long invioventomosso = 60000; //millisecondi
unsigned long invioventopreallarme = 15000; //millisecondi
unsigned long invioventoallarme = 10000; //millisecondi
unsigned long invioventoprecedente = 0;
unsigned long previousMillisluce = 0;
unsigned long previousMillisanemometro = 0;
unsigned long currentMillis = 0;
int somma = 0;
int i = 0;
int media = 0;
volatile unsigned long imp_vento = 0;
float vento = 0.0;


SoftwareSerial Serialint(RISCRX, RISCTX); //seriale secondaria
SoftwareSerial Serialvento(rxvento, txvento); //seriale secondaria

void setup() {

  pinMode(RISCTX, OUTPUT);
  pinMode(RISCRX, INPUT);
  pinMode(txvento, OUTPUT);
  pinMode(rxvento, INPUT);
  pinMode(anemometro, INPUT_PULLUP);
  pinMode (luce, INPUT);
  //Serial.begin(9600);
  Serialint.begin (9600);
  Serialvento.begin (9600);
  attachInterrupt(digitalPinToInterrupt(anemometro), controllovento, RISING);

}

void loop() {
  currentMillis = millis();

  //-----------------sensore luminosità-------------

  if (currentMillis - previousMillisluce >= intervalloluce) {
    previousMillisluce = currentMillis;
    valori[i] = analogRead(luce);
    // Serial.print("valore =");
    //Serial.println(valori[i]);
    i++;
    if (i > 9) {
      somma = 0;
      i = 0;
      for (int i = 0; i < 10; i++) {
        somma += valori[i];
        // Serial.print("somma =");
        //  Serial.println(somma);
      }
      media = somma / 10;
      //   Serial.print("media =");
      //   Serial.println(media);
      vdiviso = (media / 4);
      // Serial.print("dimezzato =");
      // Serial.println(vdiviso);
      Serialint.write(vdiviso);
      i = 0;
    }
  }
  //-------------- sensore vento --------------------

  if ((currentMillis - previousMillisanemometro) >= (intervalloanemometro * 1000)) {
    vento = ((float)imp_vento / (float)intervalloanemometro) * 8;
    //Serial.println(vento);
    previousMillisanemometro = millis() ;
    imp_vento = 0;
  }


  if ((currentMillis - invioventoprecedente >= invioventostandard) and (vento <= 8)) {
    invioventoprecedente = currentMillis;
    Serialvento.write (vento);
    //  Serial.print("vento standard - ");
    //  Serial.println(vento);
    // Serial.println("km/h");
  }

  if ((currentMillis - invioventoprecedente >= invioventomosso) and (vento >= 9) and (vento <= 15)) {
    invioventoprecedente = currentMillis;
    Serialvento.write (vento);
    //  Serial.print("vento mosso - ");
    // Serial.println(vento);
    // Serial.println("km/h");
  }


  if ((currentMillis - invioventoprecedente >= invioventopreallarme) and (vento >= 16) and (vento <= 35)) {
    invioventoprecedente = currentMillis;
    Serialvento.write (vento);
    //  Serial.print("vento preallarme - ");
    // Serial.println(vento);
    // Serial.println("km/h");
  }

  if  (((currentMillis - invioventoprecedente) >= invioventoallarme) and (vento >= 36)) {
    invioventoprecedente = currentMillis;
    Serialvento.write (vento);
    //  Serial.print("vento allarme - ");
    // Serial.println(vento);
    // Serial.println("km/h");
  }
}


void controllovento()
{
  imp_vento++;
}