Filtro passa basso

Buongiorno,
vorrei realizzare un contachilometri (distanza e velocità) da installare in un fuoristrada, utilizzando un sensore hall del tipo linkato posizionato sull'albero di trasmissione. Noto il rapporto di riduzione e la circonferenza delle ruote, risulta semplice calcolare la distanza percorsa, analogamente a quanto succede per i contachilometri da bicicletta.

https://www.google.com/search?tbm=isch&sa=1&ei=wyynXOHbK5mn1fAPsv6h4AE&q=sensore+hall+contakm&oq=sensore+hall+contakm&gs_l=img.3...28825.31892..32200...1.0..1.259.1658.0j7j2......1....1..gws-wiz-img.......0j0i30j0i8i30j0i24.oPE8ZpmDY0Y#imgrc=ov0oawFF7iVk9M:

Ho scritto una prima bozza di codice utilizzando un interrupt per incrementare un contatore, ma evidentemente il disturbo sul cavo è eccessivo e la lettura risulta falsata.

Immagino di dover filtrare il segnale con un passa basso, esiste una funzione già pronta?

Per fini pratici, provvisoriamente la visualizzazione è eseguita attraverso un lcd.

Allego codice, grazie dell'attenzione.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

const byte switch_1 = 4;
const byte switch_2 = 9;
const byte azzera_a = 6;
const byte azzera_b = 7;

float trip_a;
float trip_b;
float v;
unsigned long t;

volatile unsigned long a;
volatile unsigned long b;

float rap  = 11.0 / 43.0;             // 43 giri albero = 11 giri ruota  rapporto coppie coniche differenziale sj410
float circ = 2.18;                    // [m] (MISURARE)
float dist = circ * rap;              // PER VERIFICARE: misurare spazio noto e visualizzare sul display a ---> dist = spazio/a


void setup() {

  //  Serial.begin(9600);

  pinMode(switch_1, INPUT);
  pinMode(switch_2, INPUT);
  pinMode(azzera_a, INPUT);
  pinMode(azzera_b, INPUT);

  attachInterrupt(0, contatore, RISING);      // interrupt 0 = pin D2   interrupt 1 = pin D3

  lcd.init();
  lcd.backlight();

}


void loop() {

  trip_a = a * dist;
  trip_b = b * dist;
  
  lcd.setCursor(0, 0);
  lcd.print("impulsi = ");
  lcd.print(a);

  lcd.setCursor(0, 1);
  lcd.print("trip_a = ");
  lcd.print(trip_a);
  lcd.print(" m");

  if (digitalRead(switch_1) == HIGH) {            // visualizzare nello schermo trip_a [m]

  }

  if (digitalRead(switch_1) == LOW) {             // visualizzare nello schermo trip_b [m]

  }

  if (digitalRead(azzera_a) == HIGH) {
    a = 0;
  }
  
  if (digitalRead(azzera_b) == HIGH) {
    b = 0;
  }

  if (digitalRead(switch_2) == HIGH) {             // visualizzare nello schermo il tempo [ore:min] DI MOVIMENTO! Quando si è fermi non incrrementare!

  }

  if (digitalRead(switch_2) == LOW) {              // visualizzare nello schermo la velocità [km/h]

  }

}


void contatore() {
  a++;
  b++;
}

Non hai comunicato quale sensore vuoi usare ma solo la pagina di ricerca con diversi risultati.

Io presumo che il sensore é un reed che chiude solo i contatti e Tu non stai usando un pullup/pulldown.
Ciao Uwe

No, non è reed, è hall!

Giusto per capirci, anche senza toccare il cavetto che fa scattare l'interrupt, il contatore viene incrementato molto rapidamente, immagino per del rumore (che non saprei come gestire!)

Appunto..
O metti una resistenza di PullUp ( una 10K tra il pin 2 e il +5V ) o al limite abiliti la PullUp interna

Premetto che non ho ancora il sensore, e le prove le sto eseguendo manualmente facendo contatto tra il pin D2 ed i 5V.

A quanto ho capito, senza una resistenza di pullup (o pulldown), nel momento in cui scollego il cavo dai 5V la tensione non va a 0V ma oscilla liberamente creando dei falsi contatti.

Per evitare tale fenomeno dovrei collegare attraverso una resistenza il pin D2 a massa, in modo tale che quando è connessa ai 5V il valore logico sia alto (ma non in corto!) e quando viene disconnessa sia forzatamente portata a 0V.
E' corretto?

Se così fosse, la tessa cosa dovrebbe avvenire per i pin che utilizzo per azzerare il valore letto.

Eventualmente come posso attivare la resistenza interna?

Grazie.

Allora devi dirci il modello preciso per capire che tipo di uscita ha il Tuo sensore.
Ciao Uwe

photobyfs:
Premetto che non ho ancora il sensore, e le prove le sto eseguendo manualmente facendo contatto tra il pin D2 ed i 5V.

