Chronomètre au millième près

Bonjour,

Je viens demander votre aide car je rencontre un problème avec mon programme. Je souhaite réaliser un chronomètre précis au millième près, et voir les valeurs sur le moniteur série intégré au logiciel Arduino. Le programme march normalement, mais il avance trop lentement par rapport à la réalité. Je ne sait pas si ça viens de mon programme, ou de la carte que j'utilise.
Je précise que je suis débutant en Arduino.
J'utilise une Arduino Léonardo.

Le programme est le suivant:

int MS = 0;
int S = 0;
int M = 0;

void setup()
{
Serial.begin (9600);
}

void loop()
{
Serial.print ("MS = ");
Serial.println (MS);
Serial.print ("S = ");
Serial.println (S);
Serial.print ("M = ");
Serial.println (M);
delay (1);
MS = MS + 1;
if (MS == 1000)
{
S = S + 1;
MS = 0;
}
if (S == 60)
{
M = M + 1;
S = 0;
}
}

Auriez-vous une solution ?

Merci d'avance.

Bonjour,

Tu utilises un delay() qui se cumule avec le temps mis par les autres instructions . Il faut utiliser la fonction millis().

int MS = 0; 
int S = 0; 
int M = 0; 

unsigned long start;

void setup() 
{
  Serial.begin (9600);
  start=millis();
}

void loop() 
{
  Serial.print ("MS = ");
  Serial.println (MS);
  Serial.print ("S = ");
  Serial.println (S);
  Serial.print ("M = ");
  Serial.println (M);
  MS = millis()-start;
  if (MS >= 1000)
  {
    S = S + 1;
    MS -= 1000;
  }
  if (S >= 60)
  {
    M = M + 1;
    S = 0;
  }
}

PS: pour mettre ton code entre balises c'est ici.

Merci de ta réponse.
Il y a un problème, le programme que tu m'as donné ne fonctionne pas. Il compte mais les MS montent jusqu'à 20000 voir plus.
Est-ce normal ?

Merci.

Non ce n'est pas normal.
J'avais fait une correction sur ma première version
Vérifie cette partie

 if (MS >= 1000)
 {
   S = S + 1;
   MS -= 1000;
 }

Bonjour,
désoler de la réponse tardive,
ça ne fonctionne toujours pas. J’ai cherché à savoir comment fonctionne la fonction millis mais je n’ai rein trouvé de compréhensible.
Les valeurs augmentent à une vitesse très élevée et finissent par se bloquer avec:
MS = -23386
S = 45
M = 925

Je je comprend pas comment c’est possible.

@Kamill
MS -= 1000 pour dire avant MS = millis()-start;
ca ne serait pas MS = 0;

  if (MS >= 1000)
  {
    S = S + 1;
    MS -= 1000; //??????????????
  }
  if (S >= 60)
  {
    M = M + 1;
    S = 0;
  }

au bout d'un moment MS va être > 32,767 en + ou - donc plus int mais unsigned long

Bonjour,

Met ton dernier code

@infobarquee
Non c'est bien MS-1000 car du fait de l'affichage qui peut durer (largement ?) plus de 1ms quand tu arrives au test tu peux avoir MS=1000 ou 1002 ou peut être plus, donc il faut incrémenter les secondes, mais ne pas perdre les ms en trop sous peine de retard.

Mon dernier code c'est celui là :

int MS = 0; 
int S = 0; 
int M = 0; 

unsigned long start;

void setup() 
{
  Serial.begin (9600);
  start=millis();
}

void loop() 
{
  Serial.print ("MS = ");
  Serial.println (MS);
  Serial.print ("S = ");
  Serial.println (S);
  Serial.print ("M = ");
  Serial.println (M);
  MS = millis()-start;
  if (MS >= 1000)
  {
    S = S + 1;
    MS -= 1000;
  }
  if (S >= 60)
  {
    M = M + 1;
    S = 0;
  }
}

Je tiens à préciser que je ne connaissait pas la fonction millis, et je ne sait pas comment elle fonctionne.

Bonjour,

un code complet ici : http://forum.arduino.cc/index.php?topic=33147.0

sinon, plus simple mais pas testé :

unsigned long MS; 
unsigned long start;

void setup() 
{ 
  Serial.begin (9600);                  // Serial.begin (115200);
  start=millis();
}

void loop() 
{
  MS = millis()-start;
/*
  centitot1 = (MS % 1000) / 10 ;        // centieme to display
  secotot1 = (MS / 1000) % 60 ;         // second to display
  minutot1 = (MS / 1000) / 60 ;         // minute to display
*/
  Serial.print ((MS / 1000) / 60);      // minutes
  Serial.print ("' ");
  Serial.print ((MS / 1000) % 60);      // secondes
  Serial.print ("'' ");
  Serial.println (MS % 1000);           // millièmes
}

fablath:
Bonjour,

un code complet ici : http://forum.arduino.cc/index.php?topic=33147.0

sinon, plus simple mais pas testé :

unsigned long MS; 

unsigned long start;

void setup()
{
  Serial.begin (9600);                  // Serial.begin (115200);
  start=millis();
}

