Cronometro TM1637

Dato che parla di letture di velocità, potrebbe anche essere un pulseIn che rallenta enormemente il loop.

Come richiesto allego l'intero codice.

Per quanto riguarda i collegamenti elettrici, l'unico input esterno è l'impulso di velocità che leggo con un interupt (che per ora simulo con un pulsante e resistenza di pull-down ma in futuro sarà un semplice sensore hall collegato ad una ruota o albero di trasmissione). Il resto sono solo switch.

Come precisato, con il codice così come è scritto il primo prototipo funziona, solamente che il cronometro va a scatti ed i minuti tra le due visualizzazioni non "cambiano assieme".

Un ulteriore step sarebbe quello di visualizzare la velocità istantanea, ma devo capire come calcolare il tempo tra due impulsi successivi...ci devo pensare con calma viste le mie limitate conoscenze della materia.

#include <TM1637Display.h>
#define CLK1 12
#define DIO1 11
#define CLK2 10
#define DIO2 9
#define CLK3 8
#define DIO3 7
TM1637Display display1(CLK1, DIO1);
TM1637Display display2(CLK2, DIO2);
TM1637Display display3(CLK3, DIO3);

const byte switch_1 = 3;                // switch tra dist - time               ---->  lo switch avviene mandando a massa i pin per poter utilizzare la resistenza di pullup interna
const byte switch_2 = 13;               // switch tra actual - average
const byte switch_3 = 4;                // switch tra avanti - indietro
const byte switch_4 = 5;                // switch tra a - b
const byte azzera   = 6;                // azzeramento                          ---->  l'azzeramento avviene mandando a massa il pin per poter utilizzare la resistenza di pullup interna

float trip_a, trip_b, odo, v_act, v_med;
unsigned long t_parz_a, t_parz_b, t_tot;
unsigned long t0_a = 0, t0_b = 0;

volatile long a = 0;                    // a --> trip a
volatile long b = 0;                    // b --> trip b
volatile unsigned long c = 0;           // c --> odo
// 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.095;               // [m]
const float dist = circ * rap;          // PER VERIFICARE: misurare spazio noto e visualizzare la variabile a ---> dist = spazio/a
const int azzeraDelay = 250;

void contatore() {
  //delta_t = millis() - t;
  if (digitalRead(switch_3) == LOW) {      // marcia avanti
    a++;
    b++;
  }
  if (digitalRead(switch_3) == HIGH) {     // marcia indietro
    a--;
    b--;
  }
  c++;
  //t = millis();
}


void setup() {

  Serial.begin(9600);

  pinMode(switch_1, INPUT_PULLUP);
  pinMode(switch_2, INPUT_PULLUP);
  pinMode(switch_3, INPUT_PULLUP);
  pinMode(switch_4, INPUT_PULLUP);
  pinMode(azzera, INPUT_PULLUP);

  display1.setBrightness(7, true);
  display2.setBrightness(7, true);
  display3.setBrightness(7, true);

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

}

...continua...

