Go Down

Topic: Compte Tour Chronomètre Slot Racing et fonction Millis (Read 177 times) previous topic - next topic

unguibus

Bonjour,

Voici un projet que je reprends en main après l'avoir abandonné pendant presque un an. J'ai débuté l'arduino avec ce montage et je n'avais aucune connaissance en programmation et à peine en électronique. J'ai récupéré des informations à gauche et à droite pour obtenir le compte rour ci-dessous. Je n'avais à l'époque pas trouvé de solution à mon problème de Chronometrage. Les différents Chronomètres perdaient certainement la tête à cause de la fonction Millis.

Voici la présentation du montage:

ce montage est équipé d'un arduino Uno, d'un écran LCD 20x4, une photodiode pour detecter le passage de la voiture, d'un buzzer, 1 double afficheur 7 Digit pour le nombre de tour restant à effectué, d'un bouton pour incrémenter le nombre de tour à effectuer et de diode de couleurs pour le départ, meilleur tour...



L'écran LCD affiche plusieurs informations:
- Nombre de tour réalisé (ligne 1 à Droite - R/4 sur la photo) couplé à l'afficheur 7 digit
- Temps du tour précédent ( Ligne 1 à gauche - Go sur la photo car 1er tour)
- Temps du tour en cours (Ligne 2)
- Temps du meilleur tour (Ligne 3)
- Temps Total (Ligne 4)


Description du problème:

A l'origine, j'avais un écran LCD deux lignes et les différents temps s'affichaient alternativement sans aucun problème dans le chronométrage
Avec un écran 4 lignes, on dirait que le temps se mélange entre toute les lignes de Chronométrage.
Au bout de 30 secondes de tentmps total, le temps de la ligne 2 passe à 1 minute, bug sur le meilleur temps au tour... Voici le lien vers la video

https://www.youtube.com/watch?v=TT4gqhCh_qY



Code Partie 1:
Code: [Select]
// include the library code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,20,4);  //l adresse 0x27 est a changé en fonction de votre écrant

// Broches du CD4511 et du point décimal de l'afficheur
const byte PIN_CD4511_A1 = 2;
const byte PIN_CD4511_A2 = 3;
const byte PIN_CD4511_A3 = 4;
const byte PIN_CD4511_A4 = 5;

// 11 non branché
const byte PIN_SEGMENT_DP = 11;

// définitions des broches des transistors pour chaque afficheur
const int alim_dizaine = 7; // les dizaines
const int alim_unite = 6;   // les unites

byte chiffre = 0;
static byte etat_dp = 0;

const int photoPin = 0; // analog input of the photoresistor

const int RED_PIN = 8; // red LED
const int YELLOW_PIN = 9; // yellow LED
const int GREEN_PIN = 10; // green LED

const int BUZZER_PIN = 12;
const int BUTTON_PIN = 13;

const int CONFIG = 0;
const int RACE = 1;
const int FINISH = 2;

int mode = CONFIG;

boolean buttonWasPressed = false;

const int TOTAL_LAP_INCREMENT = 1 ;
const int TOTAL_LAP_DECREMENT = 1;
const int MAX_TOTAL_LAPS = 99;

long raceStart;
long totalLaps = TOTAL_LAP_INCREMENT;
int lap;
long decrementation = TOTAL_LAP_DECREMENT;
int lapStart;
long lastLapTime;
long lastTotalTimeSeconds;
boolean newLapStarted = false;

long bestTime = 100000;

const int BARRIER_THRESHOLD_LOW = 900;
const int BARRIER_THRESHOLD_HIGH = 950;

const int BARRIER_OPENED = 0;
const int BARRIER_CLOSED = 1;
const int BARRIER_NOCHANGE = 2;
boolean barrierClosed = false;

const int MINIMUM_LAP_TIME_MILLIS = 300;
const int LAST_LAP_DISPLAY_MILLIS = 1500;

const int COL_TOTAL_LAPS = 2;
const int COL_LIGHT = 8;
const int COL_LAP_TOTAL = 1;
const int COL_LAP_TIME = 7;

const int PRECISION_SECONDS = 0;
const int PRECISION_TENS = 1;
const int PRECISION_MILLIS = 2;

const int SHOW_LAP = 0;
const int SHOW_TOTAL_TIME = 1;
int lapTimeMode;

