Un dispositif qui mêle affichage écran (Processing) ET bouton physique (Arduino) pour créer un simple compte-temps pour une réalisation chroonométrée.

On lance l'activité, le compteur démarre pour tous et le premier qui a fini appuie sur le bouton pour arrêter le compteur.

vide-armoire arduino processing en cours 3D warning danger

Le code Processing pour un chrono sans interaction.

⬇️ le code à télécharger : Compte Temps 0

CompteTemps0.java
 // objet global Chrono, déclaration de classe
 StopChronoTimer sc; 
 
 // Communication avec Arduino 
 import processing.serial.*;
Serial myPort;  // Create object from Serial class
static String val;    // Data received from the serial port
int btnVal = 0;
 
void setup() {
  size(800, 600);
  println (millis());
  sc = new StopChronoTimer();
  sc.start();
 
  String portName = "COM3";//à changer selon config matériel
  myPort = new Serial(this, portName, 9600); 
 
 
}
 
void draw() {
  top();
}
 
/// FONCTIONS
 
void top() { // dessine le texte-temps sur l'écran
  background(220);
  fill(000);
  textSize(128);
  textAlign(CENTER);
 
  // nf est utile pour transformer des chiffres en string text https://processing.org/reference/nf_.html
  text(nf(sc.heures(), 2)+":"+nf(sc.minutes(), 2)+":"+nf(sc.secondes(), 2), width/2,height/2);
}
 
 
// CLASSES
 
class StopChronoTimer {
  int startTime = 0;
  int stopTime = 0;
  boolean running = false;
 
  void start() {
    startTime = millis();
    running = true;
  }
 
  void stop() {
    stopTime = millis();
    running = false;
  }
 
  int gTempsPasse() {
    int tempsP;
    if (running) {
      tempsP = (millis()-startTime);
    } else {
      tempsP =(stopTime - startTime);
    }
    return tempsP;
  }
 
  int secondes() {
    return (gTempsPasse()/1000) % 60;
  }
 
  int minutes() {
    return (gTempsPasse()/(1000*60)) % 60;
  }
 
  int heures() {
    return (gTempsPasse()/(1000*60*60)) % 24;
  }
}
Arduino : un bouton poussoir qui change une valeur…

⬇️ le code à télécharger : Btn_Poussoir

BtnPoussoir.ino
/*
   Projet Compte-Temps interactif avec Processing
   Matériel : Arduino UNO + Bouton Poussoir + LED(& sa résistance)
   Quand on appuie sur le bouton le compteur à l'écran s'arrête !
 
   v1 : utilisation du Serial pour parler à Processing donc halte aux grands messages
 
*/
 
// Cablage
const int btnPin  = A0; // bouton poussoir 6 pattes : 4 fonctionnent, c'est le même côté qui est mis en relation ! (1 sur gnd et 1 sur A0)
const int ledPin = 8; // on envoie du courant sur l'anode via le pin 8
 
//Variables
int btnVal  = 0;
bool btnEtat = false;
bool OldbtnEtat = false;
bool ledEtat = LOW;
 
void setup() {
  //Init Serial USB
  Serial.begin(9600);
  //// Serial.println(F("Coucou c'est le début"));
  //Init btn avec une résistance interne pour éviter les fronts
  pinMode(btnPin, INPUT_PULLUP);
  // init Led
  pinMode(ledPin, OUTPUT);
}
 
void loop() {
  testBtn();
}
 
void testBtn() {
 
  ////Read pushbutton
  btnVal = analogRead(btnPin);
 
 //// Serial.print(btnVal);
 //// Serial.print(F("-->"));
 
  if (btnVal < 200) {
    btnEtat = true;
  ////  Serial.println(F("Bouton Appuyé"));
      // alors on envoie une info au serial
        Serial.println("btnA");
  } else {
    btnEtat = false;
 ////   Serial.println(F("Bouton relâché"));
 Serial.println("btnR"); 
  }
 
  // si  l'tat du bouton a changé
  if (OldbtnEtat != btnEtat) {
  ////    Serial.println(F("Bouton change"));
    // ET si l'etat actuel est pressé
    if (btnEtat == true) {
      // alors on change la variable état de led
      ledEtat =! ledEtat;
  ////    Serial.println( ledEtat );
      // et on actionne la led en fonction
      digitalWrite(ledPin,ledEtat);
    }
  }
  OldbtnEtat = btnEtat;
  // delay(800);
}