void loop() {

  trip_a = a * dist;                                 // [m]
  trip_b = b * dist;                                 // [m]
  odo = c * dist / 1000;                             // [km]

  t_parz_a = (millis() - t0_a) / 1000;               // [s]
  t_parz_b = (millis() - t0_b) / 1000;               // [s]
  t_tot = millis() / 1000;                           // [s]

  //v_act = (dist / delta_t) * 3600 * 1000 * 1000;     // [km/h]
  v_med = odo / (t_tot / 3600);                        // [km/h]

  Serial.print(trip_a);
  Serial.print(" ");
  Serial.print(odo);
  Serial.print(" ");
  Serial.print(v_med);
  Serial.println(" ");

  if (digitalRead(switch_1) == LOW) {                           // visualizza le distanze su schermo 1 e 2
    display2.showNumberDec(odo);

    if (digitalRead(switch_4) == LOW) {                         // visualizza trip_a su schermo 1
      display1.showNumberDec(trip_a);
    }

    if (digitalRead(switch_4) == HIGH) {                        // visualizza trip_b su schermo 1
      display1.showNumberDec(trip_b);
    }
  }

  if (digitalRead(switch_1) == HIGH) {                          // visualizza i tempi su schermo 1 e 2

    //                                                          // esempio 4429 secondi
    float numero = t_tot / 3200.0;                              // numero = 4429 / 3200 = 1.23
    int ore = numero;                                           // ore = 1
    numero = (numero - ore) * 60.0;                             // numero = 0.23 * 60 = 13.8
    int minuti = numero;                                        // minuti = 13

    //                                                          // esempio ore = 1  min = 13
    float i = ore / 10.0;                                       // i = 0.1
    int ore_dec = i;                                            // ore_dec = 0
    i = (i - ore_dec) * 10.0;                                   // i = 1.0
    int ore_uni = i;                                            // ore_uni = 1
    float j = minuti / 10.0;                                    // j = 1.3
    int minuti_dec = j;                                         // minuti_dec = 1
    j = (j - minuti_dec) * 10.0;                                // j = 3.0
    int minuti_uni = j;                                         // minuti_uni = 3

    int disp = ore_dec * 1000 + ore_uni * 100 + minuti_dec * 10 + minuti_uni;
    display2.showNumberDecEx(disp, 0b11100000, true);

    if (digitalRead(switch_4) == LOW) {                         // visualizza t_parz_a su schermo 1

      //                                                        // esempio 429 secondi              // esempio 43 secondi
      float numero = t_parz_a / 60.0;                           // numero = 429 / 60 = 7.15         // numero = 0.716
      int minuti = numero;                                      // minuti = 7                       // minuti = 0
      numero = (numero - minuti) * 60.0;                        // numero = 0.15 * 60 = 9.0         // numero = 43.0
      int secondi = numero;                                     // secondi = 9                      // secondi = 43

      //                                                        // esempio min = 32  sec = 27        // esempio min = 5  sec = 9
      float i = minuti / 10.0;                                  // i = 3.2                           // i = 0.5
      int minuti_dec = i;                                       // minuti_dec = 3                    // minuti_dec = 0
      i = (i - minuti_dec) * 10.0;                              // i = 2.0                           // i = 5.0
      int minuti_uni = i;                                       // minuti_uni = 2                    // minuti_uni = 5
      float j = secondi / 10.0;                                 // j = 2.7                           // j = 0.9
      int secondi_dec = j;                                      // secondi_dec = 2                   // secondi_dec = 0
      j = (j - secondi_dec) * 10.0;                             // j = 7.0                           // j = 9.0
      int secondi_uni = j;                                      // secondi_uni = 7                   // secondi_uni = 9

      int disp = minuti_dec * 1000 + minuti_uni * 100 + secondi_dec * 10 + secondi_uni;
      display1.showNumberDecEx(disp, 0b11100000, true);
    }

    if (digitalRead(switch_4) == HIGH) {                        // visualizza t_parz_b su schermo 1

      float numero = t_parz_b / 60.0;
      int minuti = numero;
      numero = (numero - minuti) * 60.0;
      int secondi = numero;

      float i = minuti / 10.0;
      int minuti_dec = i;
      i = (i - minuti_dec) * 10.0;
      int minuti_uni = i;
      float j = secondi / 10.0;
      int secondi_dec = j;
      j = (j - secondi_dec) * 10.0;
      int secondi_uni = j;

      int disp = minuti_dec * 1000 + minuti_uni * 100 + secondi_dec * 10 + secondi_uni;
      display1.showNumberDecEx(disp, 0b11100000, true);
    }
  }

  if (digitalRead(switch_2) == LOW) {                           // visualizza v_act su schermo 3
  }

  if (digitalRead(switch_2) == HIGH) {                          // visualizza v_med su schermo 3
    //                                                          // esempio v_med = 43.54               // esempio v_med = 123.72
    float v = (v_med * 10.0);                                   // v = 435.4                           // v = 1237.2
    int disp = v;                                               // disp = 435                          // disp = 1237
    display3.showNumberDecEx(disp, 0b00100000);                 // _43.5                               // 123.7
  }

  if (digitalRead(azzera) == LOW) {

    delay(azzeraDelay);

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == LOW) {
      a = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == HIGH) {
      b = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == LOW) {
      t0_a = millis();
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == HIGH) {
      t0_b = millis();
    }
  }
}

pgiagno:
Come suggerisce Datman non è necessario usare il tipo float per i calcoli che vuoi fare tu, ma il tipo unsigned long. Il linguaggio C consente di ricavare ore, minuti e secondi in modo molto più diretto. Ad es:

  unsigned long numero;

uint8_t ore, minuti, secondi;
 uint16_t disp;

. . .