const char TOTAL_LAPS_MARKER = 'R';
const char TOTAL_TIME_MARKER = 'G';
const char FASTEST_LAP_MARKER = 'B';
const char LAP_TIME_MARKER = 'Z';
const char LIGHT_MARKER = 'L';

boolean ledsOn;

// Fonction setup() afficheur 7 digit
void setup() {
  lcd.init();                      // initialize the lcd
   
  /* Toutes les broches en sorties */
  pinMode(PIN_CD4511_A1, OUTPUT);
  digitalWrite(PIN_CD4511_A1, LOW);
  pinMode(PIN_CD4511_A2, OUTPUT);
  digitalWrite(PIN_CD4511_A2, LOW);
  pinMode(PIN_CD4511_A3, OUTPUT);
  digitalWrite(PIN_CD4511_A3, LOW);
  pinMode(PIN_CD4511_A4, OUTPUT);
  digitalWrite(PIN_CD4511_A4, LOW);
  pinMode(PIN_SEGMENT_DP, OUTPUT);
  digitalWrite(PIN_SEGMENT_DP, LOW);
  pinMode(alim_dizaine, OUTPUT);
  pinMode(alim_unite, OUTPUT);
  digitalWrite(alim_dizaine, LOW);
  digitalWrite(alim_unite, LOW);
  pinMode(RED_PIN, OUTPUT);
  pinMode(YELLOW_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);
  lcd.begin(20, 4);
 
  Serial.begin(57600);
 
  readySetGo();
  initConfig();
}   



unguibus

Code Partie 2:
Code: [Select]
// Fonction loop()
void loop() {
  char i = decrementation;
    {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(i);
    }
 
  int light = analogRead(photoPin);
 
  int barrierState = checkBarrierState(light);
 
  switch (mode) {
    case CONFIG:
      doConfig(barrierState, light);
      break;
     
    case RACE:
      doRace(barrierState);
      break;
     
    case FINISH:
      doFinish();
      break;
  }
   
  delay(5);
}

// fonction permettant d'afficher un nombre sur deux afficheurs
void afficher_nombre(char nombre)
{
    long temps; // variable utilisée pour savoir le temps écoulé...
    char unite = 0, dizaine = 0; // variable pour chaque afficheur

    if(nombre > 9) // si le nombre reçu dépasse 9
    {
        dizaine = nombre / 10; // on récupère les dizaines
    }

    unite = nombre - (dizaine*10); // on récupère les unités

           {
        // on affiche le nombre

        // d'abord les dizaines pendant 10 ms

        // le transistor de l'afficheur des dizaines est saturé,
        // donc l'afficheur est allumé
        digitalWrite(alim_dizaine, HIGH);
        // on appel la fonction qui permet d'afficher le chiffre dizaine
        afficher(dizaine);
        // l'autre transistor est bloqué et l'afficheur éteint
        digitalWrite(alim_unite, LOW);
        delay(1);

        // puis les unités pendant 10 ms

        // on éteint le transistor allumé
        digitalWrite(alim_dizaine, LOW);
        // on appel la fonction qui permet d'afficher le chiffre unité
        afficher(unite);
        // et on allume l'autre
        digitalWrite(alim_unite, HIGH);
        delay(1);
    }
}

// fonction écrivant sur un seul afficheur
void afficher(char chiffre)
{
    // on met à zéro tout les bits du décodeur
    digitalWrite(PIN_CD4511_A1, LOW);
    digitalWrite(PIN_CD4511_A2, LOW);
    digitalWrite(PIN_CD4511_A3, LOW);
    digitalWrite(PIN_CD4511_A4, LOW);

    // On allume les bits nécessaires
    if(chiffre >= 8)
    {
        digitalWrite(PIN_CD4511_A4, HIGH);
        chiffre = chiffre - 8;
    }
    if(chiffre >= 4)
    {
        digitalWrite(PIN_CD4511_A3, HIGH);
        chiffre = chiffre - 4;
    }
    if(chiffre >= 2)
    {
        digitalWrite(PIN_CD4511_A2, HIGH);
        chiffre = chiffre - 2;
    }
    if(chiffre >= 1)
    {
        digitalWrite(PIN_CD4511_A1, HIGH);
        chiffre = chiffre - 1;
    }
}

void readySetGo() {
  char chiffre = totalLaps;
    static byte etat_dp = 0;
  {
      afficher(chiffre); // on appel la fonction d'affichage
        }
  char nombre = totalLaps;
  {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(totalLaps);
    }
  setLed(RED_PIN, true);
  lcd.backlight();
  lcd.print("CONFIGURATION");
  tone(BUZZER_PIN, 440, 1000);
   }

