Arduino Forum

International => Italiano => Generale => Topic started by: photobyfs on Jul 18, 2019, 09:55 am

Title: Cronometro TM1637
Post by: photobyfs on Jul 18, 2019, 09:55 am
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

Code: [Select]

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

}
Title: Re: Cronometro TM1637
Post by: pgiagno on Jul 18, 2019, 11:37 am
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

Code: [Select]
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.
Title: Re: Cronometro TM1637
Post by: Datman on Jul 18, 2019, 12:45 pm
Dovendo avere una risoluzione di 1 secondo, fai l'aggiornamento del display solo una volta al secondo:
Code: [Select]
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:
Code: [Select]
uint8_t minuti;
uint8_t secondi;

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


Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 18, 2019, 02:10 pm
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.

Code: [Select]
#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();
  }
}



Quote
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).


Quote
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?
Code: [Select]

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


Title: Re: Cronometro TM1637
Post by: pgiagno on Jul 18, 2019, 02:47 pm
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.
Title: Re: Cronometro TM1637
Post by: Datman on Jul 18, 2019, 03:20 pm
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.

Code: [Select]
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:
Code: [Select]
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.
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 18, 2019, 10:15 pm
Quote
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.

Code: [Select]

  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!
Title: Re: Cronometro TM1637
Post by: pgiagno on Jul 19, 2019, 08:02 am
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:

Code: [Select]
  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.
Title: Re: Cronometro TM1637
Post by: Datman on Jul 19, 2019, 08:25 am
Dice chiaramente che per "azzeramento" intende il porre a zero la differenza tra millis() e t0, ponendo t0=millis().
Title: Re: Cronometro TM1637
Post by: paolo311 on Jul 19, 2019, 09:37 am
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
Title: Re: Cronometro TM1637
Post by: Datman on Jul 19, 2019, 10:29 am
Se non ti sei capito nemmeno tu, è un problema.
Title: Re: Cronometro TM1637
Post by: pgiagno on Jul 19, 2019, 10:39 am
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.
Title: Re: Cronometro TM1637
Post by: gpb01 on Jul 19, 2019, 10:41 am
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.  :smiley-confuse:

Guglielmo
Title: Re: Cronometro TM1637
Post by: Datman on Jul 19, 2019, 02:13 pm
Dato che parla di letture di velocità, potrebbe anche essere un pulseIn che rallenta enormemente il loop.
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 19, 2019, 11:15 pm
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.

Code: [Select]

#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...
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 19, 2019, 11:22 pm
Code: [Select]


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();
    }
  }
}
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 19, 2019, 11:29 pm
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:

Code: [Select]
 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!
Title: Re: Cronometro TM1637
Post by: pgiagno on Jul 20, 2019, 09:02 am
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.

Code: [Select]


#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.
Title: Re: Cronometro TM1637
Post by: Datman on Jul 20, 2019, 09:09 pm
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!
Title: Re: Cronometro TM1637
Post by: paolo311 on Jul 21, 2019, 10:14 pm
A me risulta che in un ora ci siano 3600 secondi (60*60..) non 3200 ;)

Code: [Select]

  //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:

Code: [Select]

    //                                                                     // 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
Title: Re: Cronometro TM1637
Post by: pgiagno on Jul 22, 2019, 06:56 am
A me risulta che in un ora ci siano 3600 secondi (60*60..) non 3200 ;)
E bravo Paolo! Ottima vista sulle sviste!
Occorre sostituire 3600 a 3200.

Ciao,
P.
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 23, 2019, 07:28 pm
Perdonate il ritardo nella risposta, in questi giorni sono stato lontano dal PC.

Quote
A me risulta che in un ora ci siano 3600 secondi (60*60..) non 3200 ;)
Quote
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).
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 23, 2019, 08:19 pm
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.

Code: [Select]


#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.

Code: [Select]
////////////////////////////////////////////////////////////////////////////////// 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();
    }
  }

}







Title: Re: Cronometro TM1637
Post by: gpb01 on Jul 23, 2019, 08:36 pm
.... 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 % (https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/remainder/) un valore ... float !!!   3600.0, scritto così, è un float !!!

Guglielmo
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 23, 2019, 09:45 pm
No, NON gradisce che tu dia in pasto all'operatore % (https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/remainder/) un valore ... float !!!   3600.0, scritto così, è un float !!!

Guglielmo
Senza dubbio hai ragione!   :smiley-eek:

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

Code: [Select]
////////////////////////////////////////////////////////////////////////////////// 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();
    }
  }

}
Title: Re: Cronometro TM1637
Post by: photobyfs on Jul 23, 2019, 10:10 pm
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  :)


Title: Re: Cronometro TM1637
Post by: photobyfs on Aug 28, 2019, 11:41 pm
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.

Code: [Select]
////////////////////////////////////////////////////////////////////////////////// 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.
Title: Re: Cronometro TM1637
Post by: Arco_500 on Aug 29, 2019, 09:15 am
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.
Title: Re: Cronometro TM1637
Post by: photobyfs on Sep 03, 2019, 03:29 pm
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.
Title: Re: Cronometro TM1637
Post by: Datman on Sep 03, 2019, 03:48 pm
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 (https://www.google.com/search?tbm=isch&q=cavo+audio+microfonico+bobina)

(https://assets.highlite.com/catalog/product/cache/74c1057f7991b4edb2bc7bdaa94de933/d/9/d9435b.jpg)
Title: Re: Cronometro TM1637
Post by: photobyfs on Sep 05, 2019, 02:09 pm
Grazie ;)
Title: Re: Cronometro TM1637
Post by: Datman on Sep 05, 2019, 02:13 pm
Prego :)

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