Manuel de laboratoire pour contrôleurs embarqués

Utilisation du langage C et de la plateforme Arduino


précédentsommairesuivant

IX. Les sorties numériques

Dans cet exercice, on manipulera les sorties numériques en utilisant à la fois les bibliothèques de l'environnement Arduino et plus directement par « manipulation bit à bit » des registres. Le but sera de contrôler une LED interfacée à l'Arduino avec les circuits électroniques adéquats.

Premièrement, on utilise une version modifiée du programme exemple Blink. Celle-ci fait clignoter la LED montée en surface de la carte et reliée au connecteur 13 de l'Arduino. Périodiquement, la LED sera allumée pendant deux secondes, puis éteinte pendant une seconde. Des messages seront produits en sortie via la liaison série pour rendre compte du résultat.

Tapez le code suivant dans l'éditeur :

 
Sélectionnez
/*
  MyBlink
  Faire clignoter une LED en boucle
  avec affichage sur le moniteur série
*/

// Le connecteur 13 est connecté à une LED montée en surface
// sur la plupart des cartes Arduino. On lui attribue un nom :
#define LEDPIN 13

void setup() 
{
  // Configurer le connecteur en sortie
  pinMode(LEDPIN, OUTPUT); 
  // Configurer la communication série à la vitesse de 9600 bits par seconde
  Serial.begin(9600); 
}
void loop() 
{
  Serial.println("On");
  digitalWrite(LEDPIN, HIGH); // Allumer la LED 
  delay(2000); // Temporiser 2 secondes
  Serial.println("Off");
  digitalWrite(LEDPIN, LOW); // Éteindre la LED 
  delay(1000); // Temporiser 1 seconde
}

Compilez le code et téléversez-le dans la carte. Ouvrez le Moniteur Série. Vous devriez voir des messages s'afficher, reflétant l'état de la LED montée en surface de la carte.

Le code est plutôt évident, mais quelques précisions s'imposent. Tout d'abord, le connecteur 13 de l'Arduino Uno est connecté à une petite LED montée en surface de la carte. Le connecteur est relié à une résistance de limitation du courant, elle-même reliée à l'anode de la LED, la cathode retournant à la masse. Ainsi, la mise en tension du connecteur allume la LED. La routine setup configure le connecteur en sortie et établit le système de communication série. La routine loop utilise digitalWrite() pour basculer la sortie du connecteur alternativement à l'état haut ou bas, ce qui permet d'allumer ou éteindre la LED. La fonction delay() est utilisée pour maintenir l'état temporairement, et permettre ainsi d'observer le clignotement de la LED à l’œil nu. Cette fonction de temporisation fonctionne très bien ici, mais ce n'est qu'une simple boucle d'attente qui fait qu'aucune autre tâche utile ne peut être exécutée durant ce laps de temps. C'est une sérieuse limitation pour des programmes avec des tâches intensives, mais on s'en contentera pour l'instant.

On quitte maintenant l'utilisation de la LED interne à la carte pour une LED externe. Tandis que l'AVR 328P peut délivrer un courant de 20 mA par broche, si on choisit de piloter plusieurs LED, il est préférable de passer par un transistor afin de limiter le courant demandé au microcontrôleur. Le schéma général est le suivant :

Image non disponible

Le transistor NPN saturera et la LED s'allumera avec une tension élevée sur sa base, tandis que dans la version avec le transistor PNP, celui-ci saturera avec une tension basse sur sa base. Dans les deux cas, le courant qui traverse la LED est le courant de saturation du transistor qui est approximativement égal à la tension d'alimentation Vcc, moins la tension de seuil de la LED, le tout divisé par la résistance du collecteur Rc. Par exemple, pour obtenir 10 mA avec une alimentation 5 V et une LED rouge (tension de seuil à 2 V environ), la résistance Rc nécessaire est d'environ 300 Ω. La résistance de base Rb doit être environ égale à 20 fois cette valeur pour un courant de pilotage d'environ 700 microampères. Cela devrait garantir la saturation pour les valeurs courantes de gain en courant β. Les transistors comme les 2N3904 ou 2N3906 sont des choix classiques, mais si un grand nombre de composants doivent être pilotés, il peut être intéressant de se tourner vers un circuit intégré comme l'ULN2003.