int checkBarrierState(int light) {
  int state = BARRIER_NOCHANGE;
 
  if (barrierClosed && light >= BARRIER_THRESHOLD_HIGH) {
    barrierClosed = false;
    state = BARRIER_OPENED;
    setLed(YELLOW_PIN, false);
  } else if (!barrierClosed && light <= BARRIER_THRESHOLD_LOW) {
    barrierClosed = true;
    state = BARRIER_CLOSED;
    setLed(YELLOW_PIN, true);
  }
 
  return state;
}

void initConfig() {
    char chiffre = totalLaps;
  static byte etat_dp = 0;
  {
      afficher(chiffre); // on appel la fonction d'affichage
        }
  char nombre = totalLaps;
  {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(totalLaps);
    }
  // affichage R colonne 15 ligne 0 - Supprimer les deux lignes ci dessous
  //lcd.setCursor(15, 0);
  //lcd.print(TOTAL_LAPS_MARKER);
  printTotalLaps();
  // affichage L colonne 0 ligne 1
  lcd.setCursor(COL_LIGHT - 8, 1);
  lcd.print(LIGHT_MARKER);
  lcd.print(' ');
}

void doConfig(int barrierState, int light) {
  char chiffre = totalLaps;
  static byte etat_dp = 0;
  {
      afficher(chiffre); // on appel la fonction d'affichage
        }
  char nombre = totalLaps;
  {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(totalLaps);
    }
  if (barrierState == BARRIER_CLOSED) {
    depart();
  } else {
    boolean buttonPressed = digitalRead(BUTTON_PIN) == LOW;
    if (buttonPressed && !buttonWasPressed) {
      incrementTotalLaps();
      incrementDecrementation();
    }
    buttonWasPressed = buttonPressed;
   
    printLight(light);
  }
}

void incrementDecrementation() {
  decrementation += TOTAL_LAP_DECREMENT;

  if (decrementation > MAX_TOTAL_LAPS) {
    decrementation = TOTAL_LAP_DECREMENT;
  }
}

void incrementTotalLaps() {
  totalLaps += TOTAL_LAP_INCREMENT;
 
  if (totalLaps > MAX_TOTAL_LAPS) {
    totalLaps = TOTAL_LAP_INCREMENT;
  }

  printTotalLaps();
 }

void printTotalLaps() {
  // affichage Nombre de Tour total à faire colonne 15 ligne 0
  lcd.setCursor(COL_TOTAL_LAPS + 15, 0);
  if (totalLaps < 100) {
    lcd.print(' ');
  }
  lcd.print(totalLaps);
}

void printLight(long light) {
  // affichage valeur luminosité colonne 0 ligne 1
  lcd.setCursor(COL_LIGHT - 5, 1);
  lcd.print(light);
  lcd.print("   ");
}

void depart() {
  char chiffre = totalLaps;
  static byte etat_dp = 0;
  {
      afficher(chiffre); // on appel la fonction d'affichage
  }
  char nombre = totalLaps;
  {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(nombre);
    }
 
  setLed(RED_PIN, true);
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("READY        ");
  tone(BUZZER_PIN, 440, 1000);
  delay (1000);
 
  setLed(YELLOW_PIN, true);
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("READY        ");
  tone(BUZZER_PIN, 440, 1000);
 
  setLed(GREEN_PIN, true);
  lcd.setCursor(0,0);
  lcd.print("GO         ");
  tone(BUZZER_PIN, 880, 1000);
  startRace();
}

unguibus

Code Partie 3:
Code: [Select]
void startRace() {
  char chiffre = totalLaps;
  static byte etat_dp = 0;
  {
      afficher(chiffre); // on appel la fonction d'affichage
  }
   char nombre = totalLaps;
  {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(totalLaps);
    }
  mode = RACE;
  lapTimeMode = SHOW_LAP;
  lap = 1;
  raceStart = millis();
  lapStart = raceStart;
  lastTotalTimeSeconds = 0;

  Serial.print("START ");
    setLed(GREEN_PIN, false);
  tone(BUZZER_PIN, 880, 500);
  // affichage BEST LAP: colonne 0 ligne 2
  lcd.setCursor(0, 2);
  lcd.print("BEST LAP:");
  // affichage TIME LAP: colonne 0 ligne 1
  lcd.setCursor(0, 1);
  lcd.print("TIME LAP:");
  // affichage TOTAL LAP: colonne 0 ligne 3
  lcd.setCursor(0, 3);
  lcd.print("TOTAL TIME:");
  // affichage 1/ colonne 17 ligne 0
  lcd.setCursor(16, 0);
  lcd.print("1/");
    }

