Manuel de laboratoire pour contrôleurs embarqués

Utilisation du langage C et de la plateforme Arduino


précédentsommairesuivant

XI. Les entrées analogiques

Dans cet exercice, nous allons examiner la méthode d’acquisition des signaux analogiques tels que ceux délivrés par divers capteurs à mesure continue. On utilise ces capteurs délivrant un signal à variation continue pour mesurer des températures, forces, accélérations, etc. Cette capacité doit être combinée aux techniques d’entrées/sorties numériques déjà vues afin de bâtir un système indiquant la force appliquée par une série de LED. Plus la force appliquée est grande, plus il y aura de LED allumées.

Les microcontrôleurs utilisent des Convertisseurs Analogique-Numérique (CAN ou ADC pour Analog to Digital Converter) pour mesurer des tensions d’entrée variables en continu. L’ATmega 328P possède un CAN 10 bits précédé d’un multiplexeur à six canaux. Ces six lignes sont reliées au port des entrées analogiques de l’Arduino, connecteurs A0 à A5. La tension de référence par défaut du convertisseur est le 5 V de la carte. Elle représente la tension maximale qui peut être numérisée/mesurée. La tension minimale est la masse ou zéro volt (si des signaux négatifs sont nécessaires, leur niveau devra être décalé d’une façon ou d’une autre). Un convertisseur 10 bits distingue 210 soit 1024 niveaux discrets. Cela signifie que chaque pas représente un peu moins de cinq millivolts (NDLR quantum=5/1024≈4,9 mV ; la résolution du convertisseur).

Pour utiliser le CAN, une tension de référence doit être initialement configurée. Après cela, à chaque fois qu’une valeur/mesure est requise, il suffira d’appeler la fonction analogRead(). Le seul argument de la fonction est le numéro du canal d’entrée désiré (de zéro à cinq pour la Uno). La fonction retourne la valeur numérisée issue de la conversion sous forme d’un entier entre 0 et 1023. Bien qu’il soit possible d’accéder directement aux registres du CAN, la bibliothèque Arduino est assez efficace et nous ne gagnerions au mieux que quelques octets à ne pas l’utiliser.

Nous allons commencer par quelque chose de simple pour montrer comment lire une broche d’entrée analogique. Notez que, à la différence des entrées numériques, l’initialisation par pinMode() ou par un registre de direction (DDRx) n’est pas nécessaire lors de l’utilisation de la fonction analogRead().

Connectez les extrémités d’un potentiomètre de 10 kΩ aux +5 V et masse GND de la carte. Connectez le curseur au connecteur d’entrée analogique 0 (A0).

Note de la rédaction

Image non disponible

Entrez le code ci-dessous, compilez-le et transférez-le dans la carte.

 
Sélectionnez
/* Lecture analogique V1. Lit la tension issue dun potentiomètre et lenvoie sur le moniteur série. Valeurs de 0 à 1023 */

#define ANALOG_IN_PIN 0

int prior = 0;

void setup()
{
  Serial.begin(9600);
  analogReference( DEFAULT );
}

void loop()
{
    int a;

    a = analogRead( ANALOG_IN_PIN );

    if( a != prior )
    {
        Serial.println(a);
        prior = a;
    }
}

Le code est explicite. Sa particularité intéressante est que, plutôt que d'afficher directement la valeur issue de la conversion, on la compare à la valeur précédente et, seulement si elle est différente, le résultat est affiché. Cela économise du temps de traitement et accélère les choses.

Ouvrez le moniteur série. Tournez le curseur du potentiomètre dans le sens horaire et anti-horaire. Les valeurs doivent changer dans le moniteur série lorsqu’on tourne le curseur. Elles doivent évoluer entre 0 et 1023 (il peut manquer une valeur à cause du bruit). Littéralement, on peut déterminer la position réelle du curseur en multipliant la valeur lue par le quantum (5 V/1024, soit environ 4,883 millivolts), et réaliser ainsi un voltmètre très rudimentaire.

XI-A. Capteur de force

Remplaçons le potentiomètre par un capteur analogique. Pour cet exercice, nous utiliserons une jauge de déformation (souvent appelée abusivement « jauge de contrainte », FSR en anglais pour Force Sensing Resistor). Une jauge de déformation est un composant à deux bornes, prenant le plus souvent la forme d’un film plat, dont la résistance dépend de la force qui lui est appliquée.

Note de la rédaction

Image non disponible
Force Sensitive Resistor FSR400 - image Sparkfun CC BY 2.0

Si aucune force n’est appliquée, la résistance est très élevée, généralement largement supérieure au mégaohm. Avec la force maximum (telle qu’une forte pression des doigts sur la partie sensible), la résistance peut chuter à une valeur aussi basse que 100 Ω. Retirez le potentiomètre et reliez une borne de la jauge de déformation au +5 V et l’autre à une résistance de 10 kΩ. Le point commun à la jauge et la résistance devra être relié à l’entrée A0, tandis que la patte libre de la résistance ira à la masse. Ce montage n’est rien d’autre qu’un diviseur de tension dont l’une des branches est la jauge de déformation.

