Cronometro TM1637

Buongiorno,

come da titolo sto cercando di visualizzare un cronometro su un display TM1637.
Nonostante la poca esperienza, dopo un po' di riflessione ho scritto il codice, che a livello matematico funziona correttamente.
L'unico problema che riscontro è che la visualizzazione non è "fluida": spesso i secondi rallentano per poi avanzare rapidamente, addirittura saltando un numero! Come se il processore fosse troppo "impegnato" nello svolgere i calcoli, che non sembrano però così impegnativi!

Esempio:
invece di procedere con 45:12 45:13 45:14 45:15 45:16
visualizzo magari 45:12 45:13 45:13 45:15 45:16

Come posso risolvere l'inconveniente?
Allego parte del codice, in quanto in realtà il cronometro è solo una piccola parte di un codice molto più strutturato.

Grazie

#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;
unsigned long t0_a = 0, t0_b = 0;


void setup() {
  display1.setBrightness(7, true);
  display2.setBrightness(7, true);
}


void loop() {

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


                                                            // 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);

}

Non avendo lo sketch completo posso solo dire che non capisco la gestione di millis().

Un esempio di cronometro semplice al decimo di secondo potrebbe essere questo

unsigned long t_tot, t_init, t_clock;

void setup() {
  //..
  t_clock = 100;        //precisione del decimo di secondo
  t_init = millis();
}

void loop() {
  if (millis() - t_init >= t_clock) {
    t_init = millis();
    // Sono passati 100 millisecondi
    // Aggiorna il display
    //...
    // Fai quello che devi fare
    //...
  }
  // Se hai altro da fare, fallo qui, senza usare "delay();"
}

Ciao,
P.

Dovendo avere una risoluzione di 1 secondo, fai l'aggiornamento del display solo una volta al secondo:

unsigned long t;

if(millis()-t>999)
 {
 t=millis();
 display();
 }

Considera, però, che potrebbe anche essere il resto del programma a rallentare il loop!
Comunque, per i calcoli che fai non è necessario usare variabili float:

uint8_t minuti;
uint8_t secondi;

minuti=secondiTotali/60;
secondi=seconditotali%60;

pgiagno:
Non avendo lo sketch completo posso solo dire che non capisco la gestione di millis().

Effettivamente non ho spiegato l'utilizzo della variabile t0: serve per azzerare il cronometro. In pratica alla pressione di un tasto, t0=millis() ed i secondi totali sono millis()-t0, quindi di fatto ripartono da zero!

Riporto il codice con la parte di azzeramento, per essere più chiaro.

#include <TM1637Display.h>
#define CLK1 12
#define DIO1 11
TM1637Display display(CLK1, DIO1);

unsigned long t_parz, t_tot;
unsigned long t0 = 0;

#define azzera 6

void setup() {
  display.setBrightness(7, true);
}


void loop() {

  t_parz = (millis() - t0) / 1000;                   // [s]
  t_tot = millis() / 1000;                           // [s]

  //                                                        // esempio 429 secondi              // esempio 43 secondi
  float numero = t_parz / 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;
  display.showNumberDecEx(disp, 0b11100000, true);

  if (digitalRead(azzera) == LOW) {
    t0 = millis();
  }
}

Comunque, per i calcoli che fai non è necessario usare variabili float

