MTradioButton: Exemple 2

Ce programme va simuler un choix MW-LW-FM. On choisit la gamme par des boutons câblés sur A0, A1, et A2. La console nous indique les changements. On va utiliser un objet dérivé pour n'écrire qu'une fois seulement les actions des boutons. C'est aussi à but pédagogique pour montrer comment reféfinir un bouton.

La classe dérivée

Nous allons créer une classe dérivée de MTradioButton, ce qui est intéressant si on a plusieurs boutons au comportement identique. Si on ne voulait pas le faire, il faudrait alors écrire les actions des boutons 3 fois comme dans l'exemple précédent.

Les deux fonctions à surcharger sont les fonctions onSelect et onUnselect qui vont procéder aux affichages. Comme les messages diffèrent par le nom de la gamme seulement, il va falloir mémoriser cette différence dans une variable de l'objet (on dit dans une propriété):

  String nom; // Nom qui sera affiché sur la voie série

Les fonctions qui vont faire les affichages sont alors:

  virtual void onSelect(void) // Fonction à surcharger qui informe la sélection
  {
    Serial.print("On vient de choisir ");
    Serial.println(nom);
  }
  virtual void onUnselect(void) // Fonction à surcharger qui informe la désélection
  {
    Serial.print("On vient d'annuler ");
    Serial.println(nom);
  }

Pour construire un bouton, il faut lui donner le numéro de la broche, les deux lettres à afficher (nom) et la valeur. On pourrait se passer de donner la valeur si on utilise une variable globale qui compte le nombre de boutons initialisés, ce qui donnerait 0 pour le premier, 1 pour le suivant... L'entête du constructeur ressemblera à:

MonBouton (uint8_t pin, String nom, byte valeur)

nom initialisera la variable correspondante, le reste sera initialisé par le constructeur de MTradioButton:

  MonBouton (uint8_t pin, String p_nom, byte valeur) // Nouveau constructeur
    :MTradioButton(pin, PAS_D_ACTION, PAS_D_ACTION, HIGH si_non_appuye, valeur), nom(p_nom)
    {};

Les deux PAS_D_ACTION correspondent aux fonctions callback que nous n'avons pas besoin d'appeler. Le HIGH si_non_appuye, bien qu'étant la valeur par défaut, ne peut être omis car il nous faut spécifier le paramètre valeur qui suit.

La définition complète de la classe sera ainsi:

class MonBouton: public MTradioButton
{
 public:
  MonBouton (uint8_t pin, String p_nom, byte valeur) // Nouveau constructeur
    :MTradioButton(pin, PAS_D_ACTION, PAS_D_ACTION, HIGH si_non_appuye, valeur), nom(p_nom)
    {};
 private:
  String nom; // Nom qui sera affiché sur la voie série
  virtual void onSelect(void) // Fonction à surcharger qui informe la sélection
  {
    Serial.print("On vient de choisir ");
    Serial.println(nom);
  }
  virtual void onUnselect(void) // Fonction à surcharger qui informe la désélection
  {
    Serial.print("On vient d'annuler ");
    Serial.println(nom);
  }
};

