Apprentissage pour MTanalogButtons
Gestion par événements pour Uno, Nano, Mega
Quand on utilise MTanalogButtons, il faut donner une table des valeurs des seuils qui permettent de différencier les combinaisons. Le programme qui suit permet de donner quasi automatiquement cette table en donnant un programme de test. Elle informe aussi sur la qualité des lectures analogiques.
Configuration
Il faut bien sûr adapter ce programme à votre montage, et changer éventuellement la broche analogique utilisée, la tension de référence du convertisseur et la vitesse de la console. Cela se fait dans les premières lignes du programme.
Programme d'apprentissage
// Ce programme utilise l'apprentissage pour générer un programme de démonstration
// de MTanalogButtons
//
// Il faut changer quelques constantes pour le configurer.
//
// Il faut donner la broche pour la lecture analogique
#define PIN A0 // Changer A5 en A0..A7 suivant le cas
//
// Il faut choisir la référence de tension à utiliser pour la conversion
// DEFAULT: pour Vcc
// INTERNAL: 1,1V pour Nano/Uno
// INTERNAL1V1: 1,1V pour Mega
// INTERNAL2V56: 2,56V pour Mega
// EXTERNAL: pour utiliser AREF
#define REFERENCE DEFAULT
//
// Il faut donner le taux de transfert de la console
#define BAUDS 115200 // 115200 conseillée, mais on peut mettre 9600
// Ne pas oublier de régler la console à 115200 bauds
// *************************** Mémorisation des valeurs du CAN pour tous les boutons
byte lecture[128]; // Contiendra les valeurs possibles du CAN pour tous les boutons
inline void ecrire(word valeur) // Enregistre que l'on a vu la valeur passée en argument (0 à 1023)
{
lecture[valeur/8] = bitSet(lecture[valeur/8], valeur%8);
}
byte lire(word valeur) // true si le CAN a eu cette valeur
{
return bitRead(lecture[valeur/8], valeur%8);
}
// *************************** Variables globales
boolean repos; // true pour 1023, false pour 0 quand aucun bouton n'est appuyé
word valeurLue, // Résultat de la conversion puis n° de la touche
oldValeurLue, oldOldValeurLue, // Mémorisation pour permettre trois lectures consécutives identiques
tempsDepart; // Pour patienter tant qu'on appuie sur une touche; word suffit car on ne dépassera jamais 3000
int indexDebut = 0, indexFin = 0; // Pour explorer la table et lire les valeurs limites
byte nbBoutons = 0;
boolean pasPremiereVirgule = false;
void setup()
{
// *************************** Initialisations
Serial.begin(BAUDS); // Régler aussi la console à BAUDS bauds!
analogReference(REFERENCE); // Permet de choisir la référence de tension
Serial.println(F("/*\nAppuyez sur toutes les touches, une par une\n"));
repos = (analogRead(PIN) > 512); // Au repos on a 0 ou 1023
// *************************** On attend qu'une touche soit appuyée
do
{
oldValeurLue = valeurLue; // Sauvegarde de la mesure précédente du CAN
valeurLue = analogRead(PIN); // Nouvelle lecture
} while ((valeurLue!=oldValeurLue) || // Il faut lire deux valeurs identiques (double lecture par sécurité)
(repos && (valeurLue > 1020)) || (!repos && (valeurLue < 3))); // Et on s'écarte du repos
// *************************** Recherche des valeurs possibles du CAN
do // Tant qu'on appui sur des touches
{
do // Tant que l'on ne lit pas une bonne valeur du CAN
{
oldOldValeurLue = oldValeurLue; // Sauvegarde des mesures précédentes du CAN
oldValeurLue = valeurLue;
valeurLue = analogRead(PIN); // Nouvelle lecture
} while ((valeurLue!=oldValeurLue) || (valeurLue!=oldOldValeurLue)); // On recommence jusqu'à avoir trois lectures identiques
ecrire(valeurLue); // On trouve une valeur, on l'enregistre
// Gestion du timer, on sortir de la boucle si on n'appuie plus sur une touche pendant 3s
if (repos) // Suivant qu'on ait 0 ou 1023 sans appuis
{
if (analogRead(PIN) < 1020) tempsDepart = millis(); // RAZ du timer tant qu'on appuie
}
else if (analogRead(PIN) > 5) tempsDepart = millis();
} while ((word)millis() - tempsDepart < 3000);
// *************************** Affichage des valeurs lues pour contrôle
// 1 indique une valeur vue, 0 une valeur que ne donne pas le CAN
for (word ligne=0; ligne<16; ligne++) // 1023 valeurs possibles affichées avec 16 lignes de 64 valeurs
{
if (ligne == 0) Serial.print(" 0"); // N° de la ligne affichée à gauche
else if (ligne == 1) Serial.print(" 64");
else Serial.print(ligne*64);
Serial.print(" "); // Pour aligner la table
for (word colonne=0; colonne<64; colonne++) Serial.print(lire(ligne*64+colonne)); // Les valeurs
Serial.println(); // Fin de ligne
}
Serial.println();
// *************************** On compte le nombre de boutons.
// C'est le nombre d'intervalle de la table qui contiennent que des 0. Les 1 indiquent un bouton
while (indexDebut < 1024)
{
while (!lire(indexDebut)) indexDebut++; // On se place sur la première valeur 1
while (lire(indexDebut) && (indexDebut < 1024)) indexDebut++; // On se place sur le premier 0 qui suit
nbBoutons++;
}
// *************************** Affichage un nombre de boutons sur la console
Serial.print(F("\nJ'ai vu "));
Serial.print(--nbBoutons);
Serial.print(F(" boutons\n*/\n\n"));
// *************************** On fait maintenant l'affichage du programme de test
// Commentaires du départ, début commun
Serial.print(F("// Ce programme teste la lecture de l'ensemble de boutons avec MTanalogButtons\n\n"
"#include <MTobjects.h> // V1.1.1 Voir http://arduino.dansetrad.fr/MTobjects\n\n"
"const byte PIN = "));
Serial.print(PIN);
Serial.print(F(";\nconst word TABLE_DES_SEUILS[] = {"));
// Il faut donner la table des valeurs
// Les valeurs sont par ordre décroissantes si au repos on a CAN=1023
if (repos)
{
indexDebut = 1023;
while (!lire(indexDebut)) indexDebut--; // On se place sur la dernière valeur
while (lire(indexDebut) && (indexDebut >= 0)) indexDebut--; // On se place avant la dernière valeur
while ((indexDebut >= 0) && (indexFin >= 0))
{
indexFin = indexDebut; // On cherche un intervalle sans bouton. Cela finit à indexDebut
while (!lire(indexFin) && (indexFin >= 0)) indexFin--; // La zone commence à indexFin + 1
if (indexFin >= 0) // C'est un intervalle sans boutons
{
if (pasPremiereVirgule) Serial.print(F(", ")); // La première fois on ne met pas de virgules
pasPremiereVirgule = true; // Les autres fois on la mettra
Serial.print((indexDebut + indexFin + 1)/2); // Et on met le milieu de l'intervalle
}
indexDebut = indexFin;
while (lire(indexDebut) && (indexDebut >= 0)) indexDebut--; // On se replace avant le bouton
}
Serial.print(F(", 0"));
}
// Les valeurs sont par ordre croissant si au repos on a CAN=0
else
{
indexDebut = 0;
while (!lire(indexDebut)) indexDebut++; // On se place sur la première valeur
while (lire(indexDebut) && (indexDebut < 1024)) indexDebut++; // On se place après la première valeur
while ((indexDebut < 1024) && (indexFin < 1024))
{
indexFin = indexDebut; // On cherche un intervalle sans bouton. Cela commence à indexDebut
while (!lire(indexFin) && (indexFin < 1024)) indexFin++; // La zone finit à indexFin - 1
if (indexFin < 1024) // C'est un intervalle sans boutons
{
if (pasPremiereVirgule) Serial.print(F(", ")); // La première fois on ne met pas de virgules
pasPremiereVirgule = true; // Les autres fois on la mettra
Serial.print((indexDebut + indexFin - 1)/2); // Et on met le milieu de l'intervalle
}
indexDebut = indexFin;
while (lire(indexDebut) && (indexDebut < 1024)) indexDebut++; // On se replace après le bouton
}
Serial.print(F(", 1024"));
}
// Suite du programme
Serial.print(F("}; // Valeurs des seuils de comparaisons\n\n"
"void appuis(byte touche)\n"
"{\n"
" Serial.print(\"La touche n°\");\n"
" Serial.print(touche);\n"
" Serial.print(\" vient d'être appuyée \");\n"
"}\n"
"void relachement(void)\n"
"{\n"
" Serial.println(\"et relâchée\");\n"
"}\n"
"MTanalogButtons Keypad(PIN, TABLE_DES_SEUILS, appuis, relachement);\n\n"
"void setup()\n"
"{\n"
" Serial.begin("));
Serial.print(BAUDS);
Serial.print(F("); // Régler aussi la console à "));
Serial.print(BAUDS);
Serial.print(F(" bauds!\n"));
if (REFERENCE != DEFAULT)
{
Serial.print(F(" analogReference("));
Serial.print(REFERENCE);
Serial.print(F(");\n"));
}
Serial.print(F(" Serial.println(\"Appuyez sur des touches\");\n"
"}\n\n"
"void loop(){}"));
}
void loop()
{
}
Ce programme se trouve dans la bibliothèque, chapitre Examples/MTanalogButtons, avec le nom 1_fr_Apprentissage.ino.
Analyse du résultat
Quand on arrête d'appuyer sur les touches pendant plus de 3 secondes, le programme affiche sur la console tout d'abord une table et le nombre de boutons. Dans la suite, j'ai utilisé un keypad analogique de 20 touches avec une tension de référence du CAN de 1,1V et avec une Uno. Le montage est le suivant:
Il est calculé pour une référence à 1,1V. J'ai donc change la ligne 16:
#define REFERENCE DEFAULT
par
#define REFERENCE INTERNAL
Le début du résultat est:
0 1000000000000000000000000000000000000000000000000000000001100000 64 0000000000000000000000000000000000000000000000000000110000000000 128 0000000000000000000000000000000000000000000000110000000000000000 192 0000000000000000000000000000000000000001100000000000000000000000 256 0000000000000000000000000000000011100000000000000000000000000000 320 0000000000000000000000111000000000000000000000000000000000000000 384 0000000000011100000000000000000000000000000000000000000000000011 448 1000000000000000000000000000000000000000000000011111000000000000 512 0000000000000000000000000000000000011110000000000000000000000000 576 0000000000000000001111000000000000000000000000000000000000000000 640 0111100000000000000000000000000000000000000000011110000000000000 704 0000000000000000000000000001111000000000000000000000000000000000 768 0000000011110000000000000000000000000000000000000011100000000000 832 0000000000000000000000000001111000000000000000000000000000000000 896 0000111100000000000000000000000000000000001111100000000000000000 960 0000000000000000000000000000000000000000000000000000000000000001
La grille indique ce que l'on a vu pour les valeurs en sortie du CAN entre 0 et 1023. Un "1" indique que si en appuyant sur les boutons, on obtient la valeur considérée, un "0" indique que l'on n'obtient pas cette valeur. En regardant le tableau, on voit que l'on peut avoir 0, 57, 58, 116, 117... 1023. "0" correspond à un appui sur le bouton n°0, 57 et 58 correspond à un appui sur le bouton n°1... et 1023 est obtenu si aucun bouton n'est appuyé.
On observera que l'appui sur un bouton donne de 1 à 4 valeurs possibles. Si tout étaii parfait, on aurait des paquets de un seul "1". On peut voir de plus que les paquets de 1 sont très espacés, ce qui indique que l'on pourrait presque mettre 4 fois plus de boutons.
Si pour un bouton, on obtenait 0000101110000, cela signifierait que l'on n'a pas appuyé suffisamment longtemps sur la touche.
On remarquera aussi que les valeurs utilisent quasiment tout l'espace ce qui fait que l'on peut se permettre plus de bruit et d'incertitudes.
Cette représentation permet de se rendre compte de la qualité de la réalisation.
Suit ensuite le nombre de boutons vus:
J'ai vu 20 boutons
J'ai bien un keypad de 20 touches, tout va bien. Si j'avais eu moins de 20 boutons, ce serait sans doute un oubli d'un appui, ou suffisamment de dispersion qui ferait une seule suite de 1 pour deux boutons différents (trop de bruits ou trop e boutons). Si j'avais eu plus de 20 boutons, c'est que j'aurais une suite genre 000000101100000 pour un bouton. Soit je n'aurais pas appuyé assez longtemps, soit le montage est trop perturbé.
Le programme résultat
Suit enfin un programme de test. On peut par exemple obtenir:
// Ce programme teste la lecture de l'ensemble de boutons avec MTanalogButtons
#include <MTobjects.h> // V1.1.1 Voir http://arduino.dansetrad.fr/MTobjects
const byte PIN = 14;
const word TABLE_DES_SEUILS[] = {982, 920, 880, 840, 797, 754, 710, 665, 619, 571, 523, 471, 421, 369, 316, 260, 204, 145, 87, 28, 0}; // Valeurs des seuils de comparaisons
void appuis(byte touche)
{
Serial.print("La touche n°");
Serial.print(touche);
Serial.print(" vient d'être appuyée ");
}
void relachement(void)
{
Serial.println("et relâchée");
}
MTanalogButtons Keypad(PIN, TABLE_DES_SEUILS, appuis, relachement);
void setup()
{
Serial.begin(115200); // Régler aussi la console à 115200 bauds!
analogReference(3);
Serial.println("Appuyez sur des touches");
}
void loop(){}