void doRace(int barrierState) {
  long now = millis();
  updateLapTime(now);
  updateTotalTime(now);

  if (barrierState == BARRIER_CLOSED && lastLapTime >= MINIMUM_LAP_TIME_MILLIS) {
    newLap(now);
  }
 
  if (newLapStarted && lastLapTime >= LAST_LAP_DISPLAY_MILLIS) {
    setLed(GREEN_PIN, false);
    setLed(RED_PIN, false);
    // affichage "  " colonne 12 ligne 0
    lcd.setCursor(COL_LAP_TIME + 5,0);
    lcd.print("  ");
    newLapStarted = false;
  }
}

void newLap(long now) {
          long lapTime = now - lapStart;
  // affichage temps au tour colonne 0 ligne 0
  printTime(lapTime, COL_LAP_TIME - 7, 0, PRECISION_MILLIS);

  boolean isNewBestLap = lapTime < bestTime;
  serialPrintLapTime(lap, lapTime, isNewBestLap);

  if (isNewBestLap) {
    newBestLap(lap, lapTime);
  } else {
    noBestLap();
  }

  if (lap == totalLaps) {
    finish(now);
  } else {
    lap++;
    decrementation--;
    char chiffre = decrementation;
  static byte etat_dp = 0;
  {
      afficher(chiffre); // on appel la fonction d'affichage
  }
  char nombre = decrementation;
  {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(decrementation);
    }
    // affichage numero de tour colonne 5 ligne 0
    printLap(lap, 0);
    lapStart = now;
    lastLapTime = -1;
    newLapStarted = true;
  }
}

void serialPrintLapTime(int lap, long lapTime, boolean isNewBestLap) {
  Serial.print("LAP ");
  Serial.print(lap);
  Serial.print(' ');
  serialPrintTime(lapTime);
  if (isNewBestLap) {
    Serial.print('!');
  }
  Serial.println();
}


// temps tour ligne 1
void updateLapTime(long now) {
  long lapTime = now - lapStart;
  long lapTimeTenth = lapTime/100;
 
  if (lapTimeTenth != lastLapTime / 100) {
    if (!newLapStarted) {
      printTime(lapTime, COL_LAP_TIME + 4, 1, PRECISION_TENS);
    }
    lastLapTime = lapTime;
  }
}

// meilleur tour ligne 2
void newBestLap(int lap, int lapTime) {
  setLed(GREEN_PIN, true);
  tone(BUZZER_PIN, 880, 350);
  printLap(lap, 2);
  bestTime = lapTime;
  // affichage meilleur temps au tour colonne 12 ligne 2
  printTime(bestTime, COL_LAP_TIME + 4, 2, PRECISION_MILLIS);
}

void noBestLap() {
  setLed(RED_PIN, true);
  tone(BUZZER_PIN, 220, 200);
}

void updateTotalTime(long now) {
  long totalTime = now - raceStart;
  // 3000 decale l'affichage du TOTAL TIME de 3 secondes - j'ai mis 0100 pour que le TOTAL TIME s'affiche immédiatement au départ de la course
  if ((totalTime / 0100) % 2 == 0) {
    if (lapTimeMode != SHOW_LAP) {
      switchLapMode();
    }
  } else {
    long totalTimeSeconds = totalTime / 1000;
    if (lapTimeMode != SHOW_TOTAL_TIME) {
      switchTotalTimeMode(totalTime);
    } else if (lastTotalTimeSeconds < totalTimeSeconds) {
      showTotalTime(totalTime);
    }
    lastTotalTimeSeconds = totalTimeSeconds;
  }
}

// changement lettre alternance R G
void switchLapMode() {
  // affichage R colonne 9 ligne 0 - Supprimer les deux lignes ci dessous
  //lcd.setCursor(9, 2);
  //lcd.print(TOTAL_LAPS_MARKER);
  // affichage numero de tour en cours ligne 0 au bout de 5 secondes mais pourquoi 5 secondes?
  printLap(lap, 0);
  lapTimeMode = SHOW_LAP;
}

