Premiers montages

PWM et bouton poussoir

Un montage à peine plus compliqué que le précédent, support de deux applications.

Le schéma électrique est donné à titre indicatif.

Dans l'optique de simplifier le montage nous utilisons une LED comme dispositif commandé. Il est tout à fait possible de la remplacer par autre chose, comme par exemple un ventilateur (peut-être un relai sera-t-il nécessaire).

Cette fois ci, la LED est branchée de manière à ce que le courant ne soit pas tiré du port de l'Arduino qui ne peut pas délivrer beaucoup de puissance.

Nous illustrons également les problèmes liés à l'utilisation d'un bouton poussoir et aux oscillations dans les acquisitions de grandeurs physiques.

Montage

Impossible d'afficher l'image
Vue de la platine d'essai.
Impossible d'afficher l'image
Schéma électrique.

Un montage avec deux LED 5mm, une jaune et une rouge. La première est commandée par le port 6 et la seconde par le port 9. Les deux sont reliées à la masse via une résistance de 330 Ω.

Liste des composants

Nom Type
Composant1 Arduino Uno (Rev3)
LED1 LED Rouge
R2 Résistance 330 Ω
R3 Petit potentiomètre rotatif
S1 Bouton poussoir
T1 Capteur de température TMP36

Commentaires

Les points intéressants du montage concernent donc le branchement de la LED, du bouton poussoir et du capteur de température. Le branchement du potentiomètre a déjé été abordé dans les exemples précédents.

Le capteur de température utilisé est un composant actif, c'est à dire qu'il doit être alimenté par une source de courant externe. Ici nous prenons la source 5 V fournie par l'Arduino. Ce genre de capteur possède une datasheet (document le décrivant tant au niveau physique, qu'électronique, thermique, ... et donnant ses modalités d'utilisation) qui va expliquer comment le brancher. Ce modèle, le TMP36, est très simple à utiliser et la valeur reçue se lit comme celle d'un potentiomètre.

La LED est branchée dans un sens différent de ce que nous avons vu jusqu'à présent. Une de ses pâte est toujours connectée à l'Arduino, mais l'autre n'est pas connectée à la masse comme précédemment, mais au 5 V. Le fonctionnement de l'Arduino ne va donc pas être le même. En effet, au repos, il va falloir que le signal soit haut (5 V), pour qu'il n'y ait pas de différence de potentiel entre les deux broches de la LED et qu'elle soit éteinte. L'allumage de la LED se fera en forçant un état bas sur ce port, créant ainsi la différence de potentiel nécessaire.

Le bouton poussoir va fonctionner de la manière suivante. Au repos, le signal qu'on lira sur le port sur lequel il est branché sera haut (5 V). Un pression sur le bouton fera passer le signal à l'état bas. Ceci signifie qu'il doit être possible d'avoir un état de repos haut alors que le port n'est connecté à rien. Ceci est réalisé en activant un petit dispositif interne au micro-contrôleur, qui est une résistance de pull-up, qui va tirer le signal vers le haut quand il est au repos. Comme cette résistance est interne au micro-contrôleur, il n'est pas nécessaire de l'ajouter sur la plaque de montage. Il suffit de l'activer par programme comme nous le verrons dans la section suivante.

Les micro-contrôleurs utilisés sur les cartes Arduino n'ont qu'une résistance de pull-up par port. D'autres modèles de micro-contrôleurs ont également des résistances de pull-down (ce qui permettrait de faire un montage ou l'interrupteur est branché au 5 V, où le signal au repos est à 0 et s'active sur un niveau haut).

Programmes et commentaires

Dans les exemples qui suivent vous allez apprendre à utiliser des dispositifs mécaniques comme un bouton poussoir (le processus serait très semblable avec un interrupteur à bascule) et à écrire des valeurs quasi-analogiques.

Ce sera également l'occasion d'introduire un concept de programmation : les fonctions. Elles permettent de rendre le code modulaire, de faire des blocs qui pourront éventuellement être utiliser plusieurs fois dans le programme ou même, dans d'autres programmes.

Utilisation d'un bouton poussoir