void loop()
{
  MS = millis()-start;
/*
  centitot1 = (MS % 1000) / 10 ;        // centieme to display
  secotot1 = (MS / 1000) % 60 ;        // second to display
  minutot1 = (MS / 1000) / 60 ;        // minute to display
*/
  Serial.print ((MS / 1000) / 60);      // minutes
  Serial.print ("' ");
  Serial.print ((MS / 1000) % 60);      // secondes
  Serial.print ("'' ");
  Serial.println (MS % 1000);          // millièmes
}

Merci !! Le programme que tu viens de me donner fonctionne parfaitement !
Pourrais-je avoir quelques explications sur la fonction millis, notamment sur le "start = millis" et le "MS = millis-start". Ça servira toujours de savoir ça, surtout si je dois rajouter des choses au programme.
Merci !

Millis est une valeur qui augmente depuis l’allumage de la carte.

start=millis donne à start la valeur de millis a ce moment, start reste constant alors que millis continue d’augmenter… la différence entre les deux te donne le temps écoulé en µseconde.

D'accord c'est bon à savoir.
Je souhaite que le chronomètre se lance lorsque j'appui sur un bouton. Dans le fond ça marche, mais le problème c'est que lorsque j'appui sur le bouton, c'est l'affichage qui se lance, et pas le chronomètre, qui lui tourne déjà sans que j'ai à appuyer sur le bouton.

unsigned long MS; 
unsigned long start;
int bouton = A0;
int B = 0;

void setup() 
{ 
  Serial.begin (9600);                  // Serial.begin (115200);
  start=millis();
  pinMode (bouton, INPUT);
}

void loop() 
{
int  btn = digitalRead (bouton);
if (btn == HIGH)
{
  B = B + 1;
}
if (B >= 1)
{
  MS = millis()-start;
/*
  centitot1 = (MS % 1000) / 10 ;        // centieme to display
  secotot1 = (MS / 1000) % 60 ;         // second to display
  minutot1 = (MS / 1000) / 60 ;         // minute to display
*/
  Serial.print ((MS / 1000) / 60);      // minutes
  Serial.print ("' ");
  Serial.print ((MS / 1000) % 60);      // secondes
  Serial.print ("'' ");
  Serial.println (MS % 1000);           // millièmes
}
}

suffit de déplacer start=millis(); lorsque le bouton est appuyé

Donc si j'ai bien compris, mettre le start=millis(); dans la boucle if (B >= 1) ?
C'est ce que je viens de faire, et le moniteur m'affiche toujours 0 :frowning:

unsigned long MS; 
unsigned long start;
int bouton = A0;
int B = 0;

void setup() 
{ 
  Serial.begin (9600);                  // Serial.begin (115200);
  pinMode (bouton, INPUT);
}

void loop() 
{
int  btn = digitalRead (bouton);
if (btn == HIGH)
{
  B = B + 1;
}
if (B >= 1)
{
  start=millis();
  MS = millis()-start;
/*
  centitot1 = (MS % 1000) / 10 ;        // centieme to display
  secotot1 = (MS / 1000) % 60 ;         // second to display
  minutot1 = (MS / 1000) / 60 ;         // minute to display
*/
  Serial.print ((MS / 1000) / 60);      // minutes
  Serial.print ("' ");
  Serial.print ((MS / 1000) % 60);      // secondes
  Serial.print ("'' ");
  Serial.println (MS % 1000);           // millièmes
}
}

il suffit de mettre start=millis() quand le bouton est appuyé :

unsigned long MS; 
unsigned long start;
int bouton = A0;

void setup() 
{ 
  Serial.begin (9600);                  // Serial.begin (115200);
  pinMode (bouton, INPUT);
}

void loop() 
{
  int  btn = digitalRead (bouton);
  if (btn == HIGH)
  {
    start=millis();
  }

  MS = millis()-start;
  /*
  centitot1 = (MS % 1000) / 10 ;        // centieme to display
   secotot1 = (MS / 1000) % 60 ;         // second to display
   minutot1 = (MS / 1000) / 60 ;         // minute to display
   */
  Serial.print ((MS / 1000) / 60);      // minutes
  Serial.print ("' ");
  Serial.print ((MS / 1000) % 60);      // secondes
  Serial.print ("'' ");
  Serial.println (MS % 1000);           // millièmes
}

Effectivement là ça marche, je m’étais trompé de boucle.
Et autre petite question (surement la dernière): puis-je mettre plusieurs start=millis(), par exemple start1=millis() et start2=millis ?

oui
si tu cherche un truc pour calculer le temps sur plusieurs tours, recherche sur le forum, ca a déjà été fait

Non, ce n'est pas pour les tours, c'est pour calculer le temps de course de 2 voitures en simultané, avec affichage sur un moniteur.
Mais là je pense avoir toutes les réponses à mes questions !
Merci à tout le monde !

tu vas te butter sur un "problème" dans ce cas.
comment arrêter les chrono?

par toi avec 2 boutons =>>> quelques 1/1000 de différence

voiture en 1:1 ou modelisme?

Petite voiture de modélisme en 1vs1 sur une ligne droite de 20 mètres.
J'avais penser que lorsque les voitures terminent leurs course, j'affiche le résultat du moment sur un moniteur, mais il est vrai que je ne m'était pas penché sur la question.