Non conosco il tipo di variabile che mi hai indicato! Dovendo utilizzare numeri con la virgola, sbaglio ad usare float?
Il mio scopo è, da un dato iniziale in secondi (es 4973) ottenere la visualizzazione in minuti:secondi, peraltro salvata in una sola variabile (nell'esempio 82:53, da inviare al display come un int 8253).

Dovendo avere una risoluzione di 1 secondo, fai l'aggiornamento del display solo una volta al secondo

Quindi nel mio codice invece di lasciare display.showNumberDecEx(disp, 0b11100000, true); libero nel loop, lo dovrei scrivere come segue?

if(millis()-t>999) {
 t=millis();
 display.showNumberDecEx(disp, 0b11100000, true);
}

Provo a capire cosa vuoi fare

  • Un cronometro che parte alla pressione di un pulsante A, visualizzando in tempo reale il passare del tempo
  • Che si ferma, dando un tempo parziale, alla pressione di un pulsante B, continuando a contare il tempo in background
  • Che riprende la visualizzazione corrente in tempo reale alla successiva pressione del pulsante B
    . Che si ferma alla pressione di un pulsante C
  • Che si azzera alla successiva pressione del pulsante C

È questo che vuoi fare? Qualcosa di più semplice? di più complicato?

Se sì, che precisione vuoi? Il secondo va bene?

Ciao,
P.

uint8_t è il tipo generico di una variabile a 8 bit senza segno con valore che può andare, quindi, da 0 a 255. Nel caso specifico di Arduino equivale a byte. Se vuoi metterci minuti e secondi, ti serve un unsigned int (tipo generico: uint16_t, cioè unsigned int 16 bit), che arriva a 65535.

int disp=100*(t_parz/60) +t_parz%60;
// Può arrivare a 255 minuti e 59 secondi (4 ore e quasi 16 min.).

Fai attenzione a fare la scrittura sul display una volta al secondo in sincronia con il calcolo, altrimenti puoi avere errori di un secondo:

if(millis()-t0>999)
  {
  t0=millis();
  t_parz++;
  int disp=100*(t_parz/60) +t_parz%60;
  display.showNumberDecEx(disp, 0b11100000, true);
  }

Tieni presente che la precisione del tuo cronometro dipende dalla precisione della frequenza di clock del microcontrollore che, in Arduino Uno, è prodotta da un risuonatore ceramico, meno preciso di un quarzo.
Per avere una precisione maggiore devi usare una scheda che abbia il quarzo oppure montare il microcontrollore su un circuito stampato o mille fori con un quarzo da 16Mhz e relativi condensatori da 22pF.

Provo a capire cosa vuoi fare

  • Un cronometro che parte alla pressione di un pulsante A, visualizzando in tempo reale il passare del tempo
  • Che si ferma, dando un tempo parziale, alla pressione di un pulsante B, continuando a contare il tempo in background
  • Che riprende la visualizzazione corrente in tempo reale alla successiva pressione del pulsante B
    . Che si ferma alla pressione di un pulsante C
  • Che si azzera alla successiva pressione del pulsante C

È questo che vuoi fare? Qualcosa di più semplice? di più complicato?

Se sì, che precisione vuoi? Il secondo va bene?

Ciao,
P.

Sto cercando di creare un tripmaster per auto, che in pratica funziona come un contakm di bicicletta! Quindi assieme alla visualizzazione della velocità e della distanza percorsa mi interessa anche il tempo.
Fisicamente sarà realizzato con due schermi, uno per rappresentare le quantità TOTALI, ed uno le quantità PARZIALI, queste ultime suddivise in trip_a e trip_b.
Quindi a seconda delle posizioni degli switch visualizzerò distanza totale e distanza parziale (a o b), oppure tempo totale e tempo parziale (a o b).

In particolare il cronometro:

  • si avvia all'accensione dell'apparecchio
  • si azzera alla pressione di un tasto (solo il parziale, a o b che sia)

La parte dell distanza è relativamente semplice e già funziona. Ora sto ragionando sulla parte legata al cronometro. Il codice riportato funziona, ma va "a scatti" e non è bellissimo da vedere.
Non ho necessità di grande precisione, sarà utilizzato per 8 ore al massimo, tra l'altro i parziali verranno azzerati ogni pochi minuti, quindi la risoluzione del piccolo Arduino è più che sufficiente.

Tra l'altro ho notato un ulteriore problema: se nello schermo dei parziali visualizzo min:sec, e nello schermo dei totali visualizzo ore:min, i minuti non sono sincronizzati! E' per un problema di arrotondamento? Allego estratto del codice.

Grazie delle risposte.

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

La logica che ho pensato è la seguente:

  • se switch_1 è HIGH allora negli schermi visualizzo i tempi (altrimenti le distanze)
  • in ogni caso sul primo schermo visualizzo i tempi totali
  • poi discrimino per il secondo schermo se lo switch è su trip_a o trip_b
  • in base a questo su quello schermo visualizzo il tempo parziale (che finchè non azzero corrisponderà in realtà al totale, a differenza della visualizzazione in min:sec piuttosto che in ore:sec)

Non capisco perchè nello schermo dei totali i minuti scattino con un certo anticipo (diversi secondi) rispetto allo schermo dei parziali!
Come dicevo presumo per un arrotondamento nei calcoli...boh!

Penso che il problema sia nella gestione di millis().

Devi considerare millis() come un contatore che parte da 0 quando il programma va in esecuzione e continua a incrementarsi ogni millisecondo per circa 50 giorni, a meno che il programma non venga fatto ripartire. Non c'è altro modo di "azzerare" millis() se non con un reset

Quindi il passare del tempo viene sempre calcolato come differenza fra due valori.

Quindi il tempo t0_sec è dato da t0_sec = millis(), il passaggio di un secondo viene calcolato quando millis() - t0_sec = 1000. In realtà conviene scrivere millis() - t0_sec >= 1000 per sicurezza.

A questo punto la prima cosa da fare è "riarmare" t0_sec con un nuovo t0_sec = millis(). Ed è la prima istruzione da eseguire per avere la massima precisione che, come dice Datman, non è eccelsa, ma nel tuo caso più che sufficiente.

Se si vuole un calcolo del tempo trascorso dall'inizio, basta mettere t0_iniz = millis() al termine del setup e calcolare il tempo trascorso con t_elapsed = millis() - t0_iniz.

Conviene inoltre mantenere l'orario in termini di millisecondi, in una variabile unsigned long e decodificare ore, minuti e secondi al momento del display.

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.

Dice chiaramente che per "azzeramento" intende il porre a zero la differenza tra millis() e t0, ponendo t0=millis().

Secondo me il problema degli "scatti" dipende dal fatto che il valore restituito da millis() si incrementa in maniera asincrona, mentre la visualizzazione dei valori è sincrona al loop.

Questo implica che la velocità di resfresh degli schermi dipende da quanto ci impiega il loop ad eseguire un ciclo completo. Se il requisito è che lo schermo debba "snocciolare" un secondo per volta, bisogna essere sicuri che il loop, nel caso peggiore, ci impieghi meno di un secondo ad essere eseguito; altrimenti il refresh dello schermo accumulerà ritardo fino a saltare un secondo, pur mostrando un valore esatto.

Per i minuti "diversi" devi verificare se l'intervallo mostrato è il medesimo, l'algoritmo di calcolo è lo stesso e i schemi vengono refreshati diciamo nello stesso istante; se una di queste 3 cose non avviene, è probabile che i due valori mostrati siano diversi.

Non so se mi sono capito.

Ciao
Paolo

Se non ti sei capito nemmeno tu, è un problema.

Come sempre succede è necessario l'INTERO sketch con la configurazione HW ed eventualmente lo schema elettrico.

Se questo non è possibile, mi fermo qui.

Ciao,
P.

paolo311 ha ragione. Purtroppo la visulalizzazione corretta dei valori del tempo è sempre causa di problemi, salvo la funzione loop() non giri almeno il doppio più veloce della cifra significativa che si vuole visualizzare, altrimenti ... gli avanzamenti a scatti sono la norma. :confused:

Guglielmo

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