Quoi de plus simple qu'un bouton poussoir où il suffit d'appuyer pour que ce que l'on pilote change d'état ! Cependant, un tel bouton étant un dispositif mécanique, le fait de l'actionner provoque des rebonds. À cause de ces rebonds, ce qui devrait être une transition franche et rapide, devient une succession de transitions s'étalant sur un laps de temps non négligeable. Si rien n'est fait, notre système va réagir à toutes ces transitions et se retrouver dans un état qui n'est pas prévisible.

La première tâche sera donc d'éliminer ces rebonds. Pour cela, nous pourrions choisir une solution électronique en rajoutant un petit condensateur en parallèle du bouton poussoir. Les rebonds seraient filtrés par sa présence et le problème serait en grande partie résolu. Nous préférons cependant opter pour une solution informatique où ce filtrage est réalisé dans le programme.

En guise de filtrage nous allons simplement interdire les lectures trop rapprochées de l'état du bouton poussoir. Les rebonds ne s'étalant pas à l'infini, nous espérons que le signal se sera stabilisé entre deux lecture. En pratique, nous observons de bons résultats pour des valeurs d'attente entre deux lectures d'environ 50 ms. C'est très court, mais c'est suffisant.

La structure du programme sera la même que celle utilisée pour faire clignoter une LED : un test non bloquant sert à déterminer s'il s'est passé assez de temps entre le moment du test et la dernière lecture.

Un autre point à relever est le fait que nous voulons que le bouton poussoir agisse comme une bascule. Nous ne voulons pas qu'un appui long sur le bouton produise une salve de changements d'états. Mais pourquoi ne pas avoir pris un bouton de type bascule alors ? Parce que c'est un exemple simple permettant de voir comment détecter les fronts de signaux carrés.

Ce que nous devons détecter, c'est le passage du signal associé au bouton de l'état de repos (état HIGH) à l'état activé (état LOW). De plus, si l'état activé dure, il ne doit rien se passer. Pour réaliser cela nous sommes obligés de connaître l'état actuel du signal (c'est le rôle de la variable lecture_bouton). Mais nous devons également conserver l'état précédent (ce qui est confié à la variable lecture_precedente), c'est à dire, l'état au moment de la lecture précédente. Enfin, nous disposons d'une variable etat qui reflète l'état du système (en fonction ou pas) et dont la valeur va changer à chaque fois qu'une pression (valide) est détectée.

Comme cette méthode de lecture pourra être réutilisée à chaque fois que l'on désire employer un bouton poussoir dans un montage, nous écrivons le code correspondant dans une fonction (lire_bouton() dans notre exemple). Cette première version de la fonction a une mécanique simple qui impose la déclaration de variables globales. Son utilisation dans un autre contexte devra être entourée de quelques précautions. Nous verrons plus tard comment la rendre vraiment indépendante.

/**
 * Utilisation d'un bouton poussoir comme bascule d'état.
 * Le bouton poussoir va commander l'allumage d'une LED.
 */

#define LED 11
#define BOUTON 2

#define REBOND 50

unsigned long rebond_bouton ;
int           lecture_bouton,
              lecture_precedente ;
bool          etat ;

/** Gestion du bouton poussoir.
 * Pour éviter les rebonds la lecture n'est faite que toutes
 * les REBOND ms.
 * Pour éviter les changements d'état non désirés quand le bouton
 * reste enfoncé, on utilise un mécanisme de détection
 * des fronts descendants.
 */
void lire_bouton()
{
  if ( (millis() - rebond_bouton) > REBOND ) {
    rebond_bouton = millis() ;
    lecture_bouton = digitalRead(BOUTON) ;
    if ( lecture_bouton != lecture_precedente ) {
      if ( lecture_bouton == LOW ) {
        etat = !etat ;
      }
      lecture_precedente = lecture_bouton ;
    }
  }
} 