Modifiez maintenant le code de l'exemple précédent en utilisant cette fois un transistor NPN piloté avec le connecteur 8 de l'Arduino. Pour anticiper la suite, on précise que ce connecteur correspond au port B, bit 0 (PB0) de l'ATmega328P. Auparavant, il faut câbler les composants sur une plaque d'essais en prenant des valeurs de résistance standards (330 Ω et 6,8 kΩ feront l'affaire). Reliez Vcc au connecteur 5 V de l'Arduino, et la masse au connecteur GND (les deux connecteurs étant sur le même port POWER de la carte).

Reliez maintenant la broche de pilotage (Vbb) au connecteur D8 de l'Arduino. Le code modifié est le suivant :

 
Sélectionnez
/*  Clignotement (Blink) d'une LED externe */

#define LEDPIN 8

void setup()
{
  pinMode(LEDPIN, OUTPUT);
}

void loop()
{
  digitalWrite(LEDPIN, HIGH);
  delay(2000);  // temporiser 2 secondes
  digitalWrite(LEDPIN, LOW);
  delay(1000);  // temporiser 1 seconde
}

Compilez le code, et téléversez-le dans la carte. À l’exécution, vous devriez observer un magnifique clignotement de la LED. Observez également le cadencement. Maintenant, préparez le nouveau montage avec le transistor PNP, puis reliez-le au connecteur D8 à la place de la version NPN du transistor (sans défaire le montage NPN, juste en le déconnectant du microcontrôleur). Ne changez rien au code. Vous devriez noter une différence sur le cadencement allumé/éteint de la LED. Si vous ne constatez aucun changement, reconnectez le NPN et observez à nouveau.

Considérons maintenant l'accès direct aux ressources matérielles, sans passer par les bibliothèques de l'environnement Arduino. Il y a deux méthodes pour faire cela : la première consiste à chercher les adresses réelles des ports matériels et des registres, et de leur assigner des pointeurs. La seconde méthode (un peu plus facile) implique d'utiliser des macros prédéfinies pour les ports et les registres.

Ce qui suit est une variation du programme Blink de clignotement de LED en utilisant l'accès direct au port grâce aux pointeurs. Notez que les variables pour le port et les registres de direction des données sont déclarées, puis se voient assigner en dur les valeurs numériques des adresses.

Tout ceci varie d'un processeur à l'autre, rendant ainsi le code non portable, et ce n'est pas souhaitable. Pour autant, ce processus permet d'illustrer ce qui se passe réellement au niveau du microcontrôleur et il en résulte un code d'assemblage compact. Notez l'utilisation du masque LEDMASK. Changer sa valeur vous permet d'accéder aux différents bits du port. Notez également l'utilisation des opérateurs bit à bit OR, AND et COMPLEMENT (|, &, ~) pour configurer le ou les bits appropriés du registre.

 
Sélectionnez
/* Direct Blink: Accès direct et bit à bit via des pointeurs */
// Le port B bit 0 est relié au connecteur D8

#define LEDMASK 0x01

void setup()
{ 
  unsigned char *portDDRB;
  portDDRB = (unsigned char *)0x24;
  // Configurer la broche en sortie
  *portDDRB |= LEDMASK;
}

void loop()
{
  unsigned char *portB;
  portB = (unsigned char *)0x25;

  // Allumer la LED
  *portB |= LEDMASK;
  delay(2000);

  // Éteindre la LED
  *portB &= (~LEDMASK);
  delay(1000);
}

Tapez le code ci-dessus et reliez le montage avec le transistor NPN au connecteur 8 de l'Arduino. Compilez le code, puis téléversez-le pour le tester. Il devrait fonctionner comme le programme précédent.

Note de la rédaction : Accès aux registres
D'après la documentation (datasheet) de l'ATmega 328P :
Les registres I/O sont situés entre les adresses 0X0020 et 0x005F :

Image non disponible

Le connecteur 8 de l'Arduino Uno est relié au Port B, bit 0 :

Image non disponible

Pour configurer le connecteur 8 de l'Arduino Uno en sortie, il faut donc accéder au registre de sélection de direction des données à l'adresse 0x0024 :

Image non disponible
Si le bit DDB0 est à 1, PB0 est configurée en sortie numérique.

On peut alors configurer l'état du connecteur à l'état haut ou bas grâce au registre de données à l'adresse 0x0025 :

Image non disponible
Si le bit PORTB0 est à 1, la sortie PB0 est à l'état haut.

On peut améliorer le programme Direct Blink avec une nouvelle version utilisant des macros prédéfinies comme PORTB. Celles-ci sont définies dans un fichier d'entête, et peuvent ainsi être ajustées pour tout dispositif. Cela rend le code portable sur toute une famille de microcontrôleur plutôt que d'avoir un code spécifique à chaque unité. Et comme vous allez le constater, le code tend à être plus simple à lire.

 
Sélectionnez
/* Direct Blink 2: Accès direct et bit à bit via des variables prédéfinies.
 */

// Masque correspond au port B bit 0, connecteur D8 de l'Arduino
#define LEDMASK 0x01

void setup() 
{ 
  // Configurer la broche en sortie
  DDRB |= LEDMASK;
}

void loop() 
{
  // Allumer la LED
  PORTB |= LEDMASK;
  delay(2000);

  // Éteindre la LED
  PORTB &= (~LEDMASK);
  delay(1000); 
}

Tapez le code ci-dessus, compilez et téléversez-le dans l'Arduino pour le tester. Il devrait aussi fonctionner comme précédemment.

Toutes les versions de ce programme peuvent être améliorées et étendues au contrôle de plusieurs sorties logiques, chacune étant connectée à un périphérique différent. Par exemple, une sortie pourrait contrôler une LED tandis qu'une autre pilote un relais ou un transistor de puissance pour actionner un moteur. En utilisant la version Direct Blink 2, vous pourrez contrôler plusieurs sorties en une seule instruction, simplement par une opération de masquage appropriée. Tentez la rapide expérience suivante : modifiez LEDMASK avec la valeur 0x21 dans le programme Direct Blink 2 pour piloter en tandem la LED montée en surface de la carte et la LED externe.

Note de la rédaction

Le connecteur D8 qui pilote la LED externe est relié au port B bit 0 (PORTB0) du microcontrôleur, et le connecteur D13 qui pilote la LED montée en surface de la carte Arduino est relié au port B bit 5 (PORTB5).

Le masque approprié pour piloter les deux LED en tandem est :

 
Sélectionnez
#define LEDMASK (0b00000001 | 0b00100000)
// soit LEDMASK=0x21

On allume alors les deux LED simultanément en écrivant :

 
Sélectionnez
PORTB |= LEDMASK; // Allumer les deux LED simultanément

Il est assez courant de vouloir piloter plusieurs sorties simultanément, mais il est également possible de configurer individuellement chaque sortie en manipulant les bits un par un en insérant une temporisation entre chaque bit modifié. C'est une méthode quelque peu maladroite, qui n'est ni particulièrement précise, ni flexible lorsque de nombreuses sorties doivent être pilotées. Mais nous examinerons les recours plus tard.

Note de la rédaction
Si on reprend le pilotage des deux LED précédentes, on peut allumer individuellement chaque LED :

 
Sélectionnez
  // masque pour la LED externe, connecteur D8
  #define LEDMASK1 0b00000001

  // masque pour la LED montée en surface, connecteur D13
  #define LEDMASK2 0b00100000

Pour allumer les deux LED, chacune leur tour :

 
Sélectionnez
PORTB |= LEDMASK1; // allumer la LED externe
// delay(10);
PORTB |= LEDMASK2; // allumer la LED montée en surface

Défi

Créez un programme qui va faire clignoter deux LED, une rouge et une verte alternativement. Quand la LED rouge s'allume, la verte devra s'éteindre et inversement, quand la LED verte s'allume, la rouge devra s'éteindre. La LED rouge devra rester allumée pendant deux secondes, et la verte devra rester allumée pendant une seconde. À aucun moment les deux LED devront être allumées simultanément ou éteintes simultanément (ou du moins, cela ne doit pas être perceptible par l’œil humain ordinaire). Ce schéma de clignotement devra se répéter encore et encore : la LED rouge allumée pendant deux secondes, la verte pendant une seconde, la rouge pendant deux secondes, la verte pendant une seconde, et ainsi de suite.

Joignez votre code et un schéma électrique avec les caractéristiques des composants. Il est recommandé d'utiliser Multisim ou tout autre logiciel de conception de circuits pour générer le schéma.


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.