dimanche 1 juillet 2012

Launchpad, LED et bouton poussoir

Cette quatrième rubrique concernant le MSP 430 Launchpad de Texas Instruments consiste à allumer et éteindre une LED au moyen d'un bouton poussoir (rubriques précédentes concernant le Launchpad).

Le circuit est illustré ci-contre: une LED en série avec une résistance de protection est branchée entre la broche "P1.0" et la mise à la terre, et un bouton poussoir relié à une résistance "pull-up" contrôle le voltage de l'entrée "P1.4".  En fait, la LED n'est pas strictement nécessaire puisque la carte comporte déjà une LED rouge associée à "P1.0".

Faisons d'abord en sorte que la LED s'allume pendant que le bouton est enfoncé, et qu'elle s'éteint quand le bouton est relâché.  Texas Instruments fournit un exemple de sketch qui accomplit cette tâche:  vous le trouverez sous le nom de "msp430g2xx3_P1_01.c", et comme d'habitude la description du fichier est assez nébuleuse:  "Software Poll P1.4, Set P1.0 if P1.4 = 1".



/************************************************************************
Code d'origine fourni par TI pour allumer une LED (branchée à P1.0)
au moyen d'un bouton (branché à P1.4)
*************************************************************************/
#include  

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;              // Désactivation du chien de garde
  P1DIR |= 0x01;                         // P1.0 réglé à output

  while (1)                              // Boucle infinie
  {
    if ((0x10 & P1IN)) P1OUT |= 0x01;    // Si P1.4 est 1, on met P1.0 à 1
    else P1OUT &= ~0x01;                 // Sinon, on met P1.0 à 0
  }
}



J'ai modifié le sketch original en utilisant une syntaxe moins compacte de façon à obtenir un résultat qui est, en ce qui me concerne, un peu plus lisible:



/************************************************************************
Code pour allumer une LED (branchée à P1.0) au moyen d'un bouton 
(branché à P1.4).  La LED s'éteint dès qu'on relâche le bouton.
*************************************************************************/

#include  

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;              // Désactivation du chien de garde
  P1DIR = P1DIR | BIT0;                 // P1.0 réglé à output

  while (1)                              // Boucle infinie
  {
    if ((BIT4 & P1IN)) {
     P1OUT =  (P1OUT | BIT0);   // Si P1.4 est 1, on met P1.0 à 1
     }  
    else{ 
     P1OUT = P1OUT & ~BIT0;  // Sinon, on met P1.0 à 0
     }               
  }
}





Dans un premier temps, le code désactive le chien de garde, un dispositif qui permet de redémarrer le programme si ce dernier est gelé, mais qui ne nous intéresse pas pour l'instant.  "WDTCTL" signifie "watchdog timer control"; "WDTPW" signifie "watchdog timer password" et "WDTHOLD" signifie "watchdog timer hold".


Par défaut, toutes les broches sont réglées en "input" au démarrage.  Pour alimenter la LED, P1.0 doit être configuré en "output", et c'est ce que nous accomplissons dans la ligne suivante.  P1DIR est un nombre binaire à 8 bits qui indique l'état (entrée ou sortie) des broches P1.0 à P1.7.  "BIT0" et "0x01" sont deux façons différentes d'exprimer le nombre binaire "00000001".  Grâce à l'opérateur logique "|" ("OU"), le bit associé à P1.0 est réglé à "1" est les autres bits demeurent inchangés.



On entre ensuite dans une boucle "while" qui sera exécutée sans arrêt jusqu'à l'interruption du programme.  Nous vérifions si le bit numéro 4 (associé à P1.4) est à "1", ce qui signifie que le bouton est enfoncé.  "BIT4" et "0x10" sont deux façons différentes d'exprimer le nombre binaire "00010000".  

Si le bouton est enfoncé, on ajuste la sortie "P1.0" à "1", ce qui allume la LED.  Si le bouton n'est pas enfoncé, on ajuste la sortie "P1.0" à "0", et la LED s'éteint.

J'ai ensuite modifié le code pour obtenir le comportement suivant:  la LED s'allume lorsqu'on enfonce le bouton, et elle demeure allumée lorsqu'on le relâche.  La LED s'éteint lorsqu'on enfonce le bouton à nouveau.