void setup()
{
  // La LED étant branchée au +5V,
  // on positionne la sortie à HIGH pour l'éteindre.
  pinMode(LED, OUTPUT) ;
  digitalWrite(LED, HIGH) ;

  /* Le bouton fait tomber le signal quand
   * il est actionné. Il faut donc que le signal
   * soit à HIGH au repos. On saura qu'il a été actionné
   * si on lit la valeur LOW sur le port correspondant.
   */
  pinMode(BOUTON, INPUT_PULLUP) ;

  rebond_bouton = millis() ;

  lire_bouton() ;
}

void loop()
{
  // Lecture de l'état du bouton
  lire_bouton() ;

  // Modification de l'état de la LED
  if ( etat ) {
    digitalWrite(LED, LOW) ;
  } else {
    digitalWrite(LED, HIGH) ;
  }
}
Commander une LED avec un bouton poussoir via un Arduino.

Écriture analogique

Dans cette suite, nous améliorons notre montage pour que la LED puisse varier d'intensité avec le temps. Nous allons la faire "pulser", c'est à dire qu'elle va s'allumer doucement, puis qu'elle va s'éteindre doucement, en boucle.

Écriture analogique

Pour faire pulser une LED, il faut être capable de faire varier la tension à ses bornes très faiblement pour se déplacer sur sa courbe représentative aux alentours de la tension de seuil.

Notre famille de microcontrolleur ne dispose pas de convertisseurs numérique → analogique. Par contre, ils nous permettent d'utiliser un mécanisme qui permet, dans certaines mesures, de simuler ce comportement et qui est connu sous le doux nom de Modulation de Largeur d'Impulsion (MLI ou PWM — Pulse Width Modulation, en anglais). Vous pouvez en trouver une description complète sur, par exemple, la page Wikipedia correspondante. Pour se faire une idée de ce dont il s'agit, il faut imaginer un signal carré dont, sur un temps donné, aurait un

/**
 * Faire pulser une LED.
 * La luminosité de la LED va varier avec le temps.
 * De l'état complètement éteint, elle va
 * passer par plusieurs étapes pour arriver à un
 * état complètement allumé et inversement.
 * Le fonctionnement du pulse est toujours commandé par
 * le bouton poussoir.
 */

#define POT A4

#define LED 11
#define BOUTON 2

#define REBOND 50
#define DELTA_PULSE 1

unsigned int  seuil ;
unsigned long rebond_bouton,
              pulse_led_delai;
int           lecture_bouton,
              lecture_precedente,
              pulse_led_valeur,
              pulse_direction ;
bool          etat ;

/** Gestion du bouton poussoir.
 * Pour éviter les rebonds la lecture n'est faite que toutes
 * les REBOND ms.
 * Pour éviter les changements d'état non désirés quand le bouton
 * reste enfoncé, on utilise un mécanisme de détection
 * des fronts descendants.
 */
void lire_bouton()
{
  if ( (millis() - rebond_bouton) > REBOND ) {
    rebond_bouton = millis() ;
    lecture_bouton = digitalRead(BOUTON) ;
    if ( lecture_bouton != lecture_precedente ) {
      if ( lecture_bouton == LOW ) {
        etat = !etat ;
      }
      lecture_precedente = lecture_bouton ;
    }
  }
}

/** Une étape de pulse.
 * La fonction est appelée plus ou moins fréquemment
 * selon la vitesse de pulse que l'on désire obtenir.
 */
void pulse_LED_step()
{
  pulse_led_valeur += pulse_direction * DELTA_PULSE ;
  if ( pulse_led_valeur >= 255 || pulse_led_valeur <= 0 ) {
    pulse_direction = -1 * pulse_direction ;
    if ( pulse_led_valeur <= 0 ) {
      pulse_led_valeur = 0 ;
    } else {
      pulse_led_valeur = 255 ;
    }
  }
  analogWrite(LED, pulse_led_valeur) ;
}

/** Fonction de lecture du seuil.
 * En fonction du type de dispositif employé pour
 * fixer le seuil, on pourra adapter le comportement
 * de cette fonction, tant que son prototype reste le même.
 */
int lire_seuil()
{
  return analogRead(POT) ;
}


