Nous avons vu la technique du Charlieplexing dans « Témoins de positions : le Charlieplexing », nous allons maintenant l’appliquer à un système à 5 broches de pilotage et 16 LED puis l’intégrer dans notre application.
Charlieplexing des 16 LED témoins [1]
Le schéma pour allumer 16 LED est le suivant.
- Charlieplexing avec 5 broches et 16 LED
On peut noter que le schéma est incomplet. En effet, avec 5 broches, il est possible de piloter 20 LED. Ici les couples de broches 0-3 et 1-4 sont manquants et nous n’allons donc pas les placer dans notre table d’état des broches.
Voici donc la table d’état des broches pour chaque LED
broche 0 | broche 1 | broche 2 | broche 3 | broche 4 | |
D0 | 0 | 1 | Z | Z | Z |
D1 | 1 | 0 | Z | Z | Z |
D2 | Z | 0 | 1 | Z | Z |
D3 | Z | 1 | 0 | Z | Z |
D4 | Z | Z | 0 | 1 | Z |
D5 | Z | Z | 1 | 0 | Z |
D6 | Z | Z | Z | 0 | 1 |
D7 | Z | Z | Z | 1 | 0 |
D8 | 0 | Z | 1 | Z | Z |
D9 | 1 | Z | 0 | Z | Z |
D10 | Z | Z | 0 | Z | 1 |
D11 | Z | Z | 1 | Z | 0 |
D12 | Z | 0 | Z | 1 | Z |
D13 | Z | 1 | Z | 0 | Z |
D14 | 0 | Z | Z | Z | 1 |
D15 | 1 | Z | Z | Z | 0 |
Nous allons donc construire cette table en C comme nous l’avons fait pour la Charlieplexing avec 3 broches de commande.
- const byte etatSortiePourLED[16][5] = {
- { OUT0, OUT1, INZ, INZ, INZ }, /* D0 */
- { OUT1, OUT0, INZ, INZ, INZ }, /* D1 */
- { INZ, OUT0, OUT1, INZ, INZ }, /* D2 */
- { INZ, OUT1, OUT0, INZ, INZ }, /* D3 */
- { INZ, INZ, OUT0, OUT1, INZ }, /* D4 */
- { INZ, INZ, OUT1, OUT0, INZ }, /* D5 */
- { INZ, INZ, INZ, OUT0, OUT1 }, /* D6 */
- { INZ, INZ, INZ, OUT1, OUT0 }, /* D7 */
- { OUT0, INZ, OUT1, INZ, INZ }, /* D8 */
- { OUT1, INZ, OUT0, INZ, INZ }, /* D9 */
- { INZ, INZ, OUT0, INZ, OUT1 }, /* D10 */
- { INZ, INZ, OUT1, INZ, OUT0 }, /* D11 */
- { INZ, OUT0, INZ, OUT1, INZ }, /* D12 */
- { INZ, OUT1, INZ, OUT0, INZ }, /* D13 */
- { OUT0, INZ, INZ, INZ, OUT1 }, /* D14 */
- { OUT1, INZ, INZ, INZ, OUT0 } /* D15 */
- };
La fonction programmeBroche(...)
reste la même par contre la fonction gereLED(...)
doit être modifiée puisque l’on passe de 3 à 5 broches de commande.
- void gereLED(int num)
- {
- if (etatLED[num] == ALLUME) {
- programmeBroche(8,etatSortiePourLED[num][0]);
- programmeBroche(9,etatSortiePourLED[num][1]);
- programmeBroche(10,etatSortiePourLED[num][2]);
- programmeBroche(11,etatSortiePourLED[num][3]);
- programmeBroche(12,etatSortiePourLED[num][4]);
- }
- else {
- programmeBroche(8,INZ);
- programmeBroche(9,INZ);
- programmeBroche(10,INZ);
- programmeBroche(11,INZ);
- programmeBroche(12,INZ);
- }
- }
Et le tableau etatLED
doit être agrandi pour contenir 16 éléments.
Intégration dans l’application
Pour intégrer l’allumage des témoins dans l’application il faut tout d’abord insérer l’appel à gereLED()
dans loop()
. Nous faisons face à un premier problème. Pour que les servomoteurs pivotent suffisamment lentement, l’attente est de 5ms. Cela conduit à un balayage des 16 LED en 80ms ce qui est trop lent pour que la persistance rétinienne opère. Il faudrait balayer au moins 4 fois plus souvent. Par conséquent, le délai dans loop()
va être réduit à 1ms et la gestion des poussoirs et des servomoteurs sera appelée toutes les 5 fois alors que la gestion des LED sera appelée toutes les fois. Nous allons donc ajouter un compteur compteurGestionServos
initialisé à 0. Comme ceci.
- void loop()
- {
- compteurGestionServos++;
- if (compteurGestionServos == 5) {
- compteurGestionServos = 0;
- ...
- /* code de gestion des servos et des poussoir à l'identique */
- ...
- }
- gereLED(numLED);
- numLED++;
- if (numLED == 16)
- numLED = 0;
- delay(1);
- }
Il suffit ensuite de changer l’état des LED en ALLUME ou ETEINT dans le tableau etatLED
en fonction des événements. Deux fonctions membre de la classe DescripteurServo
sont concernées : evenementServo(...)
où on va éteindre la LED de la position que l’on quitte et gereServo()
où on va allumer la LED de la position que l’on atteint. Dans le tableau etatLED
, les LED sont alternativement rouges et vertes et par conséquent la paire de LED correspondant à un servomoteur est à la position numéro de servo × 2 (angle minimum) et numéro de servo × 2 + 1 (angle maximum).
- void evenementServo()
- {
- cptArret = -1;
- switch (etatServo) {
- case SERVO_A_ANGLE_MIN:
- etatLED[numServo * 2] = ETEINT;
- objetServo.attach(pin);
- case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
- vitesse = 1;
- etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
- break;
- case SERVO_A_ANGLE_MAX:
- etatLED[numServo * 2 + 1] = ETEINT;
- objetServo.attach(pin);
- case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
- vitesse = -1;
- etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
- break;
- }
- }
Dans la fonction membre gereServo()
, la partie qui s’occupe du passage de la vitesse à 0 quand les angles minimum ou maximum sont atteint est modifiée comme suit :
- if (! reglageEnCours ||
- etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN ||
- etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX) {
- if (angle > angleMax) {
- angle = angleMax;
- arreteServo();
- etatServo = SERVO_A_ANGLE_MAX;
- etatLED[numServo * 2 + 1] = ALLUME;
- }
- else if (angle < angleMin) {
- angle = angleMin;
- arreteServo();
- etatServo = SERVO_A_ANGLE_MIN;
- etatLED[numServo * 2] = ALLUME;
- }
- }
Il ne faut pas oublier d’allumer la LED correspondant à l’angle minimum dans la fonction membre connecte(...)
- /* allume la LED correspondante */
- etatLED[numServo * 2] = ALLUME;
Nous sommes parvenus au bout de ce développement. Voici le sketch de l’application complète à télécharger.
- Sketch de l’application complète
(clic sur l'image pour agrandir ou télécharger) - mis à jour en version 1.1. La position des servos est désormais mémorisée dans l’EEPROM.
- Dessin du montage complet
(clic sur l'image pour agrandir ou télécharger) - Attention : le montage montre les 8 servomoteurs alimentés par l’Arduino. Ce n’est pas possible en pratique et il est nécessaire d’avoir une alimentation 5V séparée pour les servomoteurs
- Dessin du montage complet à télécharger en PDF
(clic sur l'image pour agrandir ou télécharger) - Attention : le montage montre les 8 servomoteurs alimentés par l’Arduino. Ce n’est pas possible en pratique et il est nécessaire d’avoir une alimentation 5V séparée pour les servomoteurs
Ainsi qu’une vidéo de démonstration.