//ad esempio "numero" contiene 12345 secondi da dividere in ore e minuti
 ore = numero / 3200; // ore = 3
 minuti = numero % 3200 / 60; // minuti = 45
 secondi = numero % 3200 % 60;  // secondi = 45

//per visualizzare ore e minuti
 disp = ore * 100 + minuti; // disp = 300+45 = 345

//per visualizzare minuti e secondi
 disp = minuti * 100 + secondi; // disp = 4500+45 = 4545



Ciao,
P.

Non sapevo dell'esistenza dell'operatore %
Ed io che ho perso tempo a dividere, prendere la parte intera, rimoltiplicare...fatica sprecata!!!
Grazie della dritta! Sarà la prossima modifica al codice!

Come dicevo la gestione di millis() è errata.

Ho provato a cominciare a correggere lo sketch. Vedi se capisci quello che ho scritto. Chiedi quello che non ti è chiaro.

#include <TM1637Display.h>
#define CLK1 12
#define DIO1 11
#define CLK2 10
#define DIO2 9
TM1637Display display1(CLK1, DIO1);
TM1637Display display2(CLK2, DIO2);

unsigned long t_parz_a, t_parz_b, t_tot;
//==SOSTITUISCI QUESTE RIGHE===================================================
unsigned long t0_a = 0, t0_b = 0;
//==CON QUESTE=================================================================
unsigned long t0_a, t0_b;
int numero_a, numero_b;         //secondi crono_a, secondi crono_b
//=============================================================================


void setup() {
  display1.setBrightness(7, true);
  display2.setBrightness(7, true);
//==INSERISCI QUESTE RIGHE=====================================================
  numero_a = 0;         //inizializza crono_a
  numero_b = 0;         //inizializza crono_b
  t0_a = millis();      //inizializza inizio secondo crono_a
  t0_b = millis();      //inizializza inizio secondo crono_b
  t_tot = millis();     //inizializza inizio tempo totale
//=============================================================================
}


