Ardu? No!MTobjectsPour les cartes graphiques ≫ MTtouchPad4wires: Exemple 1

MTtouchPad4wires,
Exemple 1

Gestion par événements pour Uno, Nano, Mega

Identification et étalonnage

Le programme qui suit permet une identification des broches d'un touchpad ainsi qu'un étalonnage sommaire. Toutes les informations se font au travers de la console, il n'est pas nécessaire d'avoir un écran graphique.

En tout début de programme, il faut donner la vitesse de la console, puis le nom des broches dans un ordre quelconque. Si on utilise un écran réel, en donant la taille de l'écran et en pointant sur les coins, on obtient l'instruction permettant le calibrage. Le pointage du coin n'est pas aussi parfait que si on dispose d'une bibliothèque graphique, mais c'est un début.

// Ce progrmme permet d'étalonner un touchpad dont on ne connait que les
// numéros des broches dans le désordre

// A changer éventuellement par l'utilisateur
#define BAUDS 115200 // A changer éventuellement
byte broches[] = {8, 9, A2, A3}; // Numéros les 4 broches du touchpad dans n'importe quel ordre


#include <MTobjects.h> // V1.1.0 Voir http://arduino.dansetrad.fr/MTobjects

byte temp[4];
int largeur, hauteur; // Taille de l'écran en pixels
String lecture; // Pour lire la taille
int X[4], Y[4]; // Coordonnés des 4 coins
int ecart; // Pour ajuster les dimensions
int x, y, oldx, oldy; // Pour la vérification


void echange(byte *x, byte *y)
{
  *x ^= *y;  // Méthode clin d'oeil aux ou exclusif si délaissé de nos jours!
  *y ^= *x;
  *x ^= *y;
}
void echange(int *x, int *y)
{
  *x ^= *y;
  *y ^= *x;
  *x ^= *y;
}



String analogique(byte broche) // Transforme 14 en A0...
{
  String resultat = "A";
  #if defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) // Si on a une Uno ou une Nano
    if (broche >= 14) resultat += String(broche-14); else resultat = String(broche); 
  #elif defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__)
    if (broche >= 54) resultat += String(broche-54); else resultat = String(broche);
  #endif
  return resultat;
} 

void affiche(int x, int y) // Pour la vérification, affichage des coordonnées si on bouge
{
  Serial.print("x="); Serial.print(x);
  Serial.print("  y="); Serial.println(y);
}

void unselect(void) // Quand on relève le stylet
{
  Serial.println("------------");
}