C'est tout bête il me faut une carte Uno, un bouton poussoir et là j'ai mis une LED pour témoigner que ça se passe bien…

Chaun des 2 codes ici “fonctionnent”, mais comment faire pour que ces 2 pgm interagissent?

Objectif : qu'un appui sur le bouton poussoir arrête le chrono affiché à l'écran.

ici Arduino envoie un état booléen et Processing doit le traiter visuellement

Avant de bidouiller le chrono je passe par un petit code pour juste écouter, traiter et afficher les appuis.
Quelques embûches (sinon c'est pas drôle) : 

  • A partir du moment où Processing écoute la carte Arduino on ne peut plus utiliser les “serial-consoles” des outils.
  • On a besoin de transformer le signal reçu (comme 1 texte?) en un entier, en passant par un float. 2 variables sont donc nécessaires pour traiter une valeur simple.
  • On utilise la détection de fin de ligne obtenue avec println
  • On a besoin d'une variable d'historique pour ne compter l'appui bouton que si il fait changer l'état

Quelques ressources utiles à creuser :

⬇️ code Processing : écouter et afficher données Arduino à télécharger

ConnectArduino2.java
//
/* J'ai réussi à lire les données du Serial, maintenant je veux
 que Processing COMPTE chaque changement de valeur et garde ce compte en mémoire
 que l'affichage change, par ex faire grossir un cercle... v1 ça fonctionnait mais sans historique le cercle grossit à toute vitesse
 donc j'ajoute une variable pour historique d'état : je peux compter les clics et le cercle grossit 1 fois par clic (et pas en constant tant que cliqué)
 */
 
import processing.serial.*;
 
Serial myPort;  // Create object from Serial class
String dt;    // Data received from the serial port
float valD;
int btnVal = 0; // une valeur int pour d'etat bouton, 0 relache
 
int oldBtn = 0; // une valeur pour conserver l'état précédent
 
int cptBtn = 1; // une variable pour compter les appuis
 
PFont matypo;  // ça c'est parcequ'il aime pas les car du Serial il râle si on précise pas
 
void setup()
{
  size(800, 600);
 
  //  printArray(Serial.list()); // pour voir le port qui parle
  String portName = "/dev/ttyACM3";// Changer le nom selon valeur reçue du listing ligne pcdte.
  myPort = new Serial(this, portName, 9600); // valeur cadence en baud comme dans Arduino
  // myPort.bufferUntil(lf); // charge de 10 caractères ???
 
  //  printArray(PFont.list()); // pour voir les typo dispo sur le poste
  matypo = createFont("Open Sans", 48);
  textFont(matypo);
}
 
void draw()
{
 
  while (myPort.available() >0) {
 
    dt = myPort.readStringUntil('\n');
    if (dt !=null) {
      // si on lit qqchose on le trasnforme en int avec ces 2 lignes
      valD = float(dt);
      btnVal = int(valD);
    }
  }
 
  background(255);
  fill(#245682);
  translate(width/2, height/2);
 
  if(btnVal==0  &&  oldBtn !=0){ // si c relache sur les 2 on ne fait rien mais si ça vient de changer
  oldBtn = 0; 
  } else if (btnVal ==1 &&  oldBtn !=1){
    cptBtn = cptBtn + 1; 
    oldBtn = 1; 
  }  
 
  ellipse(0, 0, cptBtn*5, cptBtn*5);
  fill(#c2c3c4);
  textSize(48);
  text(btnVal, 0, 0);
    textSize(36);
  text("recoit: " +btnVal, 10, 50);
  text("nb Clic: " +cptBtn, 10, 80); 
}
Je mélange les 2 codes processing pour un chrono interactif
  • Ajout d'un compteur millisecondes pour que ça aille plus vite (les heures ne sont plus affichées)
  • Le bouton physique Arduino arrête le chrono à l'écran et affiche un meilleur temps “score”
  • Pour relancer le chrono le MJ utilise sa souris de PC
  • Possibilité de passer en Plein écran plutôt qu'en 800x600px

⬇️ Code Processing Chrono final

Compte-Temps2.java
/* MON PROJET : un compteur de seconde centré dans l'écran
 + Piloté par Arduino et un bouton ( stop / start)
 -  Utiloser millis() pour créer une horloge hors temps officiel,
 solution approhée par https://forum.processing.org/one/topic/timer-in-processing.html
 */
 
// objet global Chrono, déclaration de classe
StopChronoTimer sc;
 
// Communication avec Arduino
import processing.serial.*;
Serial myPort;  // Create object from Serial class
 
String dt;    // Data received from the serial port
float valD;
int btnVal = 0; // une valeur pour l'etat du bouton
 
int oldBtn = 0; // une valeur pour conserver l'état précédent
 
int cptBtn = 1; // une variable pour compter les appuis
 
PFont matypo;  // ça c'est parcequ'il aime pas les car du Serial il râle si on précise pas
 
void setup() {
  // fullScreen();
  size(800,600); 
 
  //  printArray(Serial.list()); // utile pour voir le port qui parle
  String portName = "/dev/ttyACM3";// Changer le nom selon valeur reçue du listing ligne pcdte.
  myPort = new Serial(this, portName, 9600); // valeur cadence en baud comme dans Arduino
 
  sc = new StopChronoTimer();
  sc.start();
}
 
void draw() {
  while (myPort.available() >0) {
 
    dt = myPort.readStringUntil('\n');
    if (dt !=null) {
      // si on lit qqchose on le trasnforme en int avec ces 2 lignes
      valD = float(dt);
      btnVal = int(valD);
    }
  }
  top();
}
 
/// FONCTONS
 
void top() { // dessine le texte-temps sur l'écran
  background(#fecb00);
  fill(000);
  textSize(208);
  textAlign(CENTER);
  // nf est utile pour transformer des chiffres en string text https://processing.org/reference/nf_.html
  text(nf(sc.minutes(), 2)+":"+nf(sc.secondes(), 2)+":"+nf(sc.millisec(), 2), width/2, height/2);
 
 
  if (btnVal==0  &&  oldBtn !=0) { // si c relache sur les 2 on ne fait rien mais si ça vient de changer
    ///
  } else if (btnVal ==1 &&  oldBtn !=1) {
    cptBtn = cptBtn + 1;
    oldBtn = 1;
    score();
  }
}
 
void score() {
  int[] score = new int[3];
  score[0] = sc.minutes();
  score[1] = sc.secondes();
  score[2] = sc.millisec();
 
  fill(#ff2503);
  textSize(24);
 
  text("MEILLEUR SCORE "+nf( score[0], 2)+":"+nf( score[1], 2)+":"+nf( score[2], 2), width/4, height/2+100);
  noLoop();
}
 
 
// Pour relancer un compteur j'utilise la souris c OK
// mais il ne faut pas cliquer si le compteur n'est pas déjà arrêté
 
void mouseReleased() {
 btnVal = 0;
oldBtn = 0;
  sc.start();
  loop();
}
 
 
 
// CLASSES
 
class StopChronoTimer {
  int startTime = 0;
  int stopTime = 0;
  boolean running = false;
 
  void start() {
    startTime = millis();
    running = true;
  }
 
  void stop() {
    stopTime = millis();
    running = false;
  }
 
  /* int[] score(int s, int m, int h){
    int s = return secondes(); 
    int m = return minutes(); 
    int h = return heures(); 
  }
  */ 
 
  void fin() {
    stopTime = 0; 
    startTime = 0; 
    running = false;  
  }
 
  int gTempsPasse() {
    int tempsP;
    if (running) {
      tempsP = (millis()-startTime);
    } else {
      tempsP =(stopTime - startTime);
    }
    return tempsP;
  }
 
int millisec(){
  return (gTempsPasse()/10 ) %100; 
}
 
  int secondes() {
    return (gTempsPasse()/1000) % 60;
  }
 
  int minutes() {
    return (gTempsPasse()/(1000*60)) % 60;
  }
 
  int heures() {
    return (gTempsPasse()/(1000*60*60)) % 24;
  }
}
Je veux un gros bouton mais je n'ai que des petits caps

Je vais donc prendre les dimensions de l'existant et modéliser un push button qui va bien… Bon évidemment le premier essai n'est pas au top mais mon fichier FreeCAD est enregistré avec les modif :

  • élargissement du diamètre accueil bouton ( de 11,2 mesuré mais trop serrant à 11,5 mm)
  • diamètre pied champi fixé à 24 mm

Il faudra regénérer un mesh si on veut le réimprimer

Mon premier jet est mal adapté, à bricoler pour que le caps bouton rentre dedans.

colonnes

  • projets/comptetemps.txt
  • Dernière modification : il y a 2 ans
  • de laure