Note de la rédaction

Image non disponible

Lorsqu’on applique une force, la résistance diminue, donc la tension au point commun augmente. Ne modifiez pas le code. Notez simplement comment les valeurs changent dans le moniteur série lorsqu’une force est appliquée sur la jauge : plus la pression est grande, plus la valeur est élevée. Pour finir, échangez les positions de la résistance et de la jauge. À une pression correspond maintenant une baisse des valeurs dans le moniteur série.

XI-B. Affichage à LED

Maintenant que le capteur et la fonction de lecture d'entrée analogique ont été testés, combinons cela à un affichage à LED. Plutôt que d'afficher les valeurs sur le moniteur série, nous allons allumer une série de LED. Cela nécessitera de programmer des sorties sur le port numérique, comme vu dans un chapitre précédentLes sorties numériques. Pour rester simple et juste « vérifier le concept », nous allumerons jusqu’à quatre LED. Chacune nécessitera un pilotage par un transistor (ou un ensemble de Darlington tel qu’un ULN2003 qui contient sept amplificateurs dans un seul composant). Nous utiliserons les quatre bits de poids faible du port B pour les sorties, connecteurs 8 à 11 de l’Arduino. Voici le code ci-dessous :

 
Sélectionnez
/* Lecture analogique V2. Utilise la jauge de déformation (reliée a la masse) et la 10k (connectée au 5V), sur la broche A0. Allumage de 4 LED sur le port B bits 0 a 3 pour indiquer la force. Allumage à létat haut. *//

#define ANALOG_IN_PIN 0

// Bits à utiliser sur le port B pour les LED
#define LEDMASK0      0x01
#define LEDMASK1      0x02
#define LEDMASK2      0x04
#define LEDMASK3      0x08
#define LEDMASK       (LEDMASK0 | LEDMASK1 | LEDMASK2 | LEDMASK3)

void  lightLEDsBar( int a );

int prior=0;

void setup()
{
  Serial.begin(9600);
  analogReference( DEFAULT );
  // Configure les bits de pilotage des LED en sorties
  DDRB |= LEDMASK;
}

void loop()
{
  int a;

  a = analogRead( ANALOG_IN_PIN );
  if( a != prior )
  {
    Serial.println(a);
    lightLEDsBar( a );
    prior = a;
  }
}

void  lightLEDsBar( int a )
{

  if( a > 820 )
    PORTB |= LEDMASK; // Allume tout
  else
  {
    if( a > 615 )
    {
      PORTB &= (~LEDMASK3); // Éteint le haut
      PORTB |= (LEDMASK2 | LEDMASK1 | LEDMASK0); // Allume tout en dessous
    }
    else
    {
      if( a > 410 )
      {
        PORTB &= (~(LEDMASK3 | LEDMASK2));
        PORTB |= (LEDMASK1 | LEDMASK0);
      }
      else
      {
        if( a > 205 )
        {
          PORTB &= (~(LEDMASK3 | LEDMASK2 | LEDMASK1));
          PORTB |= LEDMASK0;
        }
        else
          PORTB &= (~LEDMASK);
      }
    }
  }
}

Il est ici primordial de configurer les bits 0 à 3 de DDRB en sorties, elles piloteront nos LED. Des masques de bits sont définis pour chaque sortie afin de faciliter la maintenance du code. Une nouvelle fonction a été créée pour gérer l’allumage : lightLEDsBar(). Cette fonction créera un bargraphe fondé sur la valeur qu’on lui aura passée. Comme il y a quatre LED, nous pouvons diviser les 1024 points de mesure en cinq segments. Si la valeur est en dessous de 20 % (env. 205), aucune LED n’est allumée. De 20 % à 40 %, seule la première LED sera allumée. Avec l’augmentation des valeurs, de plus en plus de LED seront allumées, jusqu’à 80 % et plus, où toutes les LED seront allumées. La fonction est un peu plus évoluée qu’une cascade de if/else. Pour une zone donnée, les LED du haut sont d’abord éteintes, puis les LED restantes en bas sont allumées. Remarquez que la méthode ci-dessus est plus efficace que l’utilisation de la fonction digitalWrite(), car nous pouvons modifier l’état de plusieurs bits en une fois, en accédant directement au port B. Au contraire, digitalWrite() nécessiterait un appel pour chaque bit/LED. Le code du moniteur série a été conservé, vous pourrez ainsi vérifier les résultats et vous assurer que tout fonctionne comme prévu.

Tout en laissant la jauge de déformation en place, câblez les quatre circuits de pilotage des LED sur les broches 8 à 11. Un courant de 10 mA dans les LED sera suffisant. Entrez le code ci-dessus, compilez et transférez-le. Pour tester, ouvrez simplement le moniteur série et appuyez sur la partie sensible de la jauge. Plus la force appliquée augmente, plus les valeurs sur le moniteur série diminuent et moins les LED s’allument. Vous pouvez envisager cela comme un « absence-de-force-mètre ». Bien que d’une logique assez déroutante, cela peut être très utile. Il arrive qu’on souhaite garder les choses « sous pression », une force appliquée trop faible devenant un signal d’alarme (autrement dit, plus de LED allumées signifient un plus gros problème).