void setup()
{
  Serial.begin(BAUDS); //  Mettre aussi la console à la même valeur
  Serial.println(F("\n\n")); // Pour se débasser des "bêtises" précédentes
   // Test pour vérifier qu'il n'y ait pas deux broches identiques
  for (byte broche1=0; broche1<4; broche1++) for (byte broche2=broche1+1; broche2<4; broche2++) // Pour toutes les paires de broches
    if (broches[broche1] == broches[broche2]) // Si c'est les mêmes
    {
      Serial.print(F("La broche ")); Serial.print(broches[broche1]); Serial.println(F(" y est deux fois. Abandon du programme."));
      while(1); // Fini!
    }

  // On vérifie les numéros des broches
  for (byte broche=0; broche<4; broche++)
    #if defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) // Si on a une Uno ou une Nano
      if (broches[broche] > 21)
    #elif defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__) // Si on a une Mega
      if (broches[broche] > 69)
    #endif
    {
      Serial.print(F("La broche ")); Serial.print(broches[broche]); Serial.println(F(" n'existe pas. Abandon du programme."));
      while(1); // Fini!
    }
  
  // On recherche les paires
  // "broches" contient 4 broches; "temp" contiendra les broches avec laquelle elle est connectée
  // Par exemple si broches={1, 2, 3, 4} et que la broche 1 et 4 sont reliées ainsi que 2 et 3
  // On aura temp={4, 3, 2, 1}. broches[0] est reliée à temp[3], broches[1] est reliée à temp[3]...
  for (byte broche=0; broche<4; broche++) temp[broche] = 0; // Initialisation de temp vide: pas de connexions
  for (byte broche=0; broche<4; broche++) pinMode(broches[broche], INPUT_PULLUP); // On met toutes les broches à 5V
  for (byte broche1=0; broche1<4; broche1++) // Pour chaque broche, on va tester les contacts avec les autres
  {
    pinMode(broches[broche1], OUTPUT); // On passe la broche étudiée à LOW
    digitalWrite(broches[broche1], LOW);
    for (byte broche2=0; broche2<4; broche2++) if (broches[broche1] != broches[broche2]) // Pour chacune des autres broches
      if (digitalRead(broches[broche2]) == LOW) // On est sur le même film
      {{  // "{{" supprime un avertissement
        if (temp[broche2] == 0) temp[broche2] = broches[broche1];
        else 
        {
          Serial.print(F("problème entre les broches ")); Serial.print(broches[broche1]); Serial.print(F(", "));
          Serial.print(broches[broche2]); Serial.print(F(" et ")); Serial.print(temp[broche2]); Serial.println(F(". Abandon du programme."));
          while(1); // Fini!
        }
      }}
    pinMode(broches[broche1], INPUT_PULLUP); // On remet la broche étudiée à 5V
  }

  // Si on n'a pas de paires?
  for (byte broche=0; broche<4; broche++) if (temp[broche] == 0) // Broche non reliée
    {
      Serial.print(F("La broche ")); Serial.print(broches[broche]); Serial.println(F(" n'est connectée à rien. Abandon du programme."));
      while(1); // Fini!
    }

  // Permutation éventuelle pour avoir les couples qui vont ensembles
  if (broches[1] != temp[0]) // Il faut faire une permutation
  {{
    if (temp[0] == broches[2]) echange(&broches[1], &broches[2]); // On change les positions 1 et 2
    else echange(&broches[1], &broches[3]); // On change les positions 1 et 3
  }}

  // Permutations éventuelles pour mettre en premier une broche analogique
  #if defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) // Si on a une Uno ou une Nano
    if (broches[0] < 14) echange(&broches[0], &broches[1]); // On change les positions 0 et 1
    if (broches[2] < 14) echange(&broches[2], &broches[3]); // On change les positions 2 et 3
  #elif defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__)
    if (broches[0] < 54) echange(&broches[0], &broches[1]); // On change les positions 0 et 1
    if (broches[2] < 54) echange(&broches[2], &broches[3]); // On change les positions 2 et 3
  #endif

  // On vérifie qu'on a au moins une broche analogique
  #if defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) // Si on a une Uno ou une Nano
    if (broches[0] < 14)
  #elif defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__)
    if (broches[0] < 54)
  #endif
    {
      Serial.print(F("Une des broches ")); Serial.print(broches[0]); Serial.print(F(" ou ")); Serial.print(broches[1]); Serial.println(F(" doit être analogique. Abandon du programme."));
      while(1); // Fini!
    }
  #if defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) // Si on a une Uno ou une Nano
    if (broches[2] < 14)
  #elif defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__)
    if (broches[2] < 54)
  #endif
    {
      Serial.print(F("Une des broches ")); Serial.print(broches[2]); Serial.print(F(" ou ")); Serial.print(broches[3]); Serial.println(F(" doit être analogique. Abandon du programme."));
      while(1); // Fini!
    }

  // On va maintenant regarder les axes
  // Taille de l'écran
  Serial.print(F("Donnez la largeur de l'écran: "));
  while (Serial.available() == 0); // On vide le buffer
  lecture = Serial.readString(); // Lecture des caractères jusqu'au retour chariot
  lecture.trim(); // Suppression éventuelle d'espaces
  largeur = lecture.toInt(); // Extraction de l'entier
  Serial.println(largeur); // Echo sur la console
  Serial.print(F("Donnez la hauteur de l'écran: "));
  while (Serial.available() == 0);
  lecture = Serial.readString();
  lecture.trim();
  hauteur = lecture.toInt();
  Serial.println(hauteur);

  if (largeur < hauteur)
  {
    Serial.println(F("On se place en mode PAYSAGE. La largeur doit être plus grande que la hauteur. Abandon du programme."));
    while(1); // Fini!
  }
  if ((largeur <= 0) || (hauteur <= 0))
  {
    Serial.println(F("Largeur et hauteur doivent être positives. Abandon du programme."));
    while(1); // Fini!
  }

  // Mise en place  d'un touchpad pour lire les coordonnés des 4 points
  MTtouchPad4wires *Touchpad = new MTtouchPad4wires(broches[0], broches[1], broches[2], broches[3]);
  
  Serial.println(F("Appuyez sur le coin en haut à gauche"));
  while (Touchpad->isTouch()); // On attend que l'on relâche le stylet
  while (!Touchpad->isTouch()); // On attend un appui sur le coin
  X[0] = Touchpad->getX();  Y[0] = Touchpad->getY();
  Serial.println(F("Appuyez sur le coin en haut à droite"));
  while (Touchpad->isTouch()); // On attend que l'on relâche le stylet
  while (!Touchpad->isTouch()); // On attend un appui sur le coin
  X[1] = Touchpad->getX();  Y[1] = Touchpad->getY();
  Serial.println(F("Appuyez sur le coin en bas à droite"));
  while (Touchpad->isTouch()); // On attend que l'on relâche le stylet
  while (!Touchpad->isTouch()); // On attend un appui sur le coin
  X[2] = Touchpad->getX();  Y[2] = Touchpad->getY();
  Serial.println(F("Appuyez sur le coin en bas à gauche"));
  while (Touchpad->isTouch()); // On attend que l'on relâche le stylet
  while (!Touchpad->isTouch()); // On attend un appui sur le coin
  X[3] = Touchpad->getX();  Y[3] = Touchpad->getY();
  // Calcul des écarts
  int xHorizontal = X[0] + X[3] - X[1] - X[2];
  int xVertical = X[0] + X[1] - X[3] - X[2];
  int yHorizontal = Y[0] + Y[3] - Y[1] - Y[2];
  int yVertical = Y[0] + Y[1] - Y[3] - Y[2];

  if (((abs(xHorizontal) > abs(xVertical)) && (abs(yHorizontal) > abs(yVertical))) ||
      ((abs(xHorizontal) < abs(xVertical)) && (abs(yHorizontal) < abs(yVertical))))
  {
    Serial.println(F("Problème dans la lecture des coins. Abandon du programme."));
    while(1); // Fini!
  }

  if (abs(xHorizontal) < abs(yHorizontal)) // On change l'axe X et l'axe Y
  {
    echange(&broches[0], &broches[2]);
    echange(&broches[1], &broches[3]);
    echange(&X[0], &Y[0]);
    echange(&X[1], &Y[1]);
    echange(&X[2], &Y[2]);
    echange(&X[3], &Y[3]);
  }

  X[0] = (X[0] + X[3]) / 2; // Moyenne des deux coins de droite
  X[1] = (X[1] + X[2]) / 2;
  Y[0] = (Y[0] + Y[1]) / 2;
  Y[1] = (Y[2] + Y[3]) / 2;

  // Affichage des résultats
  Serial.print(F("\nOn peut utiliser\n     MTtouchPad4wires TouchPad(pin_X1_analogique ")); Serial.print(analogique(broches[0]));
  Serial.print(F(", pin_X2 ")); Serial.print(analogique(broches[1]));
  Serial.print(F(", pin_Y1_analogique ")); Serial.print(analogique(broches[2]));
  Serial.print(F(", pin_Y2 ")); Serial.print(analogique(broches[3])); Serial.println(");");
  
  Serial.print(F("     TouchPad.calibrate(PAYSAGE, largeur_ecran ")); Serial.print(largeur);
  Serial.print(F(", hauteur_ecran ")); Serial.print(hauteur);
  Serial.print(", x_gauche "); Serial.print(X[0]);
  Serial.print(", y_haut "); Serial.print(Y[0]);
  Serial.print(", x_droite "); Serial.print(X[1]);
  Serial.print(F(", y_bas ")); Serial.print(Y[1]); Serial.println(");\n");

  // Initialisation de la vérification
  delete Touchpad; // Au cas on on doit faire un échange, il faut réinitialiser le touchpad
  Touchpad = new MTtouchPad4wires(broches[0], broches[1], broches[2], broches[3], affiche, affiche, unselect);
   
  Touchpad->calibrate(PAYSAGE, largeur_ecran 320, hauteur_ecran 240, x_gauche X[0], y_haut Y[0], x_droite X[1], y_bas Y[1]);
  Serial.println(F("Déplacez le stylet sur l'écran"));
  while (Touchpad->isTouch()); // On attend que l'on relâche le stylet
 }