A quanto ho capito, senza una resistenza di pullup (o pulldown), nel momento in cui scollego il cavo dai 5V la tensione non va a 0V ma oscilla liberamente creando dei falsi contatti.

Per evitare tale fenomeno dovrei collegare attraverso una resistenza il pin D2 a massa, in modo tale che quando è connessa ai 5V il valore logico sia alto (ma non in corto!) e quando viene disconnessa sia forzatamente portata a 0V.
E' corretto?

Se così fosse, la tessa cosa dovrebbe avvenire per i pin che utilizzo per azzerare il valore letto.

Eventualmente come posso attivare la resistenza interna?

Grazie.

  1. un pin non collegato prende disturbi e percui puó essere un po tutto, HIGH , LOW o anche oscillante. serve una resistenza pullup o pulldown.
  2. se porti il cavetto manualmente a +5V non hai un netto passaggio da LOW a HIGH ma hai 4-5 oscillazioni che il controller vede com 4-5 impulsi. La stessa cosa succede com la maggior parte di pulsanti e interuttori e si chaima Bounce. Se col segnale chiami uninterrupt é impossibile fare un debouce via programma.

Aspetta che Ti arriva il sensore e poi ne riparloamo perché la maggiot parte dei problemi sono dovuti al fatto che non hai il sensore ma lo simuli con un cavetto.

Internamente l'arduino ha solo delle resistenze Pullup e li accendi con pinMode(pin, INPUT_PULLUP) oppure pinMode(pin, INPUT) e digitalWrite(pin, HIGH)

Ciao Uwe

Ti ringrazio, sei stato molto chiaro. Immaginavo erroneamente che un pin non fisicamente collegato ai 5V fosse sempre a 0V, invece...

Già provando con una resistenza da 10 kOhm tra il pin ed il ground il contatore non impazzisce! Chiaro che l'incremento non è preciso per i classici problemi di rimbalzi, che con il sensore "vero" non dovrebbero esserci.

Il sensore che ho acquistato è questo: https://it.aliexpress.com/item/TZT-NJK-5002C-Effetto-Hall-Interruttore-Del-Sensore-Di-Prossimit-NPN-3-Fili-Normalmente-Aperto-Magne/32922514991.html
Approfitto per un'ulteriore domanda: se volessi calcolare la velocità avrei bisogno del tempo che intercorre tra due impulsi successivi. Sarebbe sufficiente cambiare la funzione richiamata nell'interrupt nel seguente modo?

void contatore() {
  delta_t = millis() - t;
  a++;
  b++;
  t = millis();
}

Grazie

Ho editato il post e corretto il link al sensore.

Quel pezzo di sketch é inutile perché non si capisce cosa fanno le variabili. Non posso ne dire che funziona ne che é errato.

Ciao Uwe

>photobyfs: ... tieni sempre conto che, nel momento in cui entri nella ISR, millis() si ferma, quindi ... leggerne il valore OK, sperare che tale valore li dentro si incrementi NO, ma ... mi sembra che tu legga semplicemente il valore, quindi .. non dovrebbe dare problemi ... ::slight_smile:

Guglielmo

Quel pezzo di sketch é inutile perché non si capisce cosa fanno le variabili. Non posso ne dire che funziona ne che é errato.

In realtà quello che mi serve è calcolare con una certa precisione il delta_t che intercorre tra due impulsi, ossia il tempo tra un incremento del contatore ed il successivo. In questo modo dividendo dist (la distanza che la ruota percorre in un impulso) per il delta_t in cui lo percorre, è possibile ottenere la velocità istantanea.

Per questo non ho postato il resto del programma, che come richiesto riporto in seguito.

r////////////////////////////////////////////////////////////////////////////////// T R I P M A S T E R //////////////////////////////////////////////////////////////////////////////////

const byte switch_1 = 4;                // switch tra trip_a - trip_b           ---->  lo switch avviene mandando a massa i pin per poter utilizzare la resistenza di pullup interna
const byte switch_2 = 5;                // switch tra odo - v_ist
const byte switch_3 = 6;                // switch tra t_parz - t_tot
const byte azzera_1 = 9;                // azzeramento trip_a - trip_b          ---->  l'azzeramento avviene mandando a massa i pin per poter utilizzare la resistenza di pullup interna
const byte azzera_3 = 10;               // azzeramento t_parz

float trip_a, trip_b, odo, v_ist;
unsigned long t_parz, t_tot, t0 = 0;

volatile unsigned long a, b, c;
volatile unsigned long t = 0, delta_t;

const float rap  = 11.0 / 43.0;         // 43 giri albero = 11 giri ruota  rapporto coppie coniche differenziale sj410
const float circ = 2.18;                // [m] (MISURARE)
const float dist = circ * rap;          // PER VERIFICARE: misurare spazio noto e visualizzare la variabile a ---> dist = spazio/a

