Cronómetro para competición de habilidades.

Hola!

Tengo en mente realizar un cronómetro para competiciones de habilidades. Lo singular de este cronómetro es que para activarlo hay que presionar dos pulsadores al mismo tiempo (uno con cada mano) y sólo al levantar los pulsadores empezará a correr el tiempo. Cuando el participante termine de hacer el recorrido tendrá que accionar los dos pulsadores al mismo tiempo para detener la cuenta (esta vez no hará falta volver a soltar aunque podría ser más facil programarlo de esta manera)

La primera parte ha sido programar el cronómetro con dos pulsadores para activar y otro para resetear.

//Cronómetro
unsigned long start, finished, elapsed;
void setup()
{
  Serial.begin(9600);
  pinMode(2, INPUT); // el botón de inicio
  pinMode(3, INPUT); // rl botón de paro
  pinMode(4, INPUT); // el segundo botón de inicio
  Serial.println("Acciona botón 1 para empezar/reiniciar, 2 para parar");
  
}
void displayResult()
{
  float h, m, s, ms;
  unsigned long over;
  elapsed = finished - start;
  h = int(elapsed / 3600000);
  over = elapsed % 3600000;
  m = int(over / 60000);
  over = over % 60000;
  s = int(over / 1000);
  ms = over % 1000;
  Serial.print("Raw elapsed time: ");
  Serial.print(elapsed);
  Serial.print("Elapsed time: ");
  Serial.print(h, 0);
  Serial.print("h ");
  Serial.print(m, 0);
  Serial.print("m ");
  Serial.print(s, 0);
  Serial.print("s ");
  Serial.print(ms, 0);
  Serial.print("ms ");
  Serial.println();
}
void loop()
{
  if ((digitalRead(2) == HIGH) && (digitalRead(4) == HIGH))
  {
    start = millis();
    delay(200); // for debounce
    Serial.print("Started...");
  }
  if (digitalRead(3) == HIGH)
  {
    finished = millis();
   delay(200); // for debounce
  displayResult();
  }
  
}

La segunda parte es conseguir que se active al soltar los pulsadores. Aquí estoy un poco bloqueado (bastante).

La tercera parte será visualizar el tiempo en una pantalla LCD. Con esto podría dar por terminado el proyecto.

El siguiente paso, bonus extra, sería conectar el cronómetro a una base de datos donde poder poner el nombre del participante y tratar los datos.

Si me podéis echar una mano con la segunda parte os estaría muy agradecido.

Te recomiendo usar la librería Debounce2. Alli veras que hay un métodos muy interesante llamado fell() que devuelve verdadero cuando un pin pasa de HIGH a LOW.

Ahora en cuanto al concepto no esta muy claro. Pretendes que suelten los dos botones exactamente el mismo tiempo ? Recuerda que Arduino ejecuta las operaciones a 16 MHz, eso significa que para Arduino nunca lograras hacer coincidir los "flancos" (subida o bajada) de los dos botones.

Quizas sea una mejor idea poner los botones en serie en el mismo pin.

Estoy de acuerdo con @Kike_GL.
Debes manejarte con las limitaciones del caso.

Lo primero es detectar los flancos cuando sueltes 1 boton activas un flag y cuando completes el otro tienes la acción de iniciar.

La acción de detener no puede ser simultánea pero si dentro de un tiempo breve que te recomiendo ensayes en la practica. Comienza con 10 mseg entre ambos pulsadores y ve si es posible detectar en menos tiempo.

En todo esto no debe haber un solo delay().

La actualización del LCD será un problema porque insume tiempo asi que si esta en modo detección de pulsadores deberías inhibir la lectura la presesntación del LCD cuando estemos en la situación de detectar ambos. En el otrocaso no es relevante.

Para darte un empujón esta sería mi forma de encararlo: dime si trabaja mas o menos bien.

//Cronómetro
#default INTERVALO   10000 // son 10x 1000 microsegundos

unsigned long start, finished, elapsed;
const byte inicio1Pin = 2;
const byte inicio2Pin = 4;
bool fpin1 = false, stat1, stat1Ant = false;
bool fpin2 = false, stat2, stat2Ant = false;
byte modo = 0; // 0 arranque, 1 inicio o start 2 parar

void setup() {
  Serial.begin(9600);
  pinMode(inicio1Pin, INPUT); // el botón de inicio
  pinMode(inicio2Pin, INPUT); // el segundo botón de inicio
  pinMode(paroPin   , INPUT); // rl botón de paro
  
  Serial.println("Acciona botón 1 para empezar/reiniciar, 2 para parar");
  
}

void loop() {

  stat1 = digitalRead(inicio1Pin);
  stat2 = digitalRead(inicio2Pin);
    
  

  switch (modo) {
     case 0:  // modo start espero inicio o cuando se sueltan los dos pulsadores
              if (stat1 && !stat1Ant) {
                  fpin1 = true;
              }    
              if (stat2 && !stat2Ant) {
                  fpin2 = true;
              }
              if (fpin1 && fpin2) {// si los dos estan activos es porque debe iniciarse la cuenta
                  start = millis();
                  fpin1 = false;
                  fpin2 = false;
                  modo = 1; // paso a modo apagar
              }
              break;

     case 1:  if (!stat1 && stat1Ant) { // presiono boton1
                  time1 = micros();
                  fpin1 = true;
              }
              if (!stat2 && stat2Ant) { // presiono boton2
                  time2 = micros();
                  fpin2 = true;
              }
              if (fpin1 && fpin2) { // presionados los dos pulsadores calculo
                  if (abs(time1 - time2) < INTERVALO) {
                     finished = millis();
                     fpin1 = fpin2 = false;
                     modo = 2; // presento datos
                  }
              }
              break;

     case 2:  displayResult();
              modo = 0; // ?? no se si debe dejarse para volver a empezar
              break;
  }
  stat1Ant = stat1;
  stat2Ant = stat2;
}


void displayResult() {
  char buffer[30];
  int h, m, s, ms;
  unsigned long over;
  elapsed = finished - start;
  h = int(elapsed / 3600000);
  over = elapsed % 3600000;
  m = int(over / 60000);
  over = over % 60000;
  s = int(over / 1000);
  ms = over % 1000;

  Serial.print("Raw elapsed time: ");
  Serial.print(elapsed);
  sprintf(buffer,"Elapsed time: %02d:%02d:%02d.%03d", h, m, s, ms);
  Serial.println(buffer);
}

INTERVALO esta dado en microsegundos y puse 10000 = 10 mseg
es decir que los dos botones deben pulsarse en ese tiempo.