/************************************************************
 * Une LED est reliée à P1.0, un bouton est relié à P1.4
 * Lorsqu'on appuie sur le bouton, la LED s'allume.
 * L'orsqu'on relâche le bouton, la LED reste allumée.
 * Lorsqu'on appuie à nouveau sur le bouton, la LED s'éteint.
 ************************************************************/

#include  

void main(void)
{
 volatile unsigned int maintenant = 0; //état actuel du bouton
 volatile unsigned int auparavant = 0; //état précédent du bouton
 volatile unsigned int lumiere = 0; //état actuel de la LED 
 volatile unsigned int i; 
 
  WDTCTL = WDTPW + WDTHOLD;    // Désactivation du chien de garde
  P1DIR = P1DIR | BIT0;        // P1.0 réglé à output

  while (1)     // Boucle infinie
  {
    if ((BIT4 & P1IN)) { // si le bouton est enfoncé
     maintenant = 1;  
     if (!auparavant){ //s'il y a un un changement
      lumiere = !lumiere; // on change l'état de la LED          
    i = 10000;        // Délai pour contrer les rebonds du bouton
    do (i--);
    while (i != 0);
     }    
    }  
    else{ 
     maintenant = 0;
     }  
    auparavant = maintenant;
     
    if (lumiere)  {   
        P1OUT =  (P1OUT | BIT0);   // Si P1.4 est 1, on met P1.0 à 1 
    }
    else{ 
       P1OUT = P1OUT & ~BIT0;  // Sinon, on met P1.0 à 0
    }       
  } 
}




Le code est assez similaire au précédent, mais cette fois la variable "maintenant" prend la valeur "1" lorsque le bouton est enfoncé, et la valeur "0" lorsqu'il ne l'est pas.  Lorsqu'il y a un changement dans l'état du bouton (de "0" vers "1"), la LED s'allume si elle était éteinte, et s'éteint si elle était allumée (lumiere = !lumiere).  J'ai ajouté un petit délai (au moyen d'une boucle while) pour que le microcontrôleur ne tienne pas compte des rebonds du boutons (ça ne fonctionne pas à tous les coups, mais c'est assez bien).

Ceci étant dit, la méthode utilisée ici ("polling") est déconseillée par l'équipe de Texas Instruments, qui prévilégie plutôt le recours aux interruptions ("interrupts"), qui sont plus efficaces et plus économes en énergie.  Je tenterai donc de comprendre comment gérer les interruptions et je vous en reparlerai si j'y arrive.  Sinon, mes codes continueront inévitablement de porter l'étiquette "CONÇU PAR UN AMATEUR", à un point tel qu'on pourrait même me soupçonner d'avoir un Arduino à la maison!

Yves Pelletier (Twitter: @ElectroAmateur)

3 commentaires:

  1. bonjour, Déjà un grand merci pour ces infos. Je viens de commencer à utiliser le Launchpad et autant vous dire que je rencontre quelques difficultés. Sur la partie boutton poussoir, je ne comprend pas le code mais je l'ai quand même copié mais il ne marche, je voudrai donc savoir si c'était normal ou c'est dans ma config que j'ai loupé un truc.

    RépondreSupprimer
  2. Bonjour,

    Vraiment très intéressant.

    Dans le cadre d'un projet en électronique sur le MSP 430, je dois déclencher l'allumage de LEDs en fonction de la durée d'appui sur le bouton poussoir:
    - L’appui court sur le Bouton Poussoir allume la LED verte (T<1s).
    - L’appui long sur le Bouton Poussoir allume la LED rouge (T>2s).
    - Si une LED est allumée (rouge ou verte) l’appui sur le Bouton Poussoir éteinte la LED. - On recommence le cycle.

    Je n'arrive pas à trouver la bonne solution permettant de réaliser ce programme.

    Pourriez vous m'aider s'il vous plait?

    Merci d'avance pour votre aide

    Cordialement

    Anthony

    RépondreSupprimer
  3. Bonjour,
    Je suis nouveau à la programmation et je consulte ce site cette semaine. Quand vous écrivez « #include » il me semble que le compilateur attend quelque chose après include. Pouvez-vous m’aider s’il-vous-plais merci.

    RépondreSupprimer