Parfois, les LED sont disposées pour imiter un indicateur analogique. Dans un pareil cas, on peut vouloir n’allumer qu’une seule LED plutôt que toutes celles qui sont en dessous. Nous appellerons cela le « mode point », à l’opposé du « mode barre ». La version trois du programme présente le mode point sous une forme intéressante. La partie moniteur série a été retirée, vous pourrez donc noter une diminution de la taille du programme.

 
Sélectionnez
/* Lecture analogique V3. Utilise la jauge de déformation (reliée a la masse) et la 10k (au 5V), sur la broche A0. Allumage dune seule LED sur le port B bits 0 a 3 pour indiquer la force. Visualisation en mode point. Allumage a létat haut. */

#define ANALOG_IN_PIN 0
// Bits à utiliser sur le port B pour les LED
#define LEDMASK0      0x01
#define LEDMASK1      0x02
#define LEDMASK2      0x04
#define LEDMASK3      0x08
#define LEDMASK       (LEDMASK0 | LEDMASK1 | LEDMASK2 | LEDMASK3)

void  lightLEDsDot( int a );

int prior=0;
void setup()
{
  analogReference( DEFAULT );
  DDRB |= LEDMASK;  // Configure les bits de pilotage des LED en sorties
}

void loop()
{
  int a;

  a = analogRead( ANALOG_IN_PIN );
  if( a != prior )
  {
    lightLEDsDot( a );
    prior = a;
  }
}

int thresh[] = {820, 615, 410, 205};

void  lightLEDsDot( int a )
{
  int *p;
  p = thresh;
  
  if( a > *p++ )
  {
    PORTB &= (~(LEDMASK2 | LEDMASK1 | LEDMASK0)); // Éteint les trois du bas
    PORTB |= (LEDMASK3);                  // allume la plus haute
  }
  else
  {
    if( a > *p++ )
    {
      PORTB &= (~(LEDMASK3 | LEDMASK1 | LEDMASK0));
      PORTB |= (LEDMASK2);
    }
    else
    {
      if( a > *p++ )
      {
        PORTB &= (~(LEDMASK3 | LEDMASK2 | LEDMASK0));
        PORTB |= LEDMASK1;
      }
      else
      {
        if( a > *p )
        {
          PORTB &= (~(LEDMASK3 | LEDMASK2 | LEDMASK1));
          PORTB |= LEDMASK0;
        }
        else
          PORTB &= (~LEDMASK);
      }
    }
  }
}

La variante en mode point est similaire à celle avec un bargraphe, sauf que toutes les LED sont éteintes, sauf la plus haute. Vous pourriez vous demander pourquoi chercher la complication à vouloir éteindre les LED individuellement, plutôt que les éteindre toutes (faire un ET logique avec 0xF0), puis allumer celle que l’on désire. La raison est que cela peut provoquer un basculement fugitif (ON-OFF-ON) de la LED en question. Dans cette application, vous ne verrez probablement jamais la différence, mais ce basculement peut poser problème dans certaines applications. Quoi qu’il en soit, la quantité de code machine créé est à peu près la même dans les deux cas.

La modification la plus intéressante de la fonction est qu’on utilise un tableau de valeurs pour les seuils plutôt que des valeurs « en dur ». Cela rend le programme beaucoup plus flexible s’il fallait modifier les seuils ultérieurement. Pour utiliser un jeu de seuils différent, il suffit de faire pointer p sur la première valeur du tableau de seuils créé au début de la fonction. Notez également en particulier l’utilisation de la post-incrémentation du pointeur p. C’est généralement plus efficace que la classique indexation de tableau.

Défi

Modifiez le programme afin d’inverser la logique d’allumage, c.-à-d. faites en sorte que plus forte est la pression, plus le nombre de LED allumées est grand et inversez le sens en mode point. Ne modifiez pas le câblage de la jauge. Faites-le uniquement en modifiant le programme. Ensuite, ajoutez un interrupteur sur la broche 7 de l’Arduino (port D.7). La position de cet interrupteur permettra à l’utilisateur de choisir un affichage en mode barre ou en mode point. Un traitement anti-rebond de cet inverseur ne sera pas nécessaire. En bonus, ajoutez un second interrupteur sur la broche 6 de l’Arduino (Port D.6), qui permettra de choisir entre l’actuelle échelle linéaire et une échelle logarithmique de 6 dB par LED (soit une réduction du niveau de moitié, la LED supérieure s’allumant au-dessus de 512). Proposez votre code et un schéma adéquat avec les valeurs des composants.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Licence Creative Commons
Le contenu de cet article est rédigé par James M. Fiore et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2017 Developpez.com.