Enfin, il faut comme dans tous les programmes qui utilisent MTobjets, inclure la bibliothèque utile. Ici on utilise comme seul objet un bouton radio (le nom de l'objet est MTradioButton):

#include "MTradioButton.h" // V1.0.0 Voir http://arduino.dansetrad.fr/MTobjects

Je conseille fortement de laisser le commentaire, si une autre personne voulait essayer le programme, elle aurait directement un lien de téléchargement. C'est valable pour toutes les bibliothèques que vous utilisez.

Les boutons

On va commencer par donner des noms symboliques aux broches utilisées. Ici, il y en a trois, une pour chaque bouton:

const uint8_t PIN_BUTTON_MW = A0; // Bouton câblé entre GND et A0
const uint8_t PIN_BUTTON_LW = A1; // Bouton câblé entre GND et A1
const uint8_t PIN_BUTTON_FM = A2; // Bouton câblé entre GND et A2

Maintenant, nous pouvons déclarer nos boutons:

MonBouton BoutonMW(PIN_BUTTON_MW, "MW", RADIO_BUTTON_0);
MonBouton BoutonLW(PIN_BUTTON_LW, "LW", RADIO_BUTTON_1);
MonBouton BoutonFM(PIN_BUTTON_FM, "FM", RADIO_BUTTON_2);

setup()

Comme on écrit sur la console, il faut l'initialiser:

void setup()
{
  Serial.begin(115200);
  ...

Quand le programme va démarrer, aucun bouton n'est sélectionné. La fonction getMTradioButtonValeur() qui doit nous donner la valeur du bouton va donc retourner 128 qui correspond à "aucun bouton actif". Il faudrait alors regarder la valeur retournée par cette fonction et afficher "aucun bouton sélectionné" si on a 128, sinon on affiche le numéro du bouton. L'autre solution, qui correspond plus à la réalité est de présélectionner un bouton, par exemple le MW:

void setup()
{
  ...
  BoutonMW.select();
  ...

Un petit problème se pose, le bouton peut être pris en compte avec un délai 16ms. Cette sélection peut donc être prise trop tard, car un court instant après loop va nous afficher qu'aucun bouton n'est actif. Il faut donc attendre un peu, on peut dans loop attendre et afficher au lieu de faire l'inverse, ou attendre 16ms dans le setup. Choisissons cette solution:

void setup()
{
  ...
  BoutonMW.select();
  delay(16);
}

loop()

Dans loop(), nous allons afficher la gamme choisie. Pour cela, la fonction globale getMTradioButtonValeur() nous retourne la valeur du bouton actif. Si on ne précise rien, c'est le bouton du groupe 0 qui compte. Comme nous n'avons pas non plus spécifié le groupe lors de la définition des boutons, ils appartiennent tous au groupe 0. On n'a donc pas besoin de spécifier ce paramètre. Comme nous avons choisi des valeurs 0, 1 ou 2, il suffit de transformer ce nombre en chaîne de caractères:

String noms[3] = {"MW", "LW", "FM"};

void loop()
{
  ...
  noms[getMTradioButtonValeur()] // MW, LW ou FM
  ...
}

Il suffit d'afficher cette chaîne. Bien entendu, il va falloir ralentir l'affichage pour que cela ne défile pas trop vite. On peut par exemple rajouter un petit delay(2000 milli_secondes);. Notez au passage que le delay ne gêne pas du tout la prise en compte des boutons. Si on appuie sur plusieurs boutons pendant ce temps, on observera qu'ils sont tous pris en compte grâce aux phrases d'activation et de désactivations. Cela donne finalement pour loop:

String noms[3] = {"MW", "LW", "FM"};

void loop()
{
  Serial.print("La gamme actuelle est ");
  Serial.println(noms[getMTradioButtonValeur()]); // Affiche le nom du bouton sélectionné
  delay(2000); // Pour avoir un affichage qui ne défile pas trop vite
}

Programme complet

Voici donc le programme complet:

// Ce programme va simuler un choix MW-LW-FM. On choisit la gamme par des
// boutons câblés sur A0, A1, et A2. La console nous indique les changements
// On va utiliser une classe dérivée de MTradioButton

#include "MTradioButton.h" // V1.0.0 Voir http://arduino.dansetrad.fr/MTobjects

const uint8_t PIN_BUTTON_MW = A0; // Bouton câblé entre GND et A0
const uint8_t PIN_BUTTON_LW = A1; // Bouton câblé entre GND et A1
const uint8_t PIN_BUTTON_FM = A2; // Bouton câblé entre GND et A2

// Définition d'une nouvelle classe qui surcharge onSelect et onUnselect
class MonBouton: public MTradioButton
{
 public:
  MonBouton (uint8_t pin, String p_nom, byte valeur) // Nouveau constructeur
    :MTradioButton(pin, PAS_D_ACTION, PAS_D_ACTION, HIGH si_non_appuye, valeur), nom(p_nom)
    {};
 private:
  String nom; // Nom qui sera affiché sur la voie série
  virtual void onSelect(void) // Fonction à surcharger qui informe la sélection
  {
    Serial.print("On vient de choisir ");
    Serial.println(nom);
  }
  virtual void onUnselect(void) // Fonction à surcharger qui informe la désélection
  {
    Serial.print("On vient d'annuler ");
    Serial.println(nom);
  }
};



//Définition des boutons
MonBouton BoutonMW(PIN_BUTTON_MW, "MW", RADIO_BUTTON_0);
MonBouton BoutonLW(PIN_BUTTON_LW, "LW", RADIO_BUTTON_1);
MonBouton BoutonFM(PIN_BUTTON_FM, "FM", RADIO_BUTTON_2);



void setup()
{
  Serial.begin(115200);
  BoutonMW.select(); // Pour qu'il y ait au moins une gamme sélectionnée
  delay(16); // Ainsi on est sûr que le bouton est sélectionné (retard possible de la prise en compte 16ms)
}


String noms[3] = {"MW", "LW", "FM"};

void loop()
{
  Serial.print("La gamme actuelle est ");
  Serial.println(noms[getMTradioButtonValeur()]);
  delay(2000); // Pour avoir un affichage qui ne défile pas trop vite
}