void loop(){}

Voici un exemple de résultat:


Donnez la largeur de l'écran: 320
Donnez la hauteur de l'écran: 240
Appuyez sur le coin en haut à gauche
Appuyez sur le coin en haut à droite
Appuyez sur le coin en bas à droite
Appuyez sur le coin en bas à gauche

On peut utiliser
     MTtouchPad4wires TouchPad(pin_X1_analogique A2, pin_X2 8, pin_Y1_analogique A3, pin_Y2 9);
     TouchPad.calibrate(PAYSAGE, largeur_ecran 320, hauteur_ecran 240, x_gauche 925, y_haut 101, x_droite 118, y_bas 664);

Déplacez le stylet sur l'écran
------------
x=151  y=127
x=151  y=125
------------

Bien entendu j'ai donné les dimentions de l'écran. Si on n'a pas d'écran, on peut donner les mêmes chiffres. Le pointage des 4 coins permet de connaitre les axes et leur domaine de variation. On nous donne l'instruction pour déclarer un touchpad, les broches ont été mises dans un ordre correct en particulier pour que getX retourne les coordonnés de l'axe droite-gauche. L'axe peut être dans le bon sens ou dans le mauvais, mais c'est lié à la broche analogique donnée.

On a aussi une déclaration possible pour le calibrage.

Puis par la suite, les coordonnés sont affichés -------- indiquant un stylet levé.