void switchTotalTimeMode(long totalTime) {
  // affichage G colonne 9 ligne 0 - Supprimer les deux lignes ci dessous
  //lcd.setCursor(9, 0);
  //lcd.print(TOTAL_TIME_MARKER);
  lapTimeMode = SHOW_TOTAL_TIME;
  showTotalTime(totalTime);
}

void showTotalTime(long totalTime) {
  // affichage temps total colonne 11 ligne 3
  printTime(totalTime, COL_LAP_TOTAL + 10, 3, PRECISION_SECONDS);
}

void finish(long now) {
  mode = FINISH;
    long totalTime = now - raceStart;

  serialPrintFinishTotalTime(totalTime);
 
  // print laps and total time in row 0 TEMPS TOTAL ligne 3
  switchLapMode();
  lcd.setCursor(COL_LAP_TIME - 1, 0);
  //lcd.print(TOTAL_TIME_MARKER); Ligne effacer car marquait un G sur la ligne 0 une fois la course terminée
  printTime(totalTime, COL_LAP_TIME + 4, 3, PRECISION_MILLIS);
 
  tone(BUZZER_PIN, 440, 3000);
 
  ledsOn = true;
}

void serialPrintFinishTotalTime(long totalTime) {
  Serial.print("FINISH ");
  serialPrintTime(totalTime);
  Serial.println();
}

void doFinish() {
  char chiffre = 0;
  static byte etat_dp = 0;
  {
      afficher(chiffre); // on appel la fonction d'affichage
  }
  char nombre = 0;
  {
        // appel de la fonction affichage avec envoi du nombre à afficher
        afficher_nombre(nombre);
    }
  setLed(GREEN_PIN, ledsOn);
  setLed(YELLOW_PIN, ledsOn);
  setLed(RED_PIN, ledsOn);
  ledsOn = !ledsOn;
}

void setLed(int pin, boolean on) {
  digitalWrite(pin, on ? HIGH : LOW);
}

void printLap(int lap, int row) {
  int col;
  // affichage numero de tour en cours colonne 14 ligne 0
  lcd.setCursor(14, row);
  if (lap >= 10) {
    lcd.print(" ");
  } else {
    lcd.print("  ");
  }
  lcd.print(lap);
  }

void printTime(long time, int col, int row, int precision) {
  // pour une valeur de 10000 à long minutesPart et SecondsPart, rajoute 1 minute toute les 10 secondes à TOTAL TIME
  // la valeur de 1000 à secondsPart mes 4 chiffres au lieu de 2 au secondes 
  long minutesPart = time / 60000;
  long secondsPart = (time % 60000) / 1000;
  long millisPart = time % 1000;

  lcd.setCursor(col, row);

  if (minutesPart < 10) {
    lcd.print(' ');
  }
  lcd.print(minutesPart);
 
  lcd.print(':');

  if (secondsPart < 10) {
    lcd.print('0');
  }
  lcd.print(secondsPart);
 
  if (precision != PRECISION_SECONDS) {
   
    lcd.print('.');
 
    if (precision == PRECISION_TENS) {
      lcd.print(millisPart / 100);
    } else {
      if (millisPart < 10) {
        lcd.print("00");
      } else if (millisPart < 100) {
        lcd.print('0');
      }
      lcd.print(millisPart); 
    }
  }
}

void serialPrintTime(long time) {
  long minutesPart = time / 60000;
  long secondsPart = time / 1000 % 60;
  long millisPart = time % 1000;

  Serial.print(minutesPart);

  Serial.print(':');

  if (secondsPart < 10) {
    Serial.print('0');
  }
  Serial.print(secondsPart);

  Serial.print('.');
 
  if (millisPart < 10) {
    Serial.print("00");
  } else if (millisPart < 100) {
    Serial.print('0');
  }
  Serial.print(millisPart);
}

J-M-L

millis() doit être un unsigned long
Code: [Select]
  long now = millis(); --> à changer partout où vous gérez le temps

si un de vos chiffres à afficher devient un peu long ou trop court ça peut mettre le bazar à l'affichage. (trop long, ça mord sur les champs ou ligne suivants et trop court, si vous n'effacez pas l'ancienne valeur avant ça peut faire des affichages surprenant. Par exemple si vous aviez le temps à 12.58 et que le nouveau est 9.20 et que vous n'avez pas effacé les 5 cases, vous verrez 9.208


Sinon vous devriez sortir tout ce qui concerne l'affichage de votre gestion de détection de tour. Vous avez besoin de performance dans ce code et un LCD c'est super lent.  ==> Laissez ce code le plus sobre possible et traitez ce qu'il faut aux moments pertinents de manière séparée.