void setup()
{
  // La LED étant branchée au +5V,
  // on positionne la sortie à HIGH pour l'éteindre.
  pinMode(LED, OUTPUT) ;
  digitalWrite(LED, HIGH) ;

  // Le bouton fait tomber le signal quand
  // il est actionné. Il faut donc que le signal
  // soit à HIGH au repos. On saura qu'il a été actionné
  // si on lit la valeur LOW sur le port correspondant.
  pinMode(BOUTON, INPUT_PULLUP) ;

  rebond_bouton = millis() ;
  pulse_led_delai = micros() ;
  pulse_led_valeur = 0 ;
  pulse_direction = 1 ;
  
  lire_bouton() ;
}

void loop()
{
  // Lecture de la valeur du potentiomètre
  seuil = lire_seuil() ;
  
  // Lecture de l'état du bouton
  lire_bouton() ;

  // Modification de l'état de la LED
  if ( etat ) {
    if ( (micros() - pulse_led_delai) > seuil ) {
      pulse_led_delai = micros() ;
      pulse_LED_step() ;
    }
  } else {
    digitalWrite(LED, HIGH) ;
  }
}
Faire pulser une LED connectée à un Arduino à l'aide du PWM.

Exemple complet

/**
 * 
 */

#define TEMP A3
#define POT A4

#define LED 11
#define BOUTON 2

#define REBOND 50

unsigned int temperature,
             seuil,
             rebond_bouton,
             pulse_led ;
int          lecture_bouton,
             lecture_precedente ;
bool         etat ;

/** Gestion du bouton poussoir.
 * Pour éviter les rebonds la lecture n'est faite que toutes
 * les REBOND ms.
 * Pour éviter les changements d'état non désirés quand le bouton
 * reste enfoncé, on utilise un mécanisme de détection
 * des fronts descendants.
 */
void lire_bouton()
{
  if ( (millis() - rebond_bouton) > REBOND ) {
    rebond_bouton = millis() ;
    lecture_bouton = digitalRead(BOUTON) ;
    if ( lecture_bouton != lecture_precedente ) {
      if ( lecture_bouton == LOW ) {
        etat = !etat ;
      }
      lecture_precedente = lecture_bouton ;
    }
  }
} 

/** Pilotage de la LED.
 * Si la température dépasse le seuil fixé par le
 * potentiomètre, la LED est allumée à pleine puissance.
 * Sinon, sa luminosité dépend de l'écart entre le seuil
 * et la température.
 */
void pilote_LED()
{
  if ( temperature > seuil ) {
    digitalWrite(LED, LOW) ;
  } else if ( temperature < 0.95*seuil ) {
    analogWrite(LED, (int)(255./1023.*(seuil-temperature))) ;
  } 
}

/** Fonction de lecture de la température.
 * En fonction du capteur employé, on pourra changer
 * le comportement de cette fonction, tant que son
 * prototype reste le même.
 */
int lire_temperature()
{
  return analogRead(TEMP) ;
}

/** Fonction de lecture du seuil.
 * En fonction du type de dispositif employé pour
 * fixer le seuil, on pourra adapter le comportement
 * de cette fonction, tant que son prototype reste le même.
 */
int lire_seuil()
{
  return analogRead(POT) ;
}


void setup()
{
  // La LED étant branchée au +5V,
  // on positionne la sortie à HIGH pour l'éteindre.
  pinMode(LED, OUTPUT) ;
  digitalWrite(LED, HIGH) ;

  // Le bouton fait tomber le signal quand
  // il est actionné. Il faut donc que le signal
  // soit à HIGH au repos. On saura qu'il a été actionné
  // si on lit la valeur LOW sur le port correspondant.
  pinMode(BOUTON, INPUT_PULLUP) ;

  rebond_bouton = pulse_led = millis() ;

  lire_bouton() ;
}

void loop()
{
  // La lecture des valeurs de seuil et
  // de température se fait tout le temps.
  temperature = lire_temperature() ;
  seuil = lire_seuil() ;

  // Lecture de l'état du bouton
  lire_bouton() ;

  // Modification de l'état de la LED
  if ( etat ) {
    pilote_LED() ;
  } else {
    digitalWrite(LED, HIGH) ;
  }
}
Allumer une LED connectée à un Arduino.