void loop() {

  trip_a = a * dist;                                 // [m]
  trip_b = b * dist;                                 // [m]
  odo = c * dist / 1000;                             // [km]

//==SOSTITUISCI QUESTE RIGHE===================================================
  t_parz_a = (millis() - t0_a) / 1000;               // [s]
  t_parz_b = (millis() - t0_b) / 1000;               // [s]
//==CON QUESTE=================================================================
  if (millis() - t0_a >= 1000) {
    t0_a = millis();      //inizializza inizio secondo crono_a
    numero_a++;           //incrementa il numero dei secondi del crono_a
  }
  if (millis() - t0_b >= 1000) {
    t0_b = millis();      //inizializza inizio secondo crono_b
    numero_b++;           //incrementa il numero dei secondi del crono_b
  }
//=============================================================================
//==ELIMINA QUESTA RIGA========================================================
  t_tot = millis() / 1000;                           // [s]
//=============================================================================

  //v_act = (dist / delta_t) * 3600 * 1000 * 1000;     // [km/h]
//==SOSTITUISCI QUESTA RIGA====================================================
  v_med = odo / (t_tot / 3600);                        // [km/h]
//==CON QUESTA=================================================================
  v_med = odo / ((millis() - t_tot) / 3600);                        // [km/h]
//=============================================================================

//Su questa parte non so aiutarti perché non hai postato l'intero sketch e
//non so cosa siano trip_a, odo, v_med, a, b. c, etc. Se cerco di compilarlo
//mi da una serie di indefiniti

  Serial.print(trip_a);
  Serial.print(" ");
  Serial.print(odo);
  Serial.print(" ");
  Serial.print(v_med);
  Serial.println(" ");

  if (digitalRead(switch_1) == LOW) {                           // visualizza le distanze su schermo 1 e 2
    display2.showNumberDec(odo);

    if (digitalRead(switch_4) == LOW) {                         // visualizza trip_a su schermo 1
      display1.showNumberDec(trip_a);
    }

    if (digitalRead(switch_4) == HIGH) {                        // visualizza trip_b su schermo 1
      display1.showNumberDec(trip_b);
    }
  }

  if (digitalRead(switch_1) == HIGH) {                          // visualizza i tempi su schermo 1 e 2

    //                                                          // esempio 4429 secondi
//==SOSTITUISCI QUESTE RIGHE===================================================
    float numero = t_tot / 3200.0;                              // numero = 4429 / 3200 = 1.23
    int ore = numero;                                           // ore = 1
    numero = (numero - ore) * 60.0;                             // numero = 0.23 * 60 = 13.8
    int minuti = numero;                                        // minuti = 13

    //                                                          // esempio ore = 1  min = 13
    float i = ore / 10.0;                                       // i = 0.1
    int ore_dec = i;                                            // ore_dec = 0
    i = (i - ore_dec) * 10.0;                                   // i = 1.0
    int ore_uni = i;                                            // ore_uni = 1
    float j = minuti / 10.0;                                    // j = 1.3
    int minuti_dec = j;                                         // minuti_dec = 1
    j = (j - minuti_dec) * 10.0;                                // j = 3.0
    int minuti_uni = j;                                         // minuti_uni = 3

    int disp = ore_dec * 1000 + ore_uni * 100 + minuti_dec * 10 + minuti_uni;
//==CON QUESTE=================================================================
    unsigned long numero_tot = (millis() - t_tot) / 1000;       // numero_tot = secondi totali
    int ore = numero_tot / 3200;                                // ore = 1
    int minuti = numero_tot % 3200 / 60;                        // minuti = 13

    int disp = ore * 100 + minuti;
//=============================================================================
    display2.showNumberDecEx(disp, 0b11100000, true);

//============================================================================
//SE HAI CAPITO IL MECCANISMO, PROVA AD ANDARE AVANTI DA SOLO
//============================================================================

    if (digitalRead(switch_4) == LOW) {                         // visualizza t_parz_a su schermo 1


}

Non ho potuto controllare quello che ho scritto. Potrebbero esserci errori.

Ciao,
P.

Il % te lo avevo già "presentato" giorni fa...
Comunque, le visualizzazioni sul display non vanno fatte a ogni giro di loop, ma a intervalli ragionevoli predefiniti, ad esempio una volta al secondo. Sia quelle che le scritture su seriale rallentano enormemente il loop!

A me risulta che in un ora ci siano 3600 secondi (60*60..) non 3200 :wink:

  //ad esempio "numero" contiene 12345 secondi da dividere in ore e minuti
  ore = numero / 3200; // ore = 3
  minuti = numero % 3200 / 60; // minuti = 45
  secondi = numero % 3200 % 60;  // secondi = 45

Da lì in poi tutti i calcoli sono errati, forse è per questo che le visualizzazioni ore\minuti e quella minuti\secondi sono sfalsate..

EDIT: Scusate il codice dell'OP è questo:

    //                                                                     // esempio 4429 secondi
    float numero = t_tot / 3200.0;                           // numero = 4429 / 3200 = 1.23
    int ore = numero;                                             // ore = 1
    numero = (numero - ore) * 60.0;                      // numero = 0.23 * 60 = 13.8
    int minuti = numero;                                        // minuti = 13

Che comunque riporta lo stesso errore anche se stranamente i commenti sono quasi corretti.
Nel senso che: 4429 / 3200 = 1,38; mentre 1,23 è il risultato di 4429 / 3600..

Come ti hanno consigliato altri è meglio fare il conto con le divisioni intere, perchè ti restituisce un calcolo più preciso.

Ciao

paolo311:
A me risulta che in un ora ci siano 3600 secondi (60*60..) non 3200 :wink:

E bravo Paolo! Ottima vista sulle sviste!
Occorre sostituire 3600 a 3200.

Ciao,
P.

Perdonate il ritardo nella risposta, in questi giorni sono stato lontano dal PC.

A me risulta che in un ora ci siano 3600 secondi (60*60..) non 3200 :wink:

mentre 1,23 è il risultato di 4429 / 3600.

Brutta svista, avevo in mente il 3600 ma ho scritto 3200...grazie, non l'avrei notato!

Modifico il codice come consigliato e continuo con le prove! Grazie a tutti!

Aggiornamento: per semplicità e necessità di spazio (due schermi invece che tre) ho deciso di non visualizzare la velocità media ed istantanea, ma di utilizzare solo i due schermi per la distanza (totale e parziale) ed il cronometro (totale e parziale).

pgiagno:
Come dicevo la gestione di millis() è errata.

Ho provato a cominciare a correggere lo sketch. Vedi se capisci quello che ho scritto. Chiedi quello che non ti è chiaro.

#include <TM1637Display.h>

#define CLK1 12
#define DIO1 11
#define CLK2 10
#define DIO2 9
TM1637Display display1(CLK1, DIO1);
TM1637Display display2(CLK2, DIO2);

.........




Non ho potuto controllare quello che ho scritto. Potrebbero esserci errori.

Ciao,
P.

Grazie della risposta. Secondo me la gestione di millis() che ho utilizzato non è però errata.
Ti spiego la mia logica (per semplicità immaginiamo che il cronometro sia solo uno, senza a e b):

  • all'avvio di Arduino t0 = 0 e t_parz = millis() - t0 inizia a contare i millis() trascorsi che visualizzo sul display
  • quando premo il pulsante di azzeramento, t0 = millis(), dunque t_parz = 0, e visualizzo il cronometro ricominciare da zero

Secondo me funziona correttamente.

In ogni caso ho preso spunto dallo sketch che hai gentilmente scritto ed ho apportato alcune modifiche al mio, in particolare:

  • aggiorno il display, come suggerito, ogni secondo, inserendo la riga: if (millis() - t_disp >= 1000) (è corretto così???)
  • calcolo ore, minuti e secondi molto più semplicemente con l'operatore %

Riguardo questo secondo punto, purtroppo non compila. Riporta il seguente errore: invalid operands of types 'long unsigned int' and 'double' to binary 'operator%'
Come potrei risolvere? Ho usato, copiando da te, variabili int. Prendendo come esempio una riga in cui ho utilizzato tale operatore:

int minuti_tot = t_tot % 3600.0 / 60;

minuti_tot, come si vede è un int, mentre t_tot è unsigned long. Probabilmente non gradisce una o entrambe queste variabili...

Allego il nuovo codice, completo.
Grazie ancora.

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

#include <TM1637Display.h>
#define CLK1 12
#define DIO1 11
#define CLK2 10
#define DIO2 9
TM1637Display display1(CLK1, DIO1);
TM1637Display display2(CLK2, DIO2);

const byte switch_1 = 3;                // switch tra dist - time               ---->  lo switch avviene mandando a massa i pin per poter utilizzare la resistenza di pullup interna
const byte switch_3 = 4;                // switch tra avanti - indietro
const byte switch_4 = 5;                // switch tra a - b
const byte azzera   = 6;                // azzeramento                          ---->  l'azzeramento avviene mandando a massa il pin per poter utilizzare la resistenza di pullup interna

float trip_a, trip_b, odo;
unsigned long t_parz_a, t_parz_b, t_tot;
unsigned long t0_a = 0, t0_b = 0, t_disp = 0;

volatile long a = 0;                    // a --> trip a
volatile long b = 0;                    // b --> trip b
volatile unsigned long c = 0;           // c --> odo

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

const int azzeraDelay = 250;


void contatore() {
  if (digitalRead(switch_3) == LOW) {      // marcia avanti
    a++;
    b++;
  }
  if (digitalRead(switch_3) == HIGH) {     // marcia indietro
    a--;
    b--;
  }
  c++;
}


void setup() {
  pinMode(switch_1, INPUT_PULLUP);
  pinMode(switch_3, INPUT_PULLUP);
  pinMode(switch_4, INPUT_PULLUP);
  pinMode(azzera, INPUT_PULLUP);

  display1.setBrightness(7, true);
  display2.setBrightness(7, true);

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


void loop() {

  trip_a = a * dist;                                 // [m]
  trip_b = b * dist;                                 // [m]
  odo = c * dist / 1000;                             // [km]

  t_parz_a = (millis() - t0_a) / 1000;               // [s]
  t_parz_b = (millis() - t0_b) / 1000;               // [s]
  t_tot = millis() / 1000;                           // [s]


  if (digitalRead(switch_1) == LOW) {                           // visualizza le distanze su schermo 1 e 2
    display2.showNumberDec(odo);

    if (digitalRead(switch_4) == LOW) {                         // visualizza trip_a su schermo 1
      display1.showNumberDec(trip_a);
    }

    if (digitalRead(switch_4) == HIGH) {                        // visualizza trip_b su schermo 1
      display1.showNumberDec(trip_b);
    }
  }

  if (digitalRead(switch_1) == HIGH) {                          // visualizza i tempi su schermo 1 e 2

    int ore_tot = t_tot / 3600.0;
    int minuti_tot = t_tot % 3600.0 / 60;
    int disp_tot = ore * 100 + minuti;

    int minuti_a = t_parz_a / 60.0;
    int secondi_a = t_parz_a % 60.0;
    int disp_a = minuti * 100 + secondi;

    int minuti_b = t_parz_b / 60.0;
    int secondi_b = t_parz_b % 60.0;
    int disp_b = minuti * 100 + secondi;

    if (millis() - t_disp >= 1000) {

      t_disp = millis();

      display2.showNumberDecEx(disp, 0b11100000, true);

      if (digitalRead(switch_4) == LOW) {                         // visualizza t_parz_a su schermo 1
        display1.showNumberDecEx(disp_a, 0b11100000, true);
      }

      if (digitalRead(switch_4) == HIGH) {                        // visualizza t_parz_b su schermo 1
        display1.showNumberDecEx(disp_b, 0b11100000, true);
      }
    }
  }

  if (digitalRead(azzera) == LOW) {

    delay(azzeraDelay);

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == LOW) {
      a = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == HIGH) {
      b = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == LOW) {
      t0_a = millis();
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == HIGH) {
      t0_b = millis();
    }
  }

}

photobyfs:
.... Come potrei risolvere? Ho usato, copiando da te, variabili int. Prendendo come esempio una riga in cui ho utilizzato tale operatore:

int minuti_tot = t_tot % 3600.0 / 60;

minuti_tot, come si vede è un int, mentre t_tot è unsigned long. Probabilmente non gradisce una o entrambe queste variabili...

No, NON gradisce che tu dia in pasto all'operatore % un valore ... float !!! 3600.0, scritto così, è un float !!!

Guglielmo

gpb01:
No, NON gradisce che tu dia in pasto all'operatore % un valore ... float !!! 3600.0, scritto così, è un float !!!

Guglielmo

Senza dubbio hai ragione! :astonished:

Allego il codice corretto, che compila. Appena possibile lo testo.
Grazie ancora.

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

#include <TM1637Display.h>
#define CLK1 12
#define DIO1 11
#define CLK2 10
#define DIO2 9
TM1637Display display1(CLK1, DIO1);
TM1637Display display2(CLK2, DIO2);

const byte switch_1 = 3;                // switch tra dist - time               ---->  lo switch avviene mandando a massa i pin per poter utilizzare la resistenza di pullup interna
const byte switch_3 = 4;                // switch tra avanti - indietro
const byte switch_4 = 5;                // switch tra a - b
const byte azzera   = 6;                // azzeramento                          ---->  l'azzeramento avviene mandando a massa il pin per poter utilizzare la resistenza di pullup interna

float trip_a, trip_b, odo;
unsigned long t_parz_a, t_parz_b, t_tot;
unsigned long t0_a = 0, t0_b = 0, t_disp = 0;

volatile long a = 0;                    // a --> trip a
volatile long b = 0;                    // b --> trip b
volatile unsigned long c = 0;           // c --> odo

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

const int azzeraDelay = 250;


void contatore() {
  if (digitalRead(switch_3) == LOW) {      // marcia avanti
    a++;
    b++;
  }
  if (digitalRead(switch_3) == HIGH) {     // marcia indietro
    a--;
    b--;
  }
  c++;
}


void setup() {
  pinMode(switch_1, INPUT_PULLUP);
  pinMode(switch_3, INPUT_PULLUP);
  pinMode(switch_4, INPUT_PULLUP);
  pinMode(azzera, INPUT_PULLUP);

  display1.setBrightness(7, true);
  display2.setBrightness(7, true);

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


void loop() {

  trip_a = a * dist;                                 // [m]
  trip_b = b * dist;                                 // [m]
  odo = c * dist / 1000;                             // [km]

  t_parz_a = (millis() - t0_a) / 1000;               // [s]
  t_parz_b = (millis() - t0_b) / 1000;               // [s]
  t_tot = millis() / 1000;                           // [s]


  if (digitalRead(switch_1) == LOW) {                             // visualizza le distanze su schermo 1 e 2
    display2.showNumberDec(odo);

    if (digitalRead(switch_4) == LOW) {                         // visualizza trip_a su schermo 1
      display1.showNumberDec(trip_a);
    }

    if (digitalRead(switch_4) == HIGH) {                        // visualizza trip_b su schermo 1
      display1.showNumberDec(trip_b);
    }
  }

  if (digitalRead(switch_1) == HIGH) {                            // visualizza i tempi su schermo 1 e 2

    int ore_tot = t_tot / 3600;
    int minuti_tot = t_tot % 3600 / 60;
    int disp_tot = ore_tot * 100 + minuti_tot;

    int minuti_a = t_parz_a / 60;
    int secondi_a = t_parz_a % 60;
    int disp_a = minuti_a * 100 + secondi_a;

    int minuti_b = t_parz_b / 60;
    int secondi_b = t_parz_b % 60;
    int disp_b = minuti_b * 100 + secondi_b;

    if (millis() - t_disp >= 1000) {

      t_disp = millis();

      display2.showNumberDecEx(disp_tot, 0b11100000, true);

      if (digitalRead(switch_4) == LOW) {                         // visualizza t_parz_a su schermo 1
        display1.showNumberDecEx(disp_a, 0b11100000, true);
      }

      if (digitalRead(switch_4) == HIGH) {                        // visualizza t_parz_b su schermo 1
        display1.showNumberDecEx(disp_b, 0b11100000, true);
      }
    }
  }

  if (digitalRead(azzera) == LOW) {

    delay(azzeraDelay);

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == LOW) {
      a = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == HIGH) {
      b = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == LOW) {
      t0_a = millis();
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == HIGH) {
      t0_b = millis();
    }
  }

}

Da un primo test sembra funzionare tutto perfettamente: cronometri "fluidi" e soprattutto sincronizzati!

Devo ringraziare di cuore tutti voi che avete impiegato tempo ed energie per risolvere un mio problema.

Appena riesco a trovare un contenitore adatto ed appena arriverà il sensore hall potranno iniziare le prove sul campo.

Nell'ottica della condivisione delle informazioni, chi volesse usufruire del codice (per uso non commerciale) è ovviamente libero di farlo.

Grazie ancora :slight_smile:

Ringraziando tutti per l'aiuto ricevuto, ci tengo ad allegare le foto del risultato finito.

A banco funziona tutto alla perfezione: la misura delle distanze, il cronometro, parziali, totali, azzeramento, ecc.
Purtroppo però, montando lo strumento ed il sensore in macchina nella posizione definitiva, qualcosa non quadra, probabilmente a causa di disturbi elettromagnetici.

Riflettendoci, pur senza un'adeguata conoscenza del fenomeno, credo che le possibili cause possano essere:

  • disturbi nell'alimentazione
  • disturbi nel cavo del sensore
  • disturbi direttamente su Arduino (posizionato nel cruscotto, a poca distanza da bobine, candele, ecc)

Per quanto riguarda il primo punto, ho provveduto ad alimentare Arduino tramite un piccolo trasformatore ed una prolunga dalla rete di casa, ma i disturbi, che si manifestano in un aumento della distanza pur restando fermi, o un azzeramento pur senza premere il relativo pulsante, non sembrano diminuire. Non mi sento di escludere l'alimentazione dalle cause, ma sicuramente non è il problema principale.

Domani proverò ad utilizzare un altro sensore, collegandolo provvisoriamente allo strumento e tenendo a mano il cavo dentro l'abitacolo, lontano dal motore, così da capire se possa essere il cavo non schermato la fonte dei disturbi. In caso positivo provvederò ad utilizzare un cavo con schermatura.

Se invece dovesse essere proprio la troppa vicinanza di Arduino al motore che crea problemi? Si può risolvere rivestendo il case con nastro alluminio e mettendolo a massa?

Allego infine il codice definitivo, con solo qualche lievissimo ritocco dall'ultimo postato.

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

#include <TM1637Display.h>
#define CLK1 12
#define DIO1 11
#define CLK2 10
#define DIO2 9
TM1637Display display1(CLK1, DIO1);
TM1637Display display2(CLK2, DIO2);

const byte switch_1 = 3;                // switch tra dist - time               ---->  lo switch avviene mandando a massa i pin per poter utilizzare la resistenza di pullup interna
const byte switch_3 = 4;                // switch tra avanti - indietro
const byte switch_4 = 5;                // switch tra a - b
const byte azzera   = 6;                // azzeramento                          ---->  l'azzeramento avviene mandando a massa il pin per poter utilizzare la resistenza di pullup interna

float trip_a, trip_b, odo;
unsigned long t_parz_a, t_parz_b, t_tot;
unsigned long t0_a = 0, t0_b = 0, t_disp = 0;

volatile long a = 0;                    // a --> trip a
volatile long b = 0;                    // b --> trip b
volatile unsigned long c = 0;           // c --> odo

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

const int azzeraDelay = 250;


void contatore() {
  if (digitalRead(switch_3) == LOW) {      // marcia avanti
    a++;
    b++;
  }
  if (digitalRead(switch_3) == HIGH) {     // marcia indietro
    a--;
    b--;
  }
  c++;
}


void setup() {
  
  //Serial.begin(9600);
  
  pinMode(switch_1, INPUT_PULLUP);
  pinMode(switch_3, INPUT_PULLUP);
  pinMode(switch_4, INPUT_PULLUP);
  pinMode(azzera, INPUT_PULLUP);

  display1.setBrightness(7, true);
  display2.setBrightness(7, true);

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


void loop() {

  trip_a = a * dist;                                 // [m]
  trip_b = b * dist;                                 // [m]
  odo = c * dist / 1000;                             // [km]

  t_parz_a = (millis() - t0_a) / 1000;               // [s]
  t_parz_b = (millis() - t0_b) / 1000;               // [s]
  t_tot = millis() / 1000;                           // [s]

  //Serial.println(a);

  if (digitalRead(switch_1) == LOW) {                             // visualizza le distanze su schermo 1 e 2
    display2.showNumberDec(odo);

    if (digitalRead(switch_4) == LOW) {                           // visualizza trip_a su schermo 1
      display1.showNumberDec(trip_a);
    }

    if (digitalRead(switch_4) == HIGH) {                          // visualizza trip_b su schermo 1
      display1.showNumberDec(trip_b);
    }
  }

  if (digitalRead(switch_1) == HIGH) {                            // visualizza i tempi su schermo 1 e 2

    int ore_tot = t_tot / 3600;
    int minuti_tot = t_tot % 3600 / 60;
    int disp_tot = ore_tot * 100 + minuti_tot;

    int minuti_a = t_parz_a / 60;
    int secondi_a = t_parz_a % 60;
    int disp_a = minuti_a * 100 + secondi_a;

    int minuti_b = t_parz_b / 60;
    int secondi_b = t_parz_b % 60;
    int disp_b = minuti_b * 100 + secondi_b;

    if (millis() - t_disp >= 1000) {

      t_disp = millis();

      display2.showNumberDecEx(disp_tot, 0b11100000, true);

      if (digitalRead(switch_4) == LOW) {                         // visualizza t_parz_a su schermo 1
        display1.showNumberDecEx(disp_a, 0b11100000, true);
      }

      if (digitalRead(switch_4) == HIGH) {                        // visualizza t_parz_b su schermo 1
        display1.showNumberDecEx(disp_b, 0b11100000, true);
      }
    }
  }

  if (digitalRead(azzera) == LOW) {

    delay(azzeraDelay);

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == LOW) {
      a = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == LOW && digitalRead(switch_4) == HIGH) {
      b = 0;
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == LOW) {
      t0_a = millis();
    }

    if (digitalRead(azzera) == LOW && digitalRead(switch_1) == HIGH && digitalRead(switch_4) == HIGH) {
      t0_b = millis();
    }
  }

}

Ancora una volta grazie.

Potresti provare a mettere arduino in un contenitore metallico posto a massa.
Altre cose che potresti provare per eliminare i disturbi è mettere in seria all'alimentazione dell'arduino, sia sul + che sul -, due impedenza VK100. Se per i sensori utilizzi un cavo mettine uno schermato con la calza collegata solo dal lato scheda arduino.

Aggiornamento

Provando a scollegare il cavo del sensore, mettendo a massa il pin di Arduino che utilizzo con l'interrupt per far avanzare il contatore, il disturbo non si presenta. Da questo presumo che il disturbo derivi esclusivamente dal cavo non schermato.
Avrei necessità di portare al sensore l'alimentazione (+ e -) ed il cavo del segnale, quindi in tutto tre fili.
Nel caso di cavo schermato, posso utilizzare la calza per collegare il negativo al sensore (quindi utilizzare un cavo con due fili + la calza), oppure è necessario un cavo con tre fili + la calza? Ed in questo ultimo caso come dovrei collegare la calza?

Grazie dell'aiuto.

Usa una coppia schermata (2 conduttori + schermo). Con la calza trasporti il negativo di alimentazione (massa). E' il cavo che si usa comunemente per i microfoni e, in generale, per i segnali audio bilanciati.

https://www.google.com/search?tbm=isch&q=cavo+audio+microfonico+bobina

Grazie :wink:

Prego :slight_smile:

Esistono l'economico cavo per impianti atifurto, con schermo di alluminio, e gli ottimi Tasker C114 e C128 flessibili con rivestimento gommoso.