Je ne l'ai pas regardé en détail, mais la gestion du passage de la barrière lumineuse doit être aussi bien étudié. On déclenche dès qu'elle capte un signal, mais ensuite il faut attendre qu'elle revienne au niveau bas (avec des rebonds possibles) avant de compter un nouveau tour.


j'avais un vieux code qui faisait chrono pour des tours, voilà à quoi ça ressemblait si ça peut vous donner des idées

Code: [Select]
/* ============================================
  code is placed under the MIT license
  Copyright (c) 2017 J-M-L
  For the Arduino Forum : https://forum.arduino.cc/index.php?action=profile;u=438300

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/

const uint8_t pinDetection = 2;

uint32_t chronoDepart;
uint32_t chronoFin;
uint32_t chronoTour;
uint32_t chronoMeilleurTour;
uint32_t chronoTotal;
bool meilleurTour = false;

const uint32_t dureeAntiRebond = 200000; // 0,2 seconde en micro-secondes

uint8_t nbTours = 0;

enum t_compteTour : uint8_t {ATTENTE_PREMIER_PASSAGE, PASSAGE, ATTENTE_FIN_DECLENCHEMENT, ATTENTE_FIN_TOUR, INFOS_DISPO} etat = ATTENTE_PREMIER_PASSAGE;

t_compteTour nouvelleMesure(bool raz = false)
{
  static uint32_t antiRebond;

  if (raz) {
    chronoDepart = 0;
    chronoTour = 0;
    chronoMeilleurTour = 0xFFFFFFFF; // ou une très grande valeur
    chronoTotal = 0;
    nbTours = 0;
    etat = ATTENTE_PREMIER_PASSAGE;
  }

  switch (etat) {
    case ATTENTE_PREMIER_PASSAGE:
      if (digitalRead(pinDetection) == LOW) { // si on détecte un passage
        // on note quand ça s'est produit
        chronoDepart = micros();
        // et on attend la fin du déclenchemnt du capteur en gérant les rebonds
        antiRebond = chronoDepart;
        etat = PASSAGE;
      }
      break;

    case PASSAGE:
      etat = ATTENTE_FIN_DECLENCHEMENT;
      break;

    case ATTENTE_FIN_DECLENCHEMENT:
      if (digitalRead(pinDetection) == HIGH) { // si le détecteur est au repos
        if (micros() - antiRebond > dureeAntiRebond) { // et qu'il s'est écoulé plus de 100 mseconde depuis le dernier LOW
          etat = ATTENTE_FIN_TOUR; // on considère alors que le tour a commencé
        }
      } else  antiRebond = micros(); // le déclencheur est toujours actif
      break;

    case ATTENTE_FIN_TOUR:
      if (digitalRead(pinDetection) == LOW) { // si on détecte un passage
        // c'est la fin du tour. On met à jour les infos
        chronoFin = micros();
        chronoTour =  chronoFin - chronoDepart;
        if (chronoTour < chronoMeilleurTour) {
          meilleurTour = true;
          chronoMeilleurTour = chronoTour ;
        }
        chronoTotal += chronoTour;

        // cette fin de tour marque le départ d'un nouveau tour
        chronoDepart = chronoFin;

        // les infos seront dispos
        etat = INFOS_DISPO;

        // et on attend la fin du déclenchemnt du capteur en gérant les rebonds
        antiRebond = chronoDepart;

      }
      break;

    case INFOS_DISPO:
      meilleurTour = false;
      etat = ATTENTE_FIN_DECLENCHEMENT;
      break;
  }

  return etat;
}

void setup()
{
  Serial.begin(115200);
  pinMode(pinDetection, INPUT_PULLUP);
  Serial.println(F("ATTENTE PREMIER PASSAGE"));

  // initialise une nouvelle mesure
  nouvelleMesure(true);
}

void loop() {

  // on met à jour l'affichage si un évenement important se produit
  switch (nouvelleMesure()) {
    case INFOS_DISPO:
      nbTours++;

      Serial.println();
      Serial.print(F("Tour # ")); Serial.println(nbTours);
      Serial.print(F("Temps du tour = ")); Serial.print(chronoTour / 1000000.0, 3); Serial.println(F(" s."));
      if (nbTours > 1 && meilleurTour) Serial.print(F("*** NOUVEAU "));
      Serial.print(F("Meilleur Tour = ")); Serial.print(chronoMeilleurTour / 1000000.0, 3); Serial.println(F(" s."));
      Serial.print(F("Temps Total   = ")); Serial.print(chronoTotal / 1000000.0, 3); Serial.println(F(" s."));
      break;

    case PASSAGE:
      Serial.println();
      Serial.print(F("Passage !"));
      Serial.println();
      break;

    default: break;
  }

  // ici on peut faire autre chose si on ne prend pas trop longtemps

}
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

unguibus

J'ai regarder le code et j'ai modifié dans un premier temps des affichages parasites qui faisait apparaitre des lettres et des chiffres au milieu des chronos. Du coup, je n'ai aucun problème dans l'affichage des chronos. J'ai ajouté la vidéo de la modification.

https://youtu.be/pBgBS1ieblQ

En ce qui concerne la barrière lumineuse, je n'ai aucun problème de détection.

Mon problème est maintenant ligne 1 "TIME LAP" qui au bout de 30/40 secondes, un 1 s'ajoute au TIME LAP. Une fois le 1 apparu, jamais ce compteur ne revient à 0.
Si je fais des tours de 2-3 secondes, aucun problème dans les 30/40 premières secondes. Le TIME LAP revient bien à 0 à chaque nouveau tourtes.

Je ne comprends pas pourquoi le TOTAL TIME s'affiche au bout de 3 secondes et le tour en cours en haut à droite s'affiche au bout de 5 secondes???

Code: [Select]
void updateTotalTime(long now) {
  long totalTime = now - raceStart;
  
  if ((totalTime / 3000) % 2 == 0) {
    if (lapTimeMode != SHOW_LAP) {
      switchLapMode();
    }
  } else {
    long totalTimeSeconds = totalTime / 1000;
    if (lapTimeMode != SHOW_TOTAL_TIME) {
      switchTotalTimeMode(totalTime);
    } else if (lastTotalTimeSeconds < totalTimeSeconds) {
      showTotalTime(totalTime);
    }
    lastTotalTimeSeconds = totalTimeSeconds;
  }
}

// changement lettre alternance R G
void switchLapMode() {
  // affichage R colonne 9 ligne 0 - J'ai supprimer lcd.setCursor(10, 0); et lcd.print(TOTAL_LAPS_MARKER);
  
  // affichage numero de tour en cours ligne 0
  printLap(lap, 0);
  lapTimeMode = SHOW_LAP;
}

void switchTotalTimeMode(long totalTime) {
  // affichage G colonne 9 ligne 0 - J'ai supprimer lcd.setCursor(10, 0); et lcd.print(TOTAL_TIME_MARKER);
    lapTimeMode = SHOW_TOTAL_TIME;
  showTotalTime(totalTime);
}



J-M-L

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

unguibus

J'ai postez tout le code dans les trois premiers messages.

J-M-L

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

unguibus

J'ai remis les modifs dans les trois premiers message.
Pour l'affichage du total Time au bout de 3 secondes j'ai modifié le paramètre 3000 par 0100 et il s'affiche maintenant dès le départ. Cette modification ne semble pas perturber le reste.
Code: [Select]
void updateTotalTime(long now) {
  long totalTime = now - raceStart;
  // 3000 decale l'affichage du TOTAL TIME de 3 secondes - j'ai mis 0100 pour que le TOTAL TIME s'affiche immédiatement au départ de la course
  if ((totalTime / 0100) % 2 == 0) {
    if (lapTimeMode != SHOW_LAP) {
      switchLapMode();


Pour mon problème de la ligne 1, j'arrive à le changer en modifiant certaines valeurs mais cela génère des décalage de temps sur les autres lignes. Merci pour votre aide ;)

Code: [Select]
void printTime(long time, int col, int row, int precision) {
  // pour une valeur de 10000 à long minutesPart et SecondsPart, rajoute 1 minute toute les 10 secondes à TOTAL TIME
  // la valeur de 1000 à secondsPart mes 4 chiffres au lieu de 2 au secondes
  long minutesPart = time / 60000;
  long secondsPart = (time % 60000) / 1000;
  long millisPart = time % 1000;

J-M-L

totalTime est un temps en millisecondes. Lorsque vous aviez la division par 3000 (donc 3 secondes) modulo deux ça voulait dire que à chaque fois que le temps total totalTime divisé par 3 secondes et arrondi en calcul entier était un nombre pair vous rentriez dans le if. ce qui est plus ou moins arbitraire car le temps total varie en fonction du joueur. si vous n'avez pas de chance, vous ne rentrez jamais dans le if.

Maintenant vous faites
Code: [Select]
  if ((totalTime / 0100) % 2 == 0) {
Vous ne le savez peut-être pas mais 0100 est une notation numérique qui veut dire que le nombre est représenté en octal (càd en base 8 ) donc vous divisez par 64 et ensuite si le résultat est pair, vous rentrez dans le if.

Concrètement ça veut dire que vous vous donnez beaucoup plus de chances de rentrer dans le if qu'avant car dans la première version pendant 3 seconde le résultat du calcul restait identique alors que maintenant ce n'est que pendant 64 millisecondes.

fondamentalement vous n'avez rien changé à l'algo, juste amélioré vos chances de rentrer dans le if.


si vous voulez afficher de temps en temps quelque chose sur l'écran, il y a 2 possibilités:

- est-ce une donnée liée à la mesure de la course et de la performance du joueur (meilleur temps, temps du tour, nombre de tours parcourus...) = si oui dans ce cas on ne l'affiche que quand elle change - la machine à état et ses transitions vous diront quand ça arrive. (cf mon code ci dessus)

- est-ce une donnée générale indépendante du joueur (temps total de course, temps passé dans un tour) dans ce cas on l'affiche à une fréquence connue qui est indépendante de la performance du joueur, par exemple toutes les secondes et vous mettez ce code en dehors de la machine à états.







Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

unguibus

Quote
si vous voulez afficher de temps en temps quelque chose sur l'écran, il y a 2 possibilités:

- est-ce une donnée liée à la mesure de la course et de la performance du joueur (meilleur temps, temps du tour, nombre de tours parcourus...) = si oui dans ce cas on ne l'affiche que quand elle change - la machine à état et ses transitions vous diront quand ça arrive. (cf mon code ci dessus)
A l'origine ce code était pour un ecran LCD avec deux lignes. Les informations s'affichaient en alternance sans aucun bug. En passant à un LCD avec quatre lignes, je voulaient avoir les informations visibles en une fois. J'ai donc surtout modifié les affichages sans changer le fondamentalement le code de chrono.
Je dirai que les données sont liées à la mesure de la course et à la performance du joueur.
Sur la ligne 0 et sur la ligne BEST LAP, on l'affiche les données une fois par tour.
Pour le TOTAL TIME ligne 3, le compteur tourne toujours du début à la fin de la course.
Pour le Time LAP, celui si tourne en permanence mais est censé revenir à 0 à chaque tour.

Je ne savais pour la notation numérique 0100

J-M-L

le code est trop spaghetti pour lire depuis mon smartphone...

Si l'affichage fonctionnait correctement sur 2 lignes et que les infos étaient collectées correctement en permanence,  il n'y a pas de raison fondamentale qui empêcheraient d'afficher sur 4 lignes

assurez vous que l'affichage se fait au bon endroit, sur le bon nombre de caractères et que ce qui était affiché avant est bien effacé par le nouveau texte.
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

unguibus

Je connais les pâtes spaghetti mais pas le code spaghetti  :)
C'est vrai que c'est compliqué. J'ai ajouté beaucoup d'options pour en arrivé là mais mes connaissances sont trop limités pour pouvoir réorganiser complétement l'ensemble.
Certaines lignes du code sont inutiles mais c'est difficile de supprimer des lignes sans mettre le code en erreur.
Quand on regarde la seconde vidéo, le code fonctionnent parfaitement pendant 30/40 secondes peu importe le nombre de tour que je fais.

Je sèche  :smiley-confuse:

J-M-L

c'est un peu le souci du code spaghetti.. tout se mélange, les if et les switch s'entremêlent et on a du mal à suivre ce qu'il se passe et les dépendances.

Le code que j'ai posté plus haut contient le machine de base qui compte les tours et leur durée.

Tout le reste devrait être construit en dehors ce cette machine à état - comme vous le voyez l'affichage de l'information en provenance de la machine se fait dans la loop() quand un état à changé

si je voulais afficher le temps qui défile, c'est indépendant des joueurs et donc ce serait une autre partie séparée du code

 Maintenant que vous vous êtes fait la main sur les besoins et avez des spécifications claires en tête, Si c'était mon projet, je commencerai par mettre tout ça à plat dans des machines à état et je recommencerai de zéro.
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Go Up