const int debounceDelay = 20;
const int azzeraDelay = 1000;


void setup() {

  Serial.begin(9600);

  pinMode(switch_1, INPUT_PULLUP);
  pinMode(switch_2, INPUT_PULLUP);
  pinMode(switch_3, INPUT_PULLUP);
  pinMode(azzera_1, INPUT_PULLUP);
  pinMode(azzera_3, INPUT_PULLUP);

  attachInterrupt(0, contatore, RISING);             // interrupt 0 = pin D2   interrupt 1 = pin D3

}


void loop() {

  trip_a = a * dist;
  trip_b = b * dist;
  odo = c * dist / 1000;

  t_parz = (millis() - t0) * 1000;                   // [s]
  t_tot = millis() * 1000;                           // [s]
  v_ist = (dist / delta_t) * 3600000000;             // [km/h]


  Serial.print("impulsi_a = ");
  Serial.print(a);
  Serial.print("  |  ");

  Serial.print("impulsi_b = ");
  Serial.print(b);
  Serial.print("  |  ");

  Serial.print("trip_a =");
  Serial.print(trip_a);
  Serial.print(" m  |  ");

  Serial.print("trip_b =");
  Serial.print(trip_b);
  Serial.print(" m  |  ");

  Serial.print("odo =");
  Serial.print(odo);
  Serial.print(" km  |  ");

  Serial.print("t_parz =");
  Serial.print(t_parz);
  Serial.print(" s");

  Serial.print("t_tot =");
  Serial.print(t_tot);
  Serial.print(" s");

  Serial.print("delta_t = ");
  Serial.print(delta_t / 1000);
  Serial.print(" s  |  ");

  Serial.print("velocita' =");
  Serial.print(v_ist);
  Serial.println(" km/h");


  if (debounce(switch_1) == LOW) {
    // visualizza trip_a su schermo 1
  }
  if (debounce(switch_1) == HIGH) {
    // visualizza trip_b su schermo 1
  }
  if (debounce(switch_2) == LOW) {
    // visualizza odo su schermo 2
  }
  if (debounce(switch_2) == HIGH) {
    // visualizza v_ist su schermo 2
  }
  if (debounce(switch_3) == LOW) {
    // visualizza t_parz su schermo 3
    // fino ad un'ora [mm:ss], poi [hh:mm]
  }
  if (debounce(switch_3) == HIGH) {
    // visualizza t_tot su schermo 3
    // fino ad un'ora [mm:ss], poi [hh:mm]
  }

  if (debounce(azzera_1) == LOW) {
    delay(azzeraDelay);
    if (debounce(azzera_1) == LOW && debounce(switch_1) == LOW) {
      a = 0;
    }
    if (debounce(azzera_1) == LOW && debounce(switch_1) == HIGH) {
      b = 0;
    }
  }

  if (debounce(azzera_3) == LOW && debounce(switch_3) == LOW) {
    delay(azzeraDelay);
    t0 = millis();
  }
}


}


void contatore() {
  delta_t = millis() - t;
  a++;
  b++;
  c++;
  t = millis();
}

boolean debounce(int pin) {
  boolean state;
  boolean previousState;
  previousState = digitalRead(pin);
  for (int counter = 0; counter < debounceDelay; counter++) {
    delay(1);
    state = digitalRead(pin);
    if ( state != previousState) {
      counter = 0;
      previousState = state;
    }
  }
  return state;
}

Riepilogo la logica di funzionamento: lo strumento, un tripmaster, verrà montato in un fuoristrada, in quanto gli organizzatori dei diversi raduni indicano le note del percorso in un roadbook misurando la distanza tra di esse in metri. Vorrei realizzarlo utilizzando tre schermi di quattro cifre a 7 segmenti (nonostante si possano far stare tutte le informazioni in un LCD, preferisco l'aspetto vintage) e tre switch a levetta per visualizzare di volta in volta le informazioni che desidero. Leggendo le note del programma risulta molto chiaro. Infine attraverso due pulsanti è possibile azzerare le distanze o i tempi.

Questo ultimo programma riporta anche una funzione di debouncing (in realtà necessaria solo per i pulsanti di azzeramento, ma che utilizzo anche per quelli a levetta), e le resistenze di pullup, che (assieme a quella di pulldown "fisica") hanno permesso di eliminare il disturbo.

Ora, tornando al discorso iniziale, come posso misurare il tempo tra un incremento ed il successivo (cioè il tempo tra un interrupt ed il seguente)?

La mia idea è quella di salvare il tempo dell'i-esimo interrupt, e sottrarlo a quello dell'interrupt i+1-esimo, in modo da ottenere la differenza tra i due. E' un ragionamento corretto?

Dimenticavo: Visto che il sensore ha un uscita NPN devi usare una resistenza Pullup (esterna o quella interna)
Ciao Uwe