Vous êtes sur la page 1sur 300

Machine Translated by Google

Table des matières

Préface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii

1. Mise en route . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Installation de l'environnement de développement intégré (IDE) 4
1.2 Configuration de la carte Arduino 6
1.3 Utilisation de l'environnement de développement intégré (IDE) pour préparer
un croquis Arduino 8
1.4 Télécharger et exécuter le croquis Blink 1.5 11
Créer et enregistrer un croquis 1.6 Utiliser Arduino 13
15

2. Faites en sorte que le croquis fasse votre offre. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19


2.1 Structuration d'un programme Arduino 20
2.2 Utilisation de types primitifs simples (variables) 21
2.3 Utiliser des nombres à virgule 23
flottante 2.4 Travailler avec des groupes 25
de valeurs 2.5 Utiliser la fonctionnalité de 28
chaîne Arduino 2.6 Utiliser des chaînes de 30
caractères C 2.7 Fractionner du texte séparé par des 32
virgules en groupes 2.8 Convertir un nombre en chaîne 34
2.9 Convertir une chaîne en nombre 2.10 Structurer 36
votre code en fonctionnel Blocs 2.11 Renvoyer plusieurs 38
valeurs à partir d'une fonction 2.12 Effectuer des actions 41
basées sur des conditions 2.13 Répéter une séquence 44
d'instructions 2.14 Répéter des instructions avec un compteur 45
2.15 Sortir de boucles 2.16 Effectuer une variété d'actions 47
basées sur une seule variable 2.17 Comparer des caractères 49
et des valeurs numériques 2.18 Comparer des chaînes 2.19 50
Effectuer des comparaisons logiques 52
54
55

v
Machine Translated by Google

2.20 Exécution d'opérations au niveau du bit 56


2.21 Combinaison d'opérations et d'assignation 58

3. Utilisation des opérateurs mathématiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61


3.1 Additionner, soustraire, multiplier et diviser 61
3.2 Incrémentation et décrémentation des valeurs 62
3.3 Trouver le reste après avoir divisé deux valeurs 63
3.4 Détermination de la valeur absolue 64
3.5 Contraindre un nombre à une plage de valeurs 65
3.6 Trouver le minimum ou le maximum de certaines valeurs 3.7 Elever 66
un nombre à une puissance 3.8 Prendre la racine carrée 3.9 Arrondir 67
des nombres à virgule flottante vers le haut et vers le bas 3.10 Utiliser 68
des fonctions trigonométriques 3.11 Générer des nombres aléatoires 68
3.12 Définir et lire des bits 3.13 Décaler des bits 3.14 Extraire des nombres 69
à virgule flottante Octets de poids faible dans un entier ou un long 3.15 70
Formation d'un entier ou d'un long à partir d'octets de poids fort et de 72
poids faible 75
77
78

4. Communications série . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.1 Envoi d'informations de débogage d'Arduino à votre ordinateur 4.2 Envoi de texte 86
formaté et de données numériques depuis Arduino 4.3 Réception de données série 89
dans Arduino 4.4 Envoi de plusieurs champs de texte depuis Arduino dans un seul 92
message 4.5 Réception de plusieurs champs de texte dans un seul message dans 95
Arduino 4.6 Envoi de données binaires d'Arduino 4.7 Recevoir des données binaires 98
d'Arduino sur un ordinateur 4.8 Envoi de valeurs binaires du traitement à Arduino 4.9 101
Envoi de la valeur de plusieurs broches Arduino 4.10 Comment déplacer le curseur de 105
la souris sur un PC ou un Mac 4.11 Contrôler Google Earth à l'aide d'Arduino 4.12 107
Journalisation des données Arduino vers un fichier sur votre ordinateur 4.13 Envoyer 109
des données à deux périphériques série en même temps 4.14 Recevoir des données 112
série à partir de deux périphériques en même temps 4.15 Configurer le traitement sur 115
votre ordinateur pour envoyer 121
124
128

et recevoir des données série 131

5. Entrée numérique et analogique simple. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133


5.1 Utilisation d'un commutateur 136

5.2 Utilisation d'un interrupteur sans résistances externes 139


5.3 Détection fiable de la fermeture d'un interrupteur 141
5.4 Déterminer combien de temps un interrupteur est enfoncé 144

vi | Table des matières


Machine Translated by Google

5.5 Lecture d'un clavier 5.6 149

Lecture de valeurs analogiques 5.7 152

Modification de la plage de valeurs 5.8 Lecture 154

de plus de six entrées analogiques 5.9 Affichage de 155

tensions jusqu'à 5 V 5.10 Réponse aux variations de 158

tension 5.11 Mesure de tensions supérieures à 5 V 161

(diviseurs de tension) 162

6. Obtenir l'entrée des capteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165


6.1 Détection de mouvement 167
6.2 Détection de lumière 170
6.3 Détection de mouvement (intégration de détecteurs infrarouges passifs) 171
6.4 Mesurer la distance 173
6.5 Mesure précise de la distance 176
6.6 Détection des vibrations 180
6.7 Détection de son 181
6.8 Mesure de la température 185
6.9 Lecture des étiquettes RFID 187
6.10 Suivi du mouvement d'un cadran 190
6.11 Suivi du mouvement de plusieurs encodeurs rotatifs 193
6.12 Suivi du mouvement d'un cadran dans une esquisse occupée 195
6.13 Utiliser une souris 197
6.14 Obtenir une position à partir d'un GPS 201
6.15 Détection de rotation à l'aide d'un gyroscope 206
6.16 Sens de détection 208
6.17 Obtenir des entrées à partir d'une manette de jeu (PlayStation) 211
6.18 Accélération de lecture 213

7. Sortie visuelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217


7.1 Connexion et utilisation des LED 7.2 220

Réglage de la luminosité d'une LED 7.3 Commande 223

de LED haute puissance 7.4 Réglage de la couleur 224

d'une LED 7.5 Séquencement de plusieurs LED : 226

création d'un graphique à barres 7.6 Séquençage de plusieurs LED : 229

création d'une séquence de poursuite (Knight


Cavalier) 232

7.7 Contrôle d'une matrice LED à l'aide du multiplexage 7.8 Affichage 234

d'images sur une matrice LED 7.9 Contrôle d'une matrice de LED : 236

Charlieplexing 7.10 Pilotage d'un affichage LED 7 segments 7.11 239

Pilotage d'affichages LED multichiffres, 7 segments : multiplexage 245

7.12 Pilotage d'affichages LED multichiffres, 7 segments Utilisation du décalage 248

MAX7221
Registres 250

Table des matières | vii


Machine Translated by Google

7.13 Contrôle d'un réseau de LED à l'aide des registres à décalage du MAX72xx 253
7.14 Augmentation du nombre de sorties analogiques à l'aide de l'extension PWM
Puces (TLC5940) 255
7.15 Utilisation d'un indicateur analogique comme affichage 259

8. Sortie physique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261


8.1 Contrôler la position d'un servo 8.2 Contrôler 264
un ou deux servos avec un potentiomètre
ou capteur 266
8.3 Contrôle de la vitesse des servos à rotation continue 8.4 Contrôle 267
des servos à partir du port série 8.5 Commande d'un moteur sans balais 269
(à l'aide d'un contrôleur de vitesse Hobby) 271
8.6 Contrôler les solénoïdes et les relais 8.7 272
Faire vibrer un objet 8.8 Entraîner un moteur à 273
balais à l'aide d'un transistor 8.9 Contrôler la direction d'un 276
moteur à balais
avec un pont en H 277
8.10 Contrôle de la direction et de la vitesse d'un moteur à balais avec un
H-Bridge 280
8.11 Utilisation de capteurs pour contrôler la direction et la vitesse du brossage
Moteurs (Pont en H L293) 282
8.12 Commande d'un moteur pas à pas bipolaire 287
8.13 Commande d'un moteur pas à pas bipolaire (à l'aide de la carte EasyDriver) 290
8.14 Commande d'un moteur pas à pas unipolaire (ULN2003A) 293

9. Sortie audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297


9.1 Jouer des sons 299
9.2 Jouer une mélodie simple 301
9.3 Génération de plusieurs tonalités simultanées 303
9.4 Génération de tonalités audio et fondu d'une LED 305
9.5 Lire un fichier WAV 9.6 308
Contrôler le MIDI 9.7 Créer 311
un synthétiseur audio 314

10. Contrôle à distance des périphériques externes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317


10.1 Répondre à une télécommande infrarouge 318
10.2 Décodage des signaux infrarouges de la télécommande 321
10.3 Imiter les signaux de la télécommande 324
10.4 Contrôler un appareil photo numérique 327
10.5 Contrôler les appareils AC en piratant un interrupteur télécommandé 330

11. Utilisation des écrans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333


11.1 Connexion et utilisation d'un écran LCD texte 334

viii | Table des matières


Machine Translated by Google

11.2 Formatage du texte 337


11.3 Activation ou désactivation du curseur et de 340
l'affichage 11.4 Défilement du texte 11.5 Affichage de 342
symboles spéciaux 11.6 Création de caractères 345
personnalisés 11.7 Affichage de symboles plus grands 347
qu'un seul caractère 11.8 Affichage de pixels plus petits qu'un 349
seul caractère 11.9 Connexion et utilisation d'un écran LCD 352
graphique 11.10 Création de bitmaps à utiliser avec un affichage 355
graphique 11.11 Affichage de texte sur un téléviseur 359
361

12. Utilisation de l'heure et des dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367


12.1 Créer des retards 367
12.2 Utiliser des millis pour déterminer la durée 368
12.3 Mesurer plus précisément la durée d'une impulsion 12.4 372
Utiliser Arduino comme horloge 12.5 Créer une alarme pour 373
appeler périodiquement une fonction 12.6 Utiliser une horloge 380
en temps réel 384

13. Communiquer en utilisant I2C et SPI. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389


13.1 Contrôler une LED RVB à l'aide du module BlinkM 392
13.2 Utilisation de l'accéléromètre Wii Nunchuck 397
13.3 Interfaçage avec une horloge temps réel externe 401
13.4 Ajout de mémoire EEPROM externe 404
13.5 Lecture de la température avec un thermomètre numérique 408
13.6 Commande de quatre LED à 7 segments en utilisant seulement deux fils 412
13.7 Intégration d'un extenseur de port I2C 416
13.8 Pilotage d'affichages multichiffres à 7 segments à l'aide 418
de SPI 13.9 Communication entre deux ou plusieurs cartes Arduino 421

14. Communications sans fil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425

14.1 Envoi de messages à l'aide de modules sans fil à faible coût 425
14.2 Connexion d'Arduino à un réseau ZigBee ou 802.15.4 14.3 431
Envoi d'un message à un XBee particulier 14.4 Envoi de données 438
de capteur entre XBees 14.5 Activation d'un actionneur connecté à 440
un XBee 446

15. Ethernet et mise en réseau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451


15.1 Configuration du blindage Ethernet 453
15.2 Obtention automatique de votre adresse IP 15.3 455
Résolution des noms d'hôte en adresses IP (DNS) 458
15.4 Demande de données à un serveur Web 462
15.5 Demande de données à un serveur Web à l'aide de XML 466

Table des matières | ix


Machine Translated by Google

15.6 Configurer un Arduino pour qu'il devienne un serveur 469


Web 15.7 Gérer les requêtes Web entrantes 15.8 Gérer les 471
requêtes entrantes pour des pages spécifiques 15.9 Utiliser HTML 474
pour formater les réponses du serveur Web 15.10 Servir des pages 479
Web à l'aide de formulaires (POST) 483
15.11 Servir des pages Web contenant de grandes quantités de données 486
15.12 Envoyer des messages Twitter 15.13 Envoyer et recevoir des messages 493
simples (UDP) 496
15.14 Obtenir l'heure d'un serveur de temps Internet 15.15 502
Surveillance des flux Pachube 15.16 Envoi d'informations à Pachube 507
510

16. Utilisation, modification et création de bibliothèques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515

16.1 Utilisation des bibliothèques 515


intégrées 16.2 Installation de bibliothèques 517
tierces 16.3 Modification d'une bibliothèque 518
16.4 Création de votre propre bibliothèque 522
16.5 Création d'une bibliothèque utilisant d'autres bibliothèques 527

17. Codage avancé et gestion de la mémoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531

17.1 Comprendre le processus de construction Arduino 17.2 532


Déterminer la quantité de RAM libre et utilisée 17.3 Stocker et 535
récupérer des valeurs numériques dans la mémoire programme 17.4 Stocker et 537
récupérer des chaînes dans la mémoire programme 17.5 Utiliser #define et const 540
au lieu d'entiers 17.6 Utiliser des compilations conditionnelles 542
543

18. Utilisation du matériel de la puce du contrôleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547

18.1 Stockage des données dans la mémoire EEPROM permanente 551


18.2 Utilisation des interruptions matérielles 18.3 Réglage de la durée 554
de la minuterie 18.4 Réglage de la largeur et de la durée des 557
impulsions de la minuterie 18.5 Création d'un générateur d'impulsions 559
18.6 Modification de la fréquence PWM d'une minuterie 18.7 Comptage 562
des impulsions 18.8 Mesure plus précise des impulsions 18.9 Mesure 565
rapide des valeurs analogiques 18.10 Réduction de la consommation 567
de la batterie 18.11 Réglage rapide des broches numériques 569
571
572
574

A. Composants électroniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579

B. Utilisation de diagrammes schématiques et de fiches techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585

x | Table des matières


Machine Translated by Google

C. Construire et connecter le circuit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591

D. Conseils pour résoudre les problèmes de logiciel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595

E. Conseils pour résoudre les problèmes matériels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599

F. Broches numériques et analogiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603

G. Jeux de caractères ASCII et étendus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 611

Table des matières | xii


Machine Translated by Google

CHAPITRE 1

Commencer

1.0 Introduction
L'environnement Arduino a été conçu pour être facile à utiliser pour les débutants qui n'ont aucune
expérience en logiciel ou en électronique. Avec Arduino, vous pouvez créer des objets capables de réagir
et/ou de contrôler la lumière, le son, le toucher et le mouvement. Arduino a été utilisé pour créer une
incroyable variété de choses, y compris des instruments de musique, des robots, des sculptures
lumineuses, des jeux, des meubles interactifs et même des vêtements interactifs.

Si vous n'êtes pas débutant, n'hésitez pas à passer directement aux recettes qui
vous intéressent.

Arduino est utilisé dans de nombreux programmes éducatifs à travers le monde, en particulier par les
concepteurs et les artistes qui souhaitent créer facilement des prototypes mais n'ont pas besoin d'une
compréhension approfondie des détails techniques derrière leurs créations. Parce qu'il est conçu pour être
utilisé par des personnes non techniques, le logiciel comprend de nombreux exemples de code pour
montrer comment utiliser les différentes fonctionnalités de la carte Arduino.

Bien qu'il soit facile à utiliser, le matériel sous-jacent d'Arduino fonctionne au même niveau de sophistication
que celui que les ingénieurs utilisent pour construire des appareils embarqués. Les personnes travaillant
déjà avec des microcontrôleurs sont également attirées par Arduino en raison de ses capacités de
développement agiles et de sa facilité de mise en œuvre rapide des idées.

Arduino est surtout connu pour son matériel, mais vous avez également besoin d'un logiciel pour
programmer ce matériel. Le matériel et le logiciel s'appellent "Arduino". La combinaison vous permet de
créer des projets qui détectent et contrôlent le monde physique. Le logiciel est gratuit, open source et
multiplateforme. Les cartes sont peu coûteuses à l'achat, ou vous pouvez créer les vôtres (les conceptions
matérielles sont également open source). De plus, il existe une communauté Arduino active et solidaire qui
est accessible dans le monde entier via les forums Arduino et le wiki (connu sous le nom de Arduino
Playground). Les forums et les

1
Machine Translated by Google

wiki offre des exemples de développement de projets et des solutions aux problèmes qui peuvent vous
inspirer et vous aider dans la poursuite de vos propres projets.

Les recettes de ce chapitre vous aideront à démarrer en expliquant comment configurer l'environnement
de développement et comment compiler et exécuter un exemple de sketch.

Le code source contenant des instructions informatiques pour contrôler la


fonctionnalité Arduino est généralement appelé croquis dans la communauté Arduino.
Le mot croquis sera utilisé tout au long de ce livre pour désigner le code du
programme Arduino.

Le croquis Blink, fourni avec Arduino, est utilisé comme exemple pour les recettes de ce chapitre, bien
que la dernière recette du chapitre aille plus loin en ajoutant du son et en collectant des entrées via du
matériel supplémentaire, pas seulement en faisant clignoter la lumière intégrée à la carte. . Le chapitre
2 explique comment structurer une esquisse pour Arduino et fournit une introduction à la programmation.

Si vous connaissez déjà les bases d'Arduino, n'hésitez pas à passer aux chapitres
suivants. Si vous êtes un utilisateur Arduino pour la première fois, la patience dans
ces premières recettes sera payante avec des résultats plus fluides plus tard.

Logiciel Arduino
Les programmes logiciels, appelés croquis, sont créés sur un ordinateur à l'aide de l'environnement de
développement intégré (IDE) Arduino. L'IDE vous permet d'écrire et de modifier du code et de convertir
ce code en instructions que le matériel Arduino comprend. L'IDE transfère également ces instructions à
la carte Arduino (un processus appelé téléchargement).

Matériel Arduino
La carte Arduino est l'endroit où le code que vous écrivez est exécuté. La carte ne peut contrôler et
répondre qu'à l'électricité, c'est pourquoi des composants spécifiques lui sont attachés pour lui permettre
d'interagir avec le monde réel. Ces composants peuvent être des capteurs, qui convertissent un aspect
du monde physique en électricité afin que la carte puisse le détecter, ou des actionneurs, qui obtiennent
l'électricité de la carte et la convertissent en quelque chose qui change le monde. Des exemples de
capteurs comprennent des commutateurs, des accéléromètres et des capteurs de distance à ultrasons.
Les actionneurs sont des choses comme les lumières et les LED, les haut-parleurs, les moteurs et les écrans.

Il existe une variété de cartes officielles que vous pouvez utiliser avec le logiciel Arduino et une large
gamme de cartes compatibles Arduino produites par les membres de la communauté.

Les cartes les plus populaires contiennent un connecteur USB utilisé pour fournir l'alimentation et la
connectivité nécessaires au téléchargement de votre logiciel sur la carte. La figure 1-1 montre une carte
de base, l'Arduino Uno.

2 | Chapitre 1 : Mise en route


Machine Translated by Google

Illustration 1-1. Carte de base : l'Arduino Uno

Voir également

Un aperçu des cartes Arduino : http:// www.arduino.cc/ en/ Main/ Hardware.


Des guides en ligne pour démarrer avec Arduino sont disponibles sur http:// arduino.cc/
en/ Guide/ Windows pour Windows, http:// arduino.cc/ en/ Guide/ MacOSX pour Mac OS
X et http:// www .arduino.cc/ playground/ Learning/ Linux pour Linux.

1.0 Présentation | 3
Machine Translated by Google

1.1 Installation de l'environnement de développement intégré (IDE)

Problème
Vous souhaitez installer l'environnement de développement Arduino sur votre ordinateur.

Solution
Le logiciel Arduino pour Windows, Mac et Linux peut être téléchargé à partir de http:// arduino.cc/ en/ Main/
Software.

Le téléchargement Windows est un fichier ZIP. Décompressez le fichier dans n'importe quel répertoire
pratique - Program Files/ Arduino est un endroit judicieux.

Un utilitaire gratuit pour décompresser les fichiers, appelé 7-Zip, peut être téléchargé à
partir de http:// www.7-zip.org/.

La décompression du fichier créera un dossier nommé Arduino-00<nn> (où <nn> est le numéro de version
de la version Arduino que vous avez téléchargée). Le répertoire contient le fichier exécutable (nommé
Arduino.exe), ainsi que divers autres fichiers et dossiers. Double-cliquez sur le fichier Arduino.exe et l'écran
de démarrage devrait apparaître (voir Figure 1-2), suivi de la fenêtre principale du programme (voir Figure
1-3). Soyez patient, car le chargement du logiciel peut prendre un certain temps.

Illustration 1-2. Écran de démarrage Arduino (version 0019 sous Windows 7)

4 | Chapitre 1 : Mise en route


Machine Translated by Google

Illustration 1-3. Fenêtre principale de l'IDE Arduino (version 0019 sous Windows 7)

Le téléchargement Arduino pour Mac est une image disque (.dmg) ; double-cliquez sur le fichier
lorsque le téléchargement est terminé. L'image montera (elle apparaîtra comme une clé USB sur le
bureau). À l'intérieur de l'image disque se trouve l'application Arduino. Copiez ceci dans un endroit
où cela vous convient - le dossier Applications est un endroit judicieux. Double-cliquez sur l'application
une fois que vous l'avez copiée (ce n'est pas une bonne idée de l'exécuter à partir de l'image disque).
L'écran de démarrage apparaîtra, suivi de la fenêtre principale du programme.

L'installation de Linux varie en fonction de la distribution Linux que vous utilisez. Voir le wiki Arduino
pour plus d'informations (http:// www.arduino.cc/ playground/ Learning/ Linux).

Pour permettre à l'environnement de développement Arduino de communiquer avec la carte, vous


devez installer des pilotes.

1.1 Installation de l'environnement de développement intégré (IDE) | 5


Machine Translated by Google

Sous Windows, utilisez le câble USB pour connecter votre PC et la carte Arduino et attendez que l'assistant
Nouveau matériel détecté apparaisse. Si vous utilisez Windows Vista ou Windows 7 et que vous êtes en
ligne, vous pouvez laisser l'assistant rechercher les pilotes et ils s'installeront automatiquement. Sous
Windows XP, vous devez spécifier l'emplacement des pilotes. Utilisez le sélecteur de fichiers pour accéder
au répertoire des pilotes , situé dans le répertoire où vous avez décompressé les fichiers Arduino. Une fois
le pilote installé, l'assistant Nouveau matériel détecté réapparaîtra, indiquant qu'un nouveau port série a
été trouvé. Suivez le même processus que précédemment.

Il est important que vous suiviez la séquence d'étapes pour installer les pilotes
deux fois, sinon le logiciel ne pourra pas communiquer avec la carte.

Sur Mac, les dernières cartes Arduino, telles que l'Uno, peuvent être utilisées sans pilotes supplémentaires,
mais si vous utilisez des cartes plus anciennes, vous devrez installer le logiciel du pilote. Il existe un
package nommé FTDIUSBSerialDriver, suivi d'une plage de nombres, à l'intérieur de l'image disque.
Double-cliquez dessus et le programme d'installation vous guidera tout au long du processus. Vous aurez
besoin de connaître un mot de passe administrateur pour terminer le processus.

Sous Linux, la plupart des distributions ont le pilote déjà installé, mais suivez le lien Linux donné dans l'
introduction de ce chapitre pour des informations spécifiques à votre distribution.

Discussion
Si le logiciel ne démarre pas, consultez la section de dépannage du site Web Arduino, http:// arduino.cc/
en/ Guide/ Troubleshooting, pour obtenir de l'aide pour résoudre les problèmes d'installation.

Voir également

Des guides en ligne pour démarrer avec Arduino sont disponibles sur http:// arduino.cc/ en/ Guide/ Windows
pour Windows, http:// arduino.cc/ en/ Guide/ MacOSX pour Mac OS X et http:// www .arduino.cc/ playground/
Learning/ Linux pour Linux.

1.2 Configuration de la carte Arduino

Problème
Vous voulez mettre sous tension une nouvelle carte et vérifier qu'elle fonctionne.

Solution
Branchez la carte sur un port USB de votre ordinateur et vérifiez que le voyant d'alimentation vert de la
carte s'allume. Les cartes Arduino standard (Uno, Duemilanove et Mega) ont un indicateur d'alimentation
LED vert situé près du commutateur de réinitialisation.

6 | Chapitre 1 : Mise en route


Machine Translated by Google

Une LED orange près du centre de la carte (étiquetée "Pin 13 LED" dans la Figure 1-4) doit clignoter
lorsque la carte est sous tension (les cartes sont préchargées en usine avec un logiciel pour faire
clignoter la LED comme une simple vérification que le conseil fonctionne).

Illustration 1-4. Carte Arduino de base (Uno et Duemilanove)

Discussion
Si le voyant d'alimentation ne s'allume pas lorsque la carte est connectée à votre ordinateur, la
carte n'est probablement pas alimentée.

La LED clignotante (connectée à la broche de sortie numérique 13) est contrôlée par le code
exécuté sur la carte (les nouvelles cartes sont préchargées avec l'exemple de croquis Blink). Si la
LED de la broche 13 clignote, l'esquisse fonctionne correctement, ce qui signifie que la puce de la
carte fonctionne. Si le voyant d'alimentation vert est allumé mais que le voyant de la broche 13 ne
clignote pas, il se peut que le code d'usine ne soit pas sur la puceÿ; suivez les instructions de la
recette 1.3 pour charger le croquis Blink sur le tableau afin de vérifier que le tableau fonctionne. Si
vous n'utilisez pas de carte standard, il se peut qu'elle n'ait pas de LED intégrée sur la broche 13,
consultez donc la documentation pour plus de détails sur votre carte.

Voir également

Des guides en ligne pour démarrer avec Arduino sont disponibles sur http:// arduino.cc/ en/ Guide/
Windows pour Windows, http:// arduino.cc/ en/ Guide/ MacOSX pour Mac OS X et http://
www .arduino.cc/ playground/ Learning/ Linux pour Linux.

Un guide de dépannage est disponible sur http:// arduino.cc/ en/ Guide/ Troubleshooting.

1.2 Configuration de la carte Arduino | 7


Machine Translated by Google

1.3 Utilisation de l'environnement de développement intégré


(IDE) pour préparer un croquis Arduino

Problème
Vous voulez obtenir un croquis et le préparer pour le télécharger sur le tableau.

Solution
Utilisez l'IDE Arduino pour créer, ouvrir et modifier des croquis qui définissent ce que la carte fera. Vous
pouvez utiliser les boutons en haut de l'EDI pour effectuer ces actions (illustrés à la Figure 1-5), ou vous
pouvez utiliser les menus ou les raccourcis clavier (illustrés à la Figure 1-6).

La zone Sketch Editor est l'endroit où vous affichez et modifiez le code d'une esquisse. Il prend en charge
les touches d'édition de texte courantes telles que Ctrl-F (ÿ+F sur un Mac) pour rechercher, Ctrl-Z (ÿ+Z sur
un Mac) pour annuler, Ctrl-C (ÿ+C sur un Mac) pour copier texte en surbrillance et Ctrl-V (ÿ+V sur un Mac)
pour coller le texte en surbrillance.

La figure 1-6 montre comment charger l'esquisse Blink (l'esquisse qui est préchargée sur une nouvelle carte
Arduino).

Après avoir démarré l'EDI, allez dans le menu FileÿExamples et sélectionnez 1.BasicsÿBlink, comme illustré
à la Figure 1-6. Le code de clignotement de la LED intégrée s'affichera dans la fenêtre de l'éditeur de croquis
(reportez-vous à la figure 1-5).

Avant que le code puisse être envoyé à la carte, il doit être converti en instructions pouvant être lues et
exécutées par la puce du contrôleur Arduino ; c'est ce qu'on appelle compiler. Pour ce faire, cliquez sur le
bouton compiler (le bouton en haut à gauche avec un triangle à l'intérieur) ou sélectionnez SketchÿVerify/
Compile.

Vous devriez voir un message indiquant "Compilation..." dans la zone de message sous la fenêtre d'édition
de texte. Après une seconde ou deux, un message indiquant « Compilation terminée » apparaîtra. La zone
noire de la console contiendra le message supplémentaire suivantÿ:

Taille de l'esquisse binaireÿ: 1ÿ008ÿoctets (sur un maximum de 32ÿ256ÿoctets)

Le message exact peut différer selon la version Arduino ; il vous indique la taille du croquis et la taille
maximale que votre planche peut accepter.

8 | Chapitre 1 : Mise en route


Machine Translated by Google

Illustration 1-5. EDI Arduino

Discussion
Le code source d'Arduino s'appelle un croquis. Le processus qui prend une esquisse et la convertit
en une forme qui fonctionnera sur le tableau s'appelle la compilation. L'IDE utilise un certain nombre
d'outils de ligne de commande dans les coulisses pour compiler une esquisse. Pour plus d'informations
à ce sujet, voir la recette 17.1.

1.3 Utilisation de l'environnement de développement intégré (IDE) pour préparer un croquis Arduino | 9
Machine Translated by Google

Illustration 1-6. Menu IDE (sélection de l'exemple de croquis Blink)

Le message final vous indiquant la taille de l'esquisse indique la quantité d'espace programme
nécessaire pour stocker les instructions du contrôleur sur la carte. Si la taille de l'esquisse compilée
est supérieure à la mémoire disponible sur la carte, le message d'erreur suivant s'afficheÿ:

Esquisse trop grandeÿ; voir http://www.arduino.cc/en/Guide/Troubleshooting#size pour


des conseils pour le réduire.

Si cela se produit, vous devez réduire votre croquis pour pouvoir le mettre sur le tableau, ou obtenir
un tableau avec une plus grande capacité.

10 | Chapitre 1 : Mise en route


Machine Translated by Google

S'il y a des erreurs dans le code, le compilateur imprimera un ou plusieurs messages d'erreur dans la fenêtre de la
console. Ces messages peuvent aider à identifier l'erreur—voir l' annexe D sur les erreurs logicielles pour des
conseils de dépannage.

Pour éviter l'écrasement accidentel des exemples, l'IDE Arduino ne vous permet pas
d'enregistrer les modifications apportées aux exemples de croquis fournis.
Vous devez les renommer à l'aide de l'option de menu Enregistrer sous. Vous pouvez enregistrer
des croquis que vous écrivez vous-même avec le bouton Enregistrer (voir recette 1.5).

Lorsque vous développez et modifiez une esquisse, vous devez également envisager d'utiliser l'option de menu
Fichier ÿ Enregistrer sous et d'utiliser régulièrement un nom ou un numéro de version différent afin que, à mesure
que vous implémentez chaque bit, vous puissiez revenir à une version plus ancienne si nécessaire.

Le code téléchargé sur le tableau ne peut pas être téléchargé sur votre ordinateur. Assurez-
vous de sauvegarder votre code de croquis sur votre ordinateur. Vous ne pouvez pas enregistrer
les modifications dans les fichiers d'exempleÿ; vous devez utiliser Enregistrer sous et donner
un autre nom au fichier modifié.

Voir également

La recette 1.5 montre un exemple de croquis. L'annexe D contient des conseils sur la résolution des problèmes de
logiciel.

1.4 Téléchargement et exécution de Blink Sketch


Problème

Vous souhaitez transférer votre croquis compilé sur la carte Arduino et le voir fonctionner.

Solution

Connectez votre carte Arduino à votre ordinateur à l'aide du câble USB. Chargez l'esquisse Blink dans l'IDE comme
décrit dans la recette 1.3.

Ensuite, sélectionnez Outils ÿ Carte dans le menu déroulant et sélectionnez le nom de la carte que vous avez
connectée (s'il s'agit de la carte Uno standard, il s'agit probablement de la première entrée dans la liste des cartes).

Sélectionnez maintenant Outils ÿ Port série. Vous obtiendrez une liste déroulante des ports série disponibles sur
votre ordinateur. Chaque machine aura une combinaison différente de ports série, selon les autres périphériques
que vous avez utilisés avec votre ordinateur.

Sous Windows, ils seront répertoriés sous forme d'entrées COM numérotées. S'il n'y a qu'une seule entrée,
sélectionnez-la. S'il y a plusieurs entrées, votre tableau sera probablement la dernière entrée.

1.4 Téléchargement et exécution de Blink Sketch | 11


Machine Translated by Google

Sur Mac, votre carte sera répertoriée deux fois s'il s'agit d'une carte Unoÿ: /dev/
tty.usbmodem-XXXXXXX /dev/cu.usbmodem-XXXXXXX

Si vous avez une carte plus ancienne, elle sera répertoriée comme suitÿ:

/dev/tty.usbserial-XXXXXXX /
dev/cu.usbserial-XXXXXXX

Chaque tableau aura des valeurs différentes pour XXXXXXX. Sélectionnez l'une ou l'autre des entrées.

Cliquez sur le bouton de téléchargement (dans la Figure 1-5, c'est le cinquième bouton à partir de la gauche), ou choisissez
FichierÿTélécharger sur la carte d'E/S.

Le logiciel compilera le code, comme dans la recette 1.3. Une fois le logiciel compilé, il est téléchargé sur la carte. Si vous
regardez votre carte, vous verrez la LED cesser de clignoter et deux voyants (étiquetés comme LED série dans la Figure 1-4)
juste en dessous de la LED qui clignote précédemment devraient clignoter pendant quelques secondes pendant le téléchargement
du code. Le voyant d'origine devrait alors recommencer à clignoter pendant l'exécution du code.

Discussion
Pour que l'IDE envoie le code compilé à la carte, la carte doit être connectée à l'ordinateur et vous devez indiquer à l'IDE quelle
carte et quel port série vous utilisez.

Lorsqu'un téléchargement démarre, toute esquisse en cours d'exécution sur la carte est arrêtée (si vous exécutiez l'esquisse
Blink, la LED cessera de clignoter). La nouvelle esquisse est téléchargée sur le tableau, remplaçant l'esquisse précédente. La
nouvelle esquisse commencera à s'exécuter une fois le téléchargement terminé avec succès.

Les cartes Arduino plus anciennes et certains compatibles n'interrompent pas


automatiquement l'esquisse en cours d'exécution pour lancer le téléchargement.
Dans ce cas, vous devez appuyer sur le bouton Reset de la carte juste après que
le logiciel signale que la compilation est terminée (lorsque vous voyez le message
concernant la taille de l'esquisse). Cela peut prendre quelques tentatives pour
obtenir le bon timing entre la fin de la compilation et l'appui sur le bouton Reset.

L'IDE affichera un message d'erreur si le téléchargement échoue. Les problèmes sont généralement dus à la mauvaise carte ou
au mauvais port série sélectionné ou à la carte non branchée.

Si vous avez des difficultés à identifier le bon port sous Windows, essayez de débrancher la carte, puis sélectionnez Outils ÿ Port
série pour voir quel port COM n'est plus sur la liste d'affichage. Une autre approche consiste à sélectionner les ports, un par un,
jusqu'à ce que les voyants de la carte clignotent pour indiquer que le code est en cours de téléchargement.

12 | Chapitre 1 : Mise en route


Machine Translated by Google

Voir également

La page de dépannage Arduino : http:// www.arduino.cc/ en/ Guide/ Troubleshooting

1.5 Création et enregistrement d'un croquis

Problème
Vous souhaitez créer un croquis et l'enregistrer sur votre ordinateur.

Solution
Pour ouvrir une fenêtre d'éditeur prête pour une nouvelle esquisse, lancez l'IDE (voir recette 1.3), allez dans le menu Fichier
et sélectionnez Nouveau. Collez le code suivant dans la fenêtre de l'éditeur de croquis (il est similaire au croquis Blink,
mais les clignotements durent deux fois plus longtemps) :

const int ledPin = 13ÿ; // LED connectée à la broche numérique 13

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

void loop()

{ digitalWrite(ledPin, HIGH); // met la LED sur delay(2000); //


attendez deux secondes digitalWrite(ledPin,
le délai
LOW);
d'extinction
// définit
de la LED
(2000); // attend deux secondes }

Compilez le code en cliquant sur le bouton compiler (le bouton en haut à gauche avec un triangle à l'intérieur), ou
sélectionnez SketchÿVerify/Compile (voir recette 1.3).

Téléchargez le code en cliquant sur le bouton de téléchargement ou choisissez Fichier ÿ Télécharger sur la carte d'E/S
(voir recette 1.4). Après le téléchargement, le voyant doit clignoter, chaque flash durant deux secondes.

Vous pouvez enregistrer cette esquisse sur votre ordinateur en cliquant sur le bouton Enregistrer ou en sélectionnant
Fichier ÿ Enregistrer.

Vous pouvez enregistrer l'esquisse sous un nouveau nom en sélectionnant l'option de menu Enregistrer sous. Une boîte de
dialogue s'ouvrira dans laquelle vous pourrez saisir le nom du fichier.

Discussion
Lorsque vous enregistrez un fichier dans l'IDE, une boîte de dialogue standard pour le système d'exploitation s'ouvre. Il
vous suggère d'enregistrer l'esquisse dans un dossier appelé Arduino dans votre dossier Mes documents (ou votre dossier
Documents sur un Mac). Vous pouvez remplacer l'esquisse par défaut

1.5 Création et enregistrement d'un croquis | 13


Machine Translated by Google

nom avec un nom significatif qui reflète le but de votre croquis. Cliquez sur Enregistrer pour enregistrer le fichier.

Le nom par défaut est le mot croquis suivi de la date actuelle. Des lettres séquentielles
commençant par a sont utilisées pour distinguer les croquis créés le même jour. Remplacer
le nom par défaut par quelque chose de significatif vous aide à identifier le but d'une
esquisse lorsque vous y revenez plus tard.

Si vous utilisez des caractères que l'IDE n'autorise pas (par exemple, le caractère espace), l'IDE les remplacera
automatiquement par des caractères valides.

Les croquis Arduino sont enregistrés sous forme de fichiers texte brut avec l'extension .pde. Ils sont automatiquement
enregistrés dans un dossier portant le même nom que l'esquisse.

Vous pouvez enregistrer vos croquis dans n'importe quel dossier de votre ordinateur, mais si vous utilisez le dossier
par défaut (le dossier Arduino dans votre dossier Documents ), vos croquis apparaîtront automatiquement dans le
menu Sketchbook du logiciel Arduino et seront plus faciles à localiser.

Si vous avez modifié l'un des exemples du téléchargement Arduino, vous ne pourrez pas
enregistrer le fichier modifié en utilisant le même nom de fichier. Cela préserve les
exemples standard intacts. Si vous souhaitez enregistrer un exemple modifié, vous devrez
sélectionner un autre emplacement pour l'esquisse.

Après avoir apporté des modifications, une boîte de dialogue s'affiche vous demandant si vous souhaitez enregistrer
l'esquisse lorsqu'une esquisse est fermée.

Le symbole § suivant le nom de l'esquisse dans la barre supérieure de la fenêtre de l'IDE


indique que le code de l'esquisse comporte des modifications qui n'ont pas encore été
enregistrées sur l'ordinateur. Ce symbole est supprimé lorsque vous enregistrez l'esquisse.

Le logiciel Arduino ne fournit aucun type de contrôle de version, donc si vous voulez pouvoir revenir à des versions
plus anciennes d'un croquis, vous pouvez utiliser Enregistrer sous régulièrement et donner à chaque révision du
croquis un nom légèrement différent.

Une compilation fréquente lorsque vous modifiez ou ajoutez du code est un bon moyen de vérifier les erreurs lorsque
vous écrivez votre code. Il sera plus facile de trouver et de corriger les erreurs car elles seront généralement
associées à ce que vous venez d'écrire.

Une fois qu'un croquis a été téléchargé sur le tableau, il n'y a aucun moyen de le
télécharger à nouveau sur votre ordinateur. Assurez-vous d'enregistrer toutes les
modifications apportées à vos croquis que vous souhaitez conserver.

14 | Chapitre 1 : Mise en route


Machine Translated by Google

Si vous ouvrez des croquis que vous obtenez d'autres personnes qui ne se trouvent pas dans un dossier
portant le même nom que le croquis, l'IDE vous le dira et vous pourrez cliquer sur OK pour les placer dans un
dossier portant le même nom.

Les esquisses doivent se trouver dans un dossier portant le même nom que l'esquisse.

L'IDE créera automatiquement le dossier lorsque vous enregistrerez une nouvelle esquisse.

1.6 Utilisation d'Arduino

Problème
Vous souhaitez démarrer avec un projet facile à construire et amusant à utiliser.

Solution
Cette recette donne un avant-goût de certaines des techniques qui sont couvertes en détail dans les chapitres
suivants.

L'esquisse est basée sur le code de clignotement de la LED de la recette précédente, mais au lieu d'utiliser
un délai fixe, le taux est déterminé par un capteur sensible à la lumière appelé résistance dépendante de la
lumière ou LDR (voir la recette 6.2). Câblez le LDR comme illustré à la Figure 1-7.

Illustration 1-7. Arduino avec résistance dépendante de la lumière

Le croquis suivant lit le niveau de lumière d'un LDR connecté à la broche analogique 0. Le niveau de lumière
frappant le LDR modifiera le taux de clignotement de la LED interne connectée à la broche 13ÿ:

1.6 Utilisation d'Arduino | 15


Machine Translated by Google

const int ledPin = 13ÿ; const // LED connectée à la broche numérique


int sensorPin = 0ÿ; 13 // connecter le capteur à l'entrée analogique 0

void setup()
{ pinMode(ledPin,
OUTPUT); // active la sortie sur la broche led }

void loop()
{ int rate =
analogRead(sensorPin); Serial.println(taux); // lit l'entrée analogique
taux = carte (taux, 200 800, minDuration,
maxDuration); // convertir en fréquence de clignotement digitalWrite(ledPin, HIGH); // place la LED
sur delay(rate); digitalWrite(ledPin, BAS); retard (taux); }
// durée d'attente en fonction du niveau de luminosité //
éteint la LED

Discussion
La valeur de la résistance 4.7K n'est pas critique. Tout ce qui va de 1K à 10K peut être utilisé. Le niveau de lumière sur le
LDR modifiera le niveau de tension sur la broche analogique 0. La commande analogRead (voir chapitre 6) fournit une valeur
comprise entre environ 200 lorsque le LDR est sombre et 800 environ lorsqu'il est très lumineux. Cette valeur détermine la
durée des temps d'allumage et d'extinction de la LED, de sorte que le taux de clignotement augmente avec l'intensité
lumineuse.

Vous pouvez mettre à l'échelle le taux de clignotement en utilisant la fonction de carte Arduino comme

const int ledPin = 13ÿ; const suitÿ: // LED connectée à la broche numérique 13 // connectez
int sensorPin = 0ÿ; le capteur à l'entrée analogique 0

// les deux lignes suivantes définissent le délai min et max entre les clignotements
const int minDuration = 100; // attente minimum entre les clignotements const int
maxDuration = 1000; // attente maximale entre les clignotements

void setup()
{ pinMode(ledPin,
OUTPUT); // active la sortie sur la broche led }

void loop()
{ int rate =
analogRead(sensorPin); // la ligne suivante // lit l'entrée analogique
met à l'échelle le taux de clignotement entre les valeurs min et max rate = map(rate,
200,800,minDuration, maxDuration); // convertir en fréquence de clignotement digitalWrite(ledPin,
HIGH); // place la LED sur delay(rate); digitalWrite(ledPin, BAS); retard (taux); }
// durée d'attente en fonction du niveau de luminosité //
éteint la LED

La recette 5.7 fournit plus de détails sur l'utilisation de la fonction de carte pour mettre à l'échelle les valeurs.

16 | Chapitre 1 : Mise en route


Machine Translated by Google

Si vous souhaitez afficher la valeur de la variable de taux sur votre ordinateur, vous pouvez l'imprimer
sur le moniteur série Arduino, comme indiqué dans le code de boucle révisé qui suit. L'esquisse
affichera le taux de clignotement dans le moniteur série. Vous ouvrez la fenêtre Serial Monitor dans
l'IDE Arduino (voir le chapitre 4 pour en savoir plus sur l'utilisation du Serial Monitor) : const int ledPin
= 13; const int sensorPin = 0ÿ; // LED connectée à la broche numérique
13 // connecter le capteur à l'entrée analogique 0

// les deux lignes suivantes définissent le délai min et max entre les clignotements
const int minDuration = 100; // attente minimum entre les clignotements const int
maxDuration = 1000; // attente maximale entre les clignotements

void setup()
{ pinMode(ledPin,
OUTPUT); // active la sortie sur la broche led Serial.begin(9600); }
// initialise Serial

void loop()
{ int rate =
analogRead(sensorPin); // la ligne suivante // lit l'entrée analogique
met à l'échelle le taux de clignotement entre les valeurs min et max rate = map(rate,
200,800,minDuration, maxDuration); // convertir en fréquence de clignotement Serial.println(rate); //
taux d'impression sur le moniteur série digitalWrite(ledPin, HIGH);
BAS); retard
// place
(taux);
la LED
} sur delay(rate);

// durée d'attente en fonction du niveau de luminosité //


éteint la LED

Vous pouvez utiliser le LDR pour contrôler la hauteur d'un son en connectant un petit haut-parleur à la
broche, comme illustré à la Figure 1-8.

Illustration 1-8. Connexions pour un haut-parleur avec le circuit LDR

1.6 Utilisation d'Arduino | 17


Machine Translated by Google

Vous devrez augmenter le taux marche/arrêt sur la broche à une fréquence dans le spectre audio.
Ceci est réalisé, comme indiqué dans le code suivant, en divisant le taux par 100 dans la ligne après la fonction
map :

const int ledPin = 13ÿ; const // LED connectée à la broche numérique


int sensorPin = 0ÿ; 13 // connecter le capteur à l'entrée analogique 0

const int minDuration = 100ÿ; // attente minimum entre les clignotements const
int maxDuration = 1000; // attente maximale entre les clignotements

void setup()
{ pinMode(ledPin,
OUTPUT); // active la sortie sur la broche led }

void loop()
{ int
sensorReading = analogRead(sensorPin); // lit l'entrée analogique int rate =
map(sensorReading, 200,800,minDuration, maxDuration); taux = taux / 100ÿ; // ajouter
cette ligne pour la fréquence audio digitalWrite(ledPin, HIGH);
digitalWrite(ledPin, // place
BAS); retardla(taux);
LED sur} delay(rate);

// durée d'attente en fonction du niveau de luminosité //


éteint la LED

Voir également

Voir le chapitre 9 pour en savoir plus sur la création de sons avec Arduino.

18 | Chapitre 1 : Mise en route


Machine Translated by Google

CHAPITRE 2

Faire en sorte que le croquis fasse votre offre

2.0 Présentation
Bien qu'une grande partie d'un projet Arduino implique l'intégration de la carte Arduino avec du matériel de
support, vous devez être en mesure de dire à la carte quoi faire avec le reste de votre projet. Ce chapitre
présente les éléments de base de la programmation Arduino, montrant aux non-programmeurs comment
utiliser les constructions de langage courantes et fournissant un aperçu de la syntaxe du langage pour les
lecteurs qui ne sont pas familiers avec C ou C++, le langage utilisé.

Étant donné que rendre les exemples intéressants nécessite de faire faire quelque chose à Arduino, les
recettes utilisent les capacités physiques de la carte qui sont expliquées en détail dans les chapitres suivants.
Si l'un des codes de ce chapitre n'est pas clair, n'hésitez pas à passer directement au chapitre 4 pour en
savoir plus sur la sortie série et au chapitre 5 pour en savoir plus sur l'utilisation des broches numériques et
analogiques. Cependant, vous n'avez pas besoin de comprendre tout le code des exemples pour voir
comment exécuter les fonctionnalités spécifiques qui sont au centre des recettes. Voici quelques-unes des
fonctions les plus courantes utilisées dans les exemples traités dans les chapitres suivantsÿ:

Serial.println(valeur); Imprime
la valeur sur le moniteur série de votre ordinateurÿ; voir la recette 4.1 pinMode(pin, mode);

Configure une broche numérique pour lire (entrée) ou écrire (sortie) une valeur numériqueÿ; voir
l' introduction au chapitre 5 digitalRead(pin); Lit une valeur numérique (HIGH ou LOW) sur une broche
définie pour l'entréeÿ; voir recette 5.1

digitalWrite(broche, valeur);
Écrit la valeur numérique (HIGH ou LOW) sur une broche définie pour la sortieÿ; voir recette 5.1

19
Machine Translated by Google

2.1 Structurer un programme Arduino


Problème
Vous débutez en programmation et souhaitez comprendre les éléments constitutifs d'un programme
Arduino.

Solution
Les programmes pour Arduino sont généralement appelés esquisses, pour souligner la nature agile du
développement. Les termes croquis et programme sont interchangeables. Les croquis contiennent du code
- les instructions que la carte exécutera. Le code qui ne doit s'exécuter qu'une seule fois (comme pour
configurer la carte pour votre application) doit être placé dans la fonction de configuration .
Le code à exécuter en continu après la fin de la configuration initiale entre dans la fonction de boucle .
Voici un croquis typique :

const int ledPin = 13ÿ; // LED connectée à la broche numérique 13

// La méthode setup() s'exécute une fois, lorsque l'esquisse démarre


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

// initialise la broche numérique en sortie

// la méthode loop() s'exécute encore et encore, void loop()


{ digitalWrite(ledPin, HIGH); // allume la LED delay(1000);
digitalWrite(ledPin, BAS); retard(1000); }

// attendre une
seconde // éteindre la
LED // attendre une seconde

Lorsque la carte a fini de télécharger le code, ou est allumée une fois qu'elle contient ce code, elle
commence en haut de l'esquisse et exécute les instructions de manière séquentielle. Il exécute le code
dans la configuration une fois, puis parcourt le code en boucle. Lorsqu'il arrive à la fin de la boucle (marquée
par le crochet fermant, }), il revient au début de la boucle.

Discussion
Cet exemple fait clignoter une LED en continu en écrivant les sorties HIGH et LOW sur une broche.
Voir le chapitre 5 pour en savoir plus sur l'utilisation des broches Arduino. Lorsque l'esquisse commence,
le code dans la configuration définit le mode broche (il est donc capable d'allumer une LED). Une fois le
code dans la configuration terminé, le code en boucle est appelé à plusieurs reprises (pour faire clignoter
la LED) tant que la carte Arduino est sous tension.

Vous n'avez pas besoin de le savoir pour écrire des croquis Arduino, mais les programmeurs C/C++
expérimentés peuvent se demander où est passée la fonction de point d'entrée main() attendue. Il est là,
mais il est caché sous les couvertures par l'environnement de construction Arduino. La construction

20 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Le processus crée un fichier intermédiaire qui inclut le code d'esquisse et les éléments suivants
déclarations supplémentairesÿ:

int principal (vide)


{
init();

mettre en place();

pour (;;)
boucle();

renvoie 0ÿ;
}

La première chose qui se passe est un appel à une fonction init() qui initialise l'Arduino
Matériel. Ensuite, la fonction setup() du sketch est appelée. Enfin, la fonction loop() est
appelé encore et encore. Comme la boucle for ne se termine jamais, l'instruction return est
jamais exécuté.

Voir également

Le chapitre 17 et http:// www.arduino.cc/ en/ Hacking/ BuildProcess fournissent plus d'informations sur
processus de construction.

2.2 Utilisation de types primitifs simples (variables)

Problème
Arduino a différents types de variables pour représenter efficacement les valeurs. Vous voulez
savoir comment sélectionner et utiliser ces types de données Arduino.

Solution
Bien que le type de données int (abréviation d' entier, une valeur 16 bits dans Arduino) soit le plus
choix courant pour les valeurs numériques rencontrées dans les applications Arduino, vous pouvez
utilisez le tableau 2-1 pour déterminer le type de données qui correspond à la plage de valeurs de votre application
attend.

Tableau 2-1. Types de données Arduino

Utiliser
Types numériques Plage d'octets

entier 2 -32768 à 32767 Représente des valeurs entières positives et négatives.

entier non signé 2 0 à 65535 Représente uniquement des valeurs positivesÿ; sinon, similaire à int.

4 -2147483648 à Représente une très large plage de valeurs positives et négatives.


long
2147483647

4 4294967295 Représente une très large plage de valeurs positives.


non signé
long

2.2 Utilisation de types primitifs simples (variables) | 21


Machine Translated by Google

Utiliser
Types numériques Plage d'octets

flotter 4 3.4028235E+38 à Représente des nombres avec des fractionsÿ; utiliser pour approximer les
-3.4028235E+38 mesures du monde réel.

double 4 Identique au flotteur Dans Arduino, double n'est qu'un autre nom pour float.

booléen 1
faux (0) ou vrai (1) Représente les valeurs vraies et fausses.

carboniser
1 -128 à 127 Représente un seul caractère. Peut également représenter une valeur signée
entre -128 et 127.

1 0 à 255 Semblable à char, mais pour les valeurs non signées.


octet
Autres types

chaîne de caractères
Représente des tableaux de chars (caractères) généralement utilisés pour contenir du texte.

annuler Utilisé uniquement dans les déclarations de fonction où aucune valeur n'est renvoyée.

Discussion
Sauf dans les situations où des performances ou une efficacité de mémoire maximales sont requises,
les variables déclarées à l'aide de int conviendront aux valeurs numériques si les valeurs ne le sont pas
dépasser la plage (indiquée dans la première ligne du tableau 2-1) et si vous n'avez pas besoin de travailler
avec des valeurs fractionnaires. La plupart des exemples de code officiels Arduino déclarent numeric
variables comme int. Mais parfois, vous devez choisir un type qui convient spécifiquement à votre
application.

Parfois, vous avez besoin de nombres négatifs et parfois non, donc les types numériques
existent en deux variétés : signées et non signées. les valeurs non signées sont toujours positives. Les
variables sans le mot clé unsigned devant sont signées afin de pouvoir représenter des valeurs négatives
et positives. L'une des raisons d'utiliser des valeurs non signées est lorsque la plage de
les valeurs signées ne correspondent pas à la plage de la variable (une variable non signée a deux fois
capacité d'une variable signée). Une autre raison pour laquelle les programmeurs choisissent d'utiliser des
types est d'indiquer clairement aux personnes lisant le code que la valeur attendue ne sera jamais
être un nombre négatif.

Les types booléens ont deux valeurs possibles : vrai ou faux. Ils sont couramment utilisés pour
des choses comme vérifier l'état d'un interrupteur (s'il est enfoncé ou non). Vous pouvez également utiliser ÉLEVÉ
et LOW comme équivalents de vrai et faux là où cela a plus de sensÿ; numérique
Write(pin, HIGH) est un moyen plus expressif d'allumer une LED que digitalWrite(pin,
true) ou digitalWrite(pin,1), bien que tous soient traités de la même manière lorsque le
sketch s'exécute réellement, et vous rencontrerez probablement tous ces formulaires dans le code posté
sur le Web.

Voir également

La référence Arduino sur http:// www.arduino.cc/ en/ Reference/ HomePage fournit des détails sur les types
de données.

22 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

2.3 Utilisation des nombres à virgule flottante

Problème
Les nombres à virgule flottante sont utilisés pour les valeurs exprimées avec des points décimaux (c'est la
façon de représenter les valeurs fractionnaires). Vous voulez calculer et comparer ces valeurs dans votre
croquis.

Solution
Le code suivant montre comment déclarer des variables à virgule flottante, illustre les problèmes que vous
pouvez rencontrer lors de la comparaison de valeurs à virgule flottante et montre comment les surmonterÿ:

/*
* Exemple en virgule flottante *
Cette esquisse a initialisé une valeur flottante à 1,1 * Elle réduit
à plusieurs reprises la valeur de 0,1 jusqu'à ce que la valeur soit 0 */

valeur flottante = 1,1ÿ;

void setup()

{ Serial.begin(9600); }

void loop()
{ valeur =
valeur - 0,1ÿ; si( valeur == // réduit la valeur de 0,1 à chaque fois dans la boucle
0)
Serial.println("La valeur est exactement zéro");
else if(fabs(value) < .0001) // fonction pour prendre la valeur absolue d'un float Serial.println("La valeur est
assez proche de zéro"); autre

Serial.println(valeur);

retard(100); }

Discussion
Les mathématiques à virgule flottante ne sont pas exactes et les valeurs renvoyées peuvent comporter une
petite erreur d'approximation. L'erreur se produit car les valeurs à virgule flottante couvrent une vaste plage,
de sorte que la représentation interne de la valeur ne peut contenir qu'une approximation. Pour cette raison,
vous devez tester si les valeurs sont dans une plage de tolérance plutôt qu'exactement égales.

La sortie de cette esquisse est la suivanteÿ:


1,00
0,90

2.3 Utilisation des nombres à virgule flottante | 23


Machine Translated by Google

0,80
0,70
0,60
0,50
0,40
0,30
0,20
0,10
La valeur est assez proche de zéro
-0,10
-0,20

La sortie continue de produire des nombres négatifs.

Vous pouvez vous attendre à ce que la boucle s'arrête après que la valeur est de 0,1 , puis 0,1 en est soustrait.
Mais la valeur n'est jamais égale à zéroÿ; il devient très proche, mais ce n'est pas assez bon pour réussir le
test si (valeur == 0). En effet, le seul moyen efficace en mémoire pour que les nombres à virgule flottante
puissent contenir l'énorme plage de valeurs qu'ils peuvent représenter consiste à stocker une approximation du
nombre.

La solution consiste à vérifier si une variable est proche de la valeur souhaitée, comme indiqué dans le code
de la solution de cette recetteÿ:

else if(fabs(value) < .0001) // fonction pour prendre la valeur absolue d'un float
Serial.println("La valeur est suffisamment proche de zéro");

Cela teste si la valeur de la variable est à moins de 0,0001 de la cible souhaitée et imprime un message si c'est
le cas. La fonction nommée fabs (abréviation de valeur absolue à virgule flottante) renvoie la valeur absolue
d'une variable à virgule flottante. La fonction renvoie l'amplitude de la valeur, et si celle-ci est comprise entre
0,0001 et 0, le code imprimera le message indiquant que les valeurs sont suffisamment proches.

La virgule flottante se rapproche des nombres car elle n'utilise que 32 bits pour contenir toutes les
valeurs dans une plage énorme. Huit bits sont utilisés pour le multiplicateur décimal (l'exposant), ce qui
laisse 24 bits pour le signe et la valeur, juste assez pour sept chiffres décimaux significatifs.

Bien que float et double soient exactement les mêmes sur Arduino, les doubles ont une précision plus
élevée sur de nombreuses autres plates-formes. Si vous importez du code qui utilise float et double
depuis une autre plate-forme, vérifiez que la précision est suffisante pour votre application.

Voir également

La référence Arduino pour float : http:// www.arduino.cc/ en/ Reference/ Float

24 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

2.4 Travailler avec des groupes de valeurs

Problème
Vous souhaitez créer et utiliser un groupe de valeurs (appelées tableaux). Les tableaux peuvent être une
simple liste ou ils peuvent avoir deux dimensions ou plus. Vous voulez savoir comment déterminer la taille
du tableau et comment accéder aux éléments du tableau.

Solution
Cette esquisse crée deux tableauxÿ: un tableau d'entiers pour les broches connectées aux commutateurs et
un tableau de broches connectées aux LED, comme illustré à la Figure 2-1ÿ:
/*
array sketch un
tableau de commutateurs contrôle un tableau de LED voir le
chapitre 5 pour plus d'informations sur l'utilisation des commutateurs
voir le chapitre 7 pour des informations sur les LED */

int inputPins[] = {2,3,4,5}ÿ; // crée un tableau de broches pour les entrées de commutateur

int ledPins[] = {10,11,12,13}ÿ; // crée un tableau de broches de sortie pour les LED

void setup()
{ for(int index =
0; index < 4; index++) { pinMode(ledPins[index],
OUTPUT); pinMode(inputPins[index], INPUT);
digitalWrite(inputPins[index],HIGH); // déclare la LED en sortie //
déclare le bouton poussoir en entrée //
active les résistances pull-up //(voir recette
5.2)

}}

void loop(){ for(int


index = 0; index < 4; index++) { int val =
digitalRead(inputPins[i]); // lit la valeur d'entrée if (val
== LOW) { digitalWrite(ledPins[index], HIGH); // allume la LED si le commutateur
est enfoncé } else { digitalWrite(ledPins[i], LOW); } } } // vérifie si le commutateur est enfoncé

// éteint la LED

2.4 Travailler avec des groupes de valeurs | 25


Machine Translated by Google

Illustration 2-1. Connexions pour LED et interrupteurs

Discussion
Les tableaux sont des collections de variables consécutives du même type. Chaque variable de
la collection est appelée un élément. Le nombre d'éléments est appelé la dimension de la
déployer.

L'exemple précédent illustre une utilisation courante des tableaux dans le code Arduinoÿ: stocker
une collection de broches. Ici, les broches se connectent aux commutateurs et aux LED (un
sujet traité plus en détail au chapitre 5). Les parties importantes de cet exemple sont la
déclaration du tableau et l'accès aux éléments du tableau.

La ligne de code suivante déclare (crée) un tableau d'entiers avec quatre éléments et initialise
chaque élément. Le premier élément est mis égal à 2, le second à 3, et ainsi de suite :
int inputPins[] = {2,3,4,5}ÿ;

26 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Si vous n'avez pas besoin d'initialiser les valeurs lorsque vous déclarez un tableau (les valeurs ne seront peut-
être disponibles que lorsque l'esquisse est en cours d'exécution), vous pouvez déclarer le tableau comme suitÿ:

tableau int[4]ÿ;

Cela déclare un tableau de quatre éléments avec la valeur initiale de chaque élément définie sur zéro.
Le nombre entre crochets ([]) est la dimension, et cela définit le nombre d'éléments. Ce tableau a une dimension
de quatre et peut contenir au plus quatre valeurs entières. La dimension peut être omise si la déclaration de
tableau contient des initialiseurs (comme indiqué dans le premier exemple) car le compilateur détermine la
taille du tableau en comptant le nombre d'initialiseurs.

Le premier élément du tableau est element[0] :

int firstElement = inputPin[0]ÿ; // c'est le premier élément

Le dernier élément est un de moins que la dimension, donc dans l'exemple précédent, avec une dimension de
quatre, le dernier élément est l'élément 3ÿ:

Int lastElement = inputPin[3]ÿ; // c'est le dernier élément

Il peut sembler étrange qu'un tableau avec une dimension de quatre ait le dernier élément accédé en utilisant
array[3], mais comme le premier élément est array[0], les quatre éléments sont :

tableau[0],tableau[1],tableau[2],tableau[3]

Dans l'esquisse précédente, les quatre éléments sont accessibles à l'aide d'une boucle forÿ:

for(int index = 0; index < 4; index++) {

//obtenir le numéro de broche en accédant à chaque élément dans les tableaux


de broches pinMode(ledPins[index], OUTPUT); // déclare
pinMode(inputPins[index],
la LED comme sortie
INPUT); // déclare le bouton-poussoir en entrée
}

Cette boucle parcourra l' index de la variable avec des valeurs commençant à 0 et se terminant à 3. C'est une erreur
courante d'accéder accidentellement à un élément qui dépasse la dimension réelle du tableau. Il s'agit d'un bogue
qui peut avoir de nombreux symptômes différents et des précautions doivent être prises pour l'éviter. Une façon de
garder vos boucles sous contrôle est de définir la dimension d'un tableau en utilisant une constante comme suit :
const int PIN_COUNT = 4; // définit une constante pour le nombre d'éléments int inputPins[PIN_COUNT] =

{2,3,4,5}ÿ;

for(int index = 0; index < PIN_COUNT; index++)


pinMode(inputPins[index], INPUT);

Le compilateur ne signalera pas d'erreur si vous essayez accidentellement de stocker ou de lire au-
delà de la taille du tableau. Vous devez veiller à n'accéder qu'aux éléments qui se trouvent dans
les limites que vous avez définies. L'utilisation d'une constante pour définir la dimension d'un
tableau et dans le code faisant référence à ses éléments aide votre code à rester dans les limites
du tableau.

2.4 Travailler avec des groupes de valeurs | 27


Machine Translated by Google

Une autre utilisation courante des tableaux consiste à contenir une chaîne de caractères de texte. Dans le code Arduino,
celles-ci sont appelées chaînes de caractères (chaînes en abrégé). Une chaîne de caractères se compose d'un ou
plusieurs caractères, suivis du caractère nul (la valeur 0) pour indiquer la fin de la chaîne.

Le null à la fin d'une chaîne de caractères n'est pas le même que le caractère 0.
Le null a une valeur ASCII de 0, tandis que 0 a une valeur ASCII de 48.

Les méthodes d'utilisation des chaînes sont couvertes dans les recettes 2.5 et 2.6.

Voir également

Recette 5.2ÿ; Recette 7.1

2.5 Utilisation de la fonctionnalité de chaîne Arduino

Problème
Vous voulez manipuler du texte. Vous devez le copier, ajouter des bits ensemble et déterminer
le nombre de caractères.

Solution
La recette 2.4 décrit les tableaux Arduino en général. Le texte est stocké dans des tableaux de caractères.
Ils sont généralement appelés chaînes. Arduino a une capacité supplémentaire pour utiliser un tableau de caractères
appelé String qui peut stocker et manipuler des chaînes de texte.

Le mot String avec un S majuscule fait référence à la capacité de texte Arduino


fournie par la bibliothèque Arduino String. La chaîne de mots avec un s minuscule
fait référence au groupe de caractères plutôt qu'à la fonctionnalité Arduino String .

Cette recette montre comment utiliser les chaînes Arduino.

La fonctionnalité String a été introduite dans la version 19 d'Arduino. Si vous


utilisez une version plus ancienne, vous pouvez utiliser la bibliothèque TextString ;
voir le lien à la fin de cette recette.

Chargez le croquis suivant sur votre tableau et ouvrez le moniteur série pour afficher les résultatsÿ:

28 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

/*
Esquisse Basic_Strings
*/

String text1 = "Cette


" chaîne"ÿ;
String text2 = a plus de texte"ÿ;
Texte de chaîne3ÿ; // à attribuer dans l'esquisse

void setup()

{ Serial.begin(9600);

Serial.print( text1);
Serial.print(" est ");
Serial.print(text1.length());
Serial.println(" caractères de long.");

Serial.print("text2 est ");


Serial.print(text2.length());
Serial.println(" caractères de long.");

text1.concat(text2);
Serial.println("text1 contient maintenant : ");
Serial.println(text1); }

void loop()
{}

Discussion
Cette esquisse crée deux variables de type String, appelées message et anotherMessage.
Les variables de type String ont des capacités intégrées pour manipuler du texte.
L'instruction message.length() renvoie (fournit la valeur de) la longueur (nombre de
caractères) dans la chaîne message. message.concat(anotherMessage) combine le
contenu des chaînesÿ; dans ce cas, il ajoute le contenu d' un autre message à la fin du
message (concat est l'abréviation de concatenate).

Le moniteur série affichera ce qui suitÿ:

Cette chaîne comporte 11 caractères.


text2 contient 14 caractères. text1
contient maintenant : Cette chaîne a
plus de texte
Une autre façon de combiner des chaînes consiste à utiliser l'opérateur d'addition de chaînes. Ajoutez ces
deux lignes à la fin du code d' installationÿ: and more"ÿ;

"
text3 = text1 +
Serial.println(text3);

2.5 Utilisation de la fonctionnalité de chaîne Arduino | 29


Machine Translated by Google

Le nouveau code entraînera l'ajout par Serial Monitor de la ligne suivante à la fin de l'affichageÿ:

Ceci est une chaîne avec plus de texte et plus

Vous pouvez utiliser les fonctions indexOf et lastIndexOf pour rechercher une instance d'un caractère
particulier dans une chaîne.

Parce que la classe String est un nouvel ajout à Arduino, vous rencontrerez beaucoup de code qui utilise
des tableaux de caractères plutôt que le type String . Voir la recette 2.6 pour en savoir plus sur l'utilisation
de tableaux de caractères sans l'aide de la fonctionnalité Arduino String .

Si vous voyez une ligne telle que celle-ciÿ:

char oldString[] = "ceci est un tableau de caractères"ÿ;

le code utilise des tableaux de caractères de style C (voir la recette 2.6). Si la déclaration ressemble à
ceci :

String newString = "ceci est un objet chaîne"ÿ;

le code utilise des chaînes Arduino. Pour convertir un tableau de caractères de style C en une chaîne
Arduino, il suffit d'affecter le contenu du tableau à l' objet String :

char oldString[] = "Je veux ce tableau de caractères dans un objet String"ÿ;


String newsString = oldString;

Voir également

La distribution Arduino fournit des exemples de croquis String .

Des tutoriels pour la nouvelle bibliothèque String sont disponibles sur http:// arduino.cc/ en/ Tutorial/ Home
Page, et un tutoriel pour la bibliothèque String originale est disponible sur http:// www.arduino.cc/ en/
Tutorial/ TextString .

2.6 Utilisation des chaînes de caractères C

Problème

Vous voulez comprendre comment utiliser les chaînes de caractères brutesÿ: vous voulez savoir
comment créer une chaîne, trouver sa longueur et comparer, copier ou ajouter des chaînes. Le langage
C ne prend pas en charge la capacité String de style Arduino , vous voulez donc comprendre le code
écrit pour fonctionner avec des tableaux de caractères primitifs.

30 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Solution
Les tableaux de caractères sont parfois appelés chaînes de caractères (ou simplement chaînes en abrégé).
La recette 2.5 décrit les tableaux Arduino en général. Cette recette décrit les fonctions qui opèrent sur des chaînes de
caractères.

Vous déclarez des chaînes comme ceciÿ:

char ChaîneA[8]ÿ; // déclare une chaîne de 7 caractères maximum plus un caractère


nul de fin StringB[8] = "Arduino"ÿ; // comme ci-dessus et init(ialize) la chaîne à
"Arduino"ÿ;
char ChaîneC[16] = "Arduino"ÿ; // comme ci-dessus, mais la chaîne a de la place
pour s'agrandir char StringD[ ] = "Arduino"; // le compilateur initie la chaîne et
calcule la taille

Utilisez strlen (abréviation de longueur de chaîne) pour déterminer le nombre de caractères avant le
nul:

int longueur = strlen(string); // renvoie le nombre de caractères dans la chaîne

longueur sera 0 pour StringA et 7 pour les autres chaînes indiquées dans le code précédent.
Le null qui indique la fin de la chaîne n'est pas compté par strlen.

Utilisez strcpy (abréviation de copie de chaîne) pour copier une chaîne dans une autreÿ:

strcpy(destination, source); // copie la source de la chaîne vers la destination

Utilisez strncpy pour limiter le nombre de caractères à copier (utile pour éviter d'écrire plus de caractères que la chaîne
de destination ne peut en contenir). Vous pouvez voir cela utilisé dans la recette 2.7ÿ:

strncpy(destination, source, 6); // copie jusqu'à 6 caractères de la source à la destination

Utilisez strcat (abréviation de string concatenate) pour ajouter une chaîne à la fin d'une autre : strcat(destination,

source); // ajoute la chaîne source à la fin de la chaîne destination

Assurez-vous toujours qu'il y a suffisamment d'espace dans la destination lors de la copie ou de la concaténation de

chaînes. N'oubliez pas de laisser de la place pour le null de fin.

Utilisez strcmp (abréviation de comparaison de chaînes) pour comparer deux chaînes. Vous pouvez voir cela utilisé dans
la recette 2.7ÿ:

if(strcmp(str, "Arduino") == 0) //
faire quelque chose si la variable str est égale à "Arduino"

Discussion
Le texte est représenté dans l'environnement Arduino à l'aide d'un tableau de caractères appelés chaînes. Une chaîne
se compose d'un certain nombre de caractères suivis d'un null (la valeur 0). Le null n'est pas affiché, mais il est
nécessaire pour indiquer la fin de la chaîne au logiciel.

2.6 Utilisation des chaînes de caractères C | 31


Machine Translated by Google

Voir également

Consultez l'une des nombreuses pages de référence C/C++ en ligne, telles que http://
www.cplusplus.com/ reference/ clibrary/ cstring/ et http:// www.cppreference.com/ wiki/ string/ c/ start.

2.7 Fractionnement du texte séparé par des virgules en groupes

Problème
Vous avez une chaîne qui contient deux ou plusieurs éléments de données séparés par des virgules
(ou tout autre séparateur). Vous souhaitez diviser la chaîne afin de pouvoir utiliser chaque partie
individuelle.

Solution
Ce croquis imprime le texte trouvé entre chaque virguleÿ:
/*
* Esquisse SplitSplit *
divise une chaîne séparée par des
virgules */

String message= "Pierre, Paul, Marie"ÿ; // un exemple de chaîne int


virgulePositionÿ; // la position de la virgule suivante dans la chaîne

void setup()

{ Serial.begin(9600); }

boucle vide()
{

Serial.println(message); fais { // affiche la chaîne source

commaPosition = message.indexOf(',');
si(commaPosition != -1) {

Serial.println( message.substring(0,commaPosition)); message =


message.substring(commaPosition+1, message.length());

}
else { // ici après la dernière virgule est trouvée
if(message.length() > 0)
Serial.println(message); // s'il y a du texte après la dernière virgule,
imprime
le }

} tandis que(commaPosition
>=0); retard (5000);
}

32 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Le moniteur série affichera ce qui suitÿ:

Pierre, Paul, Marie


Pierre
Paul

Discussion
Cette esquisse utilise des fonctions String pour extraire du texte entre des virgules. Le code suivantÿ:

commaPosition = message.indexOf(',');

définit la variable commaPosition avec la position de la première virgule dans le message nommé
String (elle sera définie sur -1 si aucune virgule n'est trouvée). S'il y a une virgule, la fonction substring
est utilisée pour imprimer le texte depuis le début de la chaîne jusqu'à la position de la virgule. Le
texte qui a été imprimé est supprimé du message dans cette ligneÿ:

message = message.substring(commaPosition+1, message.length());

substring renvoie une chaîne commençant par commaPosition+1 (la position juste après la
première virgule) jusqu'à la longueur du message. Il en résulte que ce message ne contient
que le texte suivant la première virgule. Ceci est répété jusqu'à ce qu'il n'y ait plus de virgules
trouvées (commaIndex sera égal à -1).
Si vous êtes un programmeur expérimenté, vous pouvez également utiliser les fonctions de bas
niveau qui font partie de la bibliothèque C standard. L'esquisse suivante a des fonctionnalités
similaires à la précédente utilisant des chaînes Arduinoÿ:
/*
* Esquisse SplitSplit *
divise une chaîne séparée par des
virgules */

const entier MAX_STRING_LEN = 20ÿ; // définissez ceci sur la plus grande chaîne que vous traiterez
char stringList[] = "Peter,Paul,Mary"ÿ; // un exemple de chaîne

char stringBuffer[MAX_STRING_LEN+1]ÿ; // un tampon statique pour le calcul et la sortie

void setup()

{ Serial.begin(9600); }

void loop()
{ char *str;
caractère
*pÿ;
strncpy(stringBuffer, stringList, MAX_STRING_LEN); // copie la chaîne source
Serial.println(stringBuffer); for( str = strtok_r(stringBuffer, ",", &p); // affiche la chaîne source //
fractionne à l'aide d'une virgule //
boucle tant que str n'est pas nul //
chaîneÿ; str = strtok_r(NULL, ",", récupère les jetons suivants
&p) )

2.7 Fractionnement du texte séparé par des virgules en groupes | 33


Machine Translated by Google

{ Serial.println(str);
if(strcmp(str, "Paul") == 0)
Serial.println("a trouvé Paul");

} retard(5000);
}

La fonctionnalité principale provient de la fonction nommée strtok_r (le nom de la version de strtok fournie
avec le compilateur Arduino). La première fois que vous appelez strtok_r , vous lui transmettez la chaîne que
vous souhaitez segmenter (séparée en valeurs individuelles).
Mais strtok_r écrase les caractères de cette chaîne chaque fois qu'il trouve un nouveau jeton, il est donc
préférable de passer une copie de la chaîne comme indiqué dans cet exemple. Chaque appel qui suit utilise
un NULL pour indiquer à la fonction qu'elle doit passer au jeton suivant. Dans cet exemple, chaque jeton est
imprimé sur le port série et également comparé à une chaîne cible ("Paul").

Si vos jetons ne sont constitués que de chiffres, voir la recette 4.5. Cela montre comment extraire des valeurs
numériques séparées par des virgules dans un flux de caractères en série.

Voir également

Recette 2.5ÿ; références en ligne aux fonctions C/C++ strtok_r et strcmp

2.8 Conversion d'un nombre en chaîne


Problème

Vous devez convertir un nombre en chaîne, peut-être pour afficher le nombre sur un écran LCD ou un autre
écran.

Solution

La variable String convertira automatiquement les nombres en chaînes de caractères. Vous pouvez utiliser
des valeurs littérales ou le contenu d'une variable. Par exemple, le code suivant fonctionneraÿ:

Chaîne monNuméro = 1234ÿ;

Ainsi que ceci :

int value = 127


String myReadout = "La lecture était "ÿ;
myReadout.concat(valeur);

Ou ca:

valeur entière = 127ÿ;


String myReadout = "La lecture était "ÿ;
myReadout += valeurÿ;

34 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Discussion
Si vous convertissez un nombre pour l'afficher sous forme de texte sur un écran LCD ou un périphérique
série, la solution la plus simple consiste à utiliser la capacité de conversion intégrée aux bibliothèques LCD
et série (voir la recette 4.2). Mais peut-être que vous utilisez un appareil qui n'a pas cette prise en charge
intégrée (voir Chapitre 13) ou que vous voulez manipuler le nombre comme une chaîne dans votre croquis.

La classe Arduino String convertit automatiquement les valeurs numériques lorsqu'elles sont signées en
une variable String . Vous pouvez combiner (concaténer) des valeurs numériques à la fin d'une chaîne à
l'aide de la fonction concat ou de l'opérateur chaîne + .

L' opérateur + est utilisé avec les types de nombres ainsi qu'avec les chaînes, mais il
est différent avec chacun.

Le code suivant donne un nombre ayant une valeur de 13ÿ:

nombre entier = 12ÿ;


nombre += 1ÿ;

Avec une chaîne, comme illustré iciÿ:

Chaîne textNumber = 12
textNumber += 1;

textNumber est la chaîne de texte "121".

Avant l'introduction de la classe String , il était courant de trouver du code Arduino en utilisant la fonction
itoa ou ltoa . Les noms viennent de "integer to ASCII" (itoa) et "long to ASCII" (ltoa). La version String
décrite précédemment est plus facile à utiliser, mais ce qui suit vous aidera si vous souhaitez comprendre
le code qui utilise itoa ou ltoa.

Ces fonctions prennent trois paramètres : la valeur à convertir, le tampon qui contiendra la chaîne de sortie
et la base numérique (10 pour un nombre décimal, 16 pour hexadécimal et 2 pour binaire).

L'esquisse suivante illustre comment convertir des valeurs numériques à l'aide de ltoaÿ:
/*
* NombreVersChaîne
* Crée une chaîne à partir d'un nombre donné */

void setup()

{ Serial.begin(9600); }

tampon de caractères[12]ÿ; // le type de données long a 11ÿcaractères (y compris le //


signe moins) et un null de fin

2.8 Conversion d'un nombre en chaîne | 35


Machine Translated by Google

void loop()
{ valeur
longue = 12345;
ltoa(valeur, buffer, 10);
Serial.print( valeur);
Serial.print(" a ");
Serial.print(strlen(buffer));
Serial.println(" chiffres"); valeur =
123456789ÿ; ltoa(valeur, buffer,
10); Serial.print( valeur); Serial.print("
a "); Serial.print(strlen(buffer));
Serial.println(" chiffres");
retard(1000); }

Votre mémoire tampon doit être suffisamment grande pour contenir le nombre maximum de caractères dans
la chaîne. Pour les entiers 16 bits, c'est-à-dire sept caractères (cinq chiffres, un signe moins possible et un 0
de fin qui signifie toujours la fin d'une chaîne); Les entiers longs de 32 bits nécessitent des tampons de 12
caractères (10 chiffres, le signe moins et le 0 de fin). Aucun avertissement n'est donné si vous dépassez la
taille de la mémoire tampon ; c'est un bogue qui peut provoquer toutes sortes de symptômes étranges, car
le débordement corrompra une autre partie de la mémoire qui pourrait être utilisée par votre programme. Le
moyen le plus simple de gérer cela consiste à toujours utiliser un tampon de 12 caractères et à toujours
utiliser ltoa car cela fonctionnera à la fois sur les valeurs 16 bits et 32 bits.

2.9 Conversion d'une chaîne en nombre

Problème
Vous devez convertir une chaîne en nombre. Vous avez peut-être reçu une valeur sous forme de chaîne sur
une liaison de communication et vous devez l'utiliser comme valeur entière ou à virgule flottante.

Solution
Il existe plusieurs façons de résoudre ce problème. Si la chaîne est reçue sous forme de données série, elle
peut être convertie à la volée à mesure que chaque caractère est reçu. Voir la recette 4.3 pour un exemple
de comment faire cela en utilisant le port série.

Une autre approche pour convertir des chaînes de texte représentant des nombres consiste à utiliser la
fonction de conversion en langage C appelée atoi (pour les variables int ) ou atol (pour les variables longues ).

Ce fragment de code termine les chiffres entrants sur tout caractère qui n'est pas un chiffre (ou si le tampon
est plein)ÿ:

taux de clignotement // taux de clignotement stocké dans cette


entierÿ; char strValue [6]ÿ; variable // doit être assez grand pour contenir tous les chiffres et
le // 0 qui termine la chaîne // l'index dans le tableau stockant les
index entier = 0ÿ; chiffres reçus

36 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

void loop()

{ if( Serial.available()) { char


ch = Serial.read();
si(index < 5 && ch >= '0'
&& ch <= '9'){
strValeur[index++] = chÿ; // ajoute le caractère ASCII à la chaîneÿ; }
else { // ici lorsque le tampon est plein ou sur le premier chiffre non //
termine la chaîne avec un 0 strValue[index] = 0; tauxclignotant =
atoi(strValeur); // utilise atoi pour convertir la chaîne en un int index =
0ÿ; } } clignoter(); }

Discussion
Les fonctions obscures atoi (pour ASCII vers int) et atol (pour ASCII vers long) convertissent une
chaîne en entiers ou en entiers longs. Pour les utiliser, vous devez recevoir et stocker la chaîne entière
dans un tableau de caractères avant de pouvoir appeler la fonction de conversion.
Le code crée un tableau de caractères nommé strValue qui peut contenir jusqu'à cinq chiffres (il est
déclaré comme char strValue[6] car il doit y avoir de la place pour le null de fin). Il remplit ce tableau
avec des chiffres de Serial.read jusqu'à ce qu'il obtienne le premier caractère qui n'est pas un chiffre
valide. Le tableau se termine par un null et la fonction atoi est appelée pour convertir le tableau de
caractères en la variable blinkRate.
Une fonction appelée blink est appelée et utilise la valeur stockée dans blinkRate. La fonction de
clignotement est illustrée dans la recette 4.3.

Comme mentionné dans l'avertissement de la recette 2.4, vous devez faire attention à ne pas dépasser
la limite du tableau. Si vous ne savez pas comment procéder, lisez la recette 2.13.

Cet exemple construit un tableau de caractères, plutôt que d'utiliser la classe String . Au moment
d'écrire ces lignes, la bibliothèque Arduino String n'avait pas la fonctionnalité de convertir une chaîne
de nombres en une valeur numérique.

Voir également

Consultez l'une des nombreuses pages de référence C/C++ en ligne, telles que http:// www.cplusplus.com/
reference/ clibrary/ cstdlib/ atoi/ ou http:// www.cppreference.com/ wiki/ string/ c/ atoi .

2.9 Conversion d'une chaîne en nombre | 37


Machine Translated by Google

2.10 Structurer votre code en blocs fonctionnels


Problème
Vous voulez savoir comment ajouter des fonctions à une esquisse et la bonne quantité de
fonctionnalités à intégrer dans vos fonctions. Vous voulez également comprendre comment planifier
la structure globale de l'esquisse.

Solution
Les fonctions sont utilisées pour organiser les actions effectuées par votre sketch en blocs
fonctionnels. Les fonctions regroupent les fonctionnalités dans des entrées bien définies
(informations fournies à une fonction) et des sorties (informations fournies par une fonction) qui
facilitent la structuration, la maintenance et la réutilisation de votre code. Vous êtes déjà familiarisé
avec les deux fonctions présentes dans chaque sketch Arduino : setup et loop. Vous créez une
fonction en déclarant son type de retour (les informations qu'elle fournit), son nom et tous les
paramètres facultatifs (valeurs) que la fonction recevra lorsqu'elle sera appelée. Voici une fonction
simple qui fait juste clignoter une LED. Elle n'a pas de paramètres et ne renvoie rien (le vide
précédant la fonction indique que rien ne sera renvoyé)ÿ:
// fait clignoter une LED une
fois void blink1() {

digitalWrite(13,ÉLEVÉ); // allume la LED delay(500); //


attend 500 millisecondes digitalWrite(13,LOW);
éteint la LED delay(500);
// //
attend 500 millisecondes

La version suivante a un paramètre (l'entier nommé count) qui détermine combien de fois la LED
clignoteÿ:
// faire clignoter une LED le nombre de fois indiqué dans le paramètre count
void blink2(int count) { while(count > 0 ) // répéter jusqu'à ce que count ne soit
plus supérieur à zéro { digitalWrite(13,HIGH); retard (500); digitalWrite(13,BAS);
retard (500); compte = compte -1ÿ; // décrémente le nombre } }

Cette version vérifie si la valeur de count est 0. Si ce n'est pas le cas, elle fait clignoter la LED puis
réduit la valeur de count de un. Ceci sera répété jusqu'à ce que le compte ne soit plus supérieur à
0.

38 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Un paramètre est parfois appelé argument dans certaines documentations. Pour


des raisons pratiques, vous pouvez traiter ces termes comme signifiant la même
chose.

Voici un exemple d'esquisse qui prend un paramètre et renvoie une valeur. Le paramètre détermine
les temps d'allumage et d'extinction de la LED (en millisecondes). La fonction continue de faire
clignoter la LED jusqu'à ce qu'un bouton soit enfoncé, et le nombre de fois que la LED a clignoté est renvoyé
de la fonction :
/*
L'esquisse blink3
montre comment appeler une fonction avec un paramètre et renvoyer une valeur utilise le
même câblage que l'esquisse pull-up de la recette 5.2 La LED clignote lorsque le
programme démarre et s'arrête lorsqu'un commutateur connecté à la broche 2 est enfoncé,
le programme imprime le nombre de fois que la LED clignote. */

const int ledPin = 13ÿ; const // broche de sortie pour la LED //


int inputPin = 2ÿ; broche d'entrée pour l'interrupteur

void setup()
{ pinMode(ledPin, OUTPUT);
pinMode(inputPin, INPUT);
digitalWrite(inputPin,HIGH); // utilise une résistance pull-up interne (Recette 5.2)
Série.begin(9600); }

void loop()
{ Serial.println("Appuyez et maintenez le commutateur pour arrêter de
clignoter"); nombre entier = clignotement3(250); // fait clignoter la LED 250 ms
allumée et 250 ms éteinte Serial.print("Le nombre de fois que le commutateur a
clignoté était "); Serial.println(count); }

// fait clignoter une LED en utilisant le délai donné //


renvoie le nombre de fois que la LED a clignoté int
blink3(int period) { int result = 0; int switchVal = HIGHÿ; //
avec les pull-ups, ce sera élevé lorsque le commutateur
est levé

while(switchVal == HIGH) // répète cette boucle jusqu'à ce que l'interrupteur soit pressé //
(il ira bas lorsqu'il sera pressé)

{ digitalWrite(13,ÉLEVÉ);
retard (période);
digitalWrite(13,BAS); retard
(période); résultat = résultat
+ 1ÿ; // incrémente le compte switchVal =
digitalRead(inputPin); // lit la valeur d'entrée }

2.10 Structurer votre code en blocs fonctionnels | 39


Machine Translated by Google

// ici, lorsque switchVal n'est plus HIGH car le commutateur est enfoncé, return
resultÿ; // cette valeur sera retournée }

Discussion
Le code de la solution de cette recette illustre les trois formes d'appel de fonction que vous
rencontrerez. blink1 n'a pas de paramètre ni de valeur de retour. Sa forme est :
annuler le clignotement1()

// le code d'implémentation va ici...


}

blink2 prend un seul paramètre mais ne renvoie pas de valeur :


void blink2(int count) {

// le code d'implémentation va ici...


}

blink3 a un seul paramètre et renvoie une valeur : int


blink3(int period) {

// le code d'implémentation va ici...


}

Le type de données qui précède le nom de la fonction indique le type de retour (ou aucun type
de retour si void). Lors de la déclaration de la fonction (écriture du code qui définit la fonction
et son action), vous ne mettez pas de point-virgule après la parenthèse à la fin. Lorsque vous
utilisez (appelez) la fonction, vous avez besoin d'un point-virgule à la fin.

La plupart des fonctions que vous rencontrerez seront des variations sur ces formulaires. Par
exemple, voici une fonction qui prend un paramètre et renvoie une valeur :
int sensorPercent(int pin) { int
pourcentageÿ;

val = analogRead(broche); // lit le capteur (varie de 0 à 1023) percent =


map(val,0,1023,0,100); // le pourcentage sera compris entre 0 et 100. return
percentÿ; }

Le nom de la fonction est sensorPercent. Il reçoit un numéro de broche analogique à lire et


renvoie la valeur sous forme de pourcentage (voir la recette 5.7 pour plus d'informations sur
analogRead et map). L' int devant la déclaration indique au compilateur (et rappelle au
programmeur) que la fonction renverra un entier. Lors de la création de fonctions, choisissez
le type de retour approprié à l'action effectuée par la fonction. Cette fonction renvoie une valeur
entière de 0 à 100, donc un type de retour int est approprié.

40 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Il est recommandé de donner à vos fonctions des noms significatifs et il est courant
de combiner des mots en mettant en majuscule la première lettre de chaque mot, à
l'exception du premier mot. Utilisez le style que vous préférez, mais cela aide les
autres qui lisent votre code si vous gardez votre style de nommage cohérent.

sensorPercent a un paramètre appelé pin (lorsque la fonction est appelée, pin


reçoit la valeur transmise à la fonction).
Le corps de la fonction (le code entre parenthèses) exécute l'action souhaitée - ici, il lit une valeur à
partir d'une broche d'entrée analogique et la mappe à un pourcentage. Dans l'exemple précédent, le
pourcentage est temporairement contenu dans une variable appelée pourcentage. L'instruction
suivante entraîne le renvoi de la valeur contenue dans la variable temporaire pourcentage à
l'application appelanteÿ:
retour pour centÿ;

La même fonctionnalité peut être obtenue sans utiliser de variable temporaireÿ:


int sensorPercent(int pin) { val
= analogRead(pin); // lit le
capteur (varie de 0 à 1023) return map(val,0,1023,0,100); // le pourcentage
sera compris entre 0 et 100. }

Voici comment la fonction peut être appelée :

// affiche la valeur en pourcentage de 6 broches


analogiques for(int sensorPin = 0; sensorPin < 6; sensorPin+
+) { Serial.print("Pourcentage du capteur sur la broche ");
Serial.print(sensorPin); Serial.print(" est "); int val =
sensorPercent(sensorPin); Serial.print(val); }

Voir également

La page de référence de la fonction Arduino : http:// www.arduino.cc/ en/ Reference/ FunctionDe


claration

2.11 Renvoyer plusieurs valeurs à partir d'une fonction


Problème

Vous souhaitez renvoyer deux valeurs ou plus à partir d'une fonction. La recette 2.10 fournissait des
exemples pour la forme la plus courante d'une fonction, celle qui renvoie une seule valeur ou aucune.
Mais parfois, vous devez modifier ou renvoyer plusieurs valeurs.

2.11 Renvoyer plusieurs valeurs à partir d'une fonction | 41


Machine Translated by Google

Solution
Il existe différentes façons de résoudre ce problème. Le plus simple à comprendre est que la fonction
modifie certaines variables globales et ne renvoie rien de la fonctionÿ:
/*
swap sketch
montre comment changer deux valeurs à l'aide de variables globales
*/

entier xÿ; // x et y sont des variables globales


int yÿ;

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

void loop(){ x
= random(10); // sélectionne des nombres aléatoires
y = random(10);

Serial.print("La valeur de x et y avant l'échange est : "); Serial.print(x);


Serial.print(","); Serial.println(y); échanger();

Serial.print("La valeur de x et y après permutation estÿ: "); Serial.print(x);


Serial.print(","); Serial.println(y);Serial.println();

retard(1000); }

// échange les deux valeurs globales


void swap() { int temp; temp = xÿ; x
= yÿ; y = tempÿ; }

La fonction swap modifie deux valeurs en utilisant des variables globales. Les variables globales sont
faciles à comprendre (les variables globales sont des valeurs accessibles partout et tout peut les changer),
mais elles sont évitées par les programmeurs expérimentés car il est facile de modifier par inadvertance
la valeur d'une variable ou de faire cesser de fonctionner une fonction parce que vous changé le nom ou
le type d'une variable globale ailleurs dans l'esquisse.

Une solution plus sûre et plus élégante consiste à passer des références aux valeurs que vous souhaitez
modifier et à laisser la fonction utiliser les références pour modifier les valeurs. Cela se fait comme suit:
/*
L'esquisse functionReferences
montre comment renvoyer plusieurs valeurs en passant des références */

42 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

void swap(int &value1, int &value2); // les fonctions avec des références doivent être
déclaré avant utilisation

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

void loop(){ int


x = random(10); // sélectionne des nombres aléatoires int
y = random(10);

Serial.print("La valeur de x et y avant l'échange est : "); Serial.print(x);


Serial.print(","); Serial.println(y); échange(x,y);

Serial.print("La valeur de x et y après permutation estÿ: "); Serial.print(x);


Serial.print(","); Serial.println(y);Serial.println();

retard(1000); }

// échange les deux valeurs


données void swap(int &value1, int &value2)
{ int temp; temp = valeur1ÿ; valeur1 =
valeur2ÿ; valeur2 = tempÿ; }

Discussion
La fonction d' échange est similaire aux fonctions avec paramètres décrites dans la recette 2.10, mais le
symbole esperluette (&) indique que les paramètres sont des références.
Cela signifie que les changements de valeurs dans la fonction modifieront également la valeur de la variable
qui est donnée lorsque la fonction est appelée. Vous pouvez voir comment cela fonctionne en exécutant
d'abord le code dans la solution de cette recette et en vérifiant que les paramètres sont permutés. Modifiez
ensuite le code en supprimant les quatre esperluettes (les deux dans la déclaration en haut et les deux dans
la définition en bas).

Les deux lignes modifiées devraient ressembler à ceciÿ:

void swap(int value1, int value2); // les fonctions avec des références doivent être déclarées avant
utilisation
...

void swap(int value1, int value2)

L'exécution du code montre que les valeurs ne sont pas permutées - les modifications apportées à la
fonction sont locales à la fonction et sont perdues lorsque la fonction revient.

2.11 Renvoyer plusieurs valeurs à partir d'une fonction | 43


Machine Translated by Google

Une déclaration de fonction est un prototype - une spécification du nom, des types de valeurs qui peuvent
être transmises à la fonction et du type de retour de la fonction. Le processus de construction Arduino
crée généralement les déclarations pour vous sous les couvertures. Mais lorsque vous utilisez une
syntaxe non standard (pour Arduino), le processus de construction ne créera pas la déclaration et vous
devrez l'ajouter vous-même à votre code, comme cela a été fait ici avec la ligne juste avant la configuration.

Une définition de fonction est l'en-tête de la fonction et le corps de la fonction. L'en-tête de la fonction est
similaire à la déclaration sauf qu'il n'a pas de point-virgule à la fin. Le corps de la fonction est le code
entre crochets qui est exécuté pour effectuer une action lorsque la fonction est appelée.

2.12 Prendre des mesures en fonction des conditions

Problème

Vous souhaitez exécuter un bloc de code uniquement si une condition particulière est vraie. Par exemple, vous
souhaiterez peut-être allumer une LED si un interrupteur est enfoncé ou si une valeur analogique est supérieure à
un certain seuil.

Solution

Le code suivant utilise le câblage indiqué dans la recette 5.1ÿ:


/*
Esquisse d'un bouton
poussoir un interrupteur relié à la broche 2 allume la LED sur la broche
13 */

const int ledPin = 13ÿ; const // choisir la broche pour la LED // choisir
int inputPin = 2ÿ; la broche d'entrée (pour un bouton poussoir)

void setup()
{ pinMode(ledPin, OUTPUT); // déclarer la broche LED comme sortie //
pinMode(inputPin, INPUT); } déclarer la broche du bouton poussoir comme entrée

void loop(){ int


val = digitalRead(inputPin); // lit la valeur d'entrée if (val == HIGH) // vérifie
si l'entrée est HIGH { digitalWrite (ledPin, HIGH); } }

// allume la LED si l'interrupteur est enfoncé

Discussion

L' instruction if est utilisée pour tester la valeur de digitalRead. Une instruction if doit avoir un test entre
parenthèses qui ne peut être que vrai ou faux. Dans l'exemple de cette recette

44 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Solution, c'est val == HIGH, et le bloc de code suivant l' instruction if n'est exécuté que si l'expression
est vraie. Un bloc de code se compose de tout le code entre crochets (ou si vous n'utilisez pas de
crochets, le bloc est juste la prochaine instruction exécutable terminée par un point-virgule).

Si vous voulez faire une chose si une instruction est vraie et une autre si elle est fausse, utilisez l'
instruction if...else :

/*
Esquisse d'un bouton
poussoir un interrupteur relié à la broche 2 allume la LED sur la broche
13 */

const int ledPin = 13ÿ; const // choisir la broche pour la LED // choisir
int inputPin = 2ÿ; la broche d'entrée (pour un bouton poussoir)

void setup()
{ pinMode(ledPin, OUTPUT); // déclarer la broche LED comme sortie //
pinMode(inputPin, INPUT); } déclarer la broche du bouton poussoir comme entrée

void loop(){ int


val = digitalRead(inputPin); // lire la valeur d'entrée if (val == HIGH) //
vérifier si l'entrée est HIGH { // faire ceci si val est HIGH} digitalWrite(ledPin,
HIGH); else { // sinon faire ceci si val
n'est pas HIGH digitalWrite(ledPin, LOW); } }

// allume la LED si l'interrupteur est enfoncé

// éteint la LED

Voir également

Voir la discussion sur les types booléens dans la recette 2.2.

2.13 Répétition d'une séquence d'instructions

Problème
Vous souhaitez répéter un bloc d'instructions alors qu'une expression est vraie.

2.13 Répétition d'une séquence d'instructions | 45


Machine Translated by Google

Solution
Une boucle while répète une ou plusieurs instructions tant qu'une expression est vraieÿ:
while(analogRead(sensorPin) > 100) {

flashLED(); // appelle une fonction pour allumer et éteindre une LED


}

Ce code exécutera les instructions dans le bloc entre crochets, {}, tandis que la valeur de analogRead est
supérieure à 100. Cela pourrait être utilisé pour faire clignoter une LED comme un avertissement visible
qu'une valeur a dépassé un seuil. La LED est éteinte lorsque la valeur du capteur est de 100 ou moinsÿ; il
clignote en permanence lorsque la valeur est supérieure à 100.

Les symboles {} qui définissent un bloc de code reçoivent divers noms, notamment des crochets, des
accolades et des accolades. Ce livre se réfère à eux comme des parenthèses.

Discussion
Les parenthèses définissent l'étendue du bloc de code à exécuter dans une boucle. Si les parenthèses ne
sont pas utilisées, seule la première ligne de code sera répétée dans la boucleÿ:

while(analogRead(sensorPin) > 100)


flashLED(); // la ligne suivant immédiatement l'expression de la boucle est exécutée
Serial.print(analogRead(sensorPin)); // ceci n'est exécuté qu'après // la boucle while se termine !!!

Les boucles sans crochets peuvent se comporter de manière inattendue si vous avez plusieurs lignes de
code.

La boucle do... while est similaire à la boucle while , mais les instructions du bloc de code sont exécutées
avant que la condition ne soit vérifiée. Utilisez ce formulaire lorsque vous devez faire exécuter le code au
moins une fois, même si l'expression est fausseÿ:
fais

flashLED(); // appelle une fonction pour allumer et éteindre une LED

} tandis que (analogRead(sensorPin) > 100);

Le code précédent fera clignoter la LED au moins une fois et continuera à clignoter tant que la valeur lue
d'un capteur est supérieure à 100. Si la valeur n'est pas supérieure à 100, la LED ne clignotera qu'une
seule fois. Ce code pourrait être utilisé dans un circuit de charge de batterie, s'il était appelé une fois toutes
les 10 secondes environ : un seul clignotement indique que le circuit est actif, tandis qu'un clignotement
continu indique que la batterie est chargée.

46 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Voir également

Chapitres 4 et 5

2.14 Répéter des instructions avec un compteur


Problème

Vous souhaitez répéter une ou plusieurs affirmations un certain nombre de fois. La boucle for est
similaire à la boucle while , mais vous avez plus de contrôle sur les conditions de début et de fin.

Solution

Cette esquisse compte de zéro à quatre en imprimant la valeur de la variable i dans une boucle for :
/*
L'esquisse
ForLoop illustre la boucle
for */

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

void loop()
{ Serial.println("for(int i=0; i < 4; i++)"); for(int i=0; i < 4; i+
+) { Serial.println(i); } }

La sortie de ceci est la suivante :


for(int i=0; i < 4; i++)
0
1
2

Discussion

Une boucle for se compose de trois parties : initialisation, test conditionnel et itération (une
instruction qui est exécutée à la fin de chaque passage dans la boucle). Chaque partie est séparée
par un point-virgule. Dans le code de la solution de cette recette, int i=0ÿ; initialise la variable i à 0ÿ;
je < 4ÿ; teste la variable pour voir si elle est inférieure à 4ÿ; et i++ incrémente i.

2.14 Répéter des instructions avec un compteur | 47


Machine Translated by Google

Une boucle for peut utiliser une variable existante ou créer une variable à usage exclusif dans la boucle.
Cette version utilise la valeur de la variable j créée précédemment dans le sketch :

entier jÿ;

Serial.println("for(j=0; j < 4; j++ )"); for(j=0; j < 4; j+


+ ) { Serial.println(j); }

C'est presque la même chose que l'exemple précédent, mais il n'a pas le mot-clé int dans la partie
d'initialisation car la variable j a déjà été définie. La sortie de cette version est similaire à la sortie de la
version précédente : for(j=0; i < 4; i++)

0
1
2

Vous pouvez omettre complètement la partie d'initialisation si vous souhaitez que la boucle utilise la
valeur d'une variable définie précédemment. Ce code démarre la boucle avec j égal à 1ÿ:

entier j = 1ÿ;

Serial.println("for( ; j < 4; j++ )"); for( ; j < 4; j++ )


{ Serial.println(j); }

Le code précédent imprime ce qui suitÿ:

pour( ; j < 4; j++)


1
2

Vous contrôlez le moment où la boucle s'arrête dans le test conditionnel. Les exemples précédents
testent si la variable de boucle est inférieure à 4 et se terminent lorsque la condition n'est plus vraie.

Si votre variable de boucle commence à 0 et que vous voulez qu'elle se répète quatre fois, votre
instruction conditionnelle doit tester une valeur inférieure à 4. La boucle se répète tant que la condition
est vraie et qu'il y a quatre valeurs inférieures à 4 avec une boucle commençant à 0.

Le code suivant teste si la valeur de la variable de boucle est inférieure ou égale à 4. Il imprimera les
chiffres de 0 à 4ÿ:

Serial.println("for(int i=0; i <= 4; i++)"); for(int je=0; je <=


4; je++) {

48 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Serial.println(i); }

La troisième partie d'une boucle for est l'instruction iterator qui est exécutée à la fin de chaque passage
dans la boucle. Il peut s'agir de n'importe quelle instruction C/C++ valide. Ce qui suit augmente la
valeur de i de deux à chaque passeÿ:
Serial.println("for(int i=0; i < 4; i+= 2)"); for(int
i=0; i < 4; i+=2) { Serial.println(i); }

Cette expression imprime uniquement les valeurs 0 et 2.

L' expression d' itérateur peut être utilisée pour que la boucle compte de haut en bas, dans ce cas de
3 à 0ÿ:

Serial.println("for(int i=3; i > = 0 ; i--)"); for(int i=3;


i > = 0; i--) { Serial.println(i); }

Comme les autres parties d'une boucle for , l'expression de l'itérateur peut être laissée vide (vous
devez toujours avoir les deux points-virgules séparant les trois parties même si elles sont vides).

Cette version n'incrémente i que lorsqu'une broche d'entrée est haute. La boucle for ne change pas la
valeur de i ; il n'est modifié que par l' instruction if après Serial.print :
Serial.println("for(int i=0; i < 4; )"); for(int
i=0; i < 4; ) { Serial.println(i);
if(digitalRead(inPin) == HIGH); je++ÿ; //
n'incrémente la valeur que si l'entrée est
haute

Voir également

Référence Arduino pour l' instruction for : http:// www.arduino.cc/ en/ Reference/ For

2.15 Sortir des boucles


Problème

Vous souhaitez terminer une boucle plus tôt en fonction d'une condition que vous testez.

Solution

Utilisez le code suivantÿ:


while(analogRead(sensorPin) > 100) {

2.15 Sortir des boucles | 49


Machine Translated by Google

if(digitalRead(switchPin) == HIGH) {

Pause; //quitter la boucle si le commutateur est enfoncé

} flashLED(); // appelle une fonction pour allumer et éteindre une LED


}

Discussion
Ce code est similaire à celui qui utilise les boucles while , mais il utilise l' instruction break pour quitter la
boucle si une broche numérique passe au niveau haut. Par exemple, si un interrupteur est connecté sur
la broche comme indiqué dans la recette 5.1, la boucle sera quittée et la LED cessera de clignoter même
si la condition dans la boucle while est vraie.

Voir également

Référence Arduino pour l' instruction break : http:// www.arduino.cc/ en/ Reference/ Break

2.16 Prendre une variété d'actions basées sur une seule variable

Problème
Vous devez faire différentes choses en fonction d'une certaine valeur. Vous pouvez utiliser plusieurs
instructions if et else if , mais le code devient rapidement complexe et difficile à comprendre ou à modifier.
En outre, vous souhaiterez peut-être tester une plage de valeurs.

Solution
L' instruction switch permet de sélectionner un certain nombre d'alternatives. Il est fonctionnellement
similaire à plusieurs instructions if/else if mais est plus concisÿ:
/*
* Esquisse SwitchCase
* exemple montrant l'instruction switch en activant les caractères du port série
*
* l'envoi du caractère 1 fait clignoter la LED une fois, l'envoi de 2 clignote deux
fois * l'envoi + allume la LED, l'envoi - l'éteint
*
tout autre caractère imprime un message sur le moniteur série */
const int ledPin = 13; // la broche à laquelle la LED est connectée

void setup()

{ Serial.begin(9600); // Initialise le port série pour envoyer et recevoir à 9600 bauds


pinMode(13, OUTPUT); }

void loop()
{ if
( Serial.available()) // Vérifie si au moins un caractère est disponible {

50 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

char ch = Serial.read();
switch(ch) { case '1': blink();
Pause; case '2'ÿ:
clignotement(); clignoter();
Pause; cas '+' :

digitalWrite(ledPin,HIGH);
Pause; Cas '-':

digitalWrite(ledPin,BAS);
Pause; par défaut :
Serial.print(ch); Serial.println("
a été reçu mais pas attendu");
Pause; } } }

void
clignement()
{ digitalWrite(ledPin,HIGH);
retard (500);
digitalWrite(ledPin,BAS); retard
(500); }

Discussion
L' instruction switch évalue la variable ch reçue du port série et se branche sur l'étiquette qui
correspond à sa valeur. Les étiquettes doivent être des constantes numériques (vous pouvez
utiliser des chaînes dans une instruction case ) et deux étiquettes ne peuvent pas avoir la même
valeur. Si vous n'avez pas d' instruction break à la suite de chaque expression, l'exécution tombera
dans l'instructionÿ:
case '1'ÿ:
clignotement(); // pas d'instruction break avant le prochain label
case '2': blink(); // le cas '1' continuera ici blink(); Pause;

// l'instruction break quittera l'expression switch

Si l' instruction break à la fin du cas '1': a été supprimée (comme indiqué dans le code précédent),
lorsque ch est égal au caractère 1 , la fonction de clignotement sera appelée trois fois.
Oublier accidentellement la pause est une erreur courante. Omettre intentionnellement la pause
est parfois pratique ; cela peut être déroutant pour les autres qui lisent votre code, c'est donc une
bonne pratique d'indiquer clairement vos intentions avec des commentaires dans le code.

2.16 Prendre une variété d'actions basées sur une seule variable | 51
Machine Translated by Google

Si votre instruction switch se comporte mal, vérifiez que vous avez


pas oublié les instructions de rupture .

L' étiquette par défautÿ: est utilisée pour intercepter les valeurs qui ne correspondent à aucune des étiquettes de cas . Si
il n'y a pas d' étiquette par défaut , l'expression switch ne fera rien s'il n'y a pas de correspondance.

Voir également

Référence Arduino pour les instructions switch et case : http:// www.arduino.cc/ en/ Refer
ence/ SwitchCase

2.17 Comparer les caractères et les valeurs numériques

Problème

Vous voulez déterminer la relation entre les valeurs.

Solution

Comparez les valeurs entières à l'aide des opérateurs relationnels présentés dans le tableau 2-2.

Tableau 2-2. Opérateurs relationnels et d'égalité

Test opérateur pour Exemple

== Égal à 2 == 3 // évalue à faux


!= Pas égal à 2ÿ!= 3 // est évalué à vrai
Plus grand que
> 2 > 3 // évalue à faux
Moins que
< 2 < 3 // est évalué à vrai
>= Plus grand ou égal à 2 >= 3 // est évalué à faux
<= Inférieur ou égal à 2 <= 3 // est évalué à vrai

L'esquisse suivante illustre les résultats de l'utilisation des opérateurs de comparaisonÿ:


/*
* Esquisse d'expressions relationnelles
* démontre la comparaison des valeurs
*/

int je = 1ÿ; // quelques valeurs pour commencer


entier j = 2ÿ;

void setup() {
Série.begin(9600);
}

52 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

void loop()
{ Serial.print("i = ");
Serial.print(i);
Serial.print(" et j = ");
Serial.println(j);

si(je < j)
Serial.println(" i est inférieur à j"); si(je
<= j)
Serial.println(" i est inférieur ou égal à j"); si(je != j)

Serial.println(" i n'est pas égal à j"); si(je


== j)
Serial.println(" i est égal à j"); si(je >=
j)
Serial.println(" i est supérieur ou égal à j"); si(je > j)

Serial.println(" i est supérieur à j");

Serial.println(); je
= je + 1ÿ; si(i > j +
1) retard(10000); //
long délai après que i n'est plus proche de j
}

Voici la sortieÿ:
i = 1 et j = 2 i
est inférieur à ji
est inférieur ou égal à ji n'est
pas égal à j

i = 2 et j = 2 i
est inférieur ou égal à ji est
égal à ji est supérieur ou égal
àj

i = 3 et j = 2 i
n'est pas égal à ji
est supérieur ou égal à ji est
supérieur à j

Discussion
Notez que l'opérateur d'égalité est le double signe égal, ==. L'une des erreurs de
programmation les plus courantes consiste à confondre cela avec l'opérateur d'affectation,
qui utilise un seul signe égal.
L'expression suivante comparera la valeur de i à 3. Le programmeur voulait
ce:
if(i == 3) // teste si i vaut 3

Mais il a mis ceci dans le croquis :


if(i = 3) // signe égal unique utilisé par erreur !!!!

2.17 Comparaison des valeurs alphanumériques et numériques | 53


Machine Translated by Google

Cela renverra toujours vrai, car i sera défini sur 3, ils seront donc égaux lorsqu'ils seront comparés.

Une astuce pour éviter ce piège lors de la comparaison de variables à des constantes (valeurs fixes)
consiste à placer la constante à gauche de l'expressionÿ:
if(3 = i) // signe égal unique utilisé par erreur !!!!

Le compilateur vous informera de cette erreur car il sait que vous ne pouvez pas affecter une valeur
différente à une constante.

Le message d'erreur est la "valeur requise comme opérande gauche d'affectation" quelque peu hostile.
Si vous voyez ce message, le compilateur vous indique que vous essayez d'attribuer une valeur à
quelque chose qui ne peut pas être modifié.

Voir également

Référence Arduino pour les opérateurs conditionnels et de comparaison : http:// www.arduino.cc/ en/
Reference/ If

2.18 Comparer des chaînes

Problème
Vous voulez voir si deux chaînes de caractères sont identiques.

Solution
Il existe une fonction pour comparer les chaînes, appelée strcmp (abréviation de comparaison de
chaînes). Voici un fragment montrant son utilisation : char String1[ ] = "left"; char String2[ ] = "droite"ÿ;

if(strcmp(String1, String2) == 0)
Serial.print("les chaînes sont égales)

Discussion
strcmp renvoie la valeur 0 si les chaînes sont égales et une valeur supérieure à zéro si le premier
caractère qui ne correspond pas a une valeur supérieure dans la première chaîne que dans la seconde.
Elle renvoie une valeur inférieure à zéro si le premier caractère non correspondant de la première chaîne
est inférieur à celui de la seconde. Habituellement, vous voulez seulement savoir s'ils sont égaux, et bien
que le test de zéro puisse sembler peu intuitif au début, vous vous y habituerez rapidement.

54 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Gardez à l'esprit que les chaînes de longueur inégale ne seront pas évaluées comme égales même si la chaîne la
plus courte est contenue dans la plus longue. Alors:

strcmp("left", "leftcenter") == 0) // ceci sera évalué à false


Vous pouvez comparer des chaînes jusqu'à un nombre donné de caractères en utilisant la fonction strncmp . Vous
donnez à strncmp le nombre maximum de caractères à comparer et il s'arrêtera de comparer après ce nombre de
caractèresÿ:

strncmp("left", "leftcenter", 4) == 0) // ceci sera évalué à true

Voir également

Plus d'informations sur strcmp sont disponibles sur http:// www.cplusplus.com/ reference/ clibrary/ cstring/ strcmp/.

2.19 Effectuer des comparaisons logiques

Problème
Vous souhaitez évaluer la relation logique entre deux ou plusieurs expressions. Par
exemple, vous souhaitez effectuer une action différente en fonction des conditions d'un if
déclaration.

Solution
Utilisez les opérateurs logiques comme indiqué dans le Tableau 2-3.

Tableau 2-3. Opérateurs logiques

Symbole Fonction commentaires

&& Et logique Est évalué comme vrai si les conditions des deux côtés de l' opérateur && sont vraies

|| Ou logique Est évalué comme vrai si la condition sur au moins un côté du || l'opérateur est vrai

! Pas Est évalué comme vrai si l'expression est fausse, et faux si l'expression est vraie

Discussion
Les opérateurs logiques renvoient des valeurs vraies ou fausses en fonction de la relation logique.

L'opérateur logique Et && renverra vrai si ses deux opérandes sont vrais, et faux sinon. L'opérateur logique Ou ||
renverra vrai si l'un de ses deux opérandes est vrai, et faux si les deux opérandes sont faux. L'opérateur Not ! n'a
qu'un seul opérande, dont la valeur est inversée - il en résulte faux si son opérande est vrai et vrai si son opérande
est faux.

2.19 Effectuer des comparaisons logiques | 55


Machine Translated by Google

2.20 Exécution d'opérations au niveau du bit

Problème
Vous souhaitez définir ou effacer certains bits dans une valeur.

Solution
Utilisez les opérateurs de bits comme indiqué dans le Tableau 2-4.

Tableau 2-4. Opérateurs de bits

Symbole Fonction Commenter Exemple

Et au niveau du bit Définit les bits de chaque emplacement sur 1 si les deux bits sont 1ÿ; Par ailleurs,
& 3 & 1 égale 1
les bits sont mis à 0.

(11 & 01 égale 01)


Ou au niveau du bit
Définit les bits de chaque emplacement sur 1 si l'un ou l'autre bit est 1.
| 3 | 1 est égal à 3

(11 | 01 égale 11)


^ Bit à bit exclusif Définit les bits à chaque emplacement sur 1 uniquement si l'un des deux bits ^
3 1 est égal à 2
Ou est 1.

(11 ^ 01 est égal à 10)


~ Négation au niveau du bit Inverse la valeur de chaque bit. Le résultat dépend de la
~1 est égal à 254
nombre de bits dans le type de données.

(~00000001 équivaut à 11111110)

Voici un croquis qui illustre les exemples de valeurs indiqués dans le tableau 2-4ÿ:

/*
* esquisse de morceaux

* illustre les opérateurs au niveau du bit


*/

void setup() {
Série.begin(9600);
}

boucle vide(){
Serial.print("3 & 1 est égal à "); // au niveau du bit Et 3 et 1
Serial.print(3 & 1); // imprime le résultat
Serial.print(" décimal, ou en binaire : ");
Serial.println(3 & 1 , BIN); // affiche la représentation binaire du résultat

Serial.print("3 | 1 est égal à "); // au niveau du bit Ou 3 et 1


Serial.print(3 | 1 );
Serial.print(" décimal, ou en binaire : ");
Série.println(3 | 1 , BIN); // affiche la représentation binaire du résultat

Serial.print("3 ^ 1 est égal à "); // exclusif au niveau du bit ou 3 et 1


Serial.print(3 ^ 1);

56 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Serial.print(" décimal, ou en binaire : ");


Serial.println(3 ^ , BIN); //1affiche la représentation binaire du résultat

octet octetVal = 1ÿ;


int intVal = 1ÿ;

byteVal = ~byteVal; // effectue la négation au niveau du bit


intVal = ~ intVal;

Serial.print("~byteVal (1) est égal à "); // inverse au niveau du bit une valeur de 8 bits
Serial.println(byteVal, BIN); // affiche la représentation binaire du résultat
Serial.print("~intVal (1) est égal à "); // inverse au niveau du bit une valeur de 16 bits
Serial.println(intVal, BIN); // affiche la représentation binaire du résultat

retard (10000);
}

Voici ce qui s'affiche sur le moniteur sérieÿ:

3 & 1 égale 1 décimal, ou en binaire : 1


3 | 1 égale 3 décimal, ou en binaire : 11
^
3 1 égale 2 décimal, ou en binaire : 10
~byteVal (1) est égal à 11111110
~intVal (1) est égal à 111111111111111111111111111110

Discussion
Les opérateurs au niveau du bit sont utilisés pour définir ou tester des bits. Lorsque vous "Et" ou "Ou" deux valeurs, le
l'opérateur travaille sur chaque bit individuel. Il est plus facile de voir comment cela fonctionne en regardant
la représentation binaire des valeurs.

La décimale 3 est le binaire 00000011 et la décimale 1 est 00000001. Bitwise And fonctionne sur
chaque bit. Les bits les plus à droite sont tous les deux 1, donc le résultat de And-ing est 1.
à gauche, les bits suivants sont 1 et 0ÿ; Et-ing ces résultats en 0. Tous les bits restants sont
0, donc le résultat au niveau du bit de ceux-ci sera 0. En d'autres termes, pour chaque position de bit où
il y a un 1 aux deux endroits, le résultat aura un 1ÿ; sinon, il aura un 0. Donc, 11 &
01 est égal à 1.

Les tableaux 2-5, 2-6 et 2-7 devraient aider à clarifier les bits Et, Ou et Ou Exclusif
valeurs.

Tableau 2-5. Et au niveau du bit

Bit 1 Bit 2 Bit 1 et Bit 2

0 0 0

0 1 0

1 0 0

1 1 1

2.20 Exécution d'opérations au niveau du bit | 57


Machine Translated by Google

Tableau 2-6. Ou au niveau du bit

Bit 1 Bit 2 Bit 1 ou Bit 2

0 0 0

0 1 1

1 0 1

1 1 1

Tableau 2-7. Ou exclusif au niveau du bit

Bit 1 Bit 2 Bit 1 ^ Bit 2

0 0 0

0 1 1

1 0 1

1 1 0

Toutes les expressions au niveau du bit opèrent sur deux valeurs, à l'exception de l'opérateur de négation.
Cela retourne simplement chaque bit, donc 0 devient 1 et 1 devient 0. Dans l'exemple, l' octet
(8 bits) la valeur 00000001 devient 11111110. La valeur int a 16 bits, donc quand chacun est
retourné, le résultat est 15 uns suivis d'un seul zéro.

Voir également

Référence Arduino pour les opérateurs And, Or et Exclusive Or : http:// www


.arduino.cc/ en/ Reference/ Bitwise

2.21 Combinaison d'opérations et d'affectation


Problème

Vous voulez comprendre et utiliser les opérateurs composés. Il n'est pas rare de voir
code publié qui utilise des expressions qui font plus d'une chose dans une seule instruction.
Vous voulez comprendre a += b, a >>= b et a &= b.

Solution

Le tableau 2-8 montre les opérateurs d'affectation composés et leur expression complète équivalente.

58 | Chapitre 2 : Faire en sorte que le croquis fasse votre affaire


Machine Translated by Google

Tableau 2-8. Opérateurs composés

Exemple d'opérateur Expression équivalente

+= Valeur += 5ÿ; Valeur = Valeur + 5ÿ; // ajoute 5 à la valeur


-= Valeur -= 4ÿ; Valeur = Valeur - 4ÿ; // soustraire 4 de la valeur
*= Valeur *= 3ÿ; Valeur = Valeur * 3ÿ; // multiplie la valeur par 3

/= Valeur /= 2ÿ; Valeur = Valeur / 2ÿ; // divise la valeur par 2


>>= Valeur >>= 2ÿ; Valeur = Valeur >> 2ÿ; // décale la valeur de deux positions vers la droite
<<= Valeur <<= 2ÿ; Valeur = Valeur << 2ÿ; // décale la valeur vers la gauche de deux positions

&= Masque &= 2; Masque = Masque & 2; // binaire et masque avec 2

|= Masque |= 2ÿ; Masque = Masque | 2ÿ; // binaire ou masque avec 2

Discussion
Ces instructions composées ne sont pas plus efficaces à l'exécution que l'équivalent complet
expression, et si vous débutez en programmation, l'utilisation de l'expression complète est plus claire.
Les codeurs expérimentés utilisent souvent la forme la plus courte, il est donc utile de pouvoir reconnaître
les expressions lorsque vous les rencontrez.

Voir également

Voir http:// www.arduino.cc/ en/ Reference/ HomePage pour un index des pages de référence
pour les opérateurs composés.

2.21 Combinaison d'opérations et d'affectation | 59


Machine Translated by Google
Machine Translated by Google

CHAPITRE 3

Utilisation d'opérateurs mathématiques

3.0 Présentation
Presque chaque croquis utilise des opérateurs mathématiques pour manipuler la valeur des variables.
Ce chapitre donne un bref aperçu des opérateurs mathématiques les plus courants.
Comme le chapitre précédent l'est, ce résumé s'adresse principalement aux non-programmeurs ou
aux programmeurs qui ne sont pas familiarisés avec C ou C++. Pour plus de détails, voir l'un des
ouvrages de référence C mentionnés dans la préface.

3.1 Additionner, soustraire, multiplier et diviser


Problème
Vous souhaitez effectuer des calculs simples sur les valeurs de votre croquis. Vous souhaitez contrôler
l'ordre dans lequel les opérations sont effectuées et vous devrez peut-être gérer différents types de
variables.

Solution
Utilisez le code suivantÿ:

int
maValeurÿ; maValeur = 1 +
2ÿ; // addition maValeur = 3 -
* 2; // soustraction
2ÿ; // multiplication maValeur = 3
maValeur = 3 / 2; // division (le résultat est 1)
Discussion
L'addition, la soustraction et la multiplication des nombres entiers fonctionnent comme prévu.

61
Machine Translated by Google

Assurez-vous que votre résultat ne dépassera pas la taille maximale de la variable de destination. Voir
la recette 2.2.

La division entière tronque le reste fractionnaire dans l'exemple de division montré dans la solution de
cette recetteÿ; myValue sera égal à 1 après la division (voir recette 2.3 si votre application nécessite
des résultats fractionnaires) :
valeur entière = 1+2* 3 + 4ÿ;

Les instructions composées, telles que l'instruction précédente, peuvent sembler ambiguës, mais la
priorité (ordre) de chaque opérateur est bien définie. La multiplication et la division ont une priorité plus
élevée que l'addition et la soustraction, donc le résultat sera 11. Il est conseillé d'utiliser des parenthèses
dans votre code pour clarifier la priorité de calcul souhaitée. valeur entière = 1 + (2 * 3) + 4ÿ; produit le
même résultat mais est plus facile à lire.

Utilisez des parenthèses si vous devez modifier la priorité, comme dans cet exempleÿ:
valeur entière = ((1 + 2) * 3) + 4ÿ;

Le résultat sera 13. L'expression entre parenthèses intérieures est calculée en premier, donc 1 est
ajouté à 2, puis multiplié par 3 et finalement ajouté à 4, ce qui donne 13.

Voir également

Recette 2.2ÿ; Recette 2.3

3.2 Incrémentation et décrémentation des valeurs

Problème
Vous voulez augmenter ou diminuer la valeur d'une variable.

Solution

Utilisez le code suivantÿ:

int maValeur = 0;

maValeur = mavaleur + 1; // cela ajoute un à la variable myValue // cela fait la


même chose que myValue ci-dessus += 1;

maValeur = mavaleur - 1; // ceci soustrait un de la variable myValue myValue -= 1;


// cela fait la même chose que ci-dessus

maValeur = mavaleur + 5; // cela ajoute cinq à la variable myValue myValue += 5; //


cela fait la même chose que ci-dessus

62 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

Discussion
Augmenter et diminuer les valeurs des variables est l'une des tâches de programmation les plus courantes, et la
carte Arduino dispose d'opérateurs pour faciliter cette tâche. Augmenter une valeur de un s'appelle incrémenter, et la
diminuer de un s'appelle décrémenter. La manière longue de le faire est la suivante:

maValeur = mavaleur + 1; // cela ajoute un à la variable myValue

Mais vous pouvez également combiner les opérateurs d'incrémentation et de décrémentation avec l'opérateur
d'affectation, comme ceciÿ:

maValeur += 1; // cela fait la même chose que ci-dessus

Voir également

Recette 3.1

3.3 Trouver le reste après avoir divisé deux valeurs


Problème
Vous voulez trouver le reste après avoir divisé deux valeurs.

Solution
Utilisez le symboleÿ% (l'opérateur de module) pour obtenir le resteÿ:

int maValeur0 = 20 % 10; // récupère le module (reste) de 20 divisé par 10 int myValue1
= 21 % 10; // obtient le module (reste) de 21 divisé par 10

myValue0 est égal à 0 (20 divisé par 10 a un reste de 0). myValue1 est égal à 1 (21
divisé par 10 a un reste de 1).

Discussion
L'opérateur de module est étonnamment utile, en particulier lorsque vous voulez voir si une valeur est divisible par
un nombre. Par exemple, le code de la solution de cette recette peut être amélioré pour détecter lorsqu'une valeur
est un multiple de 10ÿ:

int
maValeurÿ; //... code ici pour définir la valeur de
myValue if( myValue % 10 == 0) { Serial.println("La
valeur est un multiple de 10"; }

Le code précédent prend le module de la variable myValue et compare le résultat à zéro (voir recette 2.17). Si c'est
zéro, un message est imprimé indiquant que le résultat est divisible par 10.

3.3 Trouver le reste après avoir divisé deux valeurs | 63


Machine Translated by Google

Voici un exemple similaire, mais en utilisant 2 avec l'opérateur de module, le résultat peut être utilisé
pour vérifier si une valeur est paire ou impaireÿ:

int
maValeurÿ; //... code ici pour définir la valeur
de myValue if( myValue % 2 == 0)
{ Serial.println("La valeur est paire"; } else
{ Serial.println("La valeur est impaire"; }

Cet exemple suit le jour de la semaine à partir d'une variable qui est incrémentée (par un autre code)
chaque jour et indique quand c'est le premier jour de la semaineÿ:
int nombre de joursÿ;

int jour = nombrejours %


7ÿ; if( day == 0)
{ Serial.println("C'est le
premier jour de la semaine"); }

Voir également

Référence Arduino pour % (l'opérateur de module) : http:// www.arduino.cc/ en/ Reference/ Modulo

3.4 Détermination de la valeur absolue


Problème
Vous voulez obtenir la valeur absolue d'un nombre.

Solution
abs(x) calcule la valeur absolue de x. L'exemple suivant prend la valeur absolue de la différence entre
les lectures sur deux ports d'entrée analogiques (voir le chapitre 5 pour plus d'informations sur
analogRead())ÿ:
int x = analogRead(0);
int y = analogRead(1);

if(abs(xy) > 10)


{ Serial.println("Les
valeurs analogiques diffèrent de plus de 10"); }

64 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

Discussion
abs(xy); renvoie la valeur absolue de la différence entre x et y. Il est utilisé pour les valeurs entières (et entières longues ).
Pour retourner la valeur absolue des valeurs à virgule flottante, voir la recette 2.3.

Voir également

Référence Arduino pour abs : http:// www.arduino.cc/ en/ Reference/ Abs

3.5 Contraindre un nombre à une plage de valeurs

Problème
Vous voulez vous assurer qu'une valeur se situe toujours dans une certaine limite inférieure et supérieure.

Solution
constrain(x, min, max) renvoie une valeur comprise entre min et max :
myConstrainedValue = constrain(myValue, 100, 200);

Discussion
myConstrainedValue est défini sur une valeur qui sera toujours supérieure ou égale à 100
et inférieure ou égale à 200. Si myValue est inférieur à 100, le résultat sera 100 ; s'il est
supérieur à 200, il sera défini sur 200.
Le tableau 3-1 montre quelques exemples de valeurs de sortie utilisant un minimum de 100 et un maximum de 200.

Tableau 3-1. Sortie de contrainte avec min = 100 et max = 200

myValue (la valeur d'entrée) contraindre(maValeur, 100, 200)

99 100

100 100

150 150

200 200

201 200

Voir également

Recette 3.6

3.5 Contraindre un nombre à une plage de valeurs | 65


Machine Translated by Google

3.6 Trouver le minimum ou le maximum de certaines valeurs

Problème
Vous voulez trouver le minimum ou le maximum de deux valeurs ou plus.

Solution
min(x,y) renvoie le plus petit de deux nombres. max(x,y) renvoie le plus grand de deux
Nombres.

maValeur = analogRead(0);
maValeurMin = min(maValeur, 200); // myMinValue sera le plus petit de
// maVal ou 200

maValeurMax = max(maValeur, 100); // myMaxValue sera la plus grande de


// maVal ou 100

Discussion
Le tableau 3-2 montre quelques exemples de valeurs de sortie en utilisant un minimum de 200. Le tableau montre que
la sortie est la même que l'entrée (myValue) jusqu'à ce que la valeur devienne supérieure à 200.

Tableau 3-2. Sortie de min(myValue, 200)

myValue (la valeur d'entrée) Min(myValue, 200)


99 99

100 100

150 150

200 200

201 200

Le tableau 3-3 montre la sortie en utilisant un maximum de 100. Le tableau montre que la sortie est la
identique à l'entrée (myValue) lorsque la valeur est supérieure ou égale à 100.

Tableau 3-3. Sortie de max(myValue, 100)

myValue (la valeur d'entrée) Max(myValue, 200)


99 100

100 100

150 150

200 200

201 201

66 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

Utilisez min lorsque vous souhaitez limiter la limite supérieure. Cela peut être contre-intuitif, mais en retournant
la plus petite de la valeur d'entrée et de la valeur minimale, la sortie de min ne sera jamais supérieure à la
valeur minimale (200 dans l'exemple).

De même, utilisez max pour limiter la limite inférieure. La sortie de max ne sera jamais inférieure à la valeur
maximale (100 dans l'exemple).

Si vous souhaitez trouver la valeur minimale ou maximale à partir de plus de deux valeurs, vous pouvez
cascader les valeurs comme suitÿ:

// myMinValue sera la plus petite des trois lectures analogiquesÿ: int


myMinValue = min(analogRead(0), min(analogRead(1), analogRead(2)) );

Dans cet exemple, la valeur minimale est trouvée pour les ports analogiques 1 et 2, puis la valeur minimale et
le port 0. Cela peut être étendu pour autant d'éléments que nécessaire, mais veillez à positionner correctement
les parenthèses. L'exemple suivant obtient le maximum de quatre valeursÿ:

int maValeurMax = max(analogRead(0), max(analogRead(1), max(analogRead(2),


analogRead(3))));

Voir également

Recette 3.5

3.7 Élever un nombre à une puissance

Problème
Vous voulez élever un nombre à une puissance.

Solution
pow(x, y) renvoie la valeur de x élevée à la puissance y :

maValeur = pow(3,2);

Cela calcule 32, donc myValue sera égal à 9.

Discussion
La fonction pow peut fonctionner sur des valeurs entières ou à virgule flottante et renvoie le résultat sous forme
de valeur à virgule flottante : Serial.print(pow(3,2)); // ceci imprime 9.00 int z = pow(3,2); Serial.println(z);

// cela imprime 9

La première sortie est 9.00 et la seconde est 9 ; ils ne sont pas exactement les mêmes car la première
impression affiche la sortie sous forme de nombre à virgule flottante et la seconde traite la valeur comme un
entier avant l'impression, et s'affiche donc sans la virgule décimale.

3.7 Élever un nombre à une puissance | 67


Machine Translated by Google

Si vous utilisez la fonction pow , vous voudrez peut-être lire la recette 2.3 pour comprendre la différence entre ces
valeurs et les valeurs entières.

Voici un exemple d'élévation d'un nombre à une puissance fractionnaireÿ:

float s = pow(2, 1.0 / 12); // la racine douzième de deux


La racine douzième de deux est la même que 2 à la puissance 0,083333. La valeur résultante, s, est 1,05946 (c'est
le rapport de la fréquence de deux notes adjacentes sur un piano).

3.8 Prendre la racine carrée

Problème
Vous voulez calculer la racine carrée d'un nombre.

Solution
La fonction sqrt(x) renvoie la racine carrée de x :

Serial.print( sqrt(9) ); // cela imprime 3.00

Discussion
La fonction sqrt renvoie un nombre à virgule flottante (voir la fonction pow discutée dans la recette 3.7).

3.9 Arrondir les nombres à virgule flottante vers le haut et vers le bas

Problème
Vous voulez la prochaine valeur entière la plus petite ou la plus grande d'un nombre à virgule flottante (plancher
ou plafond).

Solution
floor(x) renvoie la plus grande valeur intégrale qui n'est pas supérieure à x. ceil(x) renvoie la plus petite valeur
intégrale qui n'est pas inférieure à x.

Discussion
Ces fonctions sont utilisées pour arrondir les nombres à virgule flottanteÿ; utilisez floor pour arrondir vers le bas et
ceil pour arrondir vers le haut.

Voici quelques exemples de sortie utilisant floor :

Serial.println( floor(1) ); // ceci imprime 1.00


Serial.println( floor(1.1) ); //
ceci imprime 1.00 Serial.println( floor(0) ); // ceci imprime 0.00

68 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

Serial.println( étage(.1) ); // ceci imprime 0.00


Serial.println( étage(-1) ); // cela imprime -1.00
Serial.println( étage(-1.1) ); // cela imprime -2.00

Voici un exemple de sortie utilisant ceilÿ:


Serial.println( ceil(1) ); // ceci imprime 1.00
Serial.println( ceil(1.1) ); // cela imprime 2.00
Serial.println( ceil(0) ); // ceci imprime 0.00
Serial.println( ceil(.1) ); // ceci imprime 1.00
Serial.println( ceil(-1) ); // cela imprime -1.00
Serial.println( ceil(-1.1) ); // cela imprime -1.00

Vous pouvez tronquer un nombre à virgule flottante en transtypant (convertissant) en un


int, mais cela n'arrondit pas correctement. Les nombres négatifs tels que -1,9
devrait arrondir à -2, mais lorsqu'il est converti en entier , il est arrondi
à -1. Le même problème existe avec les nombres positifs : 1,9 devrait arrondir
jusqu'à 2 mais arrondira à 1. Utilisez le sol et le plafond pour obtenir le bon
résultats.

3.10 Utilisation des fonctions trigonométriques

Problème
Vous souhaitez obtenir le sinus, le cosinus ou la tangente d'un angle exprimé en radians ou en degrés.

Solution
sin(x) renvoie le sinus de l'angle x. cos(x) renvoie le cosinus de l'angle x. tan(x) renvoie
la tangente de l'angle x.

Discussion
Les angles sont spécifiés en radians et le résultat est un nombre à virgule flottante (voir la recette 2.3).
L'exemple suivant illustre les fonctions trigonométriquesÿ:
float deg = 30ÿ; // angle en degrés
flotteur rad = deg * PI / 180ÿ; // convertir en radians
Serial.println (rad); Serial.println // imprime les radians
sin (rad)); Serial.println (cos // imprime le sinus
(rad)); // imprime le cosinus

Cela convertit l'angle en radians et imprime le sinus et le cosinus. Voici la sortie


avec annotation ajoutéeÿ:

0,52 30 degrés correspond à 0,5235988 radians, l'impression ne montre que deux décimales
0,50 sinus de 30 degrés est 0,5000000, affiché ici avec deux décimales
0,87 cosinus est 0,8660254, qui arrondit à 0,87

3.10 Utilisation des fonctions trigonométriques | 69


Machine Translated by Google

Bien que l'esquisse calcule ces valeurs en utilisant la précision totale de la virgule flottante
nombres, la routine Serial.print affiche les valeurs des nombres à virgule flottante à deux
décimales.

La conversion des radians en degrés et inversement est la trigonométrie des manuels. PI est la constante
familière pour ÿ (3,14159265...). PI et 180 sont des constantes, et Arduino
fournit des constantes précalculées que vous pouvez utiliser pour effectuer des degrés/radians
conversionÿ:

rad = degré * DEG_TO_RADÿ; // un moyen de convertir des degrés en radians


deg = rad * RAD_TO_DEGÿ; // un moyen de convertir des radians en degrés

L'utilisation deg * DEG_TO_RAD semble plus efficace que deg * PI / 180, mais ce n'est pas le cas, car
le compilateur Arduino est assez intelligent pour reconnaître que PI/180 est une constante (la valeur
ne changera jamais), il remplace donc le résultat de la division de PI par 180, ce qui arrive à
soit la valeur de la constante (DEG_TO_RAD vaut 0.017453292519...). Ainsi, vous pouvez utiliser l'approche
que vous préférez.

Voir également

Références Arduino pour sin (http:// www.arduino.cc/ en/ Reference/ Sin), cos (http:// ardui
no.cc/ en/ Reference/ Cos), et tan (http:// arduino.cc/ en/ Reference/ Tan)

3.11 Génération de nombres aléatoires


Problème

Vous souhaitez obtenir un nombre aléatoire, allant de zéro à un maximum spécifié


ou contraint entre une valeur minimale et maximale que vous fournissez.

Solution

Utilisez la fonction random pour renvoyer un nombre aléatoire. Appeler random avec un seul paramètre fixe la
borne supérieure ; les valeurs renvoyées seront comprises entre zéro et un de moins que
la borne supérieure :

aléatoire (maximum); // retourne un nombre aléatoire entre 0 et max -1

L'appel de random avec deux paramètres définit les limites inférieure et supérieureÿ; les valeurs renvoyées
vont de la borne inférieure (inclusive) à la borne supérieure un de moinsÿ:

aléatoire(min, max); // retourne un nombre aléatoire entre min et max -1

Discussion

Bien qu'il ne semble pas y avoir de modèle évident dans les nombres renvoyés, les valeurs
ne sont pas vraiment aléatoires. Exactement la même séquence se répétera à chaque démarrage de l'esquisse.
Dans de nombreuses applications, cela n'a pas d'importance. Mais si vous avez besoin d'une séquence différente chaque
au démarrage de votre esquisse, utilisez la fonction randomSeed(seed) avec une valeur de départ différente

70 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

à chaque fois (si vous utilisez la même valeur de départ, vous obtiendrez la même séquence). Cette fonction
démarre le générateur de nombres aléatoires à un endroit arbitraire en fonction du paramètre de départ que
vous passezÿ:

randomSeed(1234); // change la séquence de départ des nombres aléatoires.

Voici un exemple qui utilise les différentes formes de génération de nombres aléatoires disponibles sur
Arduino :

// Aléatoire //
montre comment générer des nombres aléatoires

int randNumberÿ;

void setup()

{ Serial.begin(9600);

// Affiche des nombres aléatoires sans valeur de


départ Serial.println("Imprime 20 nombres aléatoires entre 0 et 9"); for(int
i=0; i < 20; i++) { randNumber = random(10); Serial.print(randNumber);
Serial.print(" "); }

Serial.println();
Serial.println("Imprime 20 nombres aléatoires entre 2 et 9"); for(int i=0; i
< 20; i++) { randNumber = random(2,10); Serial.print(randNumber);
Serial.print(" "); }

// Affiche des nombres aléatoires avec la même valeur de départ à


chaque fois randomSeed(1234); Serial.println(); Serial.println("Imprime
20 nombres aléatoires entre 0 et 9 après une graine constante "); for(int
i=0; i < 20; i++) { randNumber = random(10); Serial.print(randNumber); Serial.print(" "); }

// Affiche des nombres aléatoires avec une valeur de départ différente à


chaque fois randomSeed(analogRead(0)); // lit depuis un port analogique sans rien connecté
Serial.println(); Serial.println("Imprime 20 nombres aléatoires entre 0 et 9 après la graine flottante
"); for(int i=0; i < 20; i++) { randNumber = random(10); Serial.print(randNumber); Serial.print(" ");

3.11 Génération de nombres aléatoires | 71


Machine Translated by Google

}
Serial.println();
Serial.println(); }

void loop() { }

Voici la sortie de ce codeÿ:


Imprimer 20 nombres aléatoires entre 0 et 9 7 9 3
80248390522737902
Imprimer 20 nombres aléatoires entre 2 et 9 9 3 7
72758293425435757
Imprimer 20 nombres aléatoires entre 0 et 9 après la graine constante 8 2 8
71803659034312394
Imprimer 20 nombres aléatoires entre 0 et 9 après la graine flottante 0 9 7 4
4774491602315911

Si vous appuyez sur le bouton de réinitialisation de votre Arduino pour redémarrer l'esquisse, les trois
premières lignes de nombres aléatoires seront inchangées. Seule la dernière ligne change à chaque
démarrage de l'esquisse, car elle définit la graine sur une valeur différente en la lisant à partir d'un port
d'entrée analogique non connecté en tant que graine de la fonction randomSeed . Si vous utilisez le port
analogique 0 pour autre chose, remplacez l'argument par analogRead par un port analogique inutilisé.

Voir également

Références Arduino pour random (http:// www.arduino.cc/ en/ Reference/ Random) et randomSeed (http://
arduino.cc/ en/ Reference/ RandomSeed)

3.12 Définition et lecture des bits


Problème
Vous souhaitez lire ou définir un bit particulier dans une variable numérique.

Solution
Utilisez les fonctions suivantesÿ:

• bitSet(x, bitPosition) définit (écrit un 1 sur) le bitPosition donné de la variable x. • bitClear(x,


bitPosition) efface (écrit un 0 dans) le bitPosition donné de la variable x. • bitRead(x, bitPosition) renvoie
la valeur (sous forme de 0 ou 1) du bit à la bitPosition donnée de la variable x.

• bitWrite(x, bitPosition, value) définit la valeur donnée (comme 0 ou 1) du bit à la


donnée bitPosition de la variable x.
• bit(bitPosition) renvoie la valeur de la position de bit donnée : bit(0) vaut 1, bit(1) vaut 2, bit(2) vaut 4,
etc.

72 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

Dans toutes ces fonctions, bitPosition 0 est le bit le moins significatif (le plus à droite).

Voici une esquisse qui utilise ces fonctions pour manipuler les bits d'une variable 8 bits
appelée flagsÿ:
// bitFunctions //
démontre l'utilisation des fonctions de bit

drapeaux d'octet = 0ÿ; // ces exemples définissent, effacent ou lisent des bits dans une variable appelée flags.

// Exemple de bitSet
void setFlag( int flagNumber) {

bitSet(flags, flagNumber);
}

// exemple bitClear void


clearFlag( int flagNumber) {

bitClear(flags, flagNumber);
}

// exemple de bitPosition

int getFlag( int flagNumber) {

return bitRead(flags, flagNumber);


}

void setup()

{ Serial.begin(9600); }

boucle vide()
{
showFlags();
setFlag(2); // définit des drapeauxÿ;
setFlag(5); showFlags(); clearFlag(2);
showFlags();

retard (10000); // attendre très longtemps


}

// signale les drapeaux qui sont


définis void showFlags() {

for(int flag=0; flag < 8; flag++)


{ if(getFlag(flag) == true)

Serial.print("* bit défini pour le drapeau ");

3.12 Définition et lecture des bits | 73


Machine Translated by Google

autre
Serial.print("bit clear for flag ");

Serial.println(flag); }

Serial.println();
}

Ce code imprimera ce qui suitÿ:

peu clair pour le drapeau 0


peu clair pour le drapeau 1
peu clair pour le drapeau 2
peu clair pour le drapeau 3
peu clair pour le drapeau 4
peu clair pour le drapeau 5
peu clair pour le drapeau 6
peu clair pour le drapeau 7

bit à 0 pour l'indicateur 0


bit à 0 pour l'indicateur 1
* bit à 0 pour l'indicateur
2 bit à 0 pour l'indicateur
3 bit à 0 pour l'indicateur
4 * bit à 0 pour l'indicateur
5 bit à 0 pour l'indicateur
6 bit à 0 pour l'indicateur 7

bit en clair pour le drapeau 0


bit en clair pour le drapeau 1
bit en clair pour le drapeau 2
bit en clair pour le drapeau 3
bit en clair pour le drapeau 4
* bit défini pour le drapeau 5
bit en clair pour le drapeau 6
bit en clair pour le drapeau 7

Discussion
La lecture et le réglage des bits sont une tâche courante, et de nombreuses bibliothèques Arduino utilisent
cette fonctionnalité. L'une des utilisations les plus courantes des opérations sur les bits consiste à stocker et à
récupérer efficacement des valeurs binaires (on/off, vrai/faux, 1/0, haut/bas, etc.).

Arduino définit les constantes true et HIGH comme 1 et false et LOW comme 0.

L'état de huit commutateurs peut être regroupé dans une seule valeur de 8 bits au lieu de nécessiter huit
octets ou entiers. L'exemple de la solution de cette recette montre comment huit valeurs peuvent être définies
ou effacées individuellement dans un seul octet.

74 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

Le terme indicateur est un terme de programmation pour les valeurs qui stockent l'état de certains
aspects d'un programme. Dans cette esquisse, les bits d'indicateur sont lus à l'aide de bitRead, et ils
sont définis ou effacés à l'aide de bitSet ou bitClear. Ces fonctions prennent deux paramètres : le
premier est la valeur à lire ou à écrire (drapeaux dans cet exemple), et le second est la position du bit
indiquant où la lecture ou l'écriture doit avoir lieu. La position de bit 0 est le bit le moins significatif (le
plus à droite)ÿ; la position 1 est la deuxième position à partir de la droite, et ainsi de suite. Alors:

bitRead(2, 1); // renvoie 1 car 2 est un 10 binaire et le bit en position 1 est 1

bitRead(4, 1); // renvoie 0 car 4 est un 100 binaire et le bit en position 1


est 0

Il existe également une fonction appelée bit qui renvoie la valeur de chaque position de bit :
bit(0) est égal à 1 ; bit(1) est égal à 2ÿ; bit(2) est égal à 4ÿ;

...
bit(7) est égal à 128

Voir également

Références Arduino pour les fonctions bit et byteÿ:

lowByte
http:// www.arduino.cc/ en/ Reference/ LowByte
highByte http:// arduino.cc/ en/ Reference/ HighByte

bitRead
http:// www.arduino.cc/ en/ Reference/ BitRead

bitWrite
http:// arduino.cc/ en/ Reference/ BitWrite
bitSet
http:// arduino.cc/ en/ Reference/ BitSet
bitClear
http:// arduino.cc/ en/ Reference/ BitClear

bit
http:// arduino.cc/ en/ Reference/ Bit

3.13 Décalage des bits

Problème

Vous devez effectuer des opérations sur les bits qui décalent les bits vers la gauche ou vers la droite dans un octet, un entier ou un long.

3.13 Décalage des bits | 75


Machine Translated by Google

Solution

Utilisez les opérateurs << (décalage de bits vers la gauche) et >> (décalage de bits vers la droite) pour décaler les bits d'une valeur.

Discussion

Ce fragment définit la variable x égale à 6. Il décale les bits restants d'un et imprime le nouveau
valeur (12). Ensuite, cette valeur est décalée de deux places vers la droite (et dans cet exemple devient
égal à 3):

int x = 6ÿ;
entier résultat = x << 1; // 6 décalé vers la gauche 1 est 12
Serial.println(result);
entier résultat = x >> 2ÿ; // 12 décalé vers la droite 2 vaut 3ÿ;
Serial.println(result);

Voici comment cela fonctionne : 6 décalé d'une position vers la gauche équivaut à 12, car le nombre décimal
6 est 0110 en binaire. Lorsque les chiffres sont décalés vers la gauche, la valeur devient 1100 (décimal
12). Décaler 1100 vers la droite de deux places devient 0011 (décimal 3). Vous remarquerez peut-être que
décaler un nombre vers la gauche de n places revient à multiplier la valeur par 2 élevée au
puissance de n. Décaler un nombre de n positions vers la droite revient à diviser la valeur par 2
élevé à la puissance n. En d'autres termes, les paires d'expressions suivantes sont identiquesÿ:
• x << 1 est identique à x * 2.
• x << 2 est identique à x * 4.
• * 8.
x << 3 est identique à x

x >> 1 est identique à x / 2.

x >> 2 est identique à x / 4.

x >> 3 est identique à x / 8.

La puce du contrôleur Arduino peut décaler les bits plus efficacement qu'elle ne peut se multiplier et
diviser, et vous pouvez rencontrer du code qui utilise le décalage de bits pour multiplier et diviserÿ:

entier c = (a << 1) + (b >> 2); // additionne (a fois 2) plus ( b divisé par 4)

L'expression (a << 1) + (b >> 2); ne ressemble pas beaucoup à (a * 2) + (b / 4);, mais


les deux expressions font la même chose. En effet, le compilateur Arduino est suffisamment intelligent pour
reconnaître que le décalage d'un entier par une constante qui est une puissance de deux est identique à un
shift et produira le même code machine que la version utilisant shift. La source
code utilisant des opérateurs arithmétiques est plus facile à lire pour les humains, il est donc préférable lorsque le
l'intention est de multiplier et de diviser.

Voir également

Références Arduino pour les fonctions bit et byte : lowByte, highByte, bitRead, bitWrite,
bitSet, bitClear et bit (voir recette 3.12)

76 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

3.14 Extraction des octets haut et bas dans un int ou un long

Problème
Vous souhaitez extraire l'octet de poids fort ou l'octet de poids faible d'un entierÿ; par exemple, lors de l'envoi de
valeurs entières sous forme d'octets sur une ligne de communication série ou autre.

Solution
Utilisez lowByte(i) pour obtenir l'octet le moins significatif d'un entier. Utilisez highByte(i) pour obtenir l'octet le
plus significatif d'un entier.

L'esquisse suivante convertit une valeur entière en octets de poids faible et de poids fortÿ:

//Opérateurs d'octets

int intValeur = 258ÿ; // 258 en notation hexadécimale est 0x102

void setup()

{ Serial.begin(9600); }

void loop()
{ int loWord,
hiWordÿ; octet loByte,
hiByteÿ;

hiByte = highByte(intValue); loByte


= lowByte(intValue);

Serial.println(intValue,DEC);
Serial.println(intValue,HEX);
Serial.println(loByte,DEC);
Serial.println(hiByte,DEC);

retard (10000); // attendre très longtemps }

Discussion
L'exemple d'esquisse imprime intValue suivi de l'octet de poids faible et de l'octet de poids fortÿ: // la

258 valeur entière à convertir // la valeur en notation hexadécimale // l'octet de poids


102 faible // l'octet de poids fort
2
1

Pour extraire les valeurs d'octets d'un long, la valeur longue de 32 bits est d'abord divisée en deux mots de 16
bits qui peuvent ensuite être convertis en octets, comme indiqué dans le code précédent. Au moment d'écrire
ces lignes, la bibliothèque Arduino standard n'avait pas de fonction à remplir

3.14 Extraction des octets haut et bas dans un int ou long | 77


Machine Translated by Google

cette opération sur une longue durée, mais vous pouvez ajouter les lignes suivantes à votre croquis pour fournir
ceciÿ:

#define highWord(w) ((w) >> 16)


#define lowWord(w) ((w) & 0xffff)

Ce sont des macro-expressions : hiWord effectue une opération de décalage de 16 bits pour produire une valeur
de 16 bits, et lowWord masque les 16 bits inférieurs à l'aide de l'opérateur binaire And (voir la recette 2.20).

Le nombre de bits dans un entier varie selon les plates-formes. Sur Arduino, c'est 16 bits, mais dans
d'autres environnements, c'est 32 bits. Le terme mot tel qu'il est utilisé ici fait référence à une valeur de
16 bits.

Ce code convertit la valeur hexadécimale 32ÿbits 0x1020304 en ses valeurs haute et basse constitutives 16ÿbitsÿ:

lowword = lowWord(longValue);
hiword = highWord(longValue);
Serial.println(lowword,DEC);
Serial.println(hiword,DEC);

Cela imprime les valeurs suivantesÿ:

772 // 772 est 0x0304 en hexadécimal


258 // 258 est 0x0102 en hexadécimal

Notez que 772 en décimal est 0x0304 en hexadécimal, qui est le mot de poids faible (16 bits) de la
longValue 0x1020304. Vous pouvez reconnaître 258 dans la première partie de cette recette comme
la valeur produite en combinant un octet de poids fort de 1 et un octet de poids faible de 2 (0x0102
en hexadécimal).

Voir également

Références Arduino pour les fonctions bit et byte : lowByte, highByte, bitRead, bitWrite, bitSet,
bitClear et bit (voir recette 3.12)

3.15 Formation d'un entier ou d'un long à partir des octets de poids fort et de poids faible

Problème
Vous souhaitez créer une valeur entière 16 bits (int) ou 32 bits (long) à partir d'octets individuelsÿ; par exemple,
lors de la réception d'entiers sous forme d'octets individuels sur une liaison de communication série. C'est
l'opération inverse de la recette 3.14.

78 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

Solution
Utilisez la fonction word(h,l) pour convertir deux octets en un seul entier Arduino. Voici le code
de la recette 3.14 développé pour reconvertir les octets individuels haut et bas en entier :

//Opérateurs d'octets

int intValeur = 0x102ÿ; // 258

void setup()

{ Serial.begin(9600); }

void loop()
{ int loWord,
hiWordÿ; octet
loByte, hiByteÿ;

hiByte = highByte(intValue);
loByte = lowByte(intValue);

Serial.println(intValue,DEC);
Serial.println(loByte,DEC);
Serial.println(hiByte,DEC);

loByte = mot(hiByte, loByte); // reconvertit les octets en un mot


Serial.println(loWord,DEC); retard (10000); // attendre très longtemps }

Discussion
L' expression word(high,low) assemble un octet haut et bas en une valeur 16 bits. Le code de la
solution de cette recette prend les octets de poids faible et de poids fort formés comme indiqué
dans la recette 3.14 et les réassemble en un mot. La sortie est la valeur entière, l'octet de poids
faible, l'octet de poids fort et les octets reconvertis en une valeur entièreÿ:
258
21
258

Arduino n'a pas de fonction pour faire d'une valeur longue de 32 bits deux mots de 16 bits (au
moment d'écrire ces lignes), mais vous pouvez ajouter votre propre capacité makeLong() en
ajoutant la ligne suivante en haut de votre croquis :
#define makeLong(hi, low) ((hi) << 16 & (low))

3.15 Formation d'un int ou d'un long à partir d'octets de poids fort et de poids faible | 79
Machine Translated by Google

Ceci définit une commande qui décalera la valeur haute de 16 bits vers la gauche et l'ajoutera à
la valeur basse :

#define makeLong(hi, low) (((long) hi) << 16 | (low)) #define


highWord(w) ((w) >> 16) #define lowWord(w) ((w) & 0xffff)

// déclare une valeur à tester


long longValue = 0x1020304; // en décimal : 16909060
// en binaire : 00000001 00000010 00000011 00000100

void setup()

{ Serial.begin(9600); }

void loop()
{ int loWord,
hiWordÿ;

Serial.println(longValue,DEC); // ceci imprime 16909060 loWord


= lowWord(longValue); hiWord = highWord(longValue);
// convertit long en deux mots
Serial.println(loWord,DEC); // imprime la valeur 772
Serial.println(hiWord,DEC); // affichemakeLong(
la valeur 258hiWord,
longValue =
loWord); // reconvertit les mots en unSerial.println(longValue,DEC);
long //
cela imprime à nouveau 16909060

retard (10000); // attendre très longtemps }

La sortie estÿ:
16909060
772 258
16909060

Voir également

Références Arduino pour les fonctions bit et byte : lowByte, highByte, bitRead,
bitWrite, bitSet, bitClear et bit (voir recette 3.12)

80 | Chapitre 3 : Utilisation des opérateurs mathématiques


Machine Translated by Google

CHAPITRE 4

Communications série

4.0 Présentation
Les communications série offrent un moyen simple et flexible pour votre carte Arduino d'interagir avec
votre ordinateur et d'autres appareils. Ce chapitre explique comment envoyer et recevoir des informations
à l'aide de cette fonctionnalité.

Le chapitre 1 décrit comment connecter le port série Arduino à votre ordinateur pour télécharger des
croquis. Le processus de téléchargement envoie des données de votre ordinateur à Arduino et Arduino
renvoie des messages d'état à l'ordinateur pour confirmer que le transfert fonctionne. Les recettes ici
montrent comment vous pouvez utiliser ce lien de communication pour envoyer et recevoir des informations
entre Arduino et votre ordinateur ou un autre périphérique série.

Les communications série sont également un outil pratique pour le débogage. Vous
pouvez envoyer des messages de débogage d'Arduino à l'ordinateur et les afficher
sur l'écran de votre ordinateur.

L'IDE Arduino (décrit dans la recette 1.3) fournit un moniteur série (illustré à la figure 4-1) pour afficher les
données série reçues par Arduino.

Vous pouvez également envoyer des données du moniteur série vers Arduino en saisissant du texte dans
la zone de texte à gauche du bouton Envoyer. Le débit en bauds est sélectionné à l'aide de la liste
déroulante en bas à droite. Vous pouvez utiliser le menu déroulant intitulé "Aucune fin de ligne" pour
envoyer automatiquement un retour chariot ou une combinaison d'un retour chariot et d'une ligne à la fin
de chaque message envoyé lorsque vous cliquez sur le bouton Envoyer.

Votre sketch Arduino peut utiliser le port série pour accéder indirectement (généralement via un programme
proxy écrit dans un langage comme Processing) à toutes les ressources (mémoire, écran, clavier, souris,
connectivité réseau, etc.) dont dispose votre ordinateur. Votre ordinateur peut également utiliser la liaison
série pour interagir avec des capteurs ou d'autres appareils connectés à Arduino.

La mise en œuvre des communications série implique du matériel et des logiciels. Le matériel fournit la
signalisation électrique entre Arduino et l'appareil auquel il parle. le

81
Machine Translated by Google

Figure 4-1. Écran du moniteur série Arduino

le logiciel utilise le matériel pour envoyer des octets ou des bits que le matériel connecté comprend. Les
bibliothèques série Arduino vous isolent de la majeure partie de la complexité matérielle, mais il est utile
pour vous de comprendre les bases, en particulier si vous devez résoudre des problèmes de communication
série dans vos projets.

Matériel série
Le matériel série envoie et reçoit des données sous forme d'impulsions électriques qui représentent des
bits séquentiels. Les zéros et les uns qui portent les informations qui composent un octet peuvent être
représentés de différentes manières. Le schéma utilisé par Arduino est de 0 volt pour représenter une
valeur de bit de 0 et de 5 volts (ou 3,3 volts) pour représenter une valeur de bit de 1.

L'utilisation de 0 volts (pour 0) et de 5 volts (pour 1) est très courante. C'est ce


qu'on appelle le niveau TTL car c'est ainsi que les signaux étaient représentés
dans l'une des premières implémentations de la logique numérique, appelée
Transistor Transistor Logic (TTL).

Les cartes comprenant Uno, Duemilanove, Diecimila, Nano et Mega ont une puce pour convertir le port
série matériel de la puce Arduino en Universal Serial Bus (USB) pour la connexion au port série matériel.
D'autres cartes, telles que les cartes Mini, Pro, Pro Mini, Boarduino, Sanguino et Modern Device Bare
Bones, n'ont pas de prise en charge USB et nécessitent un adaptateur pour se connecter à votre ordinateur
qui convertit TTL en USB. Voir http:// www.arduino.cc/ en/ Main/ Hardware pour plus de détails sur ces cartes.

82 | Chapitre 4 : Communications série


Machine Translated by Google

Certains adaptateurs USB populaires incluentÿ:

• Adaptateur mini USB (http:// arduino.cc/ en/ Main/ MiniUSB)

• Adaptateur TTL USB FTDI (http:// www.ftdichip.com/ Products/ FT232R.htm)

• Carte USB BUB Modern Device (http:// shop.moderndevice.com/ products/ usb-bub)

Certains périphériques série utilisent la norme RS-232 pour la connexion série. Ceux-ci ont généralement
un connecteur à neuf broches, et un adaptateur est nécessaire pour les utiliser avec l'Arduino. RS-232
est un protocole de communication ancien et vénéré qui utilise des niveaux de tension non compatibles avec
les broches numériques Arduino.

Vous pouvez acheter des cartes Arduino conçues pour les niveaux de signal RS-232, telles que la Free duino
Serial v2.0 (http:// www.nkcelectronics.com/ freeduino-serial-v20-board-kit-ardui
no-diecimila-compatib20.html).

Les adaptateurs RS-232 qui connectent les signaux RS-232 aux broches Arduino 5V (ou 3,3V) incluent le
Suivant:

• Adaptateur RS-232 vers TTL 3ÿV-5,5ÿV (http:// www.nkcelectronics.com/ rs232-to-ttl-con


verter-board-33v232335.html)

• Kits d'adaptateur série P4 RS232 vers TTL (http:// shop.moderndevice.com/ products/ p4)

• RS232 Shifter SMD (http:// www.sparkfun.com/ commerce/ product_info.php?prod


ucts_id=449)

Un Arduino standard a un seul port série matériel, mais la communication série est également
possible à l'aide de bibliothèques logicielles pour émuler des ports supplémentaires (canaux de communication)
pour fournir une connectivité à plus d'un appareil. La série logicielle nécessite beaucoup d'aide
du contrôleur Arduino pour envoyer et recevoir des données, donc ce n'est pas aussi rapide ou efficace que
série matérielle.

L'Arduino Mega dispose de quatre ports série matériels pouvant communiquer avec jusqu'à
quatre périphériques série différents. Un seul d'entre eux possède un adaptateur USB intégré (vous pouvez
câblez un adaptateur USB-TTL à l'un des autres ports série). Le tableau 4-1 montre le port
noms et broches utilisés pour tous les ports série Mega.

Tableau 4-1. Ports série Arduino Mega

Nom du port Broche de transmission Recevoir la broche

En série 1 (également USB) 0 (également USB)

Série1 18 19

Série2 16 17

Série3 14 15

4.0 Présentation | 83
Machine Translated by Google

Série du logiciel

Vous utiliserez généralement la bibliothèque série Arduino intégrée pour communiquer avec les ports
série du matériel. Les bibliothèques série simplifient l'utilisation des ports série en vous isolant des
complexités matérielles.

Parfois, vous avez besoin de plus de ports série que le nombre de ports série matériels disponibles. Si tel
est le cas, vous pouvez utiliser une bibliothèque supplémentaire qui utilise un logiciel pour émuler le
matériel série. Les recettes 4.13 et 4.14 montrent comment utiliser une bibliothèque série logicielle pour
communiquer avec plusieurs appareils.

Protocole de message série


Les bibliothèques série matérielles ou logicielles gèrent l'envoi et la réception d'informations.
Ces informations consistent souvent en des groupes de variables qui doivent être envoyées ensemble.
Pour que les informations soient interprétées correctement, le côté récepteur doit savoir où commence et
où se termine chaque message. Une communication série significative, ou tout type de communication
machine à machine, ne peut être réalisée que si les côtés émetteur et récepteur s'accordent pleinement
sur la manière dont les informations sont organisées dans le message. L'organisation formelle des
informations dans un message et la gamme de réponses appropriées aux demandes s'appellent un
protocole de communication.

Les messages peuvent contenir un ou plusieurs caractères spéciaux qui identifient le début du message,
c'est ce qu'on appelle l' en-tête. Un ou plusieurs caractères peuvent également être utilisés pour identifier
la fin d'un message, c'est ce qu'on appelle le pied de page. Les recettes de ce chapitre montrent des
exemples de messages dans lesquels les valeurs qui composent le corps d'un message peuvent être
envoyées au format texte ou binaire.

L'envoi et la réception de messages au format texte impliquent l'envoi de commandes et de valeurs


numériques sous forme de lettres et de mots lisibles par l'homme. Les nombres sont envoyés sous forme
de chaîne de chiffres représentant la valeur. Par exemple, si la valeur est 1234, les caractères 1, 2, 3 et 4
sont envoyés en tant que caractères individuels.

Les messages binaires comprennent les octets que l'ordinateur utilise pour représenter les valeurs. Les
données binaires sont généralement plus efficaces (nécessitant moins d'octets à envoyer), mais les
données ne sont pas aussi lisibles par l'homme que le texte, ce qui les rend plus difficiles à déboguer. Par
exemple, Arduino représente 1234 sous la forme des octets 4 et 210 (4 * 256 + 210 = 1234). Si l'appareil
auquel vous vous connectez envoie ou reçoit uniquement des données binaires, c'est ce que vous devrez
utiliser, mais si vous avez le choix, les messages texte sont plus faciles à implémenter et à déboguer.

84 | Chapitre 4 : Communications série


Machine Translated by Google

Il existe de nombreuses façons d'aborder les problèmes logiciels, et certaines des recettes de ce chapitre
montrent deux ou trois façons différentes d'obtenir un résultat similaire. Les différences (par exemple, l'envoi
de texte au lieu de données binaires brutes) peuvent offrir un équilibre différent entre simplicité et efficacité.
Lorsque des choix sont proposés, choisissez la solution que vous trouvez la plus facile à comprendre et à
adapter - ce sera probablement la première solution couverte. Les alternatives peuvent être un peu plus
efficaces, ou elles peuvent être plus appropriées pour un protocole spécifique auquel vous voulez vous
connecter, mais la « bonne façon » est celle que vous trouvez la plus facile à mettre en œuvre dans votre
projet.

L'environnement de développement de traitement

Certains des exemples de ce chapitre utilisent le langage de traitement pour envoyer et recevoir des
messages série sur un ordinateur parlant à Arduino.

Processing est un outil open source gratuit qui utilise un environnement de développement similaire
à Arduino. Vous pouvez en savoir plus sur le traitement et télécharger tout ce dont vous avez besoin
sur le site Web de traitement.

Le traitement est basé sur le langage Java, mais les exemples de code de traitement de ce livre
devraient être faciles à traduire dans d'autres environnements prenant en charge les communications
série. Processing est accompagné de quelques exemples de croquis illustrant la communication entre
Arduino et Processing. SimpleRead est un exemple de traitement qui inclut du code Arduino. Dans
Traitement, sélectionnez Fichier ÿ Exemples ÿ Bibliothèques ÿ Série ÿ SimpleRead pour voir un
exemple qui lit les données du port série et change la couleur d'un rectangle lorsqu'un commutateur
connecté à Arduino est enfoncé et relâché.

Voir également

Un tutoriel Arduino RS-232 est disponible sur http:// www.arduino.cc/ en/ Tutorial/ Arduino SoftwareRS232. De
nombreuses informations et liens sont disponibles sur le site Web Serial Port Central, http:// www.lvr.com/
serport.htm.

De plus, un certain nombre de livres sur le traitement sont également disponiblesÿ:

• Premiers pas avec le traitementÿ: une introduction rapide et pratique par CaseyÿReas et
Ben Fry (Faire).

• Traitementÿ: un manuel de programmation pour les concepteurs visuels et les artistes par Casey
Reas et Ben Fry (MIT Press). •

Visualisation des données par Ben Fry (O'Reilly). •

Traitementÿ: Codage créatif et art informatique par Ira Greenberg (Apress). • Faire parler les choses de

Tom Igoe (Make). Ce livre couvre Processing et Arduino et fournit de nombreux exemples de code de
communication.

4.0 Présentation | 85
Machine Translated by Google

4.1 Envoi d'informations de débogage d'Arduino


à votre ordinateur

Problème
Vous souhaitez envoyer du texte et des données à afficher sur votre PC ou Mac en utilisant l'IDE Arduino
ou le programme de terminal série de votre choix.

Solution
Cette esquisse imprime des numéros séquentiels sur le moniteur sérieÿ:
/*
* Esquisse SerialOutput *
Affiche les numéros sur le port série */ void
setup() { Serial.begin(9600); // envoie et reçoit
à 9600 bauds }

nombre entier = 0ÿ;

void loop()
{ Serial.print("Le
nombre est "); Serial.println(nombre); //
imprime le nombre

retard (500); // délai d'une demi-seconde entre les nombres


number++ÿ; // au numéro suivant }

Connectez Arduino à votre ordinateur comme vous l'avez fait au chapitre 1 et téléchargez ce croquis.
Cliquez sur l'icône Serial Monitor dans l'IDE et vous devriez voir la sortie affichée comme suitÿ:

Le nombre est 0
Le nombre est 1
Le nombre est 2

Discussion
Pour imprimer du texte et des chiffres à partir de votre croquis, placez l' instruction Serial.begin(9600) dans
setup(), puis utilisez les instructions Serial.print() pour imprimer le texte et les valeurs que vous souhaitez.
à voir.

La fonction Arduino Serial Monitor peut afficher les données série envoyées par Arduino. Pour démarrer
Serial Monitor, cliquez sur l'icône de la barre d'outils Serial Monitor, comme illustré à la Figure 4-2.
Une nouvelle fenêtre s'ouvrira pour afficher la sortie d'Arduino.

86 | Chapitre 4 : Communications série


Machine Translated by Google

Illustration 4-2. Cliquer sur l'icône Serial Monitor pour voir la sortie série

Votre sketch doit appeler la fonction Serial.begin() avant de pouvoir utiliser l'entrée ou la sortie série.
La fonction prend un seul paramètre : la vitesse de communication souhaitée. Vous devez utiliser la
même vitesse pour le côté envoi et le côté réception, sinon vous verrez du charabia (ou rien du tout) à
l'écran. Cet exemple et la plupart des autres de ce livre utilisent une vitesse de 9 600 bauds (le baud
est une mesure du nombre de bits transmis par seconde). Le débit de 9 600 bauds correspond à
environ 1 000 caractères par seconde.
Vous pouvez envoyer à des débits inférieurs ou supérieurs (la plage est de 300 à 115 200), mais
assurez-vous que les deux côtés utilisent la même vitesse. Le moniteur série définit la vitesse à l'aide
de la liste déroulante du débit en bauds (en bas à droite de la fenêtre du moniteur série dans la Figure
4-2). Si votre sortie ressemble à ceciÿ: `3??f<ÌxÌÿÿÿü`³??f<

vous devez vérifier que le débit en bauds sélectionné sur votre ordinateur correspond au débit défini
par Serial.begin() dans votre sketch.

Si vos vitesses d'envoi et de réception en série sont correctement définies mais que
vous obtenez toujours du texte illisible, vérifiez que vous avez sélectionné la bonne
carte dans le menu IDE ToolsÿBoard. Si vous avez sélectionné le mauvais tableau,
remplacez-le par le bon et téléchargez à nouveau sur le tableau.

4.1 Envoi d'informations de débogage d'Arduino à votre ordinateur | 87


Machine Translated by Google

Vous pouvez afficher du texte à l'aide de la fonction Serial.print() . Les chaînes (texte entre guillemets doubles) seront
imprimées telles quelles (mais sans les guillemets). Par exemple, le code suivantÿ:

Serial.print("Le numéro est ");

imprime ceci :
Le nombre est

Les valeurs (nombres) que vous imprimez dépendent du type de variable ; voir la recette 4.2 pour plus d'informations
à ce sujet. Mais pour l'instant, l'impression d'un entier imprimera sa valeur numérique, donc si le numéro de la variable
est 1, le code suivant :

Serial.println(nombre);

imprimera ceci:
1

Dans l'exemple de croquis, le nombre imprimé sera 0 au début de la boucle et augmentera d'un à chaque fois dans la
boucle. Le ln à la fin de println fait démarrer la prochaine instruction d'impression sur une nouvelle ligne.

Cela devrait vous permettre de commencer à imprimer du texte et la valeur décimale des nombres entiers. Voir la
recette 4.2 pour plus de détails sur les options de formatage d'impression.

Vous voudrez peut-être envisager un programme de terminal tiers qui a plus de fonctionnalités que Serial Monitor.
L'affichage de données au format texte ou binaire (ou les deux), l'affichage de caractères de contrôle et la journalisation
dans un fichier ne sont que quelques-unes des fonctionnalités supplémentaires disponibles à partir des nombreux
programmes de terminaux tiers. En voici quelques-uns qui ont été recommandés par les utilisateurs d'Arduinoÿ:

MignonCom
Un programme de terminal open source pour Linux

Gare de Bray
Un exécutable gratuit pour PC

Écran GNU
Un programme de gestion d'écran virtuel open source qui prend en charge les communications sérieÿ; inclus
avec la série Linux et Mac OS X

Un autre programme de terminal open source pour Linux


Mastic

Un programme SSH open source pour Windowsÿ; prend en charge les communications série
RealTerm

Un programme de terminal open source pour PC


Terme Z

Un programme de shareware pour Mac

88 | Chapitre 4 : Communications série


Machine Translated by Google

De plus, un article du wiki Arduino explique comment configurer Linux pour communiquer avec Arduino en utilisant
TTY (voir http:// www.arduino.cc/ playground/ Interfacing/ LinuxTTY).

Vous pouvez utiliser un écran à cristaux liquides comme périphérique de sortie série, bien que ses fonctionnalités soient
très limitées. Consultez la documentation pour voir comment votre affichage gère les retours chariot, car certains
affichages peuvent ne pas passer automatiquement à une nouvelle ligne après les instructions println .

Voir également

La bibliothèque Arduino LiquidCrystal pour les écrans LCD textuels utilise une fonctionnalité d'impression sous-jacente
similaire à la bibliothèque Serial, vous pouvez donc utiliser de nombreuses suggestions abordées dans ce chapitre avec
cette bibliothèque (voir Chapitre 11).

4.2 Envoi de texte formaté et de données numériques depuis Arduino

Problème
Vous souhaitez envoyer des données série depuis Arduino affichées sous forme de texte, de valeurs décimales,
hexadécimales ou binaires.

Solution
Vous pouvez imprimer des données sur le port série dans de nombreux formats différents ; voici un croquis qui illustre
toutes les options de formatÿ:

/*
* SerialFormatting
* Affiche les valeurs dans divers formats sur le port série
*/ char chrValue = 65; // ce sont les valeurs de départ à
imprimer int intValue = 65; float floatValeur = 65.0ÿ;

void setup()

{ Serial.begin(9600); }

void loop()

{ Serial.println("chrValueÿ: ");
Serial.println(chrValue);
Serial.println(chrValue,BYTE);
Serial.println(chrValue,DEC);

4.2 Envoi de texte formaté et de données numériques depuis Arduino | 89


Machine Translated by Google

Serial.println("intValueÿ: ");
Serial.println(intValue);
Serial.println(intValue,BYTE);
Serial.println(intValue,DEC);
Serial.println(intValue,HEX);
Serial.println(intValue,OCT);
Serial.println(intValue,BIN);

Serial.println("floatValueÿ: ");
Serial.println(floatValue);

retard(1000); // retarde une seconde entre les nombres


chrValue++; // à la valeur suivante intValue++ÿ; }

La sortie (condensée ici en quelques lignes) est la suivante :

chrValeurÿ: AA 65
intValeurÿ: 65 A 65 41ÿ101 1000001
floatValeurÿ: 65,00

chrValeur : BB 66
intValeur : 66 B 66 42 102 1000010

Discussion
L' impression d'une chaîne de texte est simple : Serial.print("hello world"); envoie la chaîne de texte "hello
world" à un périphérique à l'autre extrémité du port série. Si vous voulez que votre sortie imprime une
nouvelle ligne après la sortie, utilisez Serial.println() au lieu de Serial.print().

L'impression de valeurs numériques peut être plus compliquée. La manière dont les valeurs d'octet et d'entier
sont imprimées dépend du type de variable et d'un paramètre de formatage facultatif. Le langage Arduino est
très simple sur la façon dont vous pouvez vous référer à la valeur de différents types de données (voir la
recette 2.2 pour plus d'informations sur les types de données). Mais cette flexibilité peut prêter à confusion,
car même lorsque les valeurs numériques sont similaires, le compilateur les considère comme des types
distincts avec des comportements différents. Par exemple, l'impression d'un char ne produira pas
nécessairement la même sortie que l'impression d'un int de la même valeur.

Voici quelques exemples spécifiques; tous créent des variables qui ont des valeurs similairesÿ:

char valeurascii = 'A'; // ASCII A a une valeur de 65 char chrValue =


65; // un caractère de 8 bits, c'estbits
aussi
défini
ASCII
sur une
'A' //valeur
un entier
de 65
de int
16 intValue = 65; float
floatValeur = 65.0ÿ; // flottant avec une valeur de 65

Le tableau 4-2 montre ce que vous verrez lorsque vous imprimez des variables à l'aide de routines Arduino.

90 | Chapitre 4 : Communications série


Machine Translated by Google

Tableau 4-2. Formats de sortie à l'aide de Serial.print

Impression Impression Impression Impression Impression Impression

Type de données (val) (val,DEC) (sélectionner, BYTE) (valeur, HEX) (val,OCT) (val, BIN)

carboniser UNE 65 UNE 41 101 1000001

entier 65 65 UNE 41 101 1000001

long Le format de long est le même que int

flotter 65.00 Formatage non pris en charge pour les valeurs à virgule flottante

double 65,00 double est le même que flottant

L'esquisse de cette recette utilise une ligne de code source distincte pour chaque instruction d'impression.
Cela peut rendre les instructions d'impression complexes volumineuses. Par exemple, pour imprimer la ligne suivanteÿ:

A 5 secondes : vitesse = 17, distance = 120

vous devriez généralement le coder comme ceci:

Serial.print("At ");
Serial.print(secondes);
Serial.print(" secondes : speed = ");
Serial.print(vitesse);
Serial.print(", distance = ");
Serial.println(distance);

Cela fait beaucoup de lignes de code pour une seule ligne de sortie. Vous pourriez les combiner comme ceci :

Serial.print("At "); Serial.print(secondes); Serial.print(" secondes, vitesse = ");


Serial.print(vitesse); Serial.print(", distance = ");Serial.println(distance);

Ou vous pouvez utiliser la capacité de style insertion du compilateur utilisé par Arduino pour
mettre en forme vos relevés d'impression. Vous pouvez tirer parti de certaines fonctionnalités C++ avancées (syntaxe
d'insertion de flux et modèles) que vous pouvez utiliser si vous déclarez un
modèle de diffusion en continu dans votre croquis. Ceci est plus facilement réalisé en incluant le
Bibliothèque de streaming développée par Mikal Hart. Vous pouvez en savoir plus sur cette bibliothèque et
téléchargez le code sur le site Web de Mikal.

Si vous utilisez la bibliothèque Streaming, ce qui suit donne le même résultat que les lignes affichées
plus tôt:
" "
Série << "À" << << secondes << secondes, vitesse = << vitesse << ", distance =
"
distanceÿ;

Voir également

Le chapitre 2 fournit plus d'informations sur les types de données utilisés par Arduino. Le site Arduino
référence à http:// arduino.cc/ en/ Reference/ HomePage couvre les commandes série, et
la référence web Arduino à http:// www.arduino.cc/ playground/ Main/ StreamingOut
put couvre la sortie en streaming (de style insertion).

4.2 Envoi de texte formaté et de données numériques depuis Arduino | 91


Machine Translated by Google

4.3 Réception de données série dans Arduino

Problème
Vous souhaitez recevoir des données sur Arduino depuis un ordinateur ou un autre périphérique sérieÿ; par
exemple, pour qu'Arduino réagisse aux commandes ou aux données envoyées depuis votre ordinateur.

Solution
Il est facile de recevoir des valeurs 8 bits (caractères et octets), car les fonctions série utilisent des valeurs 8
bits. Cette esquisse reçoit un chiffre (caractères simples de 0 à 9) et fait clignoter la LED sur la broche 13 à
un rythme proportionnel à la valeur du chiffre reçuÿ:

/*
* Esquisse de réception en série
* Faites clignoter la LED à un rythme proportionnel à la valeur numérique reçue */ const int
ledPin = 13ÿ; // la broche de la LED est connectée à int blinkRate=0ÿ;

// taux de clignotement stocké dans cette variable

void setup()

{ Serial.begin(9600); // Initialise le port série pour envoyer et recevoir à 9600 bauds pinMode(ledPin,
OUTPUT); // définit cette broche comme sortie }

void loop() { if

( Serial.available()) // Vérifie si au moins un caractère est disponible { char ch = Serial.read(); if(ch >= '0' && ch
<= '9') // est-ce un chiffre ascii entre 0 et 9ÿ? {

taux de clignotement = (ch - '0'); taux // valeur ASCII convertie en valeur numérique 100ÿ; // le
de clignotement = taux de clignotement * taux de clignotement réel est de 100 mS fois reçu
chiffre } }

clignotement(); }

// fait clignoter la LED avec les heures d'allumage et d'extinction déterminées par blinkRate
void blink() { digitalWrite(ledPin,HIGH); retard (taux de clignotement); // le délai dépend de
la valeur du taux de clignotement digitalWrite(ledPin,LOW); retard (taux de clignotement); }

Téléchargez l'esquisse et envoyez des messages à l'aide du moniteur série. Ouvrez le moniteur série en
cliquant sur l'icône du moniteur (voir recette 4.1) et tapez un chiffre dans la zone de texte en haut

92 | Chapitre 4 : Communications série


Machine Translated by Google

de la fenêtre du moniteur série. Cliquez sur le bouton Envoyer pour envoyer le caractère saisi dans la
zone de texteÿ; vous devriez voir le taux de clignotement changer.

Discussion
La conversion des caractères ASCII reçus en valeurs numériques peut ne pas être évidente si vous
n'êtes pas familiarisé avec la manière dont l'ASCII représente les caractères. Ce qui suit convertit le
caractère ch en sa valeur numériqueÿ:

taux de clignotement = (ch - '0'); // valeur ASCII convertie en valeur numérique

Cela se fait en soustrayant 48, car 48 est la valeur ASCII du chiffre 0. Par exemple, si ch représente le
caractère 1, sa valeur ASCII est 49. L'expression 49- '0' est la même que 49-48. Ceci est égal à 1, qui
est la valeur numérique du caractère 1.

En d'autres termes, l'expression (ch - '0') est la même que (ch - 48); ceci convertit la valeur ASCII de la
variable ch en une valeur numérique.

Pour avoir une idée plus claire de la relation entre les valeurs ASCII des caractères représentant les
chiffres de 0 à 9 et leurs valeurs numériques réelles, consultez le tableau ASCII à l' annexe G.

La réception de numéros à plusieurs chiffres implique l'accumulation de caractères jusqu'à ce qu'un


caractère qui n'est pas un chiffre valide soit détecté. Le code suivant utilise les mêmes fonctions setup()
et blink() que celles présentées précédemment, mais il obtient des chiffres jusqu'à ce que le caractère
de nouvelle ligne soit reçu. Il utilise la valeur accumulée pour régler le taux de clignotement.

Le caractère de nouvelle ligne (valeur ASCII 10) peut être ajouté automatiquement chaque fois que
vous cliquez sur Envoyer. Le moniteur série comporte une liste déroulante en bas de l'écran du
moniteur série (voir Figure 4-1) ; changez l'option de "Aucune fin de ligne" à "Nouvelle ligne".

Modifiez le code suivi par le code de la boucle . Entrez une valeur telle que 123 dans la zone de texte
Monitor et cliquez sur Send, et le délai de clignotement sera défini sur 123 millisecondesÿ:
valeur entièreÿ;

void loop()

{ if( Serial.available()) { char


ch = Serial.read(); if(ch >=
'0' && ch <= '9') // est-ce un
chiffre ascii entre 0 et 9ÿ? {

valeur = (valeur * 10) + (ch - '0'); // oui, accumule la valeur

} else if (ch == 10) // est le caractère le caractère de saut de ligne {

taux de clignotement = valeurÿ; // définit le taux de clignotement sur la


valeur cumulée Serial.println(blinkRate); valeur = 0ÿ; // réinitialise val à 0
prêt pour la prochaine séquence de chiffres

4.3 Réception de données série dans Arduino | 93


Machine Translated by Google

}}
clignoter(); }

Chaque chiffre est converti de sa valeur ASCII à sa valeur numérique. Comme les nombres sont des
nombres décimaux (base 10), chaque nombre successif est multiplié par 10. Par exemple, la valeur du
nombre 234 est 2 * 100 + 3 * 10 + 4. Le code pour y parvenir est :

if(ch >= '0' && ch <= '9') // est-ce un chiffre ascii entre 0 et 9ÿ? {

valeur = (valeur * 10) + (ch - '0'); // oui, accumule la valeur


}

Si vous souhaitez gérer des nombres négatifs, votre code doit reconnaître le signe moins ('-') . Par exemple:

valeur entière = 0ÿ;


signe entier = 1ÿ;

void loop()

{ if( Serial.available()) { char ch


= Serial.read(); if(ch >= '0'
&& ch <= '9') // est-ce un
chiffre ascii entre 0 et 9ÿ? valeur = (valeur * 10) + (ch - '0'); // oui, accumule la valeur
else if( ch == '-') sign = -1;

sinon // cela suppose que tout caractère n'est pas un chiffre ou un signe moins termine la valeur
{
= value * Serial.println(value);
signer ; // valeur
définit =
la 0ÿ;
valeur
// réinitialise
sur la valeur
la valeur
accumulée
à 0 prêt
value
pour
la prochaine séquence de chiffres sign = 1ÿ;

}}}

Une autre approche pour convertir des chaînes de texte représentant des nombres consiste à utiliser la
fonction de conversion en langage C appelée atoi (pour les variables int ) ou atol (pour les variables longues ).
Ces fonctions aux noms obscurs convertissent une chaîne en entiers ou en entiers longs. Pour les utiliser,
vous devez recevoir et stocker la chaîne entière dans un tableau de caractères avant de pouvoir appeler la
fonction de conversion.

Ce fragment de code termine les chiffres entrants sur tout caractère qui n'est pas un chiffre (ou si le tampon
est plein) :

const int MaxChars = 5ÿ; // une chaîne int contient jusqu'à 5 chiffres et
// se termine par un 0 pour indiquer la fin de la chaîne char
strValue[MaxChars+1]ÿ; // doit être assez grand pour les chiffres et se terminer par null int index = 0ÿ;
// l'index dans le tableau stockant les chiffres reçus

boucle vide ()

94 | Chapitre 4 : Communications série


Machine Translated by Google

{ if( Serial.available()) { char


ch = Serial.read(); if(index
< MaxChars && ch >= '0'
&& ch <= '9'){ strValue[index++] = ch; // ajoute le caractère
ASCII à la chaîneÿ; } autre

{ // ici lorsque le tampon est plein ou sur le premier non-chiffre


strValue[index] = 0ÿ; // termine la chaîne avec un 0//blinkRate
= atoi(strValue); utilise atoi pour
convertir la chaîne en un int index = 0ÿ; } } clignoter(); }

strValue est une chaîne numérique composée de caractères reçus du port série.

Voir la recette 2.6 pour des informations sur les chaînes de caractères.

atoi (abréviation d'ASCII en entier) est une fonction qui convertit une chaîne de caractères en entier (atol
convertit en entier long).

Voir également

Une recherche sur le Web pour «ÿatoiÿ» ou «ÿatolÿ» fournit de nombreuses références à ces fonctions. Voir
également la référence Wikipedia à http:// en.wikipedia.org/ wiki/ Atoi.

4.4 Envoi de plusieurs champs de texte depuis Arduino


dans un seul message

Problème
Vous souhaitez envoyer un message contenant plusieurs informations (champ).
Par exemple, votre message peut contenir des valeurs provenant de deux capteurs ou plus. Vous souhaitez
utiliser ces valeurs dans un programme tel que Processing, exécuté sur votre PC ou Mac.

Solution
Pour ce faire, le moyen le plus simple consiste à envoyer une chaîne de texte avec tous les champs séparés
par un caractère de délimitation (séparateur), tel qu'une virguleÿ:

// Esquisse CommaDelimitedOutput

void setup()

4.4 Envoi de plusieurs champs de texte depuis Arduino dans un seul message | 95
Machine Translated by Google

{ Série.begin(9600); }

void loop()
{ int value1 =
10; valeur int2 = // quelques valeurs codées en dur à envoyer
100ÿ; valeur entière3
= 1000ÿ;

Serial.print('H'); // en-tête unique pour identifier le début du message Serial.print(",");


Serial.print(value1,DEC); Serial.print(","); Serial.print(value2,DEC); Serial.print(",");
Serial.print(value3,DEC); Serial.print(","); // notez qu'une virgule est envoyée
après le dernier champ Serial.println(); // envoie un délai cr/lf(100); }

Voici l'esquisse de traitement qui lit ces données à partir du port sérieÿ:
//CommaDelimitedInput.pde (esquisse de traitement)

import processing.serial.*ÿ;

mon port sérieÿ; // Créer un objet à partir de la classe


char HEADER = 'H'; Serial // caractère pour identifier le début d'un message
LF court = 10ÿ; index // Saut de ligne ASCII
de port court = 0ÿ; // sélectionne le port com, 0 est le premier port

void setup()
{ taille(200, 200);

// ATTENTION!
// Si nécessaire, modifiez la définition de portIndex en haut de cette // esquisse pour le
port série souhaité. // println(Serial.list()); println(" Connexion à -> + Serial.list()[portIndex]);
myPort = new Serial(this,Serial.list()[portIndex], 9600); }

"

void draw() {

void serialEvent(Serial p) { String


message =
myPort.readStringUntil(LF); // lit les données série

96 | Chapitre 4 : Communications série


Machine Translated by Google

if(message != null)
{ print(message);
Chaîne [] données
= message.split(","); // Fractionne le message séparé par des virgules if(data[0].charAt(0)
== HEADER) // vérifie le caractère d'en-tête dans
data.length-1;
le premieri++
champ
) // ignore
{ for( l'en-tête
int i = 1;et
i<
termine cr et lf { int value = Integer.parseInt(data[i]); println("Valeur" + je + + valeur); //
Imprime la valeur de chaque champ } println(); } } }

" = "

Discussion
Le code de la solution de cette recette enverra la chaîne de texte suivante au port série (\r indique un retour chariot
et \n indique un saut de ligne)ÿ:

H10,100,1000,\r\n
Vous devez choisir un caractère de séparation qui n'apparaîtra jamais dans les données réellesÿ; si vos données
ne sont constituées que de valeurs numériques, une virgule est un bon choix de délimiteur. Vous pouvez également
vous assurer que le côté destinataire peut déterminer le début d'un message pour vous assurer qu'il contient toutes
les données pour tous les champs. Pour ce faire, envoyez un caractère d'en-tête pour indiquer le début du message.
Le caractère d'en-tête doit également être unique ; il ne doit apparaître dans aucun des champs de données et il
doit également être différent du caractère de séparation. L'exemple ici utilise un H majuscule pour indiquer le début
du message.
Le message se compose de l'en-tête, de trois valeurs numériques séparées par des virgules sous forme de chaînes
ASCII, ainsi que d'un retour chariot et d'un saut de ligne.

Les caractères de retour chariot et de saut de ligne sont envoyés chaque fois qu'Arduino imprime à l'aide de la
fonction println() , et ceci est utilisé pour aider le côté récepteur à savoir que la chaîne de message complète a été
reçue. Une virgule est envoyée après la dernière valeur numérique pour aider le côté récepteur à détecter la fin de
la valeur.

Le code de traitement lit le message sous forme de chaîne et utilise la méthode Java split() pour créer un tableau à
partir des champs séparés par des virgules.

Dans la plupart des cas, le premier port série sera celui que vous souhaitez lorsque vous utilisez un
Mac et le dernier port série sera celui que vous souhaitez lorsque vous utilisez Windows. L'esquisse
de traitement comprend un code indiquant les ports disponibles et celui actuellement sélectionné.
Vérifiez qu'il s'agit du port connecté à Arduino.

4.4 Envoi de plusieurs champs de texte depuis Arduino dans un seul message | 97
Machine Translated by Google

Voir également

Le site Web Processing fournit plus d'informations sur l'installation et l'utilisation de cet
environnement de programmation. Voir http:// processing.org/.

4.5 Recevoir plusieurs champs de texte dans un seul


message dans Arduino

Problème
Vous souhaitez recevoir un message contenant plusieurs champs. Par exemple, votre message
peut contenir un identifiant pour indiquer un appareil particulier (comme un moteur ou un autre
actionneur) et à quelle valeur (comme la vitesse) le régler.

Solution
Arduino n'a pas la fonction split() utilisée dans le code de traitement de la recette 4.4, mais la
fonctionnalité peut être implémentée comme indiqué dans cette recette. Le code suivant reçoit
un message avec trois champs numériques séparés par des virgules. Il utilise la technique
décrite dans la recette 4.4 pour recevoir des chiffres, et il ajoute du code pour identifier les
champs séparés par des virgules et stocker les valeurs dans un tableauÿ:
/*
* Esquisse SerialReceiveMultipleFields
* Ce code attend un message au format : 12 345 678
* Ce code nécessite un caractère de saut de ligne pour indiquer la fin des données
* Configurez le moniteur série pour envoyer des caractères de saut de
ligne */

const entier NUMBER_OF_FIELDS = 3ÿ; // combien de champs séparés par des virgules
nous attendons int fieldIndex = 0; // levalues[NUMBER_OF_FIELDS]ÿ;
champ actuel étant reçu int // tableau contenant
les valeurs de tous les champs

void setup()

{ Serial.begin(9600); // Initialise le port série pour envoyer et recevoir à 9600 bauds }

void loop()

{ if( Serial.available()) { char


ch = Serial.read(); if(ch >=
'0' && ch <= '9') // est-ce un
chiffre ascii entre 0 et 9ÿ? { // oui, accumule la valeur values[fieldIndex] =
(values[fieldIndex] * 10) + (ch - '0'); }

98 | Chapitre 4 : Communications série


Machine Translated by Google

else if (ch == ',') // la virgule est notre séparateur, alors passez au champ suivant { if(fieldIndex
< NUMBER_OF_FIELDS-1)

fieldIndex++ÿ; // incrémente l'index du champ

}
else
{ // tout caractère autre qu'un chiffre ou une virgule termine l'acquisition des champs //
dans cet exemple, c'est le caractère de saut de ligne envoyé par le Serial Monitor
Serial.print( fieldIndex +1); Serial.println("ÿchamps reçusÿ:"ÿ); for(int i=0; i <= fieldIndex;
i++) { Serial.println(values[i]); valeurs[i] = 0ÿ; // met les valeurs à zéro, prêt pour le
prochain message } fieldIndex = 0; // prêt à recommencer } } }

Discussion
Cette esquisse accumule des valeurs (comme expliqué dans la recette 4.3), mais ici chaque valeur est
ajoutée à un tableau (qui doit être suffisamment grand pour contenir tous les champs) lorsqu'une
virgule est reçue. Un caractère autre qu'un chiffre ou une virgule (comme le caractère de retour à la
ligne ; voir la recette 4.3) déclenche l'impression de toutes les valeurs qui ont été stockées dans le tableau.

Une autre approche consiste à utiliser une bibliothèque appelée TextFinder, disponible sur Arduino
Playground ou sur le site Web de ce livre. TextFinder a été créé pour extraire des informations de flux
Web (voir chapitre 15), mais il fonctionne aussi bien avec des données série. L'esquisse suivante
utilise TextFinder pour fournir des fonctionnalités similaires à l'esquisse précédenteÿ:

#include <TextFinder.h>

Finder TextFinder (série);

const entier NUMBER_OF_FIELDS = 3ÿ; // combien de champs séparés par des virgules
nous attendons int fieldIndex = 0; // le champ actuel étant reçu int
values[NUMBER_OF_FIELDS]ÿ; // tableau contenant
les valeurs de tous les champs

void setup()

{ Serial.begin(9600); // Initialise le port série pour envoyer et recevoir à 9600 bauds }

boucle vide()
{

for(fieldIndex = 0; fieldIndex < 3; fieldIndex ++) { values[fieldIndex]


= finder.getValue(); // récupère une valeur numérique

4.5 Réception de plusieurs champs de texte dans un seul message dans Arduino | 99
Machine Translated by Google

}
Serial.print( fieldIndex);
Serial.println("ÿchamps reçusÿ:"ÿ);
for(int i=0; i < fieldIndex; i++) {

Serial.println(values[i]);

} fieldIndex = 0ÿ; // prêt à recommencer }

Vous pouvez télécharger la bibliothèque TextFinder depuis http:// www.arduino.cc/ playground/ Code/
TextFinder.

Voici un résumé des méthodes supportées par TextFinder (toutes ne sont pas utilisées dans l'exemple
précédent) : boolean find(char *target);

Lit à partir du flux jusqu'à ce que la cible donnée soit trouvée. Elle renvoie true si la chaîne cible est
trouvée. Un retour de false signifie que les données n'ont été trouvées nulle part dans le flux et qu'il
n'y a plus de données disponibles. Notez que TextFinder effectue un seul passage dans le fluxÿ; il n'y
a aucun moyen de revenir en arrière pour essayer de trouver ou d'obtenir autre chose (voir la méthode
findUntil ). boolean findUntil(char *target, char *terminate);

Similaire à la méthode find , mais la recherche s'arrêtera si la chaîne de terminaison est trouvée.
Renvoie vrai uniquement si la cible est trouvée. Ceci est utile pour arrêter une recherche sur un mot-
clé ou un terminateur. Par exemple:

finder.findUntil("cible", "\n");

essaiera de rechercher la chaîne "valeur", mais s'arrêtera à un caractère de nouvelle ligne afin que
votre croquis puisse faire autre chose si la cible n'est pas trouvée. long getValue(); Renvoie la
première valeur entière valide (longue). Les caractères de début qui ne sont pas des chiffres ou un signe
moins sont ignorés. L'entier se termine par le premier caractère non numérique suivant le nombre. Si
aucun chiffre n'est trouvé, la fonction renvoie 0.

long getValue(char skipChar);


Identique à getValue, mais le skipChar donné dans la valeur numérique est ignoré. Cela
peut être utile lors de l'analyse d'une seule valeur numérique qui utilise une virgule entre
des blocs de chiffres en grand nombre, mais gardez à l'esprit que les valeurs de texte
formatées avec des virgules ne peuvent pas être analysées comme une chaîne séparée par
des virgules. float getFloat(); La version flottante de getValue. int getString(char *pre_string,char
*post_string,char *buf,int length);

Trouve la pre_string puis place les caractères entrants dans le tampon donné jusqu'à ce que la
post_string soit détectée. La fin de la chaîne est déterminée par une correspondance d'un caractère
avec le premier caractère post_string. Chaînes plus longues que la longueur donnée

100 | Chapitre 4 : Communications série


Machine Translated by Google

sont tronqués pour s'adapter. La fonction renvoie le nombre de caractères placés dans le tampon
(0 signifie qu'aucune donnée valide n'a été trouvée).

Voir également

Le chapitre 15 fournit d'autres exemples de TextFinder utilisé pour rechercher et extraire des données de
un courant.

4.6 Envoi de données binaires depuis Arduino

Problème
Vous devez envoyer des données au format binaire, car vous souhaitez transmettre des informations
avec le moins d'octets possible ou parce que l'application à laquelle vous vous connectez ne gère que
des données binaires.

Solution
Cette esquisse envoie un en-tête suivi de deux valeurs entières (16 bits) sous forme de données binaires.
Les valeurs sont générées à l'aide de la fonction aléatoire Arduino (voir recette 3.11) :
/*
* Esquisse SendBinary *
Envoie un en-tête suivi de deux valeurs entières aléatoires sous forme de données binaires.
*/

int intValueÿ; // une valeur entière (16 bits)

void setup()

{ Serial.begin(9600); }

void loop()

{ Serial.print('H'); // envoie un caractère d'en-tête

// envoie un entier aléatoire


intValue = random(599); // génère un nombre aléatoire entre 0 et 599 // envoie les deux
octets qui composent un entier Serial.print(lowByte(intValue), BYTE); // envoie l'octet de
poids faible Serial.print(highByte(intValue), BYTE); // envoie l'octet de poids fort

// envoie un autre entier aléatoire


intValue = random(599); // génère un nombre aléatoire entre 0 et 599 // envoie les deux
octets qui composent un entier Serial.print(lowByte(intValue), BYTE); // envoie l'octet de
poids faible Serial.print(highByte(intValue), BYTE); // envoie l'octet de poids fort

retard(1000); }

4.6 Envoi de données binaires depuis Arduino | 101


Machine Translated by Google

Discussion
L'envoi de données binaires nécessite une planification minutieuse, car vous obtiendrez du charabia à moins que
le côté émetteur et le côté récepteur ne comprennent et ne conviennent exactement de la manière dont les données
seront envoyées. Contrairement aux données textuelles, où la fin d'un message peut être déterminée par la
présence du retour chariot de fin (ou d'un autre caractère unique que vous choisissez), il peut ne pas être possible
de dire quand un message binaire commence ou se termine en regardant simplement les données — les données
qui peuvent avoir n'importe quelle valeur peuvent donc avoir la valeur d'un caractère d'en-tête ou de fin.

Cela peut être surmonté en concevant vos messages de manière à ce que les côtés expéditeur et destinataire
sachent exactement combien d'octets sont attendus. La fin d'un message est déterminée par le nombre d'octets
envoyés plutôt que par la détection d'un caractère spécifique. Cela peut être implémenté en envoyant une valeur
initiale pour dire combien d'octets suivront. Ou vous pouvez fixer la taille du message afin qu'il soit suffisamment
grand pour contenir les données que vous souhaitez envoyer.
Faire l'un ou l'autre n'est pas toujours facile, car différentes plates-formes et langages peuvent utiliser différentes
tailles pour les types de données binaires - le nombre d'octets et leur ordre peuvent être différents d'Arduino. Par
exemple, Arduino définit un int comme deux octets, mais Processing (Java) définit un int comme quatre octets
(court est le type Java pour un entier 16 bits).
L'envoi d'une valeur int sous forme de texte (comme on le voit dans les recettes de texte précédentes) simplifie ce
problème car chaque chiffre individuel est envoyé sous forme de chiffre séquentiel (tout comme le nombre est écrit).
Le côté réception reconnaît quand la valeur a été complètement reçue par un retour chariot ou un autre délimiteur
non numérique. Les transferts binaires ne peuvent connaître la composition d'un message que si celle-ci est définie
à l'avance ou spécifiée dans le message.

La solution de cette recette nécessite une compréhension des types de données sur les plates-formes d'envoi et
de réception et une planification minutieuse. La recette 4.7 montre un exemple de code utilisant le langage de
traitement pour recevoir ces messages.

L'envoi d'octets simples est facile ; utilisez Serial.print(byteVal). Pour envoyer un entier depuis Arduino, vous devez
envoyer les octets bas et haut qui composent l'entier (voir la recette 2.2 pour plus d'informations sur les types de
données). Pour ce faire, utilisez les fonctions lowByte et highByte (voir recette 3.14) :

Serial.print(lowByte(intValue), BYTE);
Serial.print(highByte(intValue), BYTE);

Le code précédent envoie l'octet de poids faible suivi de l'octet de poids fort. Le code peut également être écrit
sans le paramètre BYTE (voir recette 4.2), mais l'utilisation du paramètre est un rappel utile (lorsque vous revenez
plus tard pour apporter des modifications, ou pour d'autres personnes susceptibles de lire votre code) que votre
intention est d'envoyer des octets plutôt que des caractères ASCII.

L'envoi d'un entier long se fait en décomposant les quatre octets qui composent un long en deux étapes. Le long
est d'abord divisé en deux entiers de 16 bits; chacun est ensuite envoyé en utilisant la méthode d'envoi d'entiers
décrite précédemmentÿ:

int valeur longue =


1000ÿ; int intValueÿ;

102 | Chapitre 4 : Communications série


Machine Translated by Google

Vous envoyez d'abord la valeur entière inférieure de 16ÿbitsÿ:

intValue = longValue && 0xFFFF; // récupère la valeur des 16 bits inférieurs


Serial.print(lowByte(intVal), BYTE); Serial.print(highByte(intVal), BYTE);

Ensuite, vous envoyez la valeur entière 16ÿbits la plus élevéeÿ:

intValue = longValue >> 16ÿ; // récupère la valeur des 16 bits supérieurs


Serial.print(lowByte(intVal), BYTE); Serial.print(highByte(intVal), BYTE);

Vous pouvez trouver pratique de créer des fonctions pour envoyer les données. Voici une fonction qui utilise le code
présenté précédemment pour imprimer un entier 16 bits sur le port sérieÿ:

// fonction pour envoyer la valeur entière donnée au port série void


sendBinary(int value) { // envoie les deux octets qui composent un
entier de deux octets (16 bits) Serial.print(lowByte(value), BYTE); //
envoie l'octet de poids faible Serial.print(highByte(value), BYTE); //
envoie l'octet de poids fort }

La fonction suivante envoie la valeur d'un entier long (4ÿoctets) en envoyant d'abord les deuxÿoctets de poids faible
(les plus à droite), suivis des octets de poids fort (les plus à gauche)ÿ:

// fonction pour envoyer la valeur entière donnée au port série void


sendBinary(long value) { // envoyer d'abord la valeur entière 16 bits int temp
= value && 0xFFFF; // récupère la valeur des 16 bits inférieurs
sendBinary(temp); // envoie ensuite la valeur entière 16ÿbits la plus
élevéeÿ: temp = valeur >> 16ÿ; // récupère la valeur des 16 bits supérieurs
sendBinary(temp); }

Ces fonctions d'envoi de valeurs binaires int et long portent le même nom : sendBinary.
Le compilateur les distingue par le type de valeur que vous utilisez pour le paramètre. Si votre code appelle printBinary
avec une valeur de 2 octets, la version déclarée comme void sendBinary(int value) sera appelée. Si le paramètre est
une valeur longue , la version déclarée comme void sendBinary(long value) sera appelée. Ce comportement est
appelé surcharge de fonction.
La recette 4.2 en fournit une autre illustration ; les différentes fonctionnalités que vous avez vues dans Serial.print sont
dues au fait que le compilateur distingue les différents types de variables utilisés.

Vous pouvez également envoyer des données binaires à l'aide de structures. Les structures sont un mécanisme
d'organisation des données, et si vous n'êtes pas déjà familiarisé avec leur utilisation, vous feriez peut-être mieux de
vous en tenir aux solutions décrites précédemment. Pour ceux qui sont à l'aise avec le concept des pointeurs de
structure, voici une fonction qui enverra les octets d'une structure au port série sous forme de données binairesÿ:

void sendStructure( char *structurePointer, int structureLength) {

int jeÿ;

4.6 Envoi de données binaires depuis Arduino | 103


Machine Translated by Google

pour (i = 0 ; i < structureLength ; i++)


serial.print(structurePointer[i], BYTE); }

sendStructure((char *)&myStruct, sizeof(myStruct));


L'envoi de données sous forme d'octets binaires est plus efficace que l'envoi de données sous forme de texte, mais
cela ne fonctionnera de manière fiable que si les côtés émetteur et récepteur s'accordent exactement sur la
composition des données. Voici un résumé des choses importantes à vérifier lors de l'écriture de votre codeÿ:

Taille variable

Assurez-vous que la taille des données envoyées est la même des deux côtés. Un entier est de 2 octets sur
Arduino, 4 octets sur la plupart des autres plates-formes. Vérifiez toujours la documentation de votre langage
de programmation sur la taille du type de données pour vous assurer de la concordance. Il n'y a aucun problème
à recevoir un entier Arduino de 2 octets en tant qu'entier de 4 octets dans Processing tant que Processing
s'attend à n'obtenir que deux octets. Mais assurez-vous que le côté envoi n'utilise pas de valeurs qui débordent
le type utilisé par le côté réception.

Ordre des
octets Assurez-vous que les octets dans un int ou un long sont envoyés dans le même ordre attendu par le côté
récepteur.

Synchronisation
Assurez-vous que votre destinataire peut reconnaître le début et la fin d'un message.
Si vous commencez à écouter au milieu d'un flux de transmission, vous n'obtiendrez pas de données valides.
Cela peut être réalisé en envoyant une séquence d'octets qui n'apparaîtront pas dans le corps d'un message.
Par exemple, si vous envoyez des valeurs binaires à partir de la lecture analogique, celles- ci ne peuvent aller
que de 0 à 1 023, de sorte que l'octet le plus significatif doit être inférieur à 4 (la valeur int de 1 023 est stockée
dans les octets 3 et 255) ; par conséquent, il n'y aura jamais de données avec deux octets consécutifs supérieurs
à 3. Ainsi, l'envoi de deux octets de 4 (ou toute valeur supérieure à 3) ne peut pas être une donnée valide et
peut être utilisé pour indiquer le début ou la fin d'un message.

Emballage de structure
Si vous envoyez ou recevez des données sous forme de structures, vérifiez la documentation de votre
compilateur pour vous assurer que l' emballage est le même des deux côtés. L'emballage est le rembourrage
qu'un compilateur utilise pour aligner des éléments de données de différentes tailles dans une structure.
Contrôle de flux

Soit choisissez une vitesse de transmission qui garantit que le côté récepteur peut suivre le côté émetteur, soit
utilisez une sorte de contrôle de flux. Le contrôle de flux est une poignée de main qui indique au côté émetteur
que le récepteur est prêt à recevoir plus de données.

Voir également

Le chapitre 2 fournit plus d'informations sur les types de variables utilisés dans les croquis Arduino.

Vérifiez également les références Arduino pour lowByte sur http:// www.arduino.cc/ en/ Reference/ LowByte et highByte
sur http:// www.arduino.cc/ en/ Reference/ HighByte.

104 | Chapitre 4 : Communications série


Machine Translated by Google

Le compilateur Arduino regroupe les structures sur les limites d'octetsÿ; consultez la documentation du compilateur que vous
utilisez sur votre ordinateur pour le configurer pour le même emballage. Si vous ne savez pas comment procéder, vous voudrez
peut-être éviter d'utiliser des structures pour envoyer des données.

Pour plus d'informations sur le contrôle de flux, voir http:// en.wikipedia.org/ wiki/ Flow_control.

4.7 Recevoir des données binaires d'Arduino sur un ordinateur

Problème
Vous souhaitez répondre aux données binaires envoyées par Arduino dans un langage de programmation tel que Processing.
Par exemple, vous souhaitez répondre aux messages Arduino envoyés dans la recette 4.6.

Solution
La solution de cette recette dépend de l'environnement de programmation que vous utilisez sur votre PC ou Mac. Si vous n'avez
pas encore d'outil de programmation préféré et que vous en voulez un qui soit facile à apprendre et qui fonctionne bien avec
Arduino, Processing est un excellent choix.

Voici les deux lignes de code Processing pour lire un octet, tirées de l'exemple Processing SimpleRead (voir l'introduction de ce
chapitre ) :

if ( myPort.available() > 0) { // Si les données sont disponibles, //


val = monPort.read (); les lisent et les stockent dans val

Comme vous pouvez le voir, cela ressemble beaucoup au code Arduino que vous avez vu dans les recettes précédentes.

Voici une esquisse de traitement qui définit la taille d'un rectangle proportionnellement aux valeurs entières reçues de l'esquisse
Arduino dans la recette 4.6 :

/*
*
ReceiveBinaryData_P
*
* portIndex doit être défini sur le port connecté à l'Arduino */ import
processing.serial.*;

mon port sérieÿ; // Créer un objet à partir de la classe


Serial short portIndex = 1ÿ; // sélectionne le port com, 0 est le premier port

char HEADER = 'H';


int valeur1, valeur2ÿ; // Données reçues du port série

void setup()
{ taille(600,
600); // Ouvrez
n'importe quel port série connecté à Arduino.
String nom_port = Serial.list()[portIndex]ÿ;
println(Serial.list()); println(" Connexion
" à ->
myPort = new Serial(this, portName, + Serial.list()[portIndex]);
9600);

4.7 Recevoir des données binaires d'Arduino sur un ordinateur | 105


Machine Translated by Google

void draw()
{ // lit l'en-
tête et deux entiers binaires *(16 bits) : if ( myPort.available()
>= 5) // Si au moins 5 octets sont disponibles, { if( myPort.read() = = HEADER) //
est-ce l'en-tête { value1 = myPort.read(); valeur1 = myPort.read() * 256 +
valeur1ÿ; // ajoute l'octet de poids fort

// lit l'octet le moins significatif

valeur2 = monPort.read(); // lit l'octet le moins significatif


valeur2 = myPort.read() * 256 + valeur2ÿ; // ajoute l'octet de poids fort
"
println("Message reçu : } } + valeur1 + "," + valeur2);
background(255); fill(0);

// Définir l'arrière-plan sur blanc //


Définir le remplissage sur noir
// dessine un rectangle avec des coordonnées basées sur les entiers reçus d'Arduino
rect(0, 0, valeur1, valeur2); }

Discussion
Le langage de traitement a influencé Arduino, et les deux sont intentionnellement similaires. La fonction
de configuration dans Processing est utilisée pour gérer une initialisation unique, tout comme dans
Arduino. Le traitement a une fenêtre d'affichage et le programme d'installation définit sa taille sur 600 ×
600 pixels avec l'appel à size(600,600).

La ligne String portName = Serial.list()[portIndex]ÿ; sélectionne le port série — dans Processing, tous
les ports série disponibles sont contenus dans l' objet Serial.list et cet exemple utilise la valeur d'une
variable appelée portIndex. println(Serial.list()) imprime tous les ports disponibles, et la ligne myPort =
new Serial(this, portName, 9600); ouvre le port sélectionné comme portName. Assurez-vous de définir
portIndex sur le port série connecté à votre Arduino.

La fonction de dessin dans Processing fonctionne comme une boucle dans Arduinoÿ; il est appelé à
plusieurs reprises. Le code dans draw vérifie si les données sont disponibles sur le port série ; si tel est le
cas, les octets sont lus et convertis en la valeur entière représentée par les octets. Un rectangle est dessiné
sur la base des valeurs entières reçues.

Voir également

Vous pouvez en savoir plus sur le traitement sur le site Web de traitement.

106 | Chapitre 4 : Communications série


Machine Translated by Google

4.8 Envoi de valeurs binaires du traitement à Arduino


Problème
Vous souhaitez envoyer des octets binaires, des entiers ou des valeurs longues de Processing à Arduino.
Par exemple, vous souhaitez envoyer un message composé d'un identifiant de message "balise", d'un
index (indiquant peut-être un périphérique particulier connecté à Arduino) et d'une valeur 16 bits.

Solution
Utilisez ce codeÿ:

/* Langage
*
SendingBinaryToArduino :
Traitement */ import
processing.serial.*;

mon port sérieÿ; // Créer un objet à partir de la classe Serial public


static final char HEADER = '|'; public static final char SOURIS =
'M';

void setup()
{ taille(200,
400); Chaîne
nom_port = Serial.list()[0]ÿ; myPort = new
Serial(this, portName, 9600); }

annuler draw()
{}

void serialEvent(Serial p) {
// traite les données série entrantes
String inString = myPort.readStringUntil('\n'); if(inString != null)
{ println( inString );
// écho de la chaîne de texte d'Arduino

}}

Lorsque la souris est cliqué dans la fenêtre de traitement, sendMessage sera appelé avec un index égal à
la position verticale de la souris dans la fenêtre lorsqu'il est cliqué et une valeur égale à la position
horizontale. La taille de la fenêtre a été définie sur 200 400, donc l' index tient dans un seul octet et la
valeur tient dans deux octetsÿ:
void mousePressed() { int
index = mouseY; valeur
int = sourisXÿ;
sendMessage(MOUSE, index, value); }

4.8 Envoi de valeurs binaires du traitement à Arduino | 107


Machine Translated by Google

sendMessage envoie un en-tête, une balise et un index sous forme d'octets uniques. Il envoie la valeur sous la
forme de deux octets, l'octet le plus significatif en premierÿ:

void sendMessage(char tag, int index, int value){


// envoie l'index et la valeur donnés au port série
myPort.write(HEADER); monPort.write(tag);
monPort.write(index); car c = (char)(valeur / 256); // msb
monPort.write(c); c = (char)(valeur & 0xff); // lsb
monPort.write(c); }

Le code Arduino pour recevoir ceci et renvoyer les résultats au traitement estÿ:

//BinaryDataFromProcessing

Les trois définitions suivantes doivent refléter les définitions utilisées dans le programme d'envoiÿ:
#define HEADER '|'
#define MOUSE 'M'
#define MESSAGE_BYTES 5 // le nombre total d'octets dans un message

void setup()

{ Serial.begin(9600); }

boucle vide(){

La vérification pour s'assurer qu'au moins MESSAGE_BYTES ont été reçus garantit que nous n'essayons
pas de traiter le message tant que toutes les données requises ne sont pas disponiblesÿ: if
( Serial.available() >= MESSAGE_BYTES) {

Ne lisez le reste du message que si un en-tête valide a été reçuÿ: if( Serial.read() ==
HEADER) { char tag = Serial.read(); if(tag == MOUSE) { int index =
Serial.read(); // ceci a été envoyé en tant que char mais c'est correct de
l'utiliser comme int

Les lignes suivantes reconvertissent les deux octets en entier. Serial.read() * 256; restaure l'octet de poids
fort à sa valeur d'origine. Comparez cela au code de traitement qui a envoyé les deux octets comprenant
la valeur : int val = Serial.read() * 256; val = val + Serial.read(); Serial.print("Msg souris reçu, index = ");
Serial.print(index); Serial.print(", valeur ");

108 | Chapitre 4 : Communications série


Machine Translated by Google

Serial.println(val); } autre

Si le code arrive ici, la balise n'a pas été reconnue. Cela vous aide à ignorer les données qui peuvent
être incomplètes ou corrompuesÿ:
Serial.print("reçu un message avec une balise inconnue
"); Serial.println(balise); } } } }

Discussion
Ce code est similaire au code de traitement dans les recettes précédentes, avec l'ajout d'une fonction
appelée sendMessage. Dans cet exemple, la fonction est appelée avec trois paramètres : une balise, un
index et une valeur. La fonction envoie d'abord le caractère d'en-tête pour identifier le début du message.
Ensuite, l'index à un seul octet est envoyé, suivi des deux octets qui composent la valeur entière. Vous
pouvez créer votre propre version de cette fonction pour envoyer la combinaison de valeurs dont vous
avez besoin pour votre application.

4.9 Envoi de la valeur de plusieurs broches Arduino

Problème
Vous souhaitez envoyer des groupes d'octets binaires, d'entiers ou de valeurs longues depuis Arduino.
Par exemple, vous pouvez envoyer les valeurs des broches numériques et analogiques au traitement.

Solution
Cette recette envoie un en-tête suivi d'un entier contenant les valeurs de bit des broches numériques 2 à
13. Ceci est suivi de six entiers contenant les valeurs des broches analogiques 0 à 5. Le chapitre 5
contient de nombreuses recettes qui définissent des valeurs sur les broches analogiques et numériques.
que vous pouvez utiliser pour tester ce sketchÿ:
/*
*ÿEnvoyer les champs binaires
* Envoie des valeurs de broches numériques et analogiques sous forme de données binaires
*/

const char HEADER = 'H'; // un seul caractère d'en-tête pour indiquer le début d'un message //
ce sont les valeurs qui seront envoyées au format binaire

void setup()

{ Serial.begin(9600);
for(int i=2; i <= 13; i++)

4.9 Envoi de la valeur de plusieurs broches Arduino | 109


Machine Translated by Google

{ pinMode(i, INPUT); // définit les broches 2 à 13 sur les entrées


digitalWrite(i, HIGH); // active les tractions } }

void loop()

{ Serial.print(HEADER,BYTE); // envoie l'en-tête //


place les valeurs binaires des broches dans un entier
int values = 0; entier bit = 0ÿ; for(int i=2; i <= 13; i++)
{ bitWrite(values, bit, digitalRead(i)); // définit le bit sur
0 ou 1 en fonction // de la valeur de la broche donnée //
incrémente au bit suivant

bit = bit + 1ÿ; }

sendBinary(valeurs); // envoie l'entier

for(int i=0; i < 6; i++)


{ valeurs = analogRead(i);
sendBinary(valeurs); //
envoie l'entier } delay(1000); //envoi toutes
les secondes }

// fonction pour envoyer la valeur entière donnée au port série void


sendBinary( int value) { // envoyer les deux octets qui composent un
entier Serial.print(lowByte(value), BYTE); // envoie l'octet de poids
faible Serial.print(highByte(value), BYTE); // envoie l'octet de poids
fort }

Discussion
Le code envoie un en-tête (le caractère H), suivi d'un entier contenant les valeurs numériques de la broche à
l'aide de la fonction bitRead pour définir un seul bit dans l'entier correspondant à la valeur de la broche (voir
Chapitre 3). Il envoie ensuite six entiers contenant les valeurs lues sur les six ports analogiques (voir le chapitre
5 pour plus d'informations). Toutes les valeurs entières sont envoyées en utilisant sendBinary, introduit dans la
recette 4.6. Le message a une longueur de 15 octets : 1 octet pour l'en-tête, 2 octets pour les valeurs de broches
numériques et 12 octets pour les six entiers analogiques. Le code des entrées numériques et analogiques est
expliqué au chapitre 5.

En supposant que les broches analogiques ont des valeurs de 0 sur la broche 0, 100 sur la broche 1 et 200 sur la
broche 2 à 500 sur la broche 5, et que les broches numériques 2 à 7 sont hautes et 8 à 13 sont basses, il s'agit
de la valeur décimale de chaque octet. qui est envoyéÿ:

72 // le caractère 'H' - c'est l'en-tête // deux octets


de poids faible contenant des bits représentant les broches 2-13
63 // binaire 00111111 : cela indique que les broches 2-7 sont hautes

110 | Chapitre 4 : Communications série


Machine Translated by Google

0 // cela indique que 8-13 sont faibles

// deux octets pour chaque broche représentant la valeur analogique // la


0 broche 0 a une valeur entière de 0 donc elle est envoyée sous la forme de deux octets
0

100 // la broche 1 a une valeur de 100, envoyée sous la forme d'un octet de 100 et d'un octet de 0
0
...
// la broche 5 a une valeur de 500
244 // le reste en divisant 500 par 256
1 // le nombre de fois 500 peut être divisé par 256

Ce code de traitement lit ce message et imprime les valeurs sur la console de traitementÿ:
/*
* ReceiveMultipleFieldsBinary_P
*

* portIndex doit être défini sur le port connecté à l'Arduino */

import processing.serial.*ÿ;

mon port sérieÿ; // Créer un objet à partir de la classe Serial


index de port court = 0ÿ; // sélectionne le port com, 0 est le premier port

char HEADER = 'H';

void setup()
{ taille(200,
200); // Ouvrez
n'importe quel port série connecté à Arduino.
String nom_port = Serial.list()[portIndex]ÿ;
println(Serial.list()); println(" Connexion à -> myPort =
"
new Serial(this, portName, 9600); } + Serial.list()[portIndex]);

void draw()
{ int val;

if ( myPort.available() >= 15) // attend que le message entier arrive { if( myPort.read() ==
HEADER) // est-ce l'en-tête { println("Message reçuÿ:"); // en-tête trouvé // récupère l'entier
contenant les valeurs de bit val = readArduinoInt(); // imprime la valeur de chaque bit for(int
pin=2, bit=1; pin <= 13; pin++){ print("digital pin + pin + int isSet = (val & bit); if( isSet == 0 )
println("0");

" " =
" );

4.9 Envoi de la valeur de plusieurs broches Arduino | 111


Machine Translated by Google

autre
println("1"); 2ÿ; //
bit = bit * décale le bit

} println(); //
imprime les six valeurs analogiques
for(int i=0; i < 6; i ++){ val =
readArduinoInt(); println("port
"
analogique + je + "= " } println("----"); } } } + heures);

// renvoie la valeur entière des octets reçus sur le port série (en ordre bas, haut) int readArduinoInt() {

valeur entièreÿ; // Données reçues du port série

val = monPort.read(); // lit l'octet le moins significatif val = myPort.read() * 256 + val; //
ajoute la valeur de retour de l'octet le plus significatifÿ; }

Le code de traitement attend l'arrivée de 15 caractères. Si le premier caractère est l'en-tête, il


appelle ensuite la fonction nommée readArduinoInt pour lire deux octets et les retransformer en
un entier en effectuant l'opération mathématique complémentaire effectuée par Arduino pour
obtenir les bits individuels représentant les broches numériques. Les six nombres entiers
représentent alors les valeurs analogiques.

Voir également

Pour renvoyer les valeurs Arduino à l'ordinateur ou piloter les broches depuis l'ordinateur (sans
prendre de décisions sur la carte), pensez à utiliser Firmata (http:// www.firmata.org). La
bibliothèque Firmata est incluse dans le logiciel Arduino, et une bibliothèque est disponible pour
être utilisée dans le traitement. Vous chargez le code Firmata sur Arduino, contrôlez si les broches
sont des entrées ou des sorties de l'ordinateur, puis définissez ou lisez ces broches.

4.10 Comment déplacer le curseur de la souris sur un PC ou un Mac

Problème

Vous voulez qu'Arduino interagisse avec une application sur votre ordinateur en déplaçant le
curseur de la souris. Vous souhaitez peut-être déplacer la position de la souris en réponse aux
informations Arduino. Par exemple, supposons que vous ayez connecté un nunchuck Wii (voir
recette 13.2) à votre Arduino et que vous souhaitiez que vos mouvements de la main contrôlent
la position du curseur de la souris dans un programme exécuté sur un PC.

112 | Chapitre 4 : Communications série


Machine Translated by Google

Solution
Vous pouvez envoyer des commandes série contenant la position du curseur de la souris à un
programme exécuté sur l'ordinateur cible. Voici un croquis qui déplace le curseur de la souris en
fonction de la position de deux potentiomètresÿ:
// Esquisse SerialMouse
#define potXPin 4
#define potYPin 5

void setup()

{ Serial.begin(9600); }

void loop()
{ int x =
analogRead(potXPin); int y =
analogRead(potYPin);
Serial.print(x,DEC);
Serial.print(",");
Serial.print(y,DEC);
Serial.println(); // envoie un cr/lf
delay(50); // envoie la position 20 fois par seconde }

La figure 4-3 illustre le câblage de deux potentiomètres (voir le chapitre 5 pour plus de détails).

Illustration 4-3. Câblage pour deux potentiomètres

4.10 Comment déplacer le curseur de la souris sur un PC ou un Mac | 113


Machine Translated by Google

Le code de traitement est basé sur le code présenté dans la recetteÿ4.4ÿ:


/*
* ArduinoMouse.pde (Esquisse de traitement) */

/* ATTENTION : Ce sketch prend le dessus sur votre souris


Appuyez sur Échap pour fermer l'esquisse en cours d'exécution */

import processing.serial.*ÿ;

mon port sérieÿ; // Créer un objet à partir de la classe Serial //


Robot monRobotÿ; créer un objet à partir de la classe Robotÿ;

public static final char HEADER = 'M'; un message // caractère pour identifier le début de

// Saut de=ligne
public static final short LF = 10; public static final short portIndex 1; // ASCII
sélectionne le port com, 0 est le premier port

void setup()
{ taille(200, 200);
println(Serial.list()); println("
"
Connexion à -> + Serial.list()[portIndex]); myPort = new Serial(this,Serial.list()
[portIndex], 9600); try { myRobot = new Robot(); // the Robot la classe
donne accès à la souris } catch (AWTException e) { // c'est le gestionnaire
d'exception Java e.printStackTrace(); } }

void draw() {

void serialEvent(Serial p) {
Message de chaîne = myPort.readStringUntil(LF); // lit les données série if(message !
= null) { print(message); Chaîne [] données = message.split(","); // Fractionne le
message séparé par des virgules if(data[0].charAt(0) == HEADER) // vérifie le
caractère d'en-tête dans le premier champ { if( data.length > 3) { int x =
Integer.parseInt( données[1]); int y = Integer.parseInt(data[2]); print("x= " + x); println(", y= + y);
myRobot.mouseMove(x,y); // déplace la souris vers la position x et y reçue } }

"

114 | Chapitre 4 : Communications série


Machine Translated by Google

}}

Le code de traitement fractionne le message contenant les coordonnées x et y et les envoie à la méthode
mouseMove de la classe Java Robot .

Discussion
Cette technique de contrôle des applications s'exécutant sur votre ordinateur est facile à mettre en œuvre et
devrait fonctionner avec n'importe quel système d'exploitation capable d'exécuter l'application de traitement.

Certaines plates-formes nécessitent des privilèges spéciaux ou des extensions pour


accéder au contrôle d'entrée de bas niveau. Si vous ne parvenez pas à contrôler la souris,
consultez la documentation de votre système d'exploitation.

Si vous avez besoin qu'Arduino apparaisse comme s'il s'agissait d'une souris sur l'ordinateur, vous devez
émuler le protocole USB utilisé par les vraies souris. Ce protocole, pour les dispositifs d'interface humaine
(HID), est complexe, mais Phillip Lindsay a des informations et du code utiles sur http:// code.google.com/ p/
vusb-for-arduino/.

Un objet Robot en fuite a la capacité de supprimer votre contrôle sur la souris et le clavier
s'il est utilisé dans une boucle sans fin.

Voir également

Accédez à http:// java.sun.com/ j2se/ 1.3/ docs/ api/ java/ awt/ Robot.html pour plus d'informations sur la classe
Java Robot .

Un article sur l'utilisation de la classe Robot est disponible sur http:// www.developer.com/ java/ other/ article.php/
10936_2212401_1.

Si vous préférez utiliser un langage de programmation Windows, la fonction API Windows de bas niveau
permettant d'insérer des événements de clavier et de souris dans le flux d'entrée est appelée SendInput. Vous
pouvez visiter http:// msdn.microsoft.com/ en-us/ library/ ms646310(VS.85) .aspx pour plus d'informations.

4.11 Contrôler Google Earth à l'aide d'Arduino


Problème
Vous souhaitez contrôler le mouvement dans une application telle que Google Earth à l'aide de capteurs
connectés à Arduino. Par exemple, vous souhaitez que des capteurs détectent les mouvements de la main pour agir

4.11 Contrôler Google Earth à l'aide d'Arduino | 115


Machine Translated by Google

comme manette de commande pour le simulateur de vol dans Google Earth. Les capteurs pourraient
utiliser un joystick (voir recette 6.17) ou un nunchuck Wii (voir recette 13.2).

Solution
Google Earth vous permet de « voler » n'importe où sur Terre pour afficher des images satellite, des
cartes, le relief et des bâtiments en 3D (voir Figure 4-4). Il contient un simulateur de vol qui peut être
contrôlé par une souris, et cette recette utilise des techniques décrites dans la recette 4.10 combinées
à un capteur connecté à Arduino pour fournir l'entrée du joystick.

Illustration 4-4. Simulateur de vol Google Earth

La solution de cette recette est basée sur la méthode utilisée dans la recette 4.10 pour émuler une
souris en envoyant des données Arduino à Processing. Le code Arduino envoie les positions
horizontale et verticale déterminées en lisant les valeurs du joystick (le code du joystick est décrit dans
la recette 6.17) à partir d'un contrôleur de jeu PlayStationÿ:

*
* GoogleEarthPSX
*
* Envoyer les données du joystick de PSX au traitement
*
utilise la bibliothèque PSX décrite dans la recette 6.17
*/

#include <Psx.h> // Inclut la bibliothèque PSX

Psx Psx; // Crée une instance de la librairie Psx


const int dataPin = 5ÿ;

116 | Chapitre 4 : Communications série


Machine Translated by Google

const int cmndPin = 4ÿ; const


entier attPin = 3ÿ; const int
clockPin = 2ÿ; const entier
psxDelay = 10ÿ; // ceci détermine le retard d'horloge en microsecondes

coup de pouce d'octet // la quantité de mouvement à envoyer lorsque le stick est poussé
constant = 64ÿ; octet const HEADER = 255ÿ; // cette valeur est envoyée comme
en-tête unsigned int dataÿ; octet x, y, boutonsÿ;

void setup()

{ Serial.begin(9600);
Psx.setupPins(dataPin, cmndPin, attPin, clockPin, psxDelay); // initialise Psx }

boucle vide() {

data = Psx.read(); // récupère les données du bouton du contrôleur psx x = y =


127; boutons = 0ÿ; // centrer les valeurs x & y, les décalages sont ajoutés si les boutons sont enfoncés

if(data & psxLeft || data & psxSqu) x = x - coup


de pouceÿ; if(data & psxDown ||data & psxX)
y = y + coup de pouceÿ; if(data & psxRight ||data
& psxO) x = x + coup de pouceÿ; if(data &
psxUp ||data & psxTri) y = y - coup de pouceÿ;
if(data & psxStrt) // (bouton Z) boutons =
boutons + 2; if(data & psxSlct) // (bouton C)
boutons = boutons + 1;

Serial.print(HEADER);
Serial.print(x); Serial.print(y);
Serial.print(boutons);

retard(20); // envoie la position 50 fois par seconde }

L'esquisse de traitement lit l'octet d'en-tête et trois octets de données pour la position x et y de
la souris et l'état du bouton. La technique de gestion des données binaires est abordée dans la
recette 4.7 : /** * GoogleEarthFS_P

* Lire les paquets série Arduino * et


envoyer la position de la souris à Google Earth

4.11 Contrôler Google Earth à l'aide d'Arduino | 117


Machine Translated by Google

*
*/

import processing.serial.*ÿ;

mon port sérieÿ; // Créer un objet à partir de la classe


int portIndex = 1ÿ; entier Serial // sélectionner le port com, 0 est le premier port
EN-TETE = 255ÿ; valeur
entièreÿ; // Données reçues du port série

GoogleFS myGoogleÿ;

void setup()
{ taille(256,
256);
println(Serial.list()); println("
"
Connexion à -> + Serial.list()[portIndex]); myPort = new
Serial(this,Serial.list()[portIndex], 9600); myGoogle = new GoogleFS();
smooth(); fill( 255); background(255); println("Démarrez Google FS au
centre de votre écran"); println("centrez le pointeur de la souris dans
google earth et appuyez sur le bouton Z pour démarrer");

faire{ getData(); }
while(boutons !
= 2 ); // attend que les données et le bouton Z démarrent

println("démarré");
myGoogle.mousePress(InputEvent.BUTTON1_MASK); // démarre le FS }

int accx, accy, boutonsÿ;


entier xOffset, yOffset = 0ÿ;

boolean getData(){ if
( myPort.available() >= 4) { // Si un paquet de données est disponible,
if(myPort.read() == HEADER){ // vérifie l'en-tête // efface les
anciens marqueurs stroke(255); ellipse(accx, accy,4,4);

accx = monPort.read();
accy = monPort.read();
boutons = myPort.read();
if(xOffset == 0){ // ici si
première fois xOffset =
accx; yDécalage = accy; }
if( boutons == 1)
{ println("tboutonÿ: c");

118 | Chapitre 4 : Communications série


Machine Translated by Google

xDécalage = accx;
yDécalage =
accy; } if(boutons ==
3 ){ exit(); } renvoie
vraiÿ; // données
disponibles } } renvoie
fauxÿ; }

void draw()
{ if(getData())
{ if(buttons != 2 )
{ // n'active la souris
que lorsque le bouton Z n'est pas enfoncé myGoogle.move(accx- xOffset,
accy - yOffset); }

print("accx: "); print(accx); print("\taccy:


"); impression(accy); println();

trait(255,0,0); } } ellipse(accx, accy,4,4);

class GoogleFS { //
crée un objet à partir
monRobotÿ; int centreX,centreYÿ; de la classe
GoogleFS(){ Robotÿ;
essayez Robot
{ monRobot
= nouveau Robot(); } catch (AWTException e) { e.printStackTrace(); }

Écran de dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); centerY =


(int)screen.getHeight() / 2 ; centerX = (int)screen.getWidth() / 2; } // déplace la souris du
centre de l'écran d'un décalage donné void move(int offsetX, int offsetY)
{ myRobot.mouseMove(centerX + 4 * offsetY); * offsetX,centerY + -4 } void mousePress( int
button){ myRobot.mousePress(button) ; } }

Discussion
Arduino détermine les positions horizontale et verticale en lisant la valeur du joystick
de la PSX (contrôleur de jeu PlayStation). Ce contrôle ne fournit pas réellement un

4.11 Contrôler Google Earth à l'aide d'Arduino | 119


Machine Translated by Google

valeur proportionnelle à la position du stick, donc le code Arduino envoie un décalage à partir du centre
lorsque le stick est déplacé - c'est la variable nudge et elle détermine la valeur de ce décalage, et donc la
sensibilité du contrôle. L'état des commutateurs Select et Start est également envoyé (lorsqu'il est
enfoncé, Select a une valeur de 2 et Start a une valeur de 1ÿ; lorsque les deux sont enfoncés, la valeur
est 3, et lorsqu'aucun bouton n'est enfoncé, la valeur est 0).

Suivez les instructions pour connecter la PSX dans la recette 6.17.

Google Earth est un téléchargement gratuit ; vous pouvez l'obtenir sur le site Web de Google, http://
earth.google.com/ download-earth.html. Téléchargez et exécutez la version de votre système d'exploitation
pour l'installer sur votre ordinateur. Démarrez Google Earth et, dans le menu Outils, sélectionnez Entrer
dans Flight Simulator. Sélectionnez un avion (le SR22 est plus facile à piloter que le F16) et un aéroport.
La prise en charge du joystick ne doit pas être cochée - vous utiliserez la souris pour contrôler l'avion.
Cliquez sur le bouton Démarrer le vol et appuyez immédiatement sur la barre d'espace pour mettre le
simulateur en pause afin que vous puissiez lancer l'esquisse de traitement.

Exécutez l' esquisse GoogleEarthFS_P et appuyez sur le bouton Démarrer du contrôleur PSX. Vous
verrez un point dans la fenêtre de dessin de traitement indiquant la position du joystick, et vous devriez
voir ce mouvement lorsque vous appuyez sur les boutons du joystick du contrôleur PSX. À ce stade, la
position de la souris est sous le contrôle d'Arduino, mais le contrôle revient à la souris de votre ordinateur
lorsque vous maintenez le bouton PSX Start enfoncé. Faites de Google Earth la fenêtre active en
maintenant enfoncé le bouton PSX Start et en cliquant sur Google Earth.

Vous êtes maintenant prêt à voler. Relâchez le bouton PSX Start, appuyez plusieurs fois sur Page Up sur
votre clavier pour augmenter la manette des gaz, puis appuyez sur la barre d'espace de votre clavier
pour réactiver le simulateur. Lorsque le SR22 atteint une vitesse d'air légèrement supérieure à 100
nœuds, vous pouvez « tirer vers l'arrière » sur le manche et voler. Des informations expliquant les
commandes du simulateur sont disponibles dans le menu Aide.

Voici une autre variante qui envoie un message similaire à l'esquisse de traitement. Celui-ci utilise le code
nunchuck Wii de la recette 13.2ÿ:
/*
* WiichuckSerial
*
* basé sur le code de Tod E. Kurt, http://thingm.com/ * Modifié
pour envoyer des paquets série à Processing
*
*/

#include <Wire.h>
#include "nunchuck_funcs.h"

int loop_cnt=0ÿ;
en-tête d'octet const = 254ÿ; // une valeur pour indiquer le début du message

octet accx, accy, joyx, joyy, boutonsÿ;

// définit les coordonnées actuelles comme points centraux

120 | Chapitre 4 : Communications série


Machine Translated by Google

void setup() {

Série.begin(9600);
nunchuck_setpowerpins();
nunchuck_init(); // envoie la poignée de main d'initialisation
nunchuck_get_data(); // ignore le premier délai (50);

boucle vide() {

if( loop_cnt > 50 ) { // toutes les 50 msecs obtenir de nouvelles


données loop_cnt = 0;

nunchuck_get_data();

accx = nunchuck_accelx(); accy


= nunchuck_accely(); boutons =
nunchuck_zbutton() * boutons = 2ÿ;

boutons + nunchuck_cbutton(); // cbutton est le bit le moins significatif

Serial.print((octet)HEADER); // valeur indiquant le début du message


Serial.print((byte)accx);
Serial.print((octet)accy);
Serial.print((octet)boutons);

} loop_cnt++;
retard(1);
}

Les connexions sont présentées dans la recette 13.2. Le fonctionnement est similaire à la version
PSX, sauf que vous utilisez le bouton Z sur le nunchuck au lieu du bouton Démarrer.

Voir également

Le site Web de Google Earth contient le code téléchargeable et les instructions nécessaires pour que
cela fonctionne sur votre ordinateurÿ: http:// earth.google.com/.

4.12 Journalisation des données Arduino dans un fichier sur votre ordinateur

Problème
Vous souhaitez créer un fichier contenant les informations reçues sur le port série d'Arduino. Par
exemple, vous souhaitez enregistrer les valeurs des broches numériques et analogiques à intervalles
réguliers dans un fichier journal.

Solution
Nous avons couvert l'envoi d'informations d'Arduino à votre ordinateur dans les recettes précédentes.
Cette solution utilise le même code Arduino expliqué dans la recette 4.9. Le traitement

4.12 Journalisation des données Arduino dans un fichier sur votre ordinateur | 121
Machine Translated by Google

L'esquisse qui gère la journalisation des fichiers est basée sur l'esquisse de traitement également décrite dans cette recette.

Cette esquisse de traitement crée un fichier (en utilisant la date et l'heure actuelles comme nom de fichier) dans un répertoire
appelé Arduino. Les messages reçus d'Arduino sont ajoutés au fichier.
Appuyer sur n'importe quelle touche enregistre le fichier et quitte le programmeÿ:

/*
* ReceiveMultipleFieldsBinaryToFile_P
*
* portIndex doit être défini sur le port connecté à l'Arduino * basé sur
ReceiveMultipleFieldsBinary, cette version enregistre les données dans un fichier
* Appuyez sur n'importe quelle touche pour arrêter la journalisation et enregistrer le
fichier */

import processing.serial.*ÿ;

Sortie PrintWriterÿ;
DateFormat fnameFormat= new SimpleDateFormat("aaMMjj_HHmm");
DateFormat timeFormat = new SimpleDateFormat("hh:mm:ss");
Chaîne fileNameÿ;

mon port sérieÿ; // Créer un objet à partir de la classe


Serial short portIndex = 0ÿ; // sélectionne le port com, 0 est le premier port
char HEADER = 'H';

void setup()
{ taille(200,
200); // Ouvrez
n'importe quel port série connecté à Arduino.
String nom_port = Serial.list()[portIndex]ÿ;
println(Serial.list()); println(" Connexion
" à -> myPort
= new Serial(this, portName, 9600); + Serial.list()[portIndex]);
Date now =
new Date(); fileName = fnameFormat.format(now);
output = createWriter(fileName + ".txt"); //
enregistrez le fichier dans le dossier de croquis }

void draw()
{ int val;

Temps de chaîneÿ;

if ( myPort.available() >= 15) // attend que le message entier arrive { if( myPort.read()
== HEADER) // est-ce l'en-tête { String timeString = timeFormat.format(new Date() );
println("Message reçu à + timeString); output.println(timeString); // en-tête trouvé //
obtenir l'entier contenant les valeurs de bit val = readArduinoInt();
"

122 | Chapitre 4 : Communications série


Machine Translated by Google

// affiche la valeur de chaque bit


for(int pin=2, bit=1; pin <="13; pin++){ "
=
print("pin numérique " ); + pin +" " =
output.print("pin numérique + pin + int " );
isSet = (val & bit);
si( estEnsemble == 0){
println("0");
sortie.println("0");
}
autre {
println("1");
sortie.println("0");
}
bit = bit * 2ÿ; // décale le bit
}
// affiche les six valeurs analogiques
pour(int je=0; je < 6; je ++){
val = readArduinoInt();
"
println("port analogique + je + "= " "+ val);
output.println("port analogique + val);+ je + "= " }

println("----");
sortie.println("----");
}
}
}

void keyPressed() {
sortie.flush(); // Écrit les données restantes dans le fichier
sortie.close(); // Termine le fichier
sortir(); // Arrête le programme
}

// renvoie la valeur entière des octets reçus sur le port série (en bas, haut
commande)

int readArduinoInt()
{
valeur entièreÿ; // Données reçues du port série

val = monPort.read(); // lit l'octet le moins significatif


val = myPort.read() * 256 + val; // ajoute l'octet de poids fort
valeur de retourÿ;
}

N'oubliez pas que vous devez définir portIndex sur le port série connecté à Arduino.

Discussion
Le nom de base du fichier journal est formé à l'aide de la fonction DateFormat dans Traitementÿ:

DateFormat fnameFormat= new SimpleDateFormat("aaMMjj_HHmm");

Le nom de fichier complet est créé avec du code qui ajoute un répertoire et une extension de fichierÿ:

sortie = createWriter(fileName + ".txt");

4.12 Journalisation des données Arduino dans un fichier sur votre ordinateur | 123
Machine Translated by Google

Le fichier sera créé dans le même répertoire que l'esquisse de traitement (l'esquisse doit être
enregistrée au moins une fois pour s'assurer que le répertoire existe). createWriter est la fonction de
traitement qui ouvre le fichierÿ; cela crée un objet (une unité de fonctionnalité d'exécution) appelé
output qui gère la sortie réelle du fichier. Le texte écrit dans le fichier est le même que celui imprimé
sur la console dans la recette 4.9, mais vous pouvez formater le contenu du fichier selon vos besoins
en utilisant les capacités standard de traitement des chaînes de traitement. Par exemple, la variante
suivante de la routine de dessin produit un fichier séparé par des virgules qui peut être lu par une
feuille de calcul ou une base de données. Le reste de l'esquisse de traitement peut être le même, bien
que vous souhaitiez peut-être changer l'extension de .txt en .csvÿ:
void draw()
{ int val;

Temps de chaîneÿ;

if ( myPort.available() >= 15) // attend que le message entier arrive


{ if( myPort.read() == HEADER) // est-ce l'en-tête {

Chaîne timeString = timeFormat.format(new Date());


sortie.print(timeString); val = readArduinoInt(); // lit
mais ne sort pas les valeurs numériques

// affiche les six valeurs analogiques délimitées par


une virgule for(int i=0; i < 6; i ++){ val = readArduinoInt();
output.print("," + val); } sortie.println(); } } }

Voir également

Pour plus d'informations sur createWriter, voir http:// processing.org/ reference/ createWriter_.html.

4.13 Envoi de données à deux périphériques série en même temps

Problème
Vous souhaitez envoyer des données à un périphérique série tel qu'un écran LCD série, mais vous
utilisez déjà le port série intégré pour communiquer avec votre ordinateur.

Solution
Sur un Mega, ce n'est pas un problème, car il dispose de quatre ports série matériels ; créez
simplement deux objets série et utilisez-en un pour l'écran LCD et un pour l'ordinateurÿ:

124 | Chapitre 4 : Communications série


Machine Translated by Google

void setup() { //
initialise deux ports série sur un megaL
Serial.begin(9600); Serial1.begin(9600); }

Sur une carte Arduino standard (telle que Uno ou Duemilanove) qui n'a qu'un seul port série matériel, vous
devrez créer un port série émulé ou "soft".

Vous pouvez utiliser NewSoftSerial de Mikal Hart, une bibliothèque d'émulation de port série, disponible sur
http:// arduiniana.org/ libraries/ newsoftserial. Téléchargez et installez NewSoftSerial.

L'équipe Arduino prévoit de fournir à NewSoftSerial les futurs téléchargements Arduino. Vérifiez
les notes de version de votre version Arduino pour voir si ce logiciel est déjà inclus.

Sélectionnez deux broches numériques disponibles, une pour la transmission et une pour la réception, et
connectez-y votre périphérique série. Il est pratique d'utiliser le port série matériel pour la communication avec
l'ordinateur car celui-ci dispose d'un adaptateur USB sur la carte. Connectez la ligne de transmission de
l'appareil à la broche de réception et la ligne de réception à la broche de transmission. Dans la Figure 4-5, nous
avons sélectionné la broche 2 comme broche de réception et la broche 3 comme broche de transmission.

Illustration 4-5. Connexion d'un périphérique série à un port série "soft"

Dans votre croquis, créez un objet NewSoftSerial et indiquez-lui les broches que vous avez choisies comme
port série émulé. Dans cet exemple, nous créons un objet nommé serial_lcd, auquel nous demandons d'utiliser
les broches 2 et 3ÿ:

/*
* Esquisse NewSoftSerialOutput
*
Sortie des données vers un port série logiciel
*/

4.13 Envoi de données à deux périphériques série en même temps | 125


Machine Translated by Google

#include <NewSoftSerial.h>
...
const int rxpin = 2ÿ; // broche utilisée pour recevoir du LCD // broche utilisée
= 3; pour envoyer au LCD const int txpin
NewSoftSerial serial_lcd(txpin, rxpin); // nouveau port série sur les broches 2 et 3

void setup()

{ Serial.begin(9600); // 9600 bauds pour le port série intégré


serial_lcd.begin(9600); //initialise le port série du logiciel également pour 9600 }

nombre entier = 0ÿ;

void loop()

{ serial_lcd.print("Le nombre est "); // envoie du texte à l'écran LCD


serial_lcd.println(number); // imprime le
Serial.print("Le
numéro sur l'écran
numéroLCD
est ");
Serial.println(nombre); // imprime le numéro sur la console du PC

retard (500); // délai d'une demi-seconde entre les nombres


number++ÿ; // au numéro suivant }

Ce schéma suppose qu'un écran LCD série a été connecté aux broches 2 et 3, comme illustré à la Figure 4-5,
et qu'une console série est connectée au port intégré. La boucle affichera à plusieurs reprises le même
message sur chaqueÿ:
Le nombre est 0
Le nombre est 1
...

Discussion
Chaque microcontrôleur Arduino contient au moins un port série intégré. Ce matériel spécial est chargé de
générer la série d'impulsions synchronisées avec précision que son appareil partenaire considère comme des
données et d'interpréter le flux similaire qu'il reçoit en retour. Bien que le Mega dispose de quatre ports de ce
type, la plupart des saveurs Arduino n'en ont qu'un.
Pour les projets qui nécessitent des connexions à deux périphériques série ou plus, vous aurez besoin d'une
bibliothèque logicielle qui émule les ports supplémentaires. Une bibliothèque "série logicielle" transforme
efficacement une paire arbitraire de broches d'E/S numériques en un nouveau port série.

Bien qu'une telle bibliothèque, SoftwareSerial, soit incluse dans chaque distribution Arduino, la plupart des
programmeurs préfèrent utiliser la bibliothèque NewSoftSerial plus puissante et plus riche en fonctionnalités.
NewSoftSerial prend en charge une plus large gamme de débits en bauds et utilise certaines fonctionnalités
avancées du processeur Arduino pour assurer une réception de données plus fiable. Il prend également en
charge plusieurs ports émulés simultanés. Vous pouvez en savoir plus sur NewSoftSerial sur le site Web de
Mikal Hart.

Le tableau 4-3 compare les fonctionnalités des bibliothèques NewSoftSerial et SoftwareSerial.

126 | Chapitre 4 : Communications série


Machine Translated by Google

Tableau 4-3. Comparaison des fonctionnalités de deux bibliothèques d'émulation

Caractéristique NewSoftSerial LogicielSerial

Distribué avec le logiciel Arduino Noé Oui

Max transmettre le débit en bauds 115.2K À environ 9 600

Max recevoir le débit en bauds 38.4K À environ 9 600

Prend en charge les processeurs 8 MHz Oui Non

Réceptions fiables pilotées par interruption Oui Non

Prend en charge plusieurs ports émulés Oui Non

Méthodes .available () et .overflow () Notez qu'à partir de la version Oui N/A

une

22 d'Arduino, NewSoftSerial n'était disponible qu'en tant que bibliothèque tierce, mais les futures versions peuvent l'inclure avec le
répartition de base.

Pour créer votre port série logiciel, vous sélectionnez une paire de broches qui agiront comme
transmettre et recevoir des lignes de la même manière que les broches 1 et 0 sont contrôlées par
Le port intégré d'Arduino. Dans la Figure 4-5, les broches 3 et 2 sont illustrées, mais tout signal numérique disponible
des épingles peuvent être utilisées. Il est sage d'éviter d'utiliser 0 et 1, car ceux-ci sont déjà pilotés
par le port intégré.

La syntaxe d'écriture sur le port logiciel est identique à celle du port matériel. Dans le
exemple d'esquisse, les données sont envoyées à la fois aux ports "réels" et émulés à l'aide de print() et
println()ÿ:
serial_lcd.print("Le numéro est "); // envoie du texte à l'écran LCD
serial_lcd.println(nombre); // envoie le numéro sur l'écran LCD

Serial.print("Le numéro est "); // envoie du texte au port matériel


Serial.println(nombre); // pour sortir sur Arduino Serial Monitor

Si vous utilisez un périphérique série unidirectionnel , c'est-à-dire un périphérique qui envoie ou reçoit uniquement,
vous pouvez économiser des ressources en spécifiant un numéro de broche inexistant dans le
Constructeur NewSoftSerial pour la ligne dont vous n'avez pas besoin. Par exemple, un LCD série est
fondamentalement un périphérique de sortie uniquement. Si vous ne vous attendez pas (ou ne voulez pas) à recevoir des données de

cela, vous pouvez indiquer à NewSoftSerial en utilisant cette syntaxeÿ:

#include <NewSoftSerial.h>
...
const int no_such_pin = 255ÿ;
const entier txpin = 3ÿ;
NewSoftSerial serial_lcd(txpin, no_such_pin); // TX uniquement sur la broche 3

Dans ce cas, nous ne connecterions physiquement qu'une seule broche (3) à "l'entrée" du LCD série
ou ligne "RX".

4.13 Envoi de données à deux périphériques série en même temps | 127


Machine Translated by Google

4.14 Réception de données série de deux appareils en même temps

Problème
Vous souhaitez recevoir des données d'un périphérique série tel qu'un GPS série, mais vous utilisez déjà le
port série intégré pour communiquer avec votre ordinateur.

Solution
Ce problème est similaire au précédent, et en effet la solution est à peu près la même.
Si le port série de votre Arduino est connecté à la console et que vous souhaitez connecter un deuxième
périphérique série, vous devez créer un port émulé à l'aide d'une bibliothèque série logicielle telle que
NewSoftSerial. Dans ce cas, nous recevrons des données du port émulé au lieu d'y écrire, mais la solution
de base est très similaire.

Téléchargez NewSoftSerial sur le site Web de Mikal Hart. Sélectionnez deux broches à utiliser comme lignes
de transmission et de réception.

Connectez votre GPS comme illustré à la Figure 4-6. Rx (réception) n'est pas utilisé dans cet exemple, vous
pouvez donc ignorer la connexion Rx à la broche 3 si votre GPS n'a pas de broche de réception.

Figure 4-6. Connexion d'un appareil GPS série à un port série "soft"

Comme vous l'avez fait dans la recette 4.13, créez un objet NewSoftSerial dans votre sketch et indiquez-lui
quelles broches contrôler. Dans l'exemple suivant, nous définissons un port série logiciel appelé serial_gps,
utilisant les broches 2 et 3 pour la réception et la transmission, respectivementÿ:
/*
* Esquisse NewSoftSerialInput
* Lire les données d'un port série logiciel */

128 | Chapitre 4 : Communications série


Machine Translated by Google

#include <NewSoftSerial.h> const


int rxpin = 2ÿ; const entier txpin = // broche utilisée pour recevoir du GPS //
3ÿ; NewSoftSerial serial_gps (txpin, broche utilisée pour envoyer au GPS
rxpin); // nouveau port série sur les broches 2 et 3

void setup()

{ Serial.begin(9600); // 9600 bauds pour le port série intégré serial_gps.begin(4800); //


initialise le port, la plupart des appareils GPS utilisent 4800 bauds }

void loop() { if

(serial_gps.available() > 0) // un caractère est-il déjà arrivéÿ? { char c =


serial_gps.read(); // si c'est le cas, lisez-le depuis le GPS Serial.print(c, BYTE); // et
l'écho à la console série } }

Ce court croquis transmet simplement toutes les données entrantes du GPS au moniteur série Arduino.
Si le GPS fonctionne et que votre câblage est correct, vous devriez voir les données GPS affichées sur
le moniteur série.

Discussion
Vous initialisez un port NewSoftSerial émulé en fournissant des numéros de broches pour la transmission
et la réception. Le code suivant configurera le port pour envoyer sur la broche 2 et recevoir sur la broche
3ÿ:
const int rxpin = 2ÿ; const // broche utilisée pour recevoir du GPS //
entier txpin = 3ÿ; broche utilisée pour envoyer au GPS
NewSoftSerial serial_gps (txpin, rxpin); // nouveau port série sur les broches 2 et 3

La syntaxe pour lire un port émulé est très similaire à celle pour lire à partir d'un port intégré. Vérifiez
d'abord qu'un caractère est bien arrivé du GPS avec available(), puis lisez-le avec read().

Il est important de se rappeler que les ports série logiciels consomment du temps et des ressources. Un
port série émulé doit faire tout ce qu'un port matériel fait, en utilisant le même processeur avec lequel
votre sketch essaie de faire un "vrai travail". Chaque fois qu'un nouveau personnage arrive, le
processeur doit interrompre tout ce qu'il faisait pour le gérer. Cela peut prendre du temps. À 4 800
bauds, par exemple, il faut environ deux millisecondes à l'Arduino pour traiter un seul caractère. Bien
que deux millisecondes puissent ne pas sembler beaucoup, considérez que si votre appareil pair, par
exemple, l'unité GPS illustrée précédemment, transmet 200 à 250 caractères par seconde, votre croquis
passe 40 à 50 % de son temps à essayer de suivre le numéro de série. contribution. Cela laisse très
peu de temps pour traiter réellement toutes ces données. La leçon est que si vous avez deux
périphériques série, connectez si possible celui qui consomme le plus de bande passante au port
(matériel) intégré. Si vous devez connecter un périphérique à large bande passante à un port série
logiciel, assurez-vous que le reste de la boucle de votre croquis est très efficace.

4.14 Réception de données série de deux appareils en même temps | 129


Machine Translated by Google

Recevoir des données de plusieurs ports

NewSoftSerial Avec NewSoftSerial (mais pas SoftwareSerial), il est possible de créer plusieurs
ports série "soft" dans la même esquisse. C'est un moyen utile de contrôler, par exemple, plusieurs
radios XBee dans le même projet. La mise en garde est qu'à un moment donné, un seul de ces ports
peut recevoir activement des données. Une réception fiable sur un port logiciel nécessite toute
l'attention du processeur. C'est pourquoi NewSoftSerial ne peut activer qu'un seul port pour la
réception des données à un instant donné. (Cette restriction ne s'applique pas à l' envoi de données,
seulement à leur réception. Voir la documentation NewSoftSerial pour plus de détails.)

Il est possible de recevoir sur deux ports NewSoftSerial différents dans le même sketch. Vous devez
juste prendre soin de ne pas essayer de recevoir des deux en même temps.
Il existe de nombreuses conceptions réussies qui, par exemple, surveillent un appareil GPS série
pendant un certain temps, puis plus tard dans l'esquisse acceptent les entrées d'un XBee. La clé
est d'alterner entre eux. NewSoftSerial considère que le port "actif" est le port auquel vous avez
accédé le plus récemment à l'aide de la méthode read, print, println ou available . Le fragment de
code suivant illustre la façon dont vous concevez une esquisse à lire d'abord à partir d'un port,
puis à partir d'un autreÿ:

/*
* Esquisse MultiRX
* Recevoir des données de deux ports série logiciels
*/

#include <NewSoftSerial.h>
const int rxpin1 = 2ÿ; const
entier txpin1 = 3ÿ; const int
rxpin2 = 4ÿ; const entier txpin2
= 5ÿ; NewSoftSerial gps
(txpin1, rxpin1); // périphérique gps connecté aux broches 2 et 3 NewSoftSerial
xbee(txpin2, rxpin2); // appareil GPS connecté aux broches 2 et 3

void setup()

{ gps.begin(4800);
xbee.begin(9600); }

void loop()
{ if
(xbee.available() > 0) // xbee est actif. Des personnages disponibles ? { if
(xbee.read() == 'y') // si xbee a reçu un caractère 'y' { début long non signé =
millis(); // commence à écouter le GPS pendant (start + 100000 > millis()) //
écoute pendant 10 secondes

130 | Chapitre 4 : Communications série


Machine Translated by Google

{ if (gps.available() > 0) // maintenant le périphérique gps est actif


{ char c = gps.read(); // *** traiter les données GPS ici } } } } }

Cette esquisse est conçue pour traiter la radio XBee comme le port actif jusqu'à ce qu'elle reçoive un
caractère y , moment auquel le GPS devient actif. Après avoir traité les données GPS pendant 10 secondes,
l'esquisse revient à nouveau à l'écoute du port XBee. Les données qui arrivent sur un port inactif sont
simplement rejetées.

Notez que la restriction "port actif" s'applique uniquement à plusieurs ports logiciels. Si votre conception doit
vraiment recevoir des données de plusieurs périphériques série simultanément, envisagez de connecter l'un
d'entre eux au port matériel intégré. Alternativement, il est parfaitement possible d'ajouter des ports matériels
supplémentaires à vos projets en utilisant des puces externes, des dispositifs appelés UART.

4.15 Configuration du traitement sur votre ordinateur pour


envoyer et recevoir des données série

Problème
Vous souhaitez utiliser l'environnement de développement Processing pour envoyer et recevoir des données
série.

Solution
Vous pouvez obtenir l'application de traitement à partir de la section Téléchargements du site Web de
traitement, http:// processing.org. Les fichiers sont disponibles pour chaque système d'exploitation majeur.
Téléchargez celui qui convient à votre système d'exploitation et décompressez le fichier à l'endroit où vous
stockez normalement les applications. Sur un ordinateur Windows, il peut s'agir d'un emplacement tel que C:
\Program Files\Processing\. Sur un Mac, cela peut être quelque chose comme /Applications/ Processing/.

Si vous avez installé Processing sur le même ordinateur qui exécute l'IDE Arduino, la seule autre chose que
vous devez faire est d'identifier le port série dans Processing. L'esquisse de traitement suivante imprime les
ports série disponiblesÿ:
/**
* Commencer
*
* Un croquis pour lister les ports série disponibles
* et afficher les caractères reçus */

4.15 Configuration du traitement sur votre ordinateur pour envoyer et recevoir des données série | 131
Machine Translated by Google

import processing.serial.*ÿ;

mon port sérieÿ; // Créer un objet à partir de la classe Serial


int portIndex = 0ÿ; // définissez ceci sur le port connecté à Arduino
// Données reçues du port série int val;

void setup()
{ taille(200,
200);
println(Serial.list()); // affiche la liste
" de tous les ports println("
Connecting to -> + Serial.list()[portIndex]);
Serial.list()[portIndex],
myPort = new Serial(this,
9600); }

void draw()
{ if
( myPort.available() > 0) // Si les données sont disponibles,
{ val = myPort.read(); impression(val); } }
// le lit et le stocke dans val

Si vous exécutez Processing sur un ordinateur qui n'exécute pas l'environnement de


développement Arduino, vous devez installer les pilotes USB Arduino (le chapitre 1 décrit
comment procéder).

Définissez la variable portIndex pour qu'elle corresponde au port utilisé par Arduino. Vous
pouvez voir les numéros de port imprimés dans la fenêtre de texte de traitement (la zone sous
le code source, pas la fenêtre d'affichage séparéeÿ; voir http:// processing.org/ reference/ environment).
La recette 1.4 décrit comment savoir quel port série votre carte Arduino utilise.

132 | Chapitre 4 : Communications série


Machine Translated by Google

CHAPITRE 5

Entrée numérique et analogique simple

5.0 Présentation
La capacité de l'Arduino à détecter les entrées numériques et analogiques lui permet de répondre à vous et
au monde qui vous entoure. Ce chapitre présente des techniques que vous pouvez utiliser pour faire des
choses utiles avec ces entrées. C'est le premier des nombreux chapitres à venir qui couvrent les connexions
électriques à Arduino. Si vous n'avez pas de formation en électronique, vous pouvez consulter l' annexe A
sur les composants électroniques, l' annexe B sur les schémas et les fiches techniques, l' annexe C sur la
construction et la connexion des circuits et l'annexe E sur le dépannage du matériel. De plus, de nombreux
bons tutoriels d'introduction sont disponibles sur l'électronique. Deux d'entre eux sont particulièrement
pertinents pour Arduino : Getting Started with Arduino de Massimo Banzi (O'Reilly) et Making Things Talk
de Tom Igoe (O'Reilly). Parmi les autres livres offrant un aperçu des sujets électroniques abordés dans ce
chapitre et les chapitres suivants, citons Getting Started in Electronics de Forrest Mims (Master Publishing)
et Physical Computing de Tom Igoe (Cengage).

Si le câblage des composants de votre Arduino est nouveau pour vous, faites attention à
la façon dont vous connectez et alimentez les éléments que vous connectez. Arduino
utilise une puce de contrôleur de buste robuste qui peut subir de nombreux abus, mais
vous pouvez endommager la puce si vous connectez les mauvaises tensions ou si vous
court-circuitez une broche de sortie. La plupart des puces de contrôleur Arduino sont
alimentées en 5 volts, et vous ne devez pas connecter d'alimentation externe aux broches
Arduino avec une tension supérieure à celle-ci (ou 3,3 volts si votre contrôleur Arduino
fonctionne sur cette tension).

Les cartes Arduino destinées aux débutants ont la puce principale dans une prise qui peut
être retirée et remplacée, vous n'avez donc pas besoin de remplacer toute la carte si vous
endommagez la puce.

La figure 5-1 montre la disposition des broches sur une carte Arduino standard. Voir http:// www.arduino.cc/
en/ Main/ Hardware pour une liste de toutes les cartes officielles ainsi que des liens vers les informations de
connexion pour chacune. Si votre carte ne figure pas sur cette liste, consultez le site Web de votre
fournisseur de carte pour obtenir des informations sur la connexion.

133
Machine Translated by Google

Figure 5-1. Carte Arduino standard

Ce chapitre couvre les broches Arduino qui peuvent détecter les entrées numériques et analogiques . Les broches
d'entrée numériques détectent la présence et l'absence de tension sur une broche. Les broches d'entrée analogiques
mesurent une plage de tensions sur une broche.

La fonction Arduino pour détecter l'entrée numérique est digitalRead et elle indique à votre croquis si
une tension sur une broche est HIGH (5 volts) ou LOW (0 volts). La fonction Arduino pour configurer
une broche pour lire l'entrée est pinMode(pin, INPUT).

Sur une carte typique, il y a 14 broches numériques (numérotées de 0 à 13) comme indiqué en haut de la Figure 5-1.
Les broches 0 et 1 (marquées RX et TX) sont utilisées pour la connexion série USB et doivent être évitées pour d'autres
utilisations. Si vous avez besoin de plus de broches numériques sur une carte standard, vous pouvez utiliser les
broches analogiques comme broches numériques (les broches analogiques 0 à 5 peuvent être utilisées comme broches
numériques 14 à 19).

La carte Mega a beaucoup plus de broches numériques et analogiques. Les broches numériques 0 à 13 et les broches
analogiques 0 à 5 sont situées au même endroit que sur la carte standard afin que les blindages matériels conçus pour
la carte standard puissent s'adapter sur un Mega. Comme avec la carte standard, vous pouvez utiliser des broches
analogiques comme broches numériques, mais avec le Mega, les broches analogiques 0 à 15 sont les numéros de
broches numériques 54 à 69. La figure 5-2 montre la disposition des broches Mega.

La plupart des cartes ont une LED connectée à la broche 13, et certaines des recettes l'utilisent comme indicateur de
sortie. Si votre carte n'a pas de LED sur la broche 13, passez à la recette 7.1 si vous avez besoin d'aide pour connecter
une LED à une broche numérique.

Les recettes couvrant l'entrée numérique utilisent parfois des résistances externes pour fournir la tension détectée par
digitalRead. Ces résistances sont appelées résistances pull-up (ainsi nommées parce que la tension est "montée"
jusqu'à la ligne 5V à laquelle la résistance est connectée) ou

134 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Figure 5-2. Carte Arduino Méga

résistances pull-down (la tension est "abaissée" à 0 volt). Bien que 10K ohms soit une valeur couramment utilisée, tout ce qui
se situe entre 4,7K et 20K ou plus fonctionnera ; voir l' annexe A pour plus d'informations sur les composants utilisés dans ce
chapitre.

Contrairement à une valeur numérique, qui est uniquement activée ou désactivée, les valeurs analogiques varient en continu.
Le réglage du volume d'un appareil en est un bon exemple ; ce n'est pas seulement activé ou désactivé, mais il peut avoir
une plage de valeurs entre les deux. De nombreux capteurs fournissent des informations en faisant varier la tension pour
correspondre à la mesure du capteur. Le code Arduino utilise une fonction appelée analogRead pour obtenir une valeur
proportionnelle à la tension qu'il voit sur l'une de ses broches analogiques.
La valeur sera 0 s'il y a 0 volt sur la broche et 1 023 pour 5 volts. La valeur intermédiaire sera proportionnelle à la tension sur
la broche, donc 2,5 volts (la moitié de 5 volts) donneront une valeur d'environ 511 (la moitié de 1 023). Vous pouvez voir les
six broches d'entrée analogiques (marquées de 0 à 5) au bas de la Figure 5-1 (ces broches peuvent également être utilisées
comme broches numériques 14 à 19 si elles ne sont pas nécessaires pour l'analogique). Certaines des recettes analogiques
utilisent un potentiomètre (pot en abrégé, également appelé résistance variable) pour faire varier la tension sur une broche.
Lors du choix d'un potentiomètre, une valeur de 10K est la meilleure option pour se connecter aux broches analogiques.

Bien que la plupart des circuits de ce chapitre soient relativement faciles à connecter, vous voudrez peut-être envisager de
vous procurer une planche à pain sans soudure pour simplifier votre câblage vers des composants externesÿ: certains choix
sont le Jameco 20723 (deux rangées de bus par côté)ÿ; RadioShack 276-174 (une rangée de bus par côté); Digi-Key
438-1045-NDÿ; et SparkFun PRT-00137.

Un autre article pratique est un multimètre peu coûteux. Presque n'importe lequel fera l'affaire, tant qu'il peut mesurer la
tension et la résistance. La vérification de la continuité et la mesure du courant sont des fonctionnalités supplémentaires
intéressantes. (Le Jameco 220812, RadioShack 22-810 et SparkFun TOL-00078 offrent ces fonctionnalités.)

5.0 Présentation | 135


Machine Translated by Google

5.1 Utilisation d'un interrupteur

Problème
Vous voulez que votre croquis réponde à la fermeture d'un contact électrique ; par exemple, un
bouton-poussoir ou un autre interrupteur ou un appareil externe qui établit une connexion électrique.

Solution
Utilisez digitalRead pour déterminer l'état d'un commutateur connecté à une broche numérique
Arduino définie comme entrée. Le code suivant allume une LED lorsqu'un interrupteur est enfoncé (la
figure 5-3 montre comment il doit être câblé)ÿ:
/*
Esquisse d'un bouton
poussoir un interrupteur relié à la broche 2 allume la LED sur la broche
13 */

const int ledPin = 13ÿ; // choisir la broche pour la LED //


const int inputPin = 2ÿ; choisir la broche d'entrée (pour un bouton poussoir)

void setup()
{ pinMode(ledPin, OUTPUT); // déclare la LED en sortie //
pinMode(inputPin, INPUT); } déclare le bouton poussoir en entrée

void loop(){ int


val = digitalRead(inputPin); // lit la valeur d'entrée if (val == HIGH) //
vérifie si l'entrée est HIGH { digitalWrite (ledPin, HIGH); } else LOW); } }
{ digitalWrite(ledPin,

// allume la LED si l'interrupteur est enfoncé

// éteint la LED

Les cartes Arduino standard ont une LED intégrée connectée à la broche 13. Si ce n'est pas le
cas, consultez la recette 7.1 pour plus d'informations sur la connexion d'une LED à une broche
Arduino.

Discussion
La fonction de configuration configure la broche LED comme OUTPUT et la broche du commutateur comme INPUT.

136 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Figure 5-3. Commutateur connecté à l'aide d'une résistance pull-down

Une broche doit être réglée sur le mode OUTPUT pour que digitalWrite contrôle la tension de
sortie de la broche. Il doit être en mode INPUT pour lire l'entrée numérique.

La fonction digitalRead surveille la tension sur la broche d'entrée (inputPin) et renvoie une valeur
HIGH si la tension est élevée (5 volts) et LOW si la tension est basse (0 volt).
En fait, toute tension supérieure à 2,5 volts (la moitié de la tension alimentant la puce) est
considérée comme HAUTE et inférieure à celle-ci est traitée comme BASSE. Si la broche n'est
pas connectée (appelée flottante) , la valeur renvoyée par digitalRead est indéterminée (elle peut
être HIGH ou LOW, et elle ne peut pas être utilisée de manière fiable). La résistance illustrée à la
Figure 5-3 garantit que la tension sur la broche sera basse lorsque l'interrupteur n'est pas enfoncé,
car la résistance « abaisse » la tension à la terre. Lorsque le commutateur est enfoncé, une
connexion est établie entre la broche et +5 volts, de sorte que la valeur sur la broche interprétée
par la lecture numérique passe de LOW à HIGH.

Ne connectez pas une broche numérique ou analogique à une tension supérieure à 5 volts
(ou 3,3 volts sur une carte 3,3 V). Cela peut endommager la broche et éventuellement détruire
toute la puce. Assurez-vous également de ne pas câbler l'interrupteur de sorte qu'il court-
circuite les 5 volts à la terre (sans résistance). Bien que cela n'endommage pas la puce
Arduino, ce n'est pas bon pour l'alimentation.

5.1 Utilisation d'un commutateur | 137


Machine Translated by Google

Dans cet exemple, la valeur de digitalRead est stockée dans la variable val. Ce sera HIGH si le bouton est enfoncé,
LOW sinon.

L'interrupteur utilisé dans cet exemple (et presque partout ailleurs dans ce livre) établit un contact
électrique lorsqu'il est enfoncé et rompt le contact lorsqu'il n'est pas enfoncé. Ces interrupteurs
sont appelés normalement ouverts (NO)ÿ; voir le site Web de ce livre pour les numéros de pièce.
L'autre type d'interrupteur momentané est appelé normalement fermé (NC).

La broche de sortie connectée à la LED est activée lorsque vous réglez val sur HIGH, ce qui allume la LED.

Bien qu'Arduino définisse toutes les broches numériques comme entrées par défaut, il est recommandé de le définir
explicitement dans votre croquis pour vous rappeler les broches que vous utilisez.

Vous pouvez voir un code similaire qui utilise true au lieu de HIGH ; ceux-ci peuvent être utilisés de manière
interchangeable (ils sont aussi parfois représentés par 1). De même, false est identique à LOW et 0. Utilisez la forme
qui exprime le mieux la signification de la logique dans votre application.

Presque tous les interrupteurs peuvent être utilisés, bien que ceux appelés interrupteurs tactiles momentanés soient
populaires car ils sont peu coûteux et peuvent se brancher directement sur une planche à pain. Consultez le site Web
de ce livre pour connaître les numéros de pièces de certains fournisseurs.

Voici une autre façon d'implémenter la logique dans l'esquisse précédenteÿ:

boucle vide()
{
digitalWrite(ledPin, digitalRead(inputPin)); // allume la LED si la broche d'entrée est
ÉLEVÉ, sinon éteindre }

Cela ne stocke pas l'état du bouton dans une variable. Au lieu de cela, il allume ou éteint la LED directement à partir
de la valeur obtenue à partir de digitalRead. C'est un raccourci pratique, mais si vous le trouvez trop concis, il n'y a
pas de différence pratique de performances, alors choisissez la forme que vous trouvez la plus facile à comprendre.

Le code pull-up est similaire à la version pull-down, mais la logique est inverséeÿ: la valeur sur la broche passe au
niveau BAS lorsque le bouton est enfoncé (voir la figure 5-4 pour un schéma de principe). Il peut être utile de
considérer cela comme une pression sur le commutateur BAS, ce qui fait que la sortie passe au niveau BASÿ: void
loop() { int val = digitalRead(inputPin); // lit la valeur d'entrée if (val == HIGH) // vérifie si l'entrée est HIGH { digitalWrite

(ledPin, LOW); }

// éteindre la LED

138 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

sinon { digitalWrite(ledPin, // allume la LED


HIGH); } }

Figure 5-4. Commutateur connecté à l'aide d'une résistance pull-up

Voir également

La référence Arduino pour digitalRead : http:// arduino.cc/ en/ Reference/ DigitalRead La référence

Arduino pour digitalWrite : http:// arduino.cc/ en/ Reference/ DigitalWrite La référence Arduino pour

pinMode : http:// arduino. cc/ en/ Reference/ PinMode Les références Arduino pour les constantes

(HIGH, LOW, etc.) : http:// arduino.cc/ en/ Reference/ Constants

Tutoriel Arduino sur les broches numériques : http:// arduino.cc/ en/ Tutorial/ DigitalPins

5.2 Utilisation d'un interrupteur sans résistances externes

Problème
Vous souhaitez simplifier votre câblage en éliminant les résistances pull-up externes lors de la
connexion des interrupteurs.

5.2 Utilisation d'un commutateur sans résistances externes | 139


Machine Translated by Google

Solution
Comme expliqué dans la recette 5.1, les entrées numériques doivent avoir une résistance pour maintenir la broche
à une valeur connue lorsque le commutateur n'est pas enfoncé. Arduino possède des résistances pull-up internes
qui peuvent être activées en écrivant une valeur HIGH sur une broche qui est en mode INPUT (le code correspondant
est indiqué dans la recette 5.1).

Pour cet exemple, le commutateur est câblé comme illustré à la Figure 5-5. C'est presque exactement la même
chose que la figure 5-4, mais sans résistance externe.

Figure 5-5. Commutateur câblé pour une utilisation avec une résistance pull-up interne

Le commutateur est uniquement connecté entre la broche 2 et Gnd. Gnd est l'abréviation de masse et est à 0 volt
par définition :

/*
Pullup croquis
un interrupteur connecté à la broche 2 allume la LED sur la broche
13 */

const int ledPin = 13ÿ; const // broche de sortie pour la LED //


int inputPin = 2ÿ; broche d'entrée pour l'interrupteur

void setup()
{ pinMode(ledPin, OUTPUT);
pinMode(inputPin, INPUT);
digitalWrite(inputPin,HIGH); // active le pull-up interne sur l'inputPin

140 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

void loop()
{ int val = digitalRead(inputPin); // lit la valeur d'entrée if (val
== HIGH) // vérifie si l'entrée est HIGH { HIGH);
digitalWrite
} else(ledPin,
{ digitalWrite(ledPin,
LOW); } }
// éteindre la LED

// allume la LED

Il y a quelques broches Gnd sur une carte Arduinoÿ; ils sont tous connectés, alors choisissez
celui qui vous convient.

Discussion
Vous activez les résistances pull-up internes en écrivant une valeur HIGH sur une broche en mode d'entrée.
L'utilisation de digitalWrite(pin, HIGH) sur une broche en mode d'entrée peut ne pas être intuitive au début,
mais vous vous y habituerez rapidement. Vous pouvez désactiver le pull-up en écrivant une valeur LOW sur la
broche.

Si votre application bascule le mode de la broche entre l'entrée et la sortie, gardez à l'esprit que l'état de la
broche restera HIGH ou LOW lorsque vous changerez de mode.
En d'autres termes, si vous avez défini une broche de sortie HIGH et que vous passez ensuite en mode
d'entrée, le pull-up sera activé et la lecture de la broche produira un HIGH. Si vous réglez la broche LOW en
mode de sortie avec digitalWrite (pin, LOW) puis passez en mode d'entrée avec la broche Mode (pin, INPUT),
le pull-up sera désactivé. Si vous activez un pull-up, le passage en mode de sortie définira la broche HIGH, ce
qui pourrait, par exemple, allumer involontairement une LED qui lui est connectée.

Les résistances pull-up internes sont de 20K ohms. Cela convient à la plupart des applications, mais certains
appareils peuvent nécessiter des résistances de valeur inférieure - consultez la fiche technique des appareils
externes que vous souhaitez connecter à Arduino pour voir si les pull-ups internes conviennent ou non.

5.3 Détection fiable de la fermeture d'un interrupteur

Problème
Vous voulez éviter les fausses lectures dues au rebond de contact (le rebond de contact produit des signaux
parasites au moment où les contacts de l'interrupteur se ferment ou s'ouvrent). Le processus d'élimination
des lectures erronées est appelé anti-rebond.

5.3 Détection fiable de la fermeture d'un interrupteur | 141


Machine Translated by Google

Solution
Il existe de nombreuses façons de résoudre ce problème; en voici une utilisant le câblage illustré
à la figure 5-3 de la recette 5.1ÿ:
/*
Esquisse anti-rebond
un interrupteur connecté à la broche 2 allume la LED sur la broche 13 la
logique anti-rebond empêche une lecture erronée de l'état de l'interrupteur
*/

const int inputPin = 2ÿ; // le numéro de la broche d'entrée //


const int ledPin = 13ÿ; const le numéro de la broche de sortie
int debounceDelay = 10ÿ; // millisecondes à attendre jusqu'à ce qu'il soit stable

// debounce renvoie true si le commutateur de la broche donnée est fermé et stable boolean
debounce(int pin) {

état booléenÿ;
booléen étatprécédentÿ;

previousState = digitalRead(pin); // stocke l'état du commutateur for(int


counter=0; counter < debounceDelay; counter++) {

retard(1); // attend 1 milliseconde


état = lecture numérique (broche); // lit la broche
if( state != previousState) {

compteur = 0ÿ; // réinitialise le compteur si l'état change


previousState = state; // et enregistre l'état actuel
}

} // ici lorsque l'état du commutateur a été stable plus longtemps que la période anti-rebond

état de retourÿ; }

void setup()

{ pinMode(inputPin, INPUT);
pinMode(ledPin, SORTIE); }

void loop()
{ if(anti-
rebond(inPin))
{ digitalWrite(outPin,
HIGH); } }

La fonction anti- rebond est appelée (utilisée) avec le numéro de broche du commutateur que
vous souhaitez anti-rebondÿ; la fonction renvoie vrai si le commutateur est enfoncé et stable. Il
renvoie faux s'il n'est pas pressé ou pas encore stable.

142 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Discussion
La méthode anti- rebond vérifie si elle obtient la même lecture du commutateur après un délai qui doit
être suffisamment long pour que les contacts du commutateur arrêtent de rebondir. Vous pouvez avoir
besoin d'intervalles plus longs pour les commutateurs "plus rebondissants" (certains commutateurs
peuvent nécessiter jusqu'à 50 ms ou plus). La fonction fonctionne en vérifiant à plusieurs reprises l'état
du commutateur pendant autant de millisecondes que défini dans le temps anti- rebond . Si le
commutateur reste stable pendant ce temps, l'état du commutateur sera retourné (vrai si appuyé et faux
sinon). Si l'état du commutateur change pendant la période anti-rebond, le compteur est réinitialisé de
sorte que les vérifications recommencent jusqu'à ce que l'état du commutateur ne change pas pendant le temps anti-rebond.

Si votre câblage utilise des résistances pull-up au lieu de résistances pull-down (voir recette 5.2) , vous
devez inverser la valeur renvoyée par la fonction anti- rebond , car l'état passe au niveau BAS lorsque
l'interrupteur est enfoncé à l'aide de pull-ups, mais la fonction doit renvoie vrai (true est identique à HIGH)
lorsque le commutateur est enfoncé. Le code anti-rebond utilisant les tractions est le suivantÿ; seules les
quatre dernières lignes (en surbrillance) sont modifiées par rapport à la version précédenteÿ:

boolean debounce(int pin)


{ état booléenÿ; booléen
étatprécédentÿ;

previousState = digitalRead(pin); // stocke l'état du commutateur for(int


counter=0; counter < debounceDelay; counter++) {

retard(1); // attend 1 milliseconde


état = lecture numérique (broche); // lit la broche
if( state != previousState) {

compteur = 0ÿ; // réinitialise le compteur si l'état change


previousState = state; // et enregistre l'état actuel
}

} // ici lorsque l'état du commutateur a été stable plus longtemps que la période anti-rebond
if(state == LOW) // LOW signifie enfoncé (parce que des pull-ups sont utilisés)
retourner
vraiÿ; sinon
retourner fauxÿ;
}

Pour les tests, vous pouvez ajouter une variable de comptage pour afficher le nombre d'appuis. Si vous
visualisez ceci sur le moniteur série (voir chapitre 4), vous pouvez voir s'il s'incrémente une fois par
pression. Augmentez la valeur de debounceDelay jusqu'à ce que le décompte suive les pressions.
Le fragment suivant imprime la valeur de count lorsqu'il est utilisé avec la fonction anti- rebond présentée
précédemmentÿ:

nombre entierÿ; // ajoute cette variable pour stocker le nombre d'appuis

void setup()
{ pinMode(inPin,
INPUT);

5.3 Détection fiable de la fermeture d'un interrupteur | 143


Machine Translated by Google

pinMode(sortiePin, SORTIE);
Série.begin(9600); // ajouter ceci à la fonction de
configuration }

void loop()
{ if(anti-
rebond(inPin))
{ digitalWrite(outPin,
HIGH); // incrémente count
count++;
Serial.println(count); // affiche le
compte sur le moniteur série } }

Cette fonction debounce() fonctionnera pour n'importe quel nombre de commutateurs, mais vous devez vous assurer
que les broches utilisées sont en mode d'entrée.

Un inconvénient potentiel de cette méthode pour certaines applications est qu'à partir du moment où la fonction anti-
rebond est appelée, tout attend que le commutateur soit stable. Dans la plupart des cas, cela n'a pas d'importance,
mais votre croquis devra peut-être s'occuper d'autres choses en attendant que votre interrupteur se stabilise. Vous
pouvez utiliser le code montré dans la recette 5.4 pour résoudre ce problème.

Voir également

Voir l'exemple de croquis Debounce distribué avec Arduino. Dans le menu Fichier, sélectionnez
ExemplesÿNumériqueÿDebounce.

5.4 Déterminer combien de temps un interrupteur est enfoncé

Problème
Votre application veut détecter la durée pendant laquelle un commutateur a été dans son état actuel. Ou vous
voulez incrémenter une valeur pendant qu'un commutateur est enfoncé et vous voulez que le taux augmente plus le
commutateur est maintenu (la façon dont de nombreuses horloges électroniques sont réglées). Ou vous voulez
savoir si un interrupteur a été enfoncé assez longtemps pour que la lecture soit stable (voir recette 5.3).

Solution
Le schéma suivant illustre le réglage d'un compte à rebours. Le câblage est le même que dans la Figure 5-5 de la
recette 5.2. Appuyer sur un interrupteur règle la minuterie en incrémentant le compte de la minuterieÿ; relâcher
l'interrupteur lance le compte à rebours. Le code anti-rebond
commutateur et accélère la vitesse à laquelle le compteur augmente lorsque le commutateur est maintenu pendant

de longues périodes. Le décompte de la minuterie est incrémenté de un lorsque le commutateur est enfoncé pour
la première fois (après l'anti-rebond). Maintenir le commutateur pendant plus d'une seconde augmente le taux
d'incrémentation de quatre ; maintenir le commutateur pendant quatre secondes augmente le taux de dix.

144 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Relâcher le commutateur démarre le compte à rebours, et lorsque le compte atteint zéro, une broche est
définie sur HIGH (dans cet exemple, allumer une LED)ÿ:
/*
Esquisse SwitchTime
Le compte à rebours qui décrémente tous les dixièmes de seconde allume
une LED lorsque 0
Appuyez sur le bouton pour compter les incréments, maintenez le bouton enfoncé pour
augmenter le taux d'incrément

*/
const int ledPin = 13; const // le numéro de la broche de sortie // le
inPin = 2ÿ; numéro de la broche d'entrée

const int debounceTime = 20ÿ; pour // le temps en millisecondes requis


que le commutateur soit stable const
int fastIncrement = 1000; millisecondes // incrémente plus vite après ce nombre

const int veryFastIncrement = 4000; // et incrémente encore plus vite après ce nombre de
millisecondes int count = 0; seconde jusqu'à atteindre 0
// compte les décréments tous les dixièmes de a

void setup()
{ pinMode(inPin,
INPUT); digitalWrite(inPin,
HIGH); // active la résistance de rappel pinMode(ledPin, OUTPUT);
Série.begin(9600); }

void loop() { int


durée =
switchTime(); if( duration >
veryFastIncrement) count = count + 10; sinon
si (durée> fastIncrement)

compter = compter + 4ÿ;


sinon si (durée> debounceTime)
compter = compter + 1ÿ;

else
{ //
commutateur non enfoncé, donc service de la minuterie
if( count == 0) digitalWrite(ledPin, HIGH); // allume la LED
si le compte est 0 else { digitalWrite(ledPin, LOW); // éteint la LED si le compte n'est pas
0 // et décrémente le compte count = count - 1; } }

5.4 Déterminer combien de temps un interrupteur est enfoncé | 145


Machine Translated by Google

Serial.println(count);
retard(100); }

// renvoie le temps en millisecondes pendant lequel le commutateur a été enfoncé (LOW) long
switchTime() { // ces variables sont statiques - voir Discussion pour une explication static unsigned
long startTime = 0; // l'heure à laquelle l'état du commutateur a changé

premier état
booléen statique détectéÿ; // l'état actuel du commutateur

if(digitalRead(inPin) != state) // vérifie si le commutateur a changé d'état { // oui, inverse l'état state = !
Etat; startTime = millis(); // stocke l'heure } if( state == LOW)

return millis() - startTimeÿ; // switch appuyé, temps de retour en millisecondes sinon return 0; //
renvoie 0 si le commutateur n'est pas enfoncé (à l'état HIGH);

Discussion
Le cœur de cette recette est la fonction switchTime . Cela renvoie le nombre de millisecondes pendant
lesquelles le commutateur a été enfoncé. Étant donné que cette recette utilise des résistances pull-up
internes (voir la recette 5.2), la lecture numérique de la broche de l'interrupteur reviendra BAS lorsque
l'interrupteur est enfoncé.

La boucle vérifie la valeur renvoyée par switchTime pour voir ce qui devrait se passer. Si le temps
pendant lequel le commutateur a été maintenu enfoncé est suffisamment long pour l'incrément le plus
rapide, le compteur est incrémenté de ce montantÿ; sinon, il vérifie la valeur rapide pour voir si cela doit
être utiliséÿ; sinon, il vérifie si le commutateur a été maintenu enfoncé suffisamment longtemps pour
arrêter de rebondir et si c'est le cas, il incrémente un peu. Tout au plus, l'un d'entre eux se produira. Si
aucune d'entre elles n'est vraie, le commutateur n'est pas enfoncé ou il n'a pas été enfoncé assez
longtemps pour arrêter de rebondir. La valeur du compteur est vérifiée et une LED s'allume si elle est
nulleÿ; si ce n'est pas zéro, le compteur est décrémenté et la LED s'éteint.

Vous pouvez utiliser la fonction switchTime uniquement pour faire rebondir un commutateur. Le code
suivant gère la logique anti-rebond en appelant la fonction switchTimeÿ:
const int debounceTime = 20ÿ; doit // le temps en millisecondes que le commutateur
être stable

if( switchTime() > debounceTime);


Serial.print("le commutateur est anti-rebond");

Cette approche de l'anti-rebond peut être pratique si vous avez plus d'un commutateur, car vous pouvez
jeter un coup d'œil et voir combien de temps un commutateur a été enfoncé et traiter d'autres tâches en
attendant qu'un commutateur se stabilise. Pour implémenter cela, vous devez stocker l'état actuel de
l'interrupteur (enfoncé ou non) et l'heure à laquelle l'état a duré

146 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

modifié. Il existe de nombreuses façons de procéder. Dans cet exemple, vous utiliserez une fonction distincte
pour chaque commutateur. Vous pouvez stocker les variables associées à tous les commutateurs en haut de
votre sketch en tant que variables globales (appelées "globales" car elles sont accessibles partout). Mais il
est plus pratique d'avoir les variables de chaque commutateur contenues dans la fonction.

La conservation des valeurs des variables définies dans une fonction est obtenue en utilisant des variables
statiques. Les variables statiques au sein d'une fonction fournissent un stockage permanent pour les valeurs
qui doivent être conservées entre les appels de fonction. Une valeur affectée à une variable statique est
conservée même après le retour de la fonction. La dernière valeur définie sera disponible au prochain appel
de la fonction. En ce sens, les variables statiques sont similaires aux variables globales (variables déclarées
en dehors d'une fonction, généralement au début d'un sketch) que vous avez vues dans les autres recettes.
Mais contrairement aux variables globales, les variables statiques déclarées dans une fonction ne sont
accessibles qu'au sein de cette fonction. L'avantage des variables statiques est qu'elles ne peuvent pas être
accidentellement modifiées par une autre fonction.

Cette esquisse montre un exemple de la façon dont vous pouvez ajouter des fonctions distinctes pour
différents commutateurs. Le câblage pour cela est similaire à la recette 5.2, avec le deuxième commutateur
câblé de la même manière que le premier (comme illustré à la Figure 5-5) mais connecté entre la broche 3 et Gndÿ:
/*
Esquisse SwitchTimeMultiple
Imprime combien de temps plus d'un interrupteur a été enfoncé */

const int switchAPin = 2ÿ; const // la broche de l'interrupteur


int switchBPin = 3ÿ; A // la broche de l'interrupteur B

// les fonctions avec des références doivent être explicitement déclarées


unsigned long switchTime(int pin, boolean &state, unsigned long &startTime);

void setup()

{ pinMode(switchAPin, INPUT);
digitalWrite(switchAPin, HIGH); // active les résistances pull-up
pinMode(switchBPin, INPUT); digitalWrite(switchBPin, HIGH); // active les
résistances pull-up Serial.begin(9600); }

void loop()
{ unsigned
long timeÿ;

Serial.print("switch A time ="); temps =


switchATime(); Serial.print(time);

Serial.print(", switch B time ="); temps =


switchBTime(); Serial.println(heure);
retard(1000);

5.4 Déterminer combien de temps un interrupteur est enfoncé | 147


Machine Translated by Google

unsigned long switchTime(int pin, boolean &state, unsigned long &startTime)


{ if(digitalRead(pin) != state) // vérifie si le commutateur a changé d'état { //oui,
inverse l'état state = ! Etat; startTime = millis(); // stocke l'heure } if( state == LOW)
return millis() - startTime; // retourne le temps en millisecondes sinon retourne 0; //
HIGH); renvoie 0 si le commutateur n'est pas enfoncé (à l'état

long switchATime()
{ // ces variables
sont statiques - voir le texte pour une explication static unsigned
long startTime = 0; // l'heure à laquelle l'état du commutateur a changé
premier
détecté
retourner // l'état actuel
switchTime de l'étatétat,
(switchAPin, booléen statique
startTime); } du commutateurÿ;

long switchBTime()
{ // ces variables
sont statiques - voir le texte pour une explication static unsigned
long startTime = 0; // l'heure à laquelle l'état du commutateur a changé
premier état
booléen statique détectéÿ; // l'état actuel du commutateur return
switchTime(switchBPin, state, startTime); }

Le calcul du temps est effectué dans une fonction appelée switchTime(). Cette fonction examine et
met à jour l'état et la durée du commutateur. La fonction utilise des références pour gérer les
paramètres - les références ont été couvertes dans la recette 2.11. Une fonction pour chaque
commutateur (switchATime() et switchBTime()) est utilisée pour conserver l'heure de début et l'état
de chaque commutateur. Étant donné que les variables contenant les valeurs sont déclarées comme
statiques, les valeurs seront conservées à la sortie des fonctions. Le maintien des variables dans la
fonction garantit que la mauvaise variable ne sera pas utilisée. Les broches utilisées par les
commutateurs sont déclarées en tant que variables globales car les valeurs sont nécessaires à l'
installation pour configurer les broches. Mais comme ces variables sont déclarées avec le mot-clé
const , le compilateur n'autorisera pas la modification des valeurs, il n'y a donc aucune chance que
celles-ci soient accidentellement modifiées par le code d'esquisse.

Limiter l'exposition d'une variable devient plus important à mesure que les projets deviennent plus
complexes. L'environnement Arduino offre une manière plus élégante de gérer cela ; voir la recette
16.4 pour une discussion sur la façon d'implémenter ceci en utilisant des classes.

148 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

5.5 Lecture d'un clavier


Problème
Vous avez un clavier matriciel et souhaitez lire les touches enfoncées dans votre croquis. Par exemple,
vous disposez d'un clavier de type téléphone similaire au clavier à 12 touches SparkFun (Spark Fun
COM-08653).

Solution
Câblez les lignes et les colonnes du connecteur du clavier à l'Arduino, comme illustré à la Figure 5-6.

Figure 5-6. Connexion de la matrice de clavier SparkFun

Si vous avez câblé votre Arduino et votre clavier comme illustré à la Figure 5-6, le croquis suivant
imprimera les pressions de touches sur le moniteur sérieÿ:
/*
L'esquisse du
clavier imprime la touche enfoncée sur un clavier sur le port
série */

const int numRows = 4ÿ; const int numCols


// nombre= de
3ÿ;lignes
// nombre
dansde
le colonnes
clavier
const int debounceTime = 20ÿ; // nombre
commutateur
de millisecondes
soit stablepour que le

5.5 Lecture d'un clavier | 149


Machine Translated by Google

// keymap définit le caractère renvoyé lorsque la touche correspondante est enfoncée const char
keymap[numRows][numCols] = {
{ '1', '2', '3' } , { '4', '5',
'6' } , { '7', '8', '9' } , { '*',
'0' , '#' } }ÿ;

// ce tableau détermine les broches utilisées pour les lignes et les colonnes
const int rowPins[numRows] = { 7, 2, 3, 6 }ÿ; // Lignes 0 à 3 const int
colPins[numCols] = { 5, 8, 4 }ÿ; // Colonnes 0 à 2

void setup()

{ Serial.begin(9600); for
(int row = 0; row < numRows; row++)
{ pinMode(rowPins[row],INPUT); // Définir les
broches de ligne comme entrée digitalWrite(rowPins[row],HIGH); // activer
les pull-ups } for (int column = 0; column < numCols; column++) { // Définir
les broches de colonne comme sorties pour écrire
pinMode(colPins[column],OUTPUT); digitalWrite(colPins[colonne],HIGH); //
Rendre toutes les colonnes inactives } }

void loop()
{ clé de
caractère = getKey();
if( key != 0) // si le caractère n'est pas 0 alors c'est une pression de touche valide
{ Serial.print("Got key ");
Serial.println(clé); } }

// renvoie avec la touche enfoncée, ou 0 si aucune touche n'est enfoncée


char getKey() { char key = 0;

// 0 indique qu'aucune touche n'a été enfoncée

for(int column = 0; column < numCols; column++)


{ digitalWrite(colPins[column],LOW); for(int row = 0; row <
numRows; row++) { if(digitalRead(rowPins[row]) == LOW) // Active la colonne courante.
{ delay(debounceTime); // anti-rebond // Analyse toutes les lignes pour une pression sur une touche.
while(digitalRead(rowPins[row]) == LOW) // attend que
la touche soit relâchée // Rappelle quelle touche a été
// Une touche est-elle enfoncéeÿ?
enfoncée.

;
clé = keymap [ligne] [colonne]ÿ; } }

150 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

digitalWrite(colPins[colonne],HIGH); † // Désactive la colonne courante.

clé de retourÿ; // renvoie la touche enfoncée ou 0 si aucune


}

Ce croquis ne fonctionnera correctement que si le câblage est conforme au code. Le tableau 5-1 montre
comment les lignes et les colonnes doivent être connectées aux broches Arduino. Si vous utilisez un
clavier différent, vérifiez votre fiche technique pour déterminer les connexions des lignes et des colonnes.
Vérifiez attentivement, car un câblage incorrect peut court-circuiter les broches, ce qui pourrait endommager votre
puce du contrôleur.

Tableau 5-1. Mappage des broches Arduino sur le connecteur SparkFun et les lignes et colonnes du clavier

Broche Arduino Connecteur du clavier Clavier rangée/colonne

2 7 Rangée 1

3 6 Rangée 2

4 5 Colonne 2

5 4 Colonne 0

6 3 Rangée 3

7 2 Ligne 0

8 1 Colonne 1

Discussion
Les claviers matriciels sont généralement constitués de commutateurs normalement ouverts qui connectent une rangée avec
une colonne lorsqu'il est pressé. (Un interrupteur normalement ouvert établit uniquement une connexion électrique
lorsqu'il est enfoncé.) La figure 5-6 montre comment les conducteurs internes connectent les rangées de boutons
et les colonnes au connecteur du clavier. Chacune des quatre rangées est connectée à une entrée
broche et chaque colonne est connectée à une broche de sortie. La fonction de configuration définit la broche
modes et active les résistances pull-up sur les broches d'entrée (voir les recettes pull-up dans le
début de ce chapitre).

La fonction getkey définit séquentiellement la broche pour chaque colonne LOW , puis vérifie pour
voir si l'une des broches de la rangée est BASSE. Parce que des résistances pull-up sont utilisées, les rangées seront
haut (tiré vers le haut) sauf si un interrupteur est fermé (la fermeture d'un interrupteur produit un signal BAS sur le
broche d'entrée). S'ils sont BAS, cela indique que le commutateur pour cette ligne et cette colonne est
fermé. Un délai est utilisé pour s'assurer que l'interrupteur ne rebondit pas (voir la recette 5.3) ; la
le code attend que l'interrupteur soit relâché, et le caractère associé à l'interrupteur

se trouve dans le tableau keymap et est renvoyé par la fonction. Un 0 est renvoyé si aucun commutateur
est pressé.

Une bibliothèque dans Arduino Playground similaire à l'exemple précédent fournit


plus de fonctionnalité. La bibliothèque facilite la gestion de différents nombres de clés et
il peut être fait pour fonctionner tout en partageant certaines des broches avec un écran LCD. Vous pouvez trouver le
bibliothèque sur http:// www.arduino.cc/ playground/ Main/ KeypadTutorial.

5.5 Lecture d'un clavier | 151


Machine Translated by Google

Voir également

Pour plus d'informations sur le clavier à 12 touches SparkFun, rendez-vous sur http:// www.sparkfun.com/
commerce/ product_info.php?products_id=8653.

5.6 Lecture des valeurs analogiques

Problème

Vous voulez lire la tension sur une broche analogique. Peut-être voulez-vous une lecture d'un potentiomètre
(pot) ou d'un appareil ou d'un capteur qui fournit une tension comprise entre 0 et 5 volts.

Solution

Cette esquisse lit la tension sur une broche analogique et fait clignoter une LED à un taux proportionnel à
la valeur renvoyée par la fonction analogRead . La tension est ajustée par un potentiomètre connecté
comme illustré à la Figure 5-7ÿ:
/*
Esquisse de
pot faire clignoter une LED à une fréquence fixée par la position d'un potentiomètre
*/

const entier potPin = 0ÿ; // sélectionne la broche d'entrée du potentiomètre //


const int ledPin = 13ÿ; valeur sélectionne la broche de la LED // variable pour stocker la
entière = 0ÿ; valeur provenant du capteur

void setup()
{ pinMode(ledPin,
OUTPUT); // déclarer le ledPin comme une SORTIE }

void loop() { // lit


HIGH); // active la le
tension
ledPinsur
delay(val);
le pot valdigitalWrite(ledPin,
= analogRead(potPin);BAS);digitalWrite(ledPin,
// éteint le ledPin
delay(val); }
// taux de clignotement défini par la valeur du pot (en millisecondes)

// éteint la led pendant la même période qu'elle a été allumée

Discussion

Cette esquisse utilise la fonction analogRead pour lire la tension sur l' essuie -glace du potentiomètre (la
broche centrale). Un pot a trois quilles ; deux sont connectés à un matériau résistif et la troisième broche
(généralement au milieu) est connectée à un essuie-glace qui peut être tourné pour établir un contact
n'importe où sur le matériau résistif. Lorsque le potentiomètre tourne, la résistance entre l'essuie-glace et
l'une des broches augmente, tandis que l'autre diminue.
Le diagramme schématique de cette recette (Figure 5-7) peut vous aider à visualiser le fonctionnement
d'un potentiomètreÿ; lorsque l'essuie-glace se déplace vers l'extrémité inférieure, l'essuie-glace (la ligne avec

152 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Figure 5-7. Connecter un potentiomètre à Arduino

la flèche) aura une résistance inférieure connectée à Gnd et une résistance supérieure connectée à 5 volts. Au
fur et à mesure que l'essuie-glace descend, la tension sur la broche analogique diminue (jusqu'à un minimum
de 0 volt). Déplacer l'essuie-glace vers le haut aura l'effet inverse et la tension sur la broche augmentera (jusqu'à
un maximum de 5 volts).

Si la tension sur la broche diminue, plutôt qu'elle n'augmente, à mesure que


vous augmentez la rotation du potentiomètre, vous pouvez inverser les
connexions aux broches +5 volts et Gnd.

La tension est mesurée à l'aide de analogRead, qui fournit une valeur proportionnelle à la tension réelle sur la
broche analogique. La valeur sera 0 lorsqu'il y a 0 volt sur la broche et 1 023 lorsqu'il y a 5 volts. Une valeur
intermédiaire sera proportionnelle au rapport de la tension sur la broche à 5 volts.

Les potentiomètres d'une valeur de 10K ohms sont le meilleur choix pour se connecter aux broches analogiques.
Consultez le site Web de ce livre pour connaître les références recommandées.

potPin n'a pas besoin d'être défini comme entrée. (Ceci est fait pour vous automatiquement
chaque fois que vous appelez analogRead.)

Voir également

Annexe B, pour des conseils sur la lecture des diagrammes

schématiques Référence Arduino pour analogRead : http:// www.arduino.cc/ en/ Reference/ AnalogRead

5.6 Lecture des valeurs analogiques | 153


Machine Translated by Google

Premiers pas avec Arduino par Massimo Banzi (Make)

5.7 Modification de la plage de valeurs

Problème
Vous souhaitez modifier la plage d'une valeur, telle que la valeur de analogRead obtenue
en connectant un potentiomètre ou un autre appareil fournissant une tension variable. Pour
Par exemple, supposons que vous souhaitiez afficher la position d'un bouton de potentiomètre sous forme de
pourcentage de 0 % à 100 %.

Solution
Utilisez la fonction de carte Arduino pour mettre les valeurs à l'échelle dans la plage souhaitée. Ce croquis se lit
la tension sur un pot dans la variable val et la met à l'échelle de 0 à 100 lorsque le pot est
tourné d'un bout à l'autre. Il fait clignoter une LED avec un taux proportionnel à la
tension sur la broche et imprime la plage mise à l'échelle sur le port série (voir la recette 4.2 pour
instructions sur la surveillance du port série). La recette 5.6 (voir Figure 5-7) montre comment le
pot est connecté:

/*
*
Croquis de la carte
*
cartographier la plage de valeurs analogiques d'un pot à l'échelle de 0 à 100
* résultant en un taux de clignotement des LED allant de 0 à 100 millisecondes.
* et le pourcentage de rotation du pot est écrit sur le port série
*/

const entier potPin = 0ÿ; // sélectionne la broche d'entrée pour le potentiomètre


int ledPin = 13ÿ; // sélectionne la broche pour la LED

void setup()
{
pinMode(ledPin, SORTIE); // déclare le ledPin comme une SORTIE
Série.begin(9600);
}

boucle vide() {
valeur // La valeur provenant du capteur
entièreÿ; entier pour centÿ; // La valeur mappée

val = analogRead(potPin); // lit la tension sur le pot (val range


// de 0 à 1023)
pourcentage = map(val,0,1023,0,100); // le pourcentage sera compris entre 0 et 100.
digitalWrite(ledPin, HIGH); // allume le ledPin
retard (pourcentage); // À l'heure donnée en pourcentage
digitalWrite(ledPin, BAS); // éteint le ledPin
retard (100 - pour cent); // Le temps d'arrêt est de 100 moins le temps d'activation
Serial.println(pourcentage); // affiche le % de rotation du pot sur Serial Monitor
}

154 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Discussion

La recette 5.6 décrit comment la position d'un pot est convertie en une valeur. Ici, vous utilisez cette valeur
avec la fonction de carte pour mettre la valeur à l'échelle de la plage souhaitée. Dans cet exemple, la valeur
fournie par analogRead (0 à 1023) est mappée à un pourcentage (0 à 100). Les valeurs de analogRead vont
de 0 à 1023 si la tension est comprise entre 0 et 5 volts, mais vous pouvez utiliser toutes les valeurs appropriées
pour les plages source et cible. Par exemple, un pot typique ne tourne que de 270 degrés d'un bout à l'autre,
et si vous vouliez afficher l'angle du bouton sur votre pot, vous pourriez utiliser ce code :

angle = carte(val,0,1023,0,270); // angle du pot dérivé de analogRead val

Les valeurs de plage peuvent également être négatives. Si vous souhaitez afficher 0 lorsque le pot est centré
et des valeurs négatives lorsque le pot est tourné vers la gauche et des valeurs positives lorsqu'il est tourné
vers la droite, vous pouvez faire ceci : angle = map(val,0,1023,-135,135); // montre l'angle du pot de 270
degrés avec le centre
comme 0

La fonction de carte peut être pratique lorsque la plage d'entrée qui vous intéresse ne commence pas à zéro.
Par exemple, si vous avez une batterie dont la capacité disponible est proportionnelle à une tension comprise
entre 1,1 volt (1 100 millivolts) et 1,5 volt (1 500 mil livolts), vous pouvez procéder comme suit :

const entier vide = 5000 / 1100ÿ; // la tension est de 1,1 volts (1100mv) lorsque vide
const int plein = 5000/1500ÿ; // la tension est de 1,5 volts (1500mv) lorsqu'elle est pleine

int val = analogRead(potPin); // lit la tension analogique int percent = map(val,


empty, full, 0,100); // mappe la plage de tension réelle sur un pourcentage
Serial.println(percent);

(Voir la recette 5.9 pour plus de détails sur la relation entre les valeurs analogRead et la tension réelle.)

Voir également

La référence Arduino pour la carte : http:// www.arduino.cc/ en/ Reference/ Map

5.8 Lecture de plus de six entrées analogiques


Problème

Vous avez plus d'entrées analogiques à surveiller que de broches analogiques disponibles. Une carte Arduino
standard a six entrées analogiques (la Mega en a 16) et il se peut qu'il n'y ait pas assez d'entrées analogiques
disponibles pour votre application. Peut-être souhaitez-vous régler huit paramètres dans votre application en
tournant les boutons sur huit potentiomètres.

5.8 Lecture de plus de six entrées analogiques | 155


Machine Translated by Google

Solution
Utilisez une puce multiplexeur pour sélectionner et connecter plusieurs sources de tension à une entrée
analogique. En sélectionnant séquentiellement parmi plusieurs sources, vous pouvez lire chaque source à tour de rôle.
Cette recette utilise la puce 4051 populaire connectée à Arduino, comme illustré à la Figure 5-8.
Vos entrées analogiques sont connectées aux broches 4051 marquées Ch 0 à Ch 7. Assurez-vous que la
tension sur les broches d'entrée du canal ne dépasse jamais 5 voltsÿ:

/*
L'esquisse du multiplexeur
lit 1 des 8 valeurs analogiques dans une seule broche d'entrée analogique avec un multiplexeur 4051 */

// tableau de broches utilisé pour sélectionner 1 des 8 entrées sur le


multiplexeur const int select[] = {2,3,4}ÿ; // tableau des broches connectées aux 4051 lignes
de sélection d'entrée const int analogPin = 0; sortir
// la broche analogique connectée au multiplexeur

// cette fonction renvoie la valeur analogique pour le canal donné int


getValue( int channel) {

// ce qui suit définit les broches du sélecteur HIGH et LOW pour correspondre à la
valeur binaire du canal
for(int bit = 0; bit < 3; bit++) {

int pin = select[bit]ÿ; // la broche câblée au multiplexeur select bit int isBitSet =
bitRead(channel, bit); // vrai si le bit donné est défini dans le canal digitalWrite(pin,
isBitSet);

} return analogRead(analogPin);
}

void setup()
{ for(int bit =
0; bit < 3; bit++)
pinMode(select[bit], OUTPUT); // définit les trois broches de sélection pour afficher
Serial.begin(9600); }

void loop () { //
affiche les valeurs de chaque canal une fois par seconde
for(int channel = 0; channel < 8; channel++) {

valeur int = getValue(canal);


Serial.print("Canal ");
Serial.print(canal); Serial.print(" =
"); Serial.println(valeur);

} retard (1000); }

156 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Figure 5-8. Le multiplexeur 4051 connecté à Arduino

Discussion
Les multiplexeurs analogiques sont des commutateurs analogiques à commande numérique. Le 4051 sélectionne l'un des
huit entrées via trois broches de sélection (S0, S1 et S2). Il existe huit combinaisons différentes de
valeurs pour les trois broches de sélection, et l'esquisse sélectionne séquentiellement chacune
des modèles de bits possiblesÿ; voir Tableau 5-2.

Tableau 5-2. Table de vérité pour le multiplexeur 4051

Broches de sélection Entrée sélectionnée

S2 S1 S0

0 0 0 0

0 0 1 1

0 1 0 2

0 1 1 3

1 0 0 4

1 0 1 5

1 1 0 6

1 1 1 7

Vous pouvez reconnaître le modèle du tableau 5-2 comme la représentation binaire de la décimale
valeurs de 0 à 7.

Dans l'esquisse précédente, getValue() est la fonction qui définit les bits de sélecteur corrects pour
le canal donné en utilisant digitalWrite(pin, isBitSet) et lit la valeur analogique de

5.8 Lecture de plus de six entrées analogiques | 157


Machine Translated by Google

l'entrée 4051 sélectionnée avec analogRead(analogPin). Le code pour produire les motifs binaires
utilise la fonction intégrée bitRead (voir la recette 3.12).

N'oubliez pas de connecter la terre des appareils que vous mesurez à la terre sur le 4051 et
l'Arduino, comme illustré à la Figure 5-8.

Gardez à l'esprit que cette technique sélectionne et surveille les huit entrées de manière séquentielle,
elle nécessite donc plus de temps entre les lectures sur une entrée donnée par rapport à l'utilisation
directe de la lecture analogique . Si vous lisez huit entrées, la lecture de chaque entrée prendra huit
fois plus de temps. Cela peut rendre cette méthode inadaptée aux entrées dont la valeur change
rapidement.

Voir également

Tutoriel Arduino Playground pour le 4051 : http:// www.arduino.cc/ playground/ Learning/ 4051

Fiche technique du CD4051 : http:// www.fairchildsemi.com/ ds/ CD%2FCD4052BC.pdf

Fiche technique de la carte de dérivation MUX analogique/numérique : http:// www.nkcelectronics.com/


analog digital-mux-breakout.html

5.9 Affichage des tensions jusqu'à 5V

Problème
Vous souhaitez surveiller et afficher la valeur d'une tension comprise entre 0 et 5 volts. Par exemple,
supposons que vous souhaitiez afficher la tension d'une seule cellule de 1,5 V sur le moniteur série.

Solution
Utilisez AnalogRead pour mesurer la tension sur une broche analogique. Convertissez la lecture en
tension en utilisant le rapport de la lecture à la tension de référence (5 volts), comme illustré à la
Figure 5-9.

158 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Figure 5-9. Mesure de tensions jusqu'à 5 volts à l'aide d'une carte 5 V

La solution la plus simple utilise un calcul en virgule flottante pour imprimer la tensionÿ; cet exemple
d'esquisse calcule et imprime le rapport sous forme de tensionÿ:
/*
L'esquisse Display5vOrless
imprime la tension sur la broche analogique vers le port série
Avertissement - ne connectez pas plus de 5 volts directement à une broche Arduino. */

const int referenceVolts = 5ÿ; const // la référence par défaut sur une carte 5 volts // la
int batteryPin = 0ÿ; batterie est connectée à la broche analogique 0

void setup() {

Série.begin(9600);
}

boucle vide()
{
int val = analogRead (batteriePin); // lit la valeur du capteur float volts = (val / 1023)
* referenceVoltsÿ; // calcule le rapport Serial.println(volts); // affiche la valeur en volts

La formule est : Volts = (lecture analogique / pas analogiques) × Tension de référence

L'impression d'une valeur à virgule flottante sur le port série avec println formatera la valeur à deux
décimales.

5.9 Affichage des tensions jusqu'à 5V | 159


Machine Translated by Google

Effectuez la modification suivante si vous utilisez une carte 3,3ÿVÿ:

const int referenceVolts = 3,3ÿ;

Les nombres à virgule flottante consomment beaucoup de mémoire, donc à moins que vous
n'utilisiez déjà la virgule flottante ailleurs dans votre esquisse, il est plus efficace d'utiliser des
valeurs entières. Le code suivant semble un peu étrange au premier abord, mais comme analogRead
renvoie une valeur de 1023 pour 5 volts, chaque pas de valeur sera de 5 divisé par 1023. En unités
de millivolts, c'est 5 000 divisé par 1 023.

Ce code imprime la valeur en millivoltsÿ:


const int batteryPin = 0ÿ;

void setup()

{ Serial.begin(9600); }

void loop()
{ long val =
analogRead(batteryPin); // lit la valeur du capteur - note
val est un entier long
Serial.println( (val * (500000/1023)) / 100); // affiche la valeur en millivolts }

Le code suivant imprime la valeur en utilisant des points décimaux. Il imprime 1,5 si la tension est
de 1,5 volts.

const int batteryPin 0ÿ;

void setup()

{ Serial.begin(9600); }

void loop()
{ int val =
analogRead(batteryPin); // lit la valeur du capteur Serial.println(val/(1023/5)); //
imprime la valeur entière de la tension Serial.print('.'); Serial.println(val % (1023/5)); }

// imprime la fraction

Si vous utilisez une carte 3.3V, remplacez (1023/5) par (int)(1023/3.3).

160 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Discussion
La fonction analogRead() renvoie une valeur proportionnelle au rapport de la tension mesurée à la tension
de référence (5 volts). Pour éviter l'utilisation de la virgule flottante, tout en maintenant la précision, le code
fonctionne sur des valeurs en millivolts au lieu de volts (il y a 1 000 millivolts dans 1 volt). Étant donné
qu'une valeur de 1023 indique 5 000 millivolts, chaque unité représente 5 000 divisé par 1 023 millivolts
(c'est-à-dire 4,89 millivolts). Pour éliminer la virgule décimale, les valeurs sont multipliées par 100. En
d'autres termes, 5 000 millivolts fois 100 divisé par 1 023 donne le nombre de millivolts fois 100. En divisant
cela par 100, on obtient la valeur en millivolts. Si multiplier des nombres fractionnaires par 100 pour
permettre au compilateur d'effectuer le calcul à l'aide de l'arithmétique à virgule fixe semble compliqué,
vous pouvez vous en tenir à la méthode à virgule flottante plus lente et plus gourmande en mémoire.

Cette solution suppose que vous utilisez un Arduino standard alimenté en 5 volts. Si vous utilisez une carte
3,3 V, la tension maximale que vous pouvez mesurer est de 3,3 volts sans utiliser de diviseur de tension -
voir la recette 5.11.

5.10 Réponse aux changements de tension

Problème
Vous souhaitez surveiller une ou plusieurs tensions et prendre des mesures lorsque la tension monte ou
descend en dessous d'un seuil. Par exemple, vous souhaitez faire clignoter une LED pour indiquer un
niveau de batterie faible, peut-être pour commencer à clignoter lorsque la tension chute en dessous d'un
seuil d'avertissement et augmenter en urgence à mesure que la tension baisse davantage.

Solution
Vous pouvez utiliser les connexions illustrées à la figure 5-7 dans la recette 5.9, mais ici nous comparerons
la valeur de analogRead pour voir si elle descend en dessous d'un seuil. Cet exemple commence à faire
clignoter une LED à 1,2 volts et augmente le temps de marche à arrêt lorsque la tension diminue en
dessous du seuil. Si la tension descend en dessous d'un second seuil, la LED reste allumée :
/*
Esquisse RespondingToChanges
fait clignoter une LED pour indiquer les niveaux de basse
tension */

Seuil d'avertissement long = 1200ÿ; // Niveau d'avertissement en millivolts - la LED clignote


longuement CriticalThreshold = 1000ÿ; // Niveau de tension critique - la LED reste allumée

const int batteryPin = 0ÿ; const


int ledPin = 13ÿ;

void setup() {

pinMode(ledPin, SORTIE);
}

5.10 Réponse aux changements de tension | 161


Machine Translated by Google

void loop()
{ int val =
analogRead(batteryPin); // lit la valeur du capteur if( val < (warningThreshold * 1023L)/
5000) { // dans la ligne ci-dessus, L suivant un nombre en fait une valeur de 32
bits flash(val) ; } }

// fonction pour faire clignoter une led avec un temps d'allumage/extinction déterminé par
la valeur passée en pourcentage void flash(int percent) { digitalWrite(ledPin, HIGH);
retard (pourcentage + 1); digitalWrite(ledPin, BAS); retard(100 - pour cent); // vérifier le
délai == 0ÿ? }

Discussion
La ligne en surbrillance dans cette esquisse calcule le rapport de la valeur lue sur le port analogique à la
valeur de la tension de seuil. Par exemple, avec un seuil d'avertissement de 1 volt et une tension de référence
de 5 volts, vous voulez savoir quand la lecture analogique est d'un cinquième de la tension de référence.
L'expression 1023L indique au compilateur qu'il s'agit d'un entier long (un entier 32 bits ; voir la recette 2.2),
donc le compilateur va promouvoir toutes les variables de cette expression en entiers longs pour éviter de
déborder de la capacité d'un int (un entier 16 bits normal). -bit entier).

Lors de la lecture de valeurs analogiques, vous pouvez travailler dans les unités renvoyées par la lecture
analogique , allant de 0 à 1023, ou vous pouvez travailler dans les tensions réelles qu'elles représentent (voir
la recette 5.7). Comme dans cette recette, si vous n'affichez pas de tension, il est plus simple et plus efficace
d'utiliser directement la sortie de analogRead .

5.11 Mesure de tensions supérieures à 5 V (diviseurs de tension)

Problème
Vous souhaitez mesurer des tensions supérieures à 5 volts. Par exemple, vous souhaitez afficher la tension
d'une pile 9V et déclencher une LED d'alarme lorsque la tension descend en dessous d'un certain niveau.

Solution
Utilisez une solution similaire à la recette 5.9, mais connectez la tension via un diviseur de tension (voir
Figure 5-10). Pour des tensions jusqu'à 10 volts, vous pouvez utiliser deux résistances de 4,7K ohms. Pour
des tensions plus élevées, vous pouvez déterminer les résistances requises à l'aide du Tableau 5-3.

162 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

Figure 5-10. Diviseur de tension pour mesurer des tensions supérieures à 5 volts

Tableau 5-3. Valeurs de résistance

Calcul

Tension maximale R1 R2 R2 (R1 + R2) valeur du facteur de résistance

5 Court (+V connecté à Aucun (Gnd connecté à Aucun 1023

broche analogique) Terre)

dix 1K 1K 1(1 + 1) 511

15 2K 1K 1(2 + 1) 341

20 3K 1K 1(3 + 1) 255

30 4K (3,9K) 1K 1(4 + 1) 170

Sélectionnez la ligne avec la tension la plus élevée que vous devez mesurer pour trouver les valeurs de
deux résistances :

/*
Esquisse DisplayMoreThan5V
imprime la tension sur la broche analogique vers le port série
Ne connectez pas plus de 5 volts directement à une broche Arduino.
*/

const int referenceVolts = 5ÿ; //const // la référence par défaut sur une carte 5 volts
float referenceVolts = 3.3ÿ; // utilisez ceci pour une carte de 3,3 volts

const entier R1 = 1000ÿ; // valeur pour une tension maximale de 10 volts


const entier R2 = 1000ÿ;
// déterminer par les résistances de diviseur de tension, voir le texte
const int résistanceFacteur = 1023.0 / (R2/(R1 + R2)); const int
batteryPin = 0ÿ; // +V de la batterie est connecté à la broche analogique 0

5.11 Mesure de tensions supérieures à 5 V (diviseurs de tension) | 163


Machine Translated by Google

void setup() {

Série.begin(9600);
}

boucle vide()
{
int val = analogRead (batteriePin); // lit la valeur du capteur float volts = (val /
resistanceFactor) * referenceVoltsÿ; // calcule le rapport Serial.println(volts); // affiche la valeur en
volts
}

Discussion
Comme les recettes analogiques précédentes, cette recette repose sur le fait que la valeur
analogRead est un rapport de la tension mesurée à la référence. Mais comme la tension mesurée
est divisée par les deux résistances de chute, la valeur analogRead doit être multipliée pour obtenir
la tension réelle. Ce code est similaire à la recette 5.7, mais la valeur de resistanceFactor est
sélectionnée en fonction des résistances du diviseur de tension, comme indiqué dans le tableau 5-3ÿ:
const int facteur de résistance = 511ÿ; // déterminer par des résistances de diviseur de tension,
voir Tableau 5-3

La valeur lue sur la broche analogique n'est pas divisée par 1 023, mais par une valeur déterminée
par les résistances de chuteÿ:
float volts = (val / resistanceFactor) * referenceVoltsÿ; // calcule le rapport

Le calcul utilisé pour produire le tableau est basé sur la formule suivante : la tension de sortie est
égale à la tension d'entrée multipliée par R2 divisée par la somme de R1 et R2. Dans l'exemple où
deux résistances de valeur égale sont utilisées pour réduire de moitié la tension d'une pile 9 V, le
facteur de résistance est de 511 (la moitié de 1 023), de sorte que la valeur de la variable volts sera
le double de la tension qui apparaît sur la broche d'entrée. Avec des résistances sélectionnées pour
10 volts, la lecture analogique d'une pile 9V sera d'environ 920.

Plus de 5 volts sur la broche peuvent endommager la broche et éventuellement détruire la puce ;
vérifiez que vous avez choisi les résistances de la bonne valeur et que vous les avez correctement
câblées avant de les connecter à une broche d'entrée Arduino. Si vous avez un multimètre,
mesurez la tension avant de connecter tout ce qui pourrait éventuellement transporter des
tensions supérieures à 5 volts.

164 | Chapitre 5 : Entrée numérique et analogique simple


Machine Translated by Google

CHAPITRE 6

Obtenir l'entrée des capteurs

6.0 Présentation
Obtenir et utiliser les entrées des capteurs permet à Arduino de répondre ou de rendre compte du monde qui
l'entoure. C'est l'une des tâches les plus courantes que vous rencontrerez. Ce chapitre fournit des exemples simples
et pratiques d'utilisation des périphériques d'entrée et des capteurs les plus populaires. Les schémas de câblage
montrent comment connecter et alimenter les appareils, et des exemples de code montrent comment utiliser les
données dérivées des capteurs.

Les capteurs répondent aux entrées du monde physique et les convertissent en un signal électrique qu'Arduino peut
lire sur une broche d'entrée. La nature du signal électrique fourni par un capteur dépend du type de capteur et de la
quantité d'informations qu'il doit transmettre. Certains capteurs (tels que les photorésistances et les capteurs de
cliquetis piézo) sont construits à partir d'une substance qui modifie leurs propriétés électriques en réponse à un
changement physique. D'autres sont des modules électroniques sophistiqués qui utilisent leur propre microcontrôleur
pour traiter les informations avant de transmettre un signal à l'Arduino.

Les capteurs utilisent les méthodes suivantes pour fournir des informations :

Marche/ arrêt numérique Certains appareils, tels que le capteur d'inclinaison de


la recette 6.1 et le capteur de mouvement de la recette 6.3, activent et désactivent simplement une tension.
Celles-ci peuvent être traitées comme les recettes de commutation présentées au chapitre 5.

Analogique
D'autres capteurs fournissent un signal analogique (une tension proportionnelle à ce qui est détecté, comme
la température ou le niveau de lumière). Les recettes de détection de la lumière (recette 6.2), du mouvement
(recettes 6.1 et 6.3), des vibrations (recette 6.6), du son (recette 6.7) et de l'accélération (recette 6.18) montrent
comment les capteurs analogiques peuvent être utilisés. Tous utilisent la commande analogRead décrite au
chapitre 5.
Largeur d'impulsion

Les capteurs de distance, tels que le PING))) dans la recette 6.4, fournissent des données en utilisant une
durée d'impulsion proportionnelle à la valeur de distance. Ces capteurs mesurent la durée d'une impulsion à
l'aide de la commande pulseIn .

165
Machine Translated by Google

Série
Certains capteurs fournissent des valeurs à l'aide d'un protocole série. Par exemple, le lecteur RFID de
la recette 6.9 et le GPS de la recette 6.14 communiquent via le port série Arduino (voir le chapitre 4
pour plus d'informations sur le port série). La plupart des cartes Arduino n'ont qu'un seul port série
matériel, alors lisez la recette 6.14 pour un exemple de la façon dont vous pouvez ajouter des ports
série logiciels supplémentaires si vous avez plusieurs capteurs série ou si le port série matériel est
occupé pour une autre tâche.

Protocoles synchrones : I2C et SPI


Les normes numériques I2C et SPI ont été créées pour que les microcontrôleurs comme Arduino
communiquent avec des capteurs et modules externes. La recette 6.16 montre comment un module
compas est connecté à l'aide de la signalisation numérique synchrone. Ces protocoles sont largement
utilisés pour les capteurs, les actionneurs et les périphériques, et ils sont traités en détail au chapitre 13.

Il existe une autre classe générique de dispositifs de détection que vous pouvez utiliser. Il s'agit d'appareils
grand public qui contiennent des capteurs, mais qui sont vendus en tant qu'appareils à part entière plutôt
qu'en tant que capteurs. Des exemples de ceux-ci dans ce chapitre incluent une souris PS2 et une manette
de jeu PlayStation. Ces appareils peuvent être très utiles ; ils fournissent des capteurs déjà intégrés dans
des dispositifs robustes et ergonomiques. Ils sont également peu coûteux (souvent moins chers que l'achat
des capteurs bruts qu'ils contiennent), car ils sont fabriqués en série.
Vous en avez peut-être quelques-uns qui traînent.

Si vous utilisez un appareil qui n'est pas spécifiquement couvert par une recette, vous pourrez peut-être
adapter une recette pour un appareil qui produit un type de sortie similaire. Les informations sur le signal de
sortie d'un capteur sont généralement disponibles auprès de la société auprès de laquelle vous avez acheté
l'appareil ou à partir d'une fiche technique de votre appareil (que vous pouvez trouver via une recherche
Google du numéro de pièce ou de la description de l'appareil).

Les fiches techniques sont destinées aux ingénieurs qui conçoivent les produits à fabriquer, et elles
fournissent généralement plus de détails que nécessaire pour que le produit soit opérationnel. Les
informations sur le signal de sortie seront généralement dans une section faisant référence au format de
données, à l'interface, au signal de sortie ou à quelque chose de similaire. N'oubliez pas de vérifier la tension
maximale (généralement dans une section intitulée « Valeurs nominales maximales absolues ») pour vous
assurer que vous n'endommagez pas le composant.

Les capteurs conçus pour un maximum de 3,3 volts peuvent être détruits en les connectant à 5 volts.
Vérifiez la cote maximale absolue de votre appareil avant de vous connecter.

La lecture des capteurs du monde analogique désordonné est un mélange de science, d'art et de
persévérance. Vous devrez peut-être faire preuve d'ingéniosité et d'essais et d'erreurs pour obtenir un
résultat réussi. Un problème courant est que le capteur vous indique simplement qu'une condition physique
s'est produite, pas ce qui l'a causée. Placer le capteur dans le bon contexte (emplacement, portée,
orientation) et limiter son exposition à des éléments que vous ne souhaitez pas activer sont des compétences
que vous acquerrez avec l'expérience.

166 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Un autre problème concerne la séparation du signal souhaité du bruit de fond ; La recette 6.6 montre comment
vous pouvez utiliser un seuil pour détecter quand un signal est au-dessus d'un certain niveau, et la recette 6.7
montre comment vous pouvez prendre la moyenne d'un certain nombre de lectures pour lisser les pics de bruit.

Voir également

Pour plus d'informations sur la connexion des composants électroniques, voir Make: Electronics by Charles
Platt (Make).

Voir l' introduction du chapitre 5 et la recette 5.6 pour en savoir plus sur la lecture des valeurs analogiques des
capteurs.

6.1 Détection de mouvement

Problème
Vous voulez détecter quand quelque chose est déplacé, incliné ou secoué.

Solution
Cette esquisse utilise un interrupteur qui ferme un circuit lorsqu'il est incliné, appelé capteur d'inclinaison. Les
recettes d'interrupteur du chapitre 5 (recettes 5.1 et 5.2) fonctionneront avec un capteur d'inclinaison à la place
de l'interrupteur.

Le schéma ci-dessous (circuit illustré à la Figure 6-1) allume la LED connectée à la broche 11 lorsque le capteur
d'inclinaison est incliné dans un sens, et la LED connectée à la broche 12 lorsqu'il est incliné dans l'autre sens : /
*

croquis d'inclinaison

un capteur d'inclinaison fixé à la broche


2, allume l'une des LED connectées aux broches 11 et 12
selon le sens d'inclinaison du capteur */

const int tiltSensorPin = 2ÿ; const //broche le capteur d'inclinaison est connecté
int firstLEDPin = 11; const int à //broche pour une LED //broche pour l'autre
secondLEDPin = 12ÿ;

void setup()
{ pinMode
(tiltSensorPin, INPUT); digitalWrite // le code lira cette broche // et
(tiltSensorPin, HIGH); utilisera une résistance pull-up

pinMode (firstLEDPin, OUTPUT); //le code contrôlera cette broche //et


pinMode (secondLEDPin, OUTPUT); } celle-ci

6.1 Détection de mouvement | 167


Machine Translated by Google

boucle vide ()
{
si (numériqueRead(tiltSensorPin)){ //vérifie si la broche est haute
digitalWrite(firstLEDPin, HIGH); // s'il est haut, allumez la première LED
digitalWrite(secondLEDPin, LOW); } //et éteindre la seconde LED

else // si ce n'est pas le cas

{ digitalWrite (firstLEDPin, LOW); //faire le contraire


digitalWrite(secondLEDPin, HIGH);
}
}

Figure 6-1. Capteur d'inclinaison et LED

Discussion
Le capteur d'inclinaison le plus courant est un roulement à billes dans une boîte avec des contacts à une extrémité. Lorsque
la boîte est inclinée la bille roule loin des contacts et la connexion est rompue.
Lorsque la boîte est inclinée pour rouler dans l'autre sens, la balle touche les contacts et complète
un circuit. Les marquages, ou configurations des broches, indiquent dans quelle direction le capteur doit être
orienté. Les capteurs d'inclinaison sont sensibles à de petits mouvements d'environ 5 à 10 degrés lorsque
orienté avec le ballon touchant juste les contacts. Si vous positionnez le capteur de sorte que le
roulement à billes est directement au-dessus (ou en dessous) des contacts, l'état de la LED ne changera que si
il est bien retourné. Cela peut être utilisé pour dire si quelque chose est debout ou à l'envers.

Pour déterminer si quelque chose est secoué, vous devez vérifier depuis combien de temps
l'état du capteur d'inclinaison a changé (la solution de cette recette vérifie simplement si l'interrupteur était
ouvert ou fermé). S'il n'a pas changé pendant un temps que vous considérez significatif, l'objet est
ne tremble pas. La modification de l'orientation du capteur d'inclinaison modifiera la vigueur du
il faut secouer pour le déclencher. Le code suivant allume une LED lorsque le capteur est secouéÿ:

168 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

/*
croquis secoué
capteur d'inclinaison connecté à la
broche 2 led connectée à la broche 13 */

const int tiltSensorPin = 2ÿ; const int


ledPin = 13ÿ; int tiltSensorPreviousValue
= 0ÿ; int tiltSensorCurrentValue = 0ÿ; long
lastTimeMoved = 0ÿ; int shakeTime=50ÿ;

void setup()
{ pinMode
(tiltSensorPin, INPUT); digitalWrite
(tiltSensorPin, HIGH); pinMode (ledPin,
SORTIE); }

void loop()

{ tiltSensorCurrentValue=digitalRead(tiltSensorPin); if
(tiltSensorPreviousValueÿ!= tiltSensorCurrentValue){ lastTimeMoved =
millis(); tiltSensorPreviousValue = tiltSensorCurrentValueÿ; }

if (millis() - lastTimeMoved < shakeTime)


{ digitalWrite(ledPin, HIGH); } else{ digitalWrite(ledPin,
LOW); } }

De nombreux capteurs à interrupteur mécanique peuvent être utilisés de manière similaire. Un interrupteur à flotteur peut s'allumer
lorsque le niveau d'eau dans un récipient atteint un certain niveau (similaire à la façon dont un robinet à bille fonctionne dans un
réservoir de toilette). Un coussin de pression tel que celui utilisé dans les entrées de magasin peut être utilisé pour détecter quand
quelqu'un se tient dessus. Si votre capteur active et désactive un signal numérique, quelque chose de similaire au croquis de cette
recette devrait convenir.

Voir également

Le chapitre 5 contient des informations générales sur l'utilisation des commutateurs avec Arduino.

La recette 12.2 contient davantage d'informations sur l'utilisation de la fonction millis pour déterminer le délai.

6.1 Détection de mouvement | 169


Machine Translated by Google

6.2 Détection de lumière

Problème
Vous voulez détecter les changements dans les niveaux de luminosité. Vous souhaiterez peut-être détecter un
changement lorsque quelque chose passe devant un détecteur de lumière ou mesurer le niveau de lumière, par
exemple, détecter lorsqu'une pièce devient trop sombre.

Solution
Le moyen le plus simple de détecter les niveaux de lumière consiste à utiliser une résistance dépendante de la
lumière (LDR). Cela change la résistance avec les niveaux de lumière changeants, et lorsqu'il est connecté dans le
circuit illustré à la figure 6-2 , il produit un changement de tension que les broches d'entrée analogiques Arduino peuvent
sens.

Illustration 6-2. Connexion d'une résistance dépendante de la lumière

Discussion
Le circuit de cette recette est la manière standard d'utiliser n'importe quel capteur qui change sa résistance en
fonction d'un phénomène physique (voir le chapitre 5 pour des informations générales sur la réponse aux signaux
analogiques). Le circuit de la figure 6-2 modifiera la tension sur la broche analogique 0 lorsque la résistance du LDR
change avec des niveaux de lumière variables.

Un circuit comme celui-ci ne donnera pas la gamme complète des valeurs possibles de l'entrée analogique - 0 à 1
023 - car la tension ne oscillera pas de 0 volt à 5 volts. En effet, il y aura toujours une chute de tension sur chaque
résistance, de sorte que la tension à leur rencontre n'atteindra jamais les limites de l'alimentation. Lors de l'utilisation
de tels capteurs, il est important de vérifier les valeurs réelles renvoyées par l'appareil dans la situation

170 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

va l'utiliser. Ensuite, vous devez déterminer comment les convertir en valeurs dont vous avez besoin pour contrôler tout ce
que vous allez contrôler. Voir la recette 5.7 pour plus de détails sur la modification de la plage de valeurs.

Le LDR est un type simple de capteur appelé capteur résistif. Une gamme de capteurs résistifs réagit aux changements de
différentes caractéristiques physiques. Le même circuit fonctionnera pour tout type de capteur résistif simple.

6.3 Détection de mouvement (intégration de détecteurs infrarouges passifs)

Problème
Vous souhaitez détecter lorsque des personnes se déplacent à proximité d'un capteur.

Solution
Utilisez un capteur de mouvement tel qu'un capteur infrarouge passif (PIR) pour modifier les valeurs sur une broche numérique
lorsque quelqu'un se déplace à proximité.

Des capteurs tels que le capteur de mouvement PIR SparkFun (SEN-08630) et le capteur PIR Parallax (555-28027) peuvent
être facilement connectés aux broches Arduino, comme illustré à la Figure 6-3.

Illustration 6-3. Connexion d'un détecteur de mouvement PIR

Consultez la fiche technique de votre capteur pour identifier les bonnes broches. Le capteur Parallax a des broches marquées
"OUT", "-" et "+" (pour Output, Gnd et +5V). Le capteur SparkFun est marqué par "Alarm", "GND" et "DC" (pour Output, Gnd
et +5V).

6.3 Détection de mouvement (intégration de détecteurs infrarouges passifs) | 171


Machine Translated by Google

Le schéma suivant allumera la LED sur la broche 13 de l'Arduino lorsque le capteur détecte un mouvementÿ:

/*
Esquisse
PIR un capteur de mouvement infrarouge passif connecté à la
broche 2 allume la LED sur la broche 13 */

const int ledPin = 13ÿ; const // choisissez la broche pour la LED //


int inputPin = 2ÿ; choisissez la broche d'entrée (pour le capteur PIR)

void setup()
{ pinMode(ledPin, OUTPUT); // déclare la LED en sortie //
pinMode(inputPin, INPUT); } déclare le bouton poussoir en entrée

void loop(){ int


val = digitalRead(inputPin); // lit la valeur d'entrée if (val == HIGH) //
vérifie si l'entrée est HIGH { digitalWrite (ledPin, HIGH); retard (500);
digitalWrite(ledPin, BAS); } }

// allume la LED si un mouvement est détecté

// éteint la LED

Discussion
Ce code est similaire aux exemples de boutons-poussoirs présentés au chapitre 5. C'est parce que le capteur agit
comme un interrupteur lorsqu'un mouvement est détecté. Différents types de capteurs PIR sont disponibles, et vous

devez vérifier les informations de celui que vous avez connecté.

Certains capteurs, tels que le Parallax, ont un cavalier qui détermine le comportement de la sortie lorsqu'un mouvement
est détecté. Dans un mode, la sortie reste HAUTE tant qu'un mouvement est détecté, ou elle peut être réglée de manière
à ce que la sortie passe brièvement à HAUTE puis à BASSE lorsqu'elle est déclenchée. L'exemple de croquis dans la
solution de cette recette fonctionnera dans les deux modes.

D'autres capteurs peuvent devenir BAS lors de la détection de mouvement. Si la broche de sortie de votre capteur passe
au niveau BAS lorsqu'un mouvement est détecté, changez la ligne qui vérifie la valeur d'entrée afin que la LED s'allume
lorsqu'elle est au niveau BASÿ:

si (val == BAS) // mouvement lorsque l'entrée est LOW

Les capteurs PIR sont disponibles dans une variété de styles et sont sensibles à différentes distances et angles. Un
choix et un positionnement judicieux peuvent les faire réagir au mouvement dans une partie d'une pièce, plutôt que dans
l'ensemble.

Les capteurs PIR réagissent à la chaleur et peuvent être déclenchés par des animaux tels que les
chats et les chiens, ainsi que par des personnes et d'autres sources de chaleur.

172 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

6.4 Distance de mesure


Problème
Vous voulez mesurer la distance à quelque chose, comme un mur ou quelqu'un marchant vers
l'Arduino.

Solution
Cette recette utilise le populaire capteur de distance à ultrasons Parallax PING))) pour mesurer
la distance d'un objet allant de 2 cm à environ 3 m. Il affiche la distance sur le moniteur série et
fait clignoter une LED plus rapidement à mesure que les objets se rapprochent (Figure 6-4 montre
les connexions) :

/* Ping))) Le capteur
*
imprime la distance et change le taux de clignotement
de la LED * en fonction de la distance du capteur Ping))) */

const int pingPin = 5; const


int ledPin = 13ÿ; // broche connectée à la LED

void setup()

{ Serial.begin(9600);
pinMode(ledPin, SORTIE); }

void loop()
{ int cm =
ping(pingPin)ÿ;
Serial.println(cm);
digitalWrite(ledPin, HIGH); retard
(cm * 10); // chaque centimètre ajoute un délai de 10 millisecondes
digitalWrite(ledPin, LOW); retard (cm * 10); }

// code suivant basé sur http://www.arduino.cc/en/Tutorial/Ping // renvoie la distance


en cm int ping(int pingPin) { // établit des variables pour la durée du ping, // et la
distance résultat en pouces et centimètres : longue durée, cm ;

// Le PING))) est déclenché par une impulsion HIGH de 2 microsecondes ou plus.


// Donnez une courte impulsion BASSE au préalable pour assurer une impulsion
HAUTE propreÿ: pinMode(pingPin, OUTPUT); digitalWrite(pingPin, BAS);
retardMicrosecondes(2); digitalWrite (pingPin, ÉLEVÉ);

6.4 Distance de mesure | 173


Machine Translated by Google

delayMicroseconds(5);digitalWrite(pingPin, LOW);

pinMode(pingPin, INPUT);
durée = pulseIn(pingPin, HIGH);

// convertit le temps en une distance


cm = microsecondsToCentimeters(duration);
retour cm ; }

long microsecondsToCentimeters(long microseconds)


{ // La vitesse du son est de 340 m/s ou 29
microsecondes par centimètre.
// Le ping va et vient, donc pour trouver la distance // de l'objet, nous
prenons la moitié de la distance parcourue. retour microsecondes /
29 / 2ÿ; }

Figure 6-4. Ping))) connexions du capteur

Discussion
Les capteurs à ultrasons fournissent une mesure du temps nécessaire au son pour rebondir sur
un objet et revenir au capteur.

L'impulsion sonore «ÿpingÿ» est générée lorsque le niveau pingPin devient ÉLEVÉ pendant
deux microsecondes. Le capteur génère alors une impulsion qui se termine lorsque le son revient.
La largeur de l'impulsion est proportionnelle à la distance parcourue par le son et l'esquisse
utilise ensuite la fonction pulseIn pour mesurer cette durée. La vitesse du son est de 340 mètres
par seconde, soit 29 microsecondes par centimètre. La formule de la distance de l'aller-retour
est : RoundTrip = microsecondes / 29

174 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Ainsi, la formule pour la distance à sens unique en centimètres est : microsecondes / 29 / 2


Le MaxBotix EZ1 est un autre capteur à ultrasons qui peut être utilisé pour mesurer la distance.
Il est plus facile à intégrer que le Ping))) car il n'a pas besoin d'être "pingé". Il peut fournir des
informations de distance continues, soit sous forme de tension analogique, soit proportionnelles à
la largeur d'impulsion. La figure 6-5 montre les connexions.

Figure 6-5. Connexion de la sortie EZ1 PW à une broche d'entrée numérique

L'esquisse qui suit utilise la sortie de largeur d'impulsion EZ1 pour produire une sortie similaire à
celle de l'esquisse précédenteÿ:
/*
* Le capteur de distance EZ1Rangefinder
*
imprime la distance et change le taux de flash LED *
en fonction de la distance du capteur Ping))) */

const int sensorPin = 5ÿ; const


int ledPin = 13ÿ; // broche connectée à la LED

valeur longue =
0ÿ; entier cm = 0ÿ;
int pouces = 0ÿ;

void setup()

{ Serial.begin(9600);
pinMode(ledPin, SORTIE); }

void loop()
{ valeur =
pulseIn(sensorPin, HIGH)ÿ; cm = valeur /
58ÿ; // la largeur d'impulsion estmicrosecondes
de 58 par cm pouces = valeur / 147ÿ; //
qui est de 147 microsecondes par pouce

6.4 Distance de mesure | 175


Machine Translated by Google

Serial.print(cm);
Serial.print(',');
Serial.println(pouces);

digitalWrite(ledPin, HIGH);
retard (cm * 10); // chaque centimètre ajoute un délai de 10
millisecondes digitalWrite(ledPin, LOW); retard (cm * 10);

retard(20); }

L'EZ1 est alimenté par des broches + 5V et de masse et celles-ci sont connectées aux broches Arduino
respectives. Connectez la broche EZ1 PW (PW est la sortie de largeur d'impulsion) à la broche
numérique Arduino 5. L'esquisse mesure la largeur de l'impulsion avec la commande pulseIn . La
largeur de l'impulsion est de 58 microsecondes par centimètre, soit 147 microsecondes par pouce.

Vous pouvez également obtenir une lecture de distance à partir de l'EZ1 via sa sortie analogique -
connectez la broche AN à une entrée analogique et lisez la valeur avec analogRead. Le code suivant
imprime l'entrée analogique convertie en pouces : value = analogRead(0) ; pouces = valeur / 2ÿ; //
chaque chiffre de lecture analogique est d'environ 5 mv Serial.println (pouces);

La sortie analogique est d'environ 9,8 mV par pouce. La valeur de analogRead est d'environ 4,8 mV par
unité (voir la recette 5.6 pour plus d'informations sur analogRead) et le code précédent les arrondit de
sorte que chaque groupe de deux unités mesure un pouce. L'erreur d'arrondi est faible par rapport à la
précision de l'appareil, mais si vous souhaitez un calcul plus précis, vous pouvez utiliser la virgule
flottante comme suit : value = analogRead(0) ; float mv = (valeur /1024.0) * 5000 ; pouces flottants =
mv / 9,8ÿ; // 9.8mv par pouce Serial.println(Inches) ;

Voir également

La recette 5.6 explique comment convertir les lectures de l'entrée analogique en valeurs de tension.

La référence Arduino pour pulseIn : http:// www.arduino.cc/ en/ Reference/ PulseIn

6.5 Mesure précise de la distance


Problème

Vous voulez mesurer la distance entre les objets et l'Arduino avec plus de précision que dans la recette
6.4.

176 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Solution
Les capteurs infrarouges (IR) fournissent généralement une sortie analogique qui peut être mesurée à
l'aide de analogRead. Ils peuvent avoir une plus grande précision que les capteurs à ultrasons, mais
avec une portée plus petite (une plage de 10 cm à 1 m ou 2 m est typique pour les capteurs IR). Cette
esquisse fournit des fonctionnalités similaires à la recette 6.4, mais elle utilise un capteur infrarouge,
le Sharp GP2Y0A02YK0F (la figure 6-6 montre les connexions)ÿ:
/* croquis de distance ir
*
imprime la distance et change le taux de flash LED en fonction de la distance du capteur IR */

int ledPin const int sensorPin


= 13ÿ;
= 0;////lalabroche
brocheconnectée
analogiqueà connectée
la LED pour
auclignoter
capteur const

référence longue constMv = 5000ÿ; // entier long pour éviter le débordement lors de la multiplication

void setup()

{ Serial.begin(9600);
pinMode(ledPin, SORTIE); }

void loop()
{ int val =
analogRead(sensorPin); int mV = (val *
referenceMv) / 1023ÿ;

Serial.print(mV);
Serial.print(","); int cm
= getDistance(mV);
Serial.println(cm);

digitalWrite(ledPin, HIGH); retard


(cm * 10); // chaque centimètre ajoute un délai de 10 millisecondes
digitalWrite(ledPin, LOW); retard (cm * 10);

retard(100); }

// ce qui suit est utilisé pour interpoler la distance à partir d'un tableau // les entrées du
tableau sont des distances par pas de 250 millivolts const int NBR_ELEMS = 10;
const int firstElement = 250; // la première entrée est 250 mV const int intervalle =
250ÿ; // millivolts entre chaque élément static int distance[TABLE_ENTRIES] =
{150,140,130,100,60,50,40,35,30,25,20,15}ÿ;

int getDistance(int mV) {

si( mV > INTERVALLE * TABLE_ENTRIES )


distance de retour[TABLE_ENTRIES-1]ÿ;
autre {

6.5 Mesurer la distance avec précision | 177


Machine Translated by Google

indice int = mV /
INTERVALLEÿ; flottant frac = (mV % 250) /
(float)INTERVALLEÿ; retour distance[index] - ((distance[index] - distance[index+1]) * frac);
}
}

Figure 6-6. Connexion du capteur de distance IR Sharp

Discussion
La sortie du capteur IR n'est pas linéaire, en d'autres termes, la valeur lue à partir de analogRead
n'est pas proportionnelle à la distance. Ainsi, le calcul est plus compliqué que celui utilisé dans
la recette 6.4. L'esquisse de la solution de cette recette utilise un tableau pour interpoler la
distance réelle en trouvant l'entrée la plus proche dans le tableau et en l'ajustant en fonction du
rapport de la valeur mesurée à l'entrée suivante du tableau (cette technique est appelée
interpolation). Vous devrez peut-être ajuster les valeurs du tableau pour votre capteur. Vous
pouvez le faire avec les informations de votre fiche technique ou par essais et erreurs.

Comme les valeurs du tableau peuvent être trouvées par essais et erreurs (mesure de la tension
jusqu'à ce qu'elle change de la quantité requise, puis mesure de la distance), cette technique peut
également être utilisée lorsque vous n'avez pas d'équation pour interpréter les valeurs. — par exemple,
lorsque vous n'avez pas de fiche technique de pièce pour l'appareil que vous utilisez.

La conversion de tension en distance se fait dans cette fonction :


int getDistance(int mV)

178 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

La fonction vérifie d'abord si la valeur se situe dans la plage indiquée dans le tableau. La distance valide la plus
courte est renvoyée si la valeur n'est pas comprise dans la plageÿ:

si( mV > INTERVALLE * TABLE_ENTRIES )


distance de retour[TABLE_ENTRIES-1]ÿ; //TABLE_ENTRIES-1 est la dernière entrée valide

Si la valeur est dans la plage du tableau, la division entière calcule quelle entrée est la plus proche mais est
inférieure à la lecture : int index = mV / INTERVAL ;

L'opérateur modulo (voir chapitre 3) est utilisé pour calculer une valeur fractionnaire lorsqu'une lecture se situe
entre deux entrées : float frac = (mV % 250) / (float)INTERVALÿ;

retour distance[index] + (distance[index]* (frac / intervalle));

La dernière ligne de la fonction getDistance utilise l'index et la fraction pour calculer et renvoyer une valeur de
distance. Il lit la valeur de la table, puis ajoute une proportion de cette valeur en fonction de la valeur frac . Ce
dernier élément est une approximation, mais comme il l'est pour une petite plage de résultat, il donne des résultats
acceptables. Si ce n'est pas assez précis pour vous, vous devez produire un tableau avec plus de valeurs
rapprochées.

Une table peut également être utilisée pour améliorer les performances si le calcul prend beaucoup de temps ou
s'il est effectué à plusieurs reprises avec un nombre limité de valeurs. Les calculs, en particulier en virgule
flottante, peuvent être lents. Remplacer le calcul par un tableau peut accélérer les choses.

Les valeurs peuvent soit être codées en dur dans l'esquisse, comme celle-ci, soit être calculées dans setup().
Cela peut rendre l'esquisse plus longue à démarrer, mais comme cela ne se produit qu'une fois à chaque fois que
l'Arduino est alimenté, vous obtiendrez alors un gain de vitesse à chaque fois autour de la boucle principale(). Le
compromis pour la vitesse est que la table consomme de la mémoire - plus la table est grande, plus la mémoire
RAM utilisée est importante. Voir le chapitre 17 pour obtenir de l'aide sur l'utilisation de Progmem pour stocker
des données dans la mémoire programme.

Vous devrez peut-être ajouter un condensateur entre les lignes + 5V et Gnd pour stabiliser
l'alimentation électrique du capteur afin que les fils de connexion ne soient pas maintenus en
court-circuit. Si vous obtenez des lectures erratiques, connectez un condensateur de 10 uF au
capteur (voir l' annexe C pour plus d'informations sur l'utilisation des condensateurs de découplage).

Voir également

Une explication détaillée du capteur IR Sharp est disponible sur http:// www.societyofrobots.com/
sensors_sharpirrange.shtml.

6.5 Mesurer la distance avec précision | 179


Machine Translated by Google

6.6 Détection des vibrations

Problème
Vous voulez répondre aux vibrationsÿ; par exemple, lorsqu'on frappe à une porte.

Solution
Un capteur Piezo réagit aux vibrations. Il fonctionne mieux lorsqu'il est connecté à une plus grande surface
qui vibre. La figure 6-7 montre les connexions :

/* croquis piezo
* s'allume et LED lorsque le Piezo est tapé */

const int sensorPin = 0ÿ; // la broche analogique connectée au capteur //


= 13ÿ; const entier SEUIL = 100ÿ; broche connectée à la LED const int ledPin

void setup() {

pinMode(ledPin, SORTIE);
}

void loop()
{ int val =
analogRead(sensorPin); if (val >=
SEUIL) { digitalWrite(ledPin, HIGH);
retard(100); // pour rendre la LED
visible } else

digitalWrite(ledPin, BAS);
}

Discussion
Un capteur piézo, également connu sous le nom de capteur de cliquetis, produit une tension en réponse à
une contrainte physique. Plus il est sollicité, plus la tension est élevée. Le Piezo est polarisé et le côté
positif (généralement un fil rouge ou un fil marqué d'un "+") est connecté à l'entrée analogiqueÿ; le fil négatif
(généralement noir ou marqué d'un "-") est relié à la terre.
Une résistance de forte valeur (1 mégohm) est connectée aux bornes du capteur.

180 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Illustration 6-7. Connexions du capteur de cliquetis

La tension est détectée par Arduino analogRead pour allumer une LED (voir le chapitre 5 pour en savoir plus sur la
fonction analogRead ). La valeur THRESHOLD détermine le niveau du capteur qui allumera la LED, et vous pouvez
diminuer ou augmenter cette valeur pour rendre l'esquisse plus ou moins sensible.

Les capteurs piézo peuvent être achetés dans des boîtiers en plastique ou sous forme de disques métalliques nus
avec deux fils attachés. Les composants sont les mêmes ; utilisez celui qui convient le mieux à votre projet.

Certains capteurs, tels que le Piezo, peuvent être pilotés par l'Arduino pour produire ce qu'ils peuvent détecter. Le
chapitre 9 en dit plus sur l'utilisation d'un Piezo pour générer du son.

6.7 Détection du son


Problème
Vous souhaitez détecter des sons tels que des applaudissements, des paroles ou des cris.

Solution
Cette recette utilise la carte de dérivation BOB-08669 pour le microphone Electret (Spark Fun). Connectez la carte
comme illustré à la Figure 6-8 et chargez le code sur la carte.

6.7 Détection de son | 181


Machine Translated by Google

Figure 6-8. Connexions de la carte microphone

La LED intégrée sur la broche 13 de l'Arduino s'allume lorsque vous applaudissez, criez ou jouez fort
musique près du microphone. Vous devrez peut-être ajuster le seuil - utilisez le
Surveiller pour afficher les valeurs hautes et basses et modifier la valeur de seuil pour qu'elle soit
entre les valeurs élevées que vous obtenez lorsque le bruit est présent et les valeurs faibles lorsqu'il y a
est peu ou pas de bruit. Téléchargez le code modifié sur le tableau et réessayezÿ:
/*
croquis de microphone

La carte de dérivation SparkFun pour microphone Electret est connectée à la broche analogique 0
*/

const int ledPin = 13ÿ; const // le code fera clignoter la LED dans la broche 13
int middleValue = 512; //le milieu de la plage des valeurs analogiques
const int numberOfSamples = 128ÿ; // combien de lectures seront prises à chaque fois

int échantillonÿ; //la valeur lue depuis le microphone à chaque fois


signal longÿ; //la lecture une fois que vous avez supprimé le décalage DC
lecture moyenne longueÿ; // la moyenne de cette boucle de lectures

long runningAverage=0ÿ; // la moyenne mobile des valeurs calculées


const int moyenne sur = 16ÿ; // à quelle vitesse les nouvelles valeurs affectent la moyenne courante
// plus grand signifie plus lent

const int seuil=400ÿ; // à quel niveau la lumière s'allume

void setup() {
pinMode(ledPin, SORTIE);
Série.begin(9600);
}

boucle vide() {
long sumOfSquares = 0ÿ;
for (int i=0; i<numberOfSamples; i++) { // prendre plusieurs lectures et en faire la moyenne

182 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

échantillon = analogRead(0); //prenez une lecture


signal = (échantillon - middleValue); signal // calcule son décalage par rapport au centre
*= signalÿ; sumOfSquares += signalÿ; } // placez-le au carré pour que toutes les valeurs soient positives
// ajouter au total

lecturemoyenne = sumOfSquares/numberOfSamplesÿ; // calcule la moyenne courante


runningAverage=(((averagedOver-1)*runningAverage)+averageReading)/averagedOverÿ;

if (runningAverage>threshold) //est-ce que la moyenne est supérieure au seuilÿ?


{ digitalWrite(ledPin, HIGH); }autre{ //si c'est le cas, allumez la LED

digitalWrite(ledPin, BAS); } //si ce n'est pas le cas, éteignez la LED

Serial.println(runningAverage); } // affiche la valeur pour que vous puissiez la vérifier

Discussion
Un microphone produit de très petits signaux électriques. Si vous l'avez connecté directement au
broche d'un Arduino, vous n'obtiendrez aucun changement détectable. Le signal doit être
amplifié d'abord pour le rendre utilisable par Arduino. La carte SparkFun a le microphone
avec un circuit amplificateur intégré pour amplifier le signal à un niveau lisible par Arduino.

Étant donné que vous lisez un signal audio dans cette recette, vous devrez effectuer quelques calculs
supplémentaires pour obtenir des informations utiles. Un signal audio change assez rapidement,
et la valeur renvoyée par analogRead dépendra du point du signal ondulant
vous prenez une lecture. Si vous n'êtes pas familiarisé avec l'utilisation d' analogRead, consultez le chapitre 5 et
Recette 6.2. Un exemple de forme d'onde pour une tonalité audio est illustré à la Figure 6-9. Comme le temps
change de gauche à droite, la tension monte et descend de façon régulière. Si vous
prenez des lectures aux trois moments différents marqués dessus, vous obtiendrez trois valeurs différentes.
Si vous l'avez utilisé pour prendre des décisions, vous pourriez conclure à tort que le signal a été
plus fort au milieu.

Une mesure précise nécessite plusieurs lectures rapprochées. Les sommets


et les creux augmentent à mesure que le signal augmente. La différence entre le fond d'un
creux et le sommet d'un pic est appelé l' amplitude du signal, et cela augmente à mesure que
le signal devient plus fort.

6.7 Détection de son | 183


Machine Translated by Google

Illustration 6-9. Signal audio mesuré à trois endroits

Pour mesurer la taille des pics et des creux, vous mesurez la différence entre la tension médiane et les
niveaux des pics et des creux. Vous pouvez visualiser cette valeur médiane sous la forme d'une ligne à
mi-chemin entre le pic le plus élevé et le creux le plus bas, comme illustré à la Figure 6-10. La ligne
représente le décalage DC du signal (c'est la valeur DC lorsqu'il n'y a pas de pics ou de creux). Si vous
soustrayez la valeur de décalage CC de vos valeurs analogRead , vous obtenez la lecture correcte pour
l'amplitude du signal.

Figure 6-10. Signal audio indiquant le décalage CC (point médian du signal)

Au fur et à mesure que le signal devient plus fort, la taille moyenne de ces valeurs augmentera, mais
comme certaines d'entre elles sont négatives (où le signal est tombé en dessous du décalage CC), elles
s'annuleront et la moyenne aura tendance à être nulle. Pour résoudre ce problème, nous élevons chaque
valeur au carré (multiplions-la par elle-même). Cela rendra toutes les valeurs positives et augmentera la
différence entre les petits changements, ce qui vous aidera également à évaluer les changements. La
valeur moyenne va maintenant monter et descendre comme le fait l'amplitude du signal.

184 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Pour faire le calcul, nous devons savoir quelle valeur utiliser pour le décalage DC. Pour obtenir un signal
propre, le circuit amplificateur du microphone aura été conçu pour avoir un décalage DC aussi proche
que possible du milieu de la plage de tension possible afin que le signal puisse devenir aussi grand que
possible sans distorsion. Le code suppose cela et utilise la valeur 512 (en plein milieu de la plage d'entrée
analogique de 0 à 1 023).

Les valeurs des variables en haut de l'esquisse peuvent être modifiées si l'esquisse ne se déclenche pas
bien pour le niveau de son souhaité.

Le nombre d'échantillons est défini sur 128. S'il est trop petit, la moyenne risque de ne pas couvrir
correctement les cycles complets de la forme d'onde et vous obtiendrez des lectures erratiques. Si la
valeur est trop élevée, la moyenne sera trop longue et un son très court peut être manqué car il ne produit
pas suffisamment de changement une fois qu'un grand nombre de lectures sont moyennées. Cela pourrait
également commencer à introduire un délai notable entre un son et la lumière qui s'allume. Les constantes
utilisées dans les calculs, telles que numberOfSamples et averageed Over, sont définies sur des
puissances de 2 (128 et 16, respectivement). Essayez d'utiliser des valeurs divisibles par deux pour que
celles-ci vous donnent les performances les plus rapides (voir le chapitre 3 pour plus d'informations sur
les fonctions mathématiques).

6.8 Mesure de la température


Problème
Vous souhaitez afficher la température ou utiliser la valeur pour piloter un appareil ; par exemple, pour
allumer quelque chose lorsque la température atteint un seuil.

Solution
Cette recette affiche la température en Fahrenheit et Celsius (Centigrade) à l'aide du populaire capteur
de détection de chaleur LM35. Le capteur ressemble à un transistor et est connecté comme illustré à la
Figure 6-11ÿ:
/*
L'esquisse
lm35 imprime la température sur le moniteur
série */

const inPin = 0ÿ; // broche analogique

void setup()

{ Serial.begin(9600); }

void loop()
{ int value =
analogRead(inPin);

6.8 Mesure de la température | 185


Machine Translated by Google

Serial.print(valeur); Serial.print(" > "); flottant


millivolts = (valeur / 1024,0) * 5000ÿ; flotteur
Celsius = millivolts / 10ÿ; // la sortie du capteur est de 10mV par degré Celsius
Serial.print(celsius); Serial.print(" degrés Celsius, ");

Serial.print( (celsius * 9)/ 5 + 32 ); // convertit en Fahrenheit Serial.println("


degrés Fahrenheit");

retard(1000); // attend une seconde

Illustration 6-11. Raccordement du capteur de température LM35

Discussion
Le capteur de température LM35 produit une tension analogique directement proportionnelle à la température
avec une sortie de 1 millivolt par 0,1°C (10 mV par degré).

L'esquisse convertit les valeurs analogRead en millivolts (voir chapitre 5) et les divise par 10 pour obtenir
des degrés.

La précision du capteur est d'environ 0,5 ° C et, dans de nombreux cas, vous pouvez utiliser des nombres
entiers au lieu de virgule flottante.

Le schéma suivant active la broche 2 lorsque la température dépasse un seuilÿ:

const inPin = 0ÿ; // capteur connecté à cette broche analogique


const int outPin = 13ÿ; //2ÿ; // broche de sortie numérique

seuil entier constant = 25ÿ; // les degrés Celsius qui déclencheront la broche de sortie

186 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

void setup()

{ Serial.begin(9600);
pinMode(sortiePin, SORTIE); }

void loop()
{ int value =
analogRead(inPin); long celsius =
(valeur * 500L) /1024ÿ; Serial.print(celsius); // 10 mV par degré c, voir texte
Serial.print(" degrés Celsius : "); si(celsius >
seuil) {

digitalWrite(outPin, HIGH);
Serial.println("la broche est allumée");

}
autre {
digitalWrite (outPin, BAS);
Serial.println("la broche est désactivée");

} retard(1000); // attend une seconde }

L'esquisse utilise des entiers longs (32 bits) pour calculer la valeur. La lettre L après le nombre entraîne l'exécution
du calcul à l'aide d'entiers longs mathématiques, de sorte que la multiplication de la température maximale (500 sur
un Arduino 5V) et la valeur lue à partir de l'entrée analogique ne déborde pas. Voir les recettes du chapitre 5 pour en
savoir plus sur la conversion des niveaux analogiques en valeurs de tension.

Si vous avez besoin des valeurs en Fahrenheit, vous pouvez utiliser le capteur LM34, car cela produit une sortie en
Fahrenheit, ou vous pouvez convertir les valeurs dans cette recette en utilisant la formule suivanteÿ:

flottant f = (celsius * 9)/ 5 + 32 );

6.9 Lecture des étiquettes RFID

Problème
Vous souhaitez lire une étiquette RFID et répondre à des identifiants spécifiques.

Solution
La figure 6-12 montre un lecteur Parallax RFID (identification par radiofréquence) connecté au port série Arduino.
(Vous devrez peut-être déconnecter le lecteur du port série lors du téléchargement de l'esquisse.)

6.9 Lecture des étiquettes RFID | 187


Machine Translated by Google

Figure 6-12. Lecteur RFID série connecté à Arduino

L'esquisse lit et affiche la valeur d'une étiquette RFIDÿ:


/*
Esquisse RFID
Affiche la valeur lue à partir d'un tag RFID */

const int startByte = 10ÿ; // Le saut de ligne ASCII précède chaque balise
const int endByte const =int13ÿ;
tagLength
// Le retour
= 10;chariot
// le nombre
ASCII de
termine
chiffres
chaque
dans balise
la balise
const int totalLength = tagLength + 2ÿ; // longueur de la balise + octets de début
et de fin

balise char[tagLength + 1]ÿ; // contient la balise et un null de fin

int octets lus = 0ÿ;

void setup()
{ // définissez
pinMode(2,SORTIE);
ceci sur le//débit
connecté
en bauds
à la broche
de votreRFID
lecteur
ENABLE
RFID Serial.begin(2400);
digitalWrite(2,
LOW); // activer le lecteur RFID }

void loop()

{ if(Serial.available() >= totalLength) // vérifie s'il y a suffisamment de données


{ if(Serial.read() == startByte) {

octets lus = 0ÿ; // début de balise donc réinitialiser le compte à 0

188 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

while(bytesread < tagLength) // lit le code à 10 chiffres { int val


= Serial.read(); if((val == startByte)||(val == endByte)) // vérifie
la fin du code

Pause;
balise [octets lus] =
sélectionnerÿ; octets lus = octets lus + 1ÿ; // prêt à lire le chiffre suivant

} if( Serial.read() == endByte) // vérifie le bon caractère de fin { tag[bytesread] = 0; //


terminer la chaîne Serial.print("La balise RFID estÿ: "); Serial.println(balise); } } } }

Discussion
Une balise se compose d'un caractère de début suivi d'une balise à 10 chiffres et se termine par un
caractère de fin. L'esquisse attend qu'un message de balise complet soit disponible et affiche la
balise si elle est valide. L'étiquette est reçue sous forme de chiffres ASCII (voir la recette 4.4 pour
plus d'informations sur la réception de chiffres ASCII). Vous voudrez peut-être convertir cela en un
nombre si vous souhaitez stocker ou comparer les valeurs reçues. Pour ce faire, modifiez les
dernières lignes comme suitÿ: if( Serial.read() == endByte) // vérifie le bon caractère de fin

{ balise[octets lus] = 0ÿ; // termine la chaîne longue


tagValue = atol(tag); // convertit la balise ASCII en un entier long Serial.print("La balise
RFID estÿ: "); Serial.println(tagValue); }

RFID signifie identification par radiofréquence et, comme son nom l'indique, il est sensible aux
radiofréquences et peut être sujet aux interférences. Le code de la solution de cette recette n'utilisera
que du code de longueur correcte contenant les bits de début et de fin corrects, ce qui devrait
éliminer la plupart des erreurs. Mais vous pouvez rendre le code plus résilient en lisant la balise
plusieurs fois et en n'utilisant les données que si elles sont identiques à chaque fois. (Les lecteurs
RFID tels que le Parallax répéteront le code lorsqu'une carte valide se trouve à proximité du lecteur.)
Pour ce faire, ajoutez les lignes suivantes aux dernières lignes de l'extrait de code précédentÿ:
if( Serial.read() == endByte) // vérifie le bon caractère de fin { tag[bytesread] = 0; //
termine la chaîne longue tagValue = atol(tag); // convertit la balise ASCII en un entier
long if (tagValue == lastTagValue) { Serial.print("La balise RFID estÿ: ");
Serial.println(tagValue); lasTagValue = tagValueÿ; } }

6.9 Lecture des étiquettes RFID | 189


Machine Translated by Google

Vous devrez ajouter la déclaration pour lastTagValue en haut de l'esquisseÿ:


Longue lastTagValue=0ÿ;

Cette approche est similaire au code de la recette 5.3. Cela signifie que vous n'obtiendrez la
confirmation d'une carte que si elle est présentée suffisamment longtemps pour que deux lectures soient
prises, mais les fausses lectures seront moins probables. Vous pouvez éviter un déclenchement
accidentel en imposant la présence de la carte pendant un certain temps avant que le numéro ne soit signalé.

6.10 Suivi du mouvement d'un cadran


Problème
Vous voulez mesurer et afficher la rotation de quelque chose pour suivre sa vitesse et/ou sa direction.

Solution
Pour détecter ce type de mouvement, vous pouvez utiliser un encodeur rotatif. Connectez l'encodeur
comme illustré à la Figure 6-13ÿ:
/*
Lire un encodeur rotatif
Cette version simple interroge les broches de l'encodeur
La position est affichée sur le Serial Monitor */

const int codeurPinA = 4ÿ; const


int codeurPinB = 2ÿ; const int
encoderStepsPerRevolution=16ÿ; angle entier = 0ÿ;

valeur entièreÿ;

int codeurPos = 0ÿ;


codeur booléenALast = LOWÿ; // se souvient de l'état précédent de la broche

void setup()

{ pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
digitalWrite(encoderPinA, HIGH);
digitalWrite(encoderPinB, HIGH); Serial.begin
(9600); }

void loop()
{ boolean
encoderA = digitalRead(encoderPinA);

190 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

if ((encoderALast == HIGH) && (encoderA == LOW))

{ if (digitalRead(encoderPinB) == LOW)
{ encoderPos--ÿ; } else { encodeurPos+
+ÿ; } angle=(encoderPos %
encoderStepsPerRevolution)*360/
encoderStepsPerRevolutionÿ; Serial.print
(encodeurPos); Serial.print (" ");
Serial.println (angle); }

codeurALast = codeurAÿ; }

Illustration 6-13. codeur rotatif

Discussion
Un encodeur rotatif produit deux signaux lorsqu'il est tourné. Les deux signaux alternent
entre HIGH et LOW lorsque l'arbre est tourné, mais les signaux sont légèrement déphasés
l'un par rapport à l'autre. Si vous détectez le point où l'un des signaux passe de HIGH à
LOW, l'état de l'autre broche (qu'elle soit HIGH ou LOW) vous indiquera dans quel sens
l'arbre tourne.

6.10 Suivi du mouvement d'un cadran | 191


Machine Translated by Google

Ainsi, la première ligne de code de la fonction de boucle lit l'une des broches de l'encodeurÿ:

int encoderA = digitalRead(encoderPinA);

Ensuite, il vérifie cette valeur et la précédente pour voir si la valeur vient de passer à LOWÿ:

if ((encoderALast == HIGH) && (encoderA == LOW))

Si ce n'est pas le cas, le code n'exécute pas le bloc suivant ; il va au bas de la boucle, enregistre la valeur qu'il
vient de lire dans encoderALast et revient en arrière pour prendre une nouvelle lecture.

Lorsque l'expression suivante est vraieÿ:

if ((encoderALast == HIGH) && (encoderA == LOW))

le code lit l'autre broche d'encodeur et incrémente ou décrémente encoderPos en fonction de la valeur renvoyée.
Il calcule l'angle de l'arbre (en prenant 0 comme étant le point où se trouvait l'arbre lorsque le code a commencé à
s'exécuter). Il envoie ensuite les valeurs sur le port série afin que vous puissiez les voir dans le moniteur série.

Les codeurs sont disponibles dans différentes résolutions, exprimées en pas par tour. Ceci indique combien de
fois les signaux alternent entre HIGH et LOW pour un tour de l'arbre. Les valeurs peuvent varier de 16 à 1 000.
Les valeurs plus élevées peuvent détecter des mouvements plus petits et ces encodeurs coûtent beaucoup plus
cher. La valeur de l'encodeur est codée en dur dans le code de la ligne suivanteÿ:

const int encoderStepsPerRevolution=16ÿ;

Si votre encodeur est différent, vous devez le modifier pour obtenir les valeurs d'angle correctes.

Si vous obtenez des valeurs qui ne montent pas et ne descendent pas, mais augmentent quelle que soit la direction
dans laquelle vous tournez l'encodeur, essayez de modifier le test pour rechercher un front montant plutôt qu'un
front descendant. Échangez les valeurs LOW et HIGH dans la ligne qui vérifie les valeurs pour qu'elle ressemble à
ceciÿ:

if ((encoderALast == LOW) && (encoderA == HIGH))

Les encodeurs rotatifs produisent simplement un signal d'incrémentation/décrémentationÿ; ils ne peuvent pas vous
dire directement l'angle de l'arbre. Le code le calcule, mais il sera relatif à la position de départ à chaque exécution
du code. Le code surveille les broches en les interrogeant (en vérifiant en permanence la valeur). Il n'y a aucune
garantie que les broches n'ont pas changé plusieurs fois depuis la dernière fois que le code a regardé, donc si le
code fait aussi beaucoup d'autres choses et que l'encodeur est tourné très rapidement, il est possible que certaines
des étapes soient manquer.
Pour les encodeurs haute résolution, cela est plus probable, car ils enverront des signaux beaucoup plus souvent
lorsqu'ils seront tournés.

Pour déterminer la vitesse, vous devez compter le nombre de pas enregistrés dans une direction dans un temps
défini.

192 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

6.11 Suivi du mouvement de plusieurs encodeurs rotatifs


Problème
Vous avez deux encodeurs rotatifs ou plus et vous souhaitez mesurer et afficher la rotation.

Solution
Le circuit utilise deux codeurs, connectés comme illustré à la Figure 6-14. Vous pouvez en savoir plus
sur les encodeurs rotatifs dans la recette 6.10ÿ:
/*
RotaryEncoderMultiPoll
Cette esquisse a deux encodeurs connectés.
L'un est connecté aux broches 2 et
3 L'autre est connecté aux broches 4 et 5 */

const int CODEURS = 2ÿ; // le nombre d'encodeurs

const int codeurPinA[ENCODEURS] = {2,4}ÿ; // broches encoderA sur 2 et 4 //


const int encoderPinB[ENCODERS] = {3,5}; int encodeurPos[
broches encoderB
ENCODEURS]
sur 3 et= 5
{ 0,0}ÿ; // initialise les positions à 0 boolean encoderALast[ENCODERS] = le dernier
{ LOW,LOW}ÿ; // détient
état de la broche encoderA

void setup()
{ for (int i=2;
i<6; i++){ pinMode(i, HIGH);
digitalWrite(i, HIGH); }

Serial.begin (9600); }

int updatePosition( int encoderIndex)


{ boolean encoderA =
digitalRead(encoderPinA[encoderIndex]); if
((encoderALast[encoderIndex] == HIGH) && (encoderA == LOW)) { if
(digitalRead(encoderPinB[encoderIndex]) == LOW)
{ encoderPos[encoderIndex]--ÿ; } else { encoderPos[encoderIndex]+
+ÿ; }

Serial.print("Encodeur ");
Serial.print(encoderIndex,DEC);
Serial.print("="); Serial.print
(encoderPos[encoderIndex]); Serial.println
("/"); }

6.11 Suivi du mouvement de plusieurs encodeurs rotatifs | 193


Machine Translated by Google

encodeurALast[encodeurIndex] = encodeurAÿ; }

void loop()
{ for(int i=0; i
< ENCODERS;i++) { updatePosition(i); } }

Figure 6-14. Connexion de deux encodeurs rotatifs

Discussion
Cette recette utilise la même logique de code que la recette 6.10, qui lisait un encodeur, mais elle utilise
des tableaux pour toutes les variables qui doivent être mémorisées séparément pour chaque encodeur.
Vous pouvez ensuite utiliser une boucle for pour parcourir chacune d'entre elles, la lire et calculer sa
rotation. Pour utiliser plus d'encodeurs, définissez les valeurs ENCODERS sur le nombre d'encodeurs
dont vous disposez et étendez les tableaux et les définitions pour indiquer les broches auxquelles ils sont attachés.
pour.

Si vous obtenez des valeurs qui ne montent pas et ne descendent pas, mais augmentent quelle que soit la
direction dans laquelle vous tournez l'encodeur, essayez de modifier le test pour rechercher un front montant
plutôt qu'un front descendant. Échangez les valeurs LOW et HIGH dans la ligne qui vérifie les valeurs à partir de
ceciÿ: if ((encoderALast[encoderIndex] == HIGH) && (encoderA == LOW))

194 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

pour ça:

if ((encoderALast[encoderIndex] == LOW) && (encoderA == HIGH))

Si l'un des encodeurs fonctionne mais que l'autre ne fait que compter, inversez les connexions A et B
pour celui qui vient de compter.

6.12 Suivi du mouvement d'un cadran dans une esquisse occupée

Problème
Au fur et à mesure que vous étendez votre code et qu'il fait d'autres choses en plus de lire l'encodeur, la
lecture de l'encodeur commence à devenir peu fiable. Ce problème est particulièrement grave si l'arbre
tourne rapidement.

Solution
Le circuit est le même que celui de la recette 6.11. Nous utiliserons une interruption sur l'Arduino pour
nous assurer qu'à chaque fois qu'une étape se produit, le code y répondÿ:
/*
Esquisse d'interruption de l'encodeur rotatif
*/

const int codeurPinA = 2ÿ; const


int codeurPinB = 4ÿ; int Pos,
oldPosÿ; codeur int volatilPos =
0ÿ; // les variables modifiées dans les interruptions sont volatiles

void setup()

{ pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
digitalWrite(encoderPinA, HIGH);
digitalWrite(encoderPinB, HIGH);
Série.begin(9600);

attachInterrupt(0, doEncoder, FALLING); // broche d'encodeur sur l'interruption 0 (broche 2) }

boucle vide()
{
uint8_t oldSREG = SREGÿ;

cli();
Pos = codeurPosÿ;
SREG =
ancienSREGÿ;
if(Pos != oldPos)
{ Serial.println(Pos,DEC);
oldPos = Posÿ;

6.12 Suivi du mouvement d'un cadran dans une esquisse occupée | 195
Machine Translated by Google

}
Délai(1000);
}

void doEncoder()
{ if
(digitalRead(encoderPinA) == digitalRead(encoderPinB)) encoderPos+
+ÿ; // compte si les deux
sinonbroches de l'encodeur sont identiques,
encoderPos--ÿ;

// compte à rebours si les broches sont différentes


}

Ce code ne rapportera la valeur Pos sur le port série, au plus, qu'une fois par seconde (à cause du retard), mais
les valeurs rapportées tiendront compte de tout mouvement qui aurait pu se produire pendant le retard.

Discussion
Comme votre code a plus de choses à faire, les broches de l'encodeur seront vérifiées moins souvent. Si les
broches passent par un changement d'étape complet avant d'être lues, l'Arduino ne détectera pas cette étape. Si
vous déplacez l'arbre rapidement, cela se produira plus souvent, car les étapes se produiront plus rapidement.

Pour vous assurer que le code répond à chaque fois qu'une étape se produit, vous devez utiliser des interruptions.
Lorsque la condition d'interruption se produit, le code saute de là où il se trouve, fait ce qui doit se passer, puis
revient là où il était et continue.

Sur une carte Arduino standard, deux broches peuvent être utilisées comme interruptionsÿ: les broches 2 et 3.
L'interruption est activée via la ligne suivanteÿ:

attachInterrupt(0, doEncoder, FALLING);

Les trois paramètres nécessaires sont l'identifiant de la broche d'interruption (0 pour la broche 2, 1 pour la broche
3)ÿ; la fonction à laquelle sauter lorsque l'interruption se produit, dans ce cas doEncoderÿ; et enfin, le comportement
de la broche pour déclencher l'interruption, dans ce cas lorsque la tension chute de 5 à 0 volts. Les autres options
sont RISING (la tension monte de 0 à 5 volts) et CHANGE (la tension chute ou monte).

La fonction doEncoder vérifie les broches de l'encodeur pour voir dans quel sens l'arbre a tourné et modifie
encoderPos pour refléter cela.

Si les valeurs signalées ne font qu'augmenter quel que soit le sens de rotation, essayez de modifier l'interruption
pour rechercher RISING plutôt que FALLING.

Étant donné que encoderPos est modifié dans la fonction appelée lorsque l'interruption se produit, il doit être
déclaré comme volatile lors de sa création. Cela indique au compilateur qu'il peut changer à tout moment ;
n'optimisez pas le code en supposant qu'il n'aura pas changé, car l'interruption peut se produire à tout moment.

196 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Le processus de construction Arduino optimise le code en supprimant le code et les variables qui ne
sont pas utilisés par votre code d'esquisse. Les variables qui ne sont modifiées que dans un gestionnaire
d'interruption doivent être déclarées volatiles pour indiquer au compilateur de ne pas supprimer ces
variables.

Pour lire cette variable dans la boucle principale, vous devez prendre des précautions particulières
pour vous assurer que l'interruption ne se produit pas au milieu de sa lecture. Ce morceau de code
fait ça :

uint8_t oldSREG = SREGÿ;

cli();
Pos = codeurPosÿ;
SREG = ancienSREGÿ;

Vous enregistrez d'abord l'état de SREG (les registres d'interruption), puis cli désactive l'interruption.
La valeur est lue, puis la restauration de SREG réactive l'interruption et remet tout en l'état. Toute
interruption qui se produit lorsque les interruptions sont désactivées attendra que les interruptions
soient réactivées. Cette période est si courte que les interruptions ne seront pas manquées (tant
que vous gardez le code dans le gestionnaire d'interruption aussi court que possible).

6.13 Utilisation d'une souris

Problème
Vous souhaitez détecter les mouvements d'une souris compatible PS2 et réagir aux changements
de coordonnées x et y .

Solution
Cette solution utilise des LED pour indiquer le mouvement de la souris. La luminosité des LED
change en réponse au mouvement de la souris dans les directions x (gauche et droite) et y (plus
près et plus loin). Cliquez sur les boutons de la souris pour définir la position actuelle comme point
de référence. La Figure 6-15 montre les connexions :
/*
Souris
un croquis arduino utilisant la bibliothèque de souris
ps2 voir: http://www.arduino.cc/playground/ComponentLib/Ps2mouse */

// bibliothèque de souris de : http://www.arduino.cc/playground/ComponentLib/Ps2mouse #include


<ps2.h>

const int dataPin = 5 const


int clockPin = 6ÿ;

const entier xLedPin = 9ÿ;


const entier yLedPin = 11ÿ;

6.13 Utilisation d'une souris | 197


Machine Translated by Google

const int mouseRange = 255; // la plage maximale de valeurs x/y

int xPosition = 0ÿ; int // valeurs incrémentées et décrémentées lors du déplacement de la souris
yPosition = 0ÿ; int
xLuminosité = 128ÿ; // valeurs augmentées et diminuées en fonction de la position de la souris int yBrightness
= 128ÿ;

octet const REQUEST_DATA = 0xebÿ; // commande pour récupérer les données de la souris

Souris PS2 (clockPin, dataPin);

void setup()

{ Serial.begin(115200); // notez la vitesse série plus élevée que d'habitude mouseBegin(); }

// obtenir une lecture de la souris et la renvoyer à l'hôte via la ligne série void loop() { char x; char y; état
des octetsÿ;

// valeurs lues à la souris

// obtenir une lecture de la souris


mouse.write(REQUEST_DATA); // demande à la souris des données
mouse.read(); // ignorer l'état deboutons
lit les l'accuséde
delaréception = mouse.read();
souris if(status & 1) // ce //
bit est défini si le bouton gauche de la souris a appuyé sur xPosition
= 0ÿ; // centrer la position x de la souris if(status & 2) // ce bit est défini si le bouton
droit de la souris a appuyé sur yPosition = 0ÿ; // centre la position y de la souris

x = souris.read(); y =
mouse.read(); if( x !=
0 || y != 0) { // ici s'il y a un
mouvement de souris

xPosition = xPosition + xÿ; // accumule la position xPosition =


constrain(xPosition,-mouseRange,mouseRange);

xBrightness = map(xPosition, -mouseRange, mouseRange, 0,255);


analogWrite(xLedPin, xBrightness);

yPosition = contrainte (yPosition + y, -mouseRange, mouseRange); yLuminosité


= carte (yPosition, -mouseRange, mouseRange, 0.255); analogWrite (yLedPin,
yBrightness); }

void mouseBegin() { //
réinitialiser et initialiser
la souris

198 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

mouse.write(0xff); // réinitialiser
retardMicrosecondes(100);
souris.read(); // octet de confirmation

souris.read(); // Vide
souris.read(); // Vide
mouse.write(0xf0); // mode distant
souris.read(); // ack
retardMicrosecondes(100);
}

Figure 6-15. Connexion d'une souris pour indiquer la position et allumer les LED

Discussion
Connectez le signal de la souris (horloge et données) et les câbles d'alimentation à Arduino, comme indiqué dans
Figure 6-15. Cette solution ne fonctionne qu'avec les appareils compatibles PS2, vous devrez donc peut-être
pour trouver une souris plus ancienne - la plupart des souris avec le connecteur PS2 rond devraient fonctionner.

La fonction mouseBegin initialise la souris pour répondre aux demandes de mouvement et


état du bouton. La bibliothèque PS2 de http:// www.arduino.cc/ playground/ ComponentLib/
Ps2mouse gère la communication de bas niveau. La commande mouse.write est utilisée pour

indiquez à la souris que les données seront demandées. Le premier appel à mouse.read obtient un
accusé de réception (qui est ignoré dans cet exemple). Le prochain appel à mouse.read obtient

6.13 Utilisation d'une souris | 199


Machine Translated by Google

l'état du bouton et les deux derniers appels mouse.read obtiennent le mouvement x et y qui a eu lieu depuis
la requête précédente.
L'esquisse teste pour voir quels bits sont HIGH dans la valeur d' état pour déterminer si le bouton gauche
ou droit de la souris a été enfoncé. Les deux bits les plus à droite seront HIGH lorsque les boutons gauche
et droit sont enfoncés, et ceux-ci sont vérifiés dans les lignes suivantesÿ:
status = mouse.read(); // lit les boutons de la souris
if(status & 1) // le bit le plus à droite est défini si le bouton gauche de la souris est enfoncé
xPosition = 0ÿ; // centrer la position x de la souris
if(status & 2) // ce bit est défini si le bouton droit de la souris a appuyé sur
yPosition = 0ÿ; // centre la position y de la souris

Les valeurs x et y lues à la souris représentent le mouvement depuis la requête précédente, et ces valeurs
sont accumulées dans les variables xPosition et yPosition.

Les valeurs de x et y seront positives si la souris se déplace vers la droite ou s'éloigne de vous, et négatives
si elle se déplace vers la gauche ou vers vous.

L'esquisse garantit que la valeur accumulée ne dépasse pas la plage définie (mouseRange) à l'aide de la
fonction de contrainteÿ: xPosition = xPosition + xÿ; // accumule la position xPosition = constrain(xPosition,-
mouseRange,mouseRange);

Le calcul de yPosition montre une manière abrégée de faire la même choseÿ; ici, le calcul de la valeur y
est effectué dans l'appel à la contrainte :

yPosition = contrainte (yPosition + y, -mouseRange, mouseRange);

Les variables xPosition et yPosition sont remises à zéro si les boutons gauche et droit de la souris sont
enfoncés.

Les LED s'allument pour correspondre à la position à l'aide de l' écriture analogiqueÿ: demi- luminosité au
centre, et augmentation et diminution de la luminosité à mesure que la position de la souris augmente
et diminue.

La position peut être affichée sur le Serial Monitor en ajoutant la ligne suivante juste après la fonction
analogWrite : printValues(); // affiche le bouton et les valeurs x et y sur Serial Monitor

Ajoutez la fonction suivante à la fin du sketch pour imprimer les valeurs reçues de la sourisÿ:

void printValues() {

Serial.println(statut, BIN);

Serial.print("X=");
Serial.print(x,DEC);
Serial.print(", position= ");
Serial.print(xPosition); Serial.print(",
luminosité= "); Serial.println(xBrightness);

200 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Serial.print("Y=");
Serial.print(y,DEC);
Serial.print(", position= ");
Serial.print(yPosition);
Serial.print(", luminosité= ");
Serial.println(yBrightness);
Serial.println();
}

6.14 Obtenir une position à partir d'un GPS

Problème
Vous souhaitez déterminer l'emplacement à l'aide d'un module GPS.

Solution
Un certain nombre d'unités GPS compatibles Arduino sont disponibles aujourd'hui. La plupart utilisent une
interface série familière pour communiquer avec leur microcontrôleur hôte à l'aide d'un protocole connu sous
le nom de NMEA 0183. Cette norme de l'industrie prévoit que les données GPS doivent être transmises à des
appareils "d'écoute" tels qu'Arduino sous forme de "phrases" ASCII lisibles par l'homme. Par exemple, la
phrase NMEA suivanteÿ: $GPGLL,4916.45,N,12311.12,W,225444,A,*1D

décrit, entre autres, un emplacement sur le globe à 49 16,45' de latitude nord par 123 11,12' de longitude ouest.

Pour établir l'emplacement, votre croquis Arduino doit analyser ces chaînes et convertir le texte pertinent sous
forme numérique. L'écriture de code pour extraire manuellement des données à partir de phrases NMEA peut
être délicate et fastidieuse dans l'espace d'adressage limité de l'Arduino, mais heureusement, il existe une
bibliothèque utile qui fait ce travail pour vous : TinyGPS de Mikal Hart.
Téléchargez-le depuis http:// arduiniana.org/ et installez-le. (Pour obtenir des instructions sur l'installation de
bibliothèques tierces, consultez le chapitre 16.)

La stratégie générale d'utilisation d'un GPS est la suivante :

1. Connectez physiquement l'appareil GPS à l'Arduino.


2. Lisez les données série NMEA de l'appareil GPS.

3. Traiter les données pour déterminer l'emplacement.

En utilisant TinyGPS, vous procédez comme

suit : 1. Connectez physiquement le périphérique GPS à l'Arduino.

2. Créez un objet TinyGPS.


3. Lisez les données série NMEA de l'appareil GPS.

4. Traitez chaque octet avec la méthode encode() de TinyGPS .

5. Interrogez périodiquement la méthode get_position() de TinyGPS pour déterminer l'emplacement.

6.14 Obtenir une position à partir d'un GPS | 201


Machine Translated by Google

Le croquis suivant illustre comment vous pouvez acquérir des données à partir d'un GPS connecté au port
série d'Arduino. Il allume la LED intégrée connectée à la broche 13 chaque fois que l'appareil se trouve
dans l'hémisphère sudÿ:

// Un croquis simple pour détecter l'hémisphère sud


// Supposeÿ: LED sur la broche 13, GPS connecté aux broches série matérielles 0/1

#include "TinyGPS.h"
GPS TinyGPSÿ; // crée un objet TinyGPS

#define HEMISPHERE_PIN
13 void setup() {

Démarrez les communications série en utilisant le débit requis par votre GPS. Voir le chapitre 4 si vous
avez besoin de plus d'informations sur l'utilisation des communications série Arduinoÿ:

Serial.begin(4800); // Les appareils GPS fonctionnent fréquemment à 4800 bauds


pinMode(HEMISPHERE_PIN, OUTPUT); digitalWrite(HEMISPHERE_PIN,
LOW); // éteint la LED pour démarrer }

void loop()
{ while
(Serial.available()) { int c =
Serial.read();

// Encode() chaque octet //


Vérifie la nouvelle position si encode() renvoie "True" if
(gps.encode(c)) { long lat, lon; gps.get_position(&lat, &lon); if (lat
< 0) // Hémisphère Sudÿ? digitalWrite(HEMISPHERE_PIN,
HIGH); autre

digitalWrite(HEMISPHERE_PIN, LOW);

}}}

Ici, une connexion à 4 800 bauds est établie avec le GPS. Une fois que les octets commencent à circuler,
ils sont traités par encode(), qui analyse les données NMEA. Un vrai retour de encode() indique que
TinyGPS a analysé avec succès une phrase complète et que de nouvelles données de position peuvent
être disponibles. C'est le bon moment pour vérifier l'emplacement actuel de l'appareil avec un appel à
get_position().

Get_position () de TinyGPS renvoie la latitude et la longitude les plus récemment observées.


L'exemple examine la latitude ; s'il est inférieur à zéro, c'est-à-dire au sud de l'équateur, la LED s'allume.

202 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Discussion
Attacher une unité GPS à un Arduino est généralement aussi simple que de connecter deux ou trois données
lignes du GPS aux broches d'entrée sur l'Arduino. Utilisation du populaire USGlobalSat
Module GPS EM-406A à titre d'exemple, vous pouvez connecter les lignes comme indiqué dans le Tableau 6-1.

Tableau 6-1. Connexions des broches GPS EM-406A

Ligne EM-406A Broche Arduino

Terre Terre

VIN +Vcc

RX TX (broche 1)

TX RX (broche 0)

Terre Terre

Certains modules GPS utilisent des niveaux de tension RS-232, qui sont incompatibles

avec la logique TTL d'Arduino. Ceux-ci nécessitent une sorte de logique intermédiaire

dispositif de conversion comme le circuit intégré MAX232.

Le code de la solution de cette recette suppose que le GPS est connecté directement à
Le port série intégré d'Arduino, mais ce n'est généralement pas la conception la plus pratique. Dans
de nombreux projets, le port série matériel est nécessaire pour communiquer avec un PC hôte ou
autre périphérique et ne peut pas être utilisé par le GPS. Dans de tels cas, sélectionnez une autre paire
de broches numériques et utiliser une bibliothèque d'émulation de port série ("soft serial") pour communiquer avec le GPS
au lieu.

SoftwareSerial est la bibliothèque d'émulation actuellement livrée avec l'IDE Arduino, mais
il est inadéquat pour la plupart des traitements GPS, en particulier pour les appareils modernes qui communiquent
à des vitesses plus élevées. À partir de la révision 0015 d'Arduino, le logiciel "soft" le plus robuste et le plus populaire
serial » est une bibliothèque tierce appelée NewSoftSerial, également publiée sur http://
arduiniana.org/. Du point de vue du programmeur, NewSoftSerial est utilisé de la même manière
vers la série matérielle, la migration n'est donc généralement pas très difficile. (Pour une discussion plus détaillée
sur l'utilisation de NewSoftSerial, voir les recettes 4.13 et 4.14.)

Vous pouvez déplacer les lignes RX et TX du GPS vers les broches 2 et 3 pour libérer la série matérielle
port pour le débogage. En laissant le câble série connecté au PC hôte, modifiez le croquis précédent pour utiliser
NewSoftSerial pour obtenir un aperçu détaillé de TinyGPS en action
via le moniteur série de l'Arduinoÿ:

// Un autre croquis simple pour détecter l'hémisphère sud


// Supposeÿ: LED sur la broche 13, GPS connecté aux broches 2/3
// (Facultatif) Console de débogage série attachée au port série matériel 0/1

#include "TinyGPS.h"
#include "NewSoftSerial.h"

6.14 Obtenir une position à partir d'un GPS | 203


Machine Translated by Google

#define HEMISPHERE_PIN 13
#define GPS_RX_PIN 2 #define
GPS_TX_PIN 3

GPS TinyGPSÿ; // crée un objet TinyGPS


NouveauSoftSerial nss(GPS_RX_PIN, GPS_TX_PIN); // crée un objet série souple

void setup() {

Notez que vous pouvez utiliser un débit en bauds différent pour la connexion au Serial Monitor et au GPSÿ:

Série.begin(9600); // pour le débogage


nss.begin(4800); // Utilisez l'objet NewSoftSerial pour parler au GPS
pinMode(HEMISPHERE_PIN, OUTPUT); digitalWrite(HEMISPHERE_PIN,
LOW); // éteint la LED pour démarrer }

void loop()
{ while
(nss.available()) { int c =
nss.read();

Serial.print(c, BYTE); // affiche les données NMEA pour le débogage

// Envoie chaque octet à encode()


// Vérifie la nouvelle position si encode() renvoie "True" if
(gps.encode(c)) { long lat, lon; gps.get_position(&lat, &lon);

// Affiche la nouvelle latitude/longitude sur la


console de débogage Serial.print("Latÿ: ");
Serial.print(lat); Serial.print("ÿLonÿ:ÿ"ÿ); Serial.println(lon);

if (lat < 0) // Hémisphère Sudÿ?


digitalWrite(HEMISPHERE_PIN, HIGH);
autre
digitalWrite(HEMISPHERE_PIN, LOW);
}

}}

Cette nouvelle esquisse se comporte exactement de la même manière que l'exemple précédent mais est
beaucoup plus facile à déboguer. À tout moment, vous pouvez simplement connecter un moniteur au port
série intégré pour regarder les phrases NMEA et les données TinyGPS défiler.

Lors de la mise sous tension, un appareil GPS commence immédiatement à transmettre des phrases
NMEA. Mais comme il faut généralement un certain temps pour établir un correctif (jusqu'à deux minutes
dans certains cas), ces premières phrases ne contiennent généralement pas de données de localisation
valides. Un temps orageux ou la présence de bâtiments ou d'autres obstacles peuvent également interférer avec le GPS.

204 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

possibilité de repérer l'emplacement. Alors, comment le croquis sait-il si TinyGPS fournit des données de
position validesÿ? La réponse réside dans le troisième paramètre de get_position(), le fix_age facultatif .

Si vous fournissez un pointeur vers une variable longue non signée comme troisième paramètre de
get_position() , TinyGPS le définit sur le nombre de millisecondes depuis que les dernières données de
position valides ont été acquisesÿ; voir aussi la recette 2.11. Une valeur de 0xFFFFFFFF ici (symboliquement,
GPS_INVALID_AGE) signifie que TinyGPS n'a pas encore analysé de phrases valides contenant des
données de position. Dans ce cas, la latitude et la longitude renvoyées sont également invalides
(GPS_INVALID_ANGLE).

En fonctionnement normal, vous pouvez vous attendre à voir des valeurs assez faibles pour fix_age. Les
appareils GPS modernes sont capables de rapporter des données de position aussi fréquemment qu'une à
cinq fois par seconde ou plus, donc un fix_age supérieur à 2 000 ms environ suggère qu'il peut y avoir un
problème. Peut-être que le GPS voyage à travers un tunnel ou qu'un défaut de câblage corrompt le flux de
données NMEA, invalidant la somme de contrôle (un calcul pour vérifier que les données ne sont pas
corrompues). Dans tous les cas, un grand fix_age indique que les coordonnées renvoyées par get_position()
sont obsolètes. Le code suivant est un exemple de la façon dont fix_age peut être utilisé pour s'assurer que
les données de position sont à jourÿ:

long lat, lon;


fix_age long non signéÿ;
gps.get_position(&lat, &lon, &fix_age); si (fix_age
== TinyGPS::INVALID_AGE)
Serial.println("Aucun correctif n'a jamais été
détecté !"); sinon si (fix_age > 2000)
Serial.println("Les données deviennent périméesÿ!");
else Serial.println("Latitude et longitude valides !");

Voir également

TinyGPS et NewSoftSerial sont disponibles en téléchargement sur http:// arduiniana.org/ libra ries/
newsoftserial.

Pour une compréhension plus approfondie du protocole NMEA, lisez l'article de Wikipédia sur http: //
en.wikipedia.org/ wiki/ NMEA.

Plusieurs magasins vendent des modules GPS qui s'interfacent bien avec TinyGPS et Arduino. Ceux-ci
diffèrent principalement par la consommation d'énergie, la tension, la précision, l'interface physique et la
prise en charge du NMEA série. SparkFun (http:// www.sparkfun.com) propose une large gamme de modules
GPS et dispose d'un excellent guide d'achat.

La technologie GPS a inspiré de nombreux projets Arduino créatifs. Un exemple très populaire est
l'enregistreur de données GPS, dans lequel un appareil en mouvement enregistre les données de localisation
à intervalles réguliers sur l'EEPROM Arduino ou un autre stockage embarqué. Voir le projet breadcrumbs
sur http:// code.google.com/ p/ breadcrumbs/ wiki/ UserDocument pour un exemple.
Ladyada fabrique un bouclier d'enregistrement de données GPS populaireÿ; voir http:// www.ladyada.net/
make/ gpsshield/.

6.14 Obtenir une position à partir d'un GPS | 205


Machine Translated by Google

D'autres projets GPS intéressants incluent des avions de loisir et des hélicoptères qui se déplacent vers des
destinations préprogrammées sous le contrôle du logiciel Arduino. Mikal Hart a construit un "coffre au trésor"
compatible GPS avec un loquet interne qui ne peut pas être ouvert tant que la boîte n'est pas physiquement
déplacée vers un certain endroit. Voir http:// arduiniana.org.

6.15 Détection de rotation à l'aide d'un gyroscope

Problème
Vous voulez réagir au taux de rotation. Cela peut être utilisé pour maintenir un véhicule en mouvement en ligne
droite ou tourner à une vitesse souhaitée.

Solution
La plupart des gyroscopes à faible coût utilisent une tension analogique proportionnelle à la vitesse de rotation,
bien que certains fournissent également une sortie utilisant I2C (voir le chapitre 13 pour en savoir plus sur
l'utilisation d'I2C pour communiquer avec les appareils). Cette recette fonctionne avec un gyroscope avec une
sortie analogique proportionnelle à la vitesse de rotation. La figure 6-16 montre une carte de dérivation
LISY300AL de SparkFun. De nombreux gyroscopes à faible coût, tels que celui utilisé ici, sont des appareils 3,3
V et ne doivent pas être branchés sur la broche d'alimentation 5 V.

Vérifiez la tension maximale de votre gyroscope avant de brancher l'alimentation.


Brancher un gyroscope de 3,3 V sur 5 volts peut endommager définitivement l'appareil.

Figure 6-16. Gyroscope LISY300AL connecté à l'aide d'une broche 3.3V

La connexion Gyro OUT est la sortie analogique et est connectée à l'entrée analogique Arduino 0. La connexion
PD permet au gyroscope d'être commuté en mode basse consommation et

206 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

est connecté à la broche analogique 1 (dans ce croquis, il est utilisé comme broche de sortie numérique). Vous pouvez
connecter PD à n'importe quelle broche numériqueÿ; la broche utilisée ici a été choisie pour garder le câblage plus propre.
Si vous n'avez pas besoin de passer le gyroscope en mode basse consommation, vous pouvez connecter la ligne PD à
Gnd.

Les broches analogiques peuvent également être utilisées comme broches numériques 14 à 19 si elles ne
sont pas nécessaires pour lire des valeurs analogiques. Voir l' introduction du chapitre 5 pour en savoir plus
sur l'utilisation des broches analogiques et numériques Arduino.

La ligne ST (auto-test) sert à tester et peut être laissée non connectéeÿ:

/*
gyro sketch
affiche le taux de rotation sur le Serial Monitor */

const int inputPin = 0ÿ; // entrée analogique 0 const int


powerDownPin = 15ÿ; // l'entrée analogique 1 est l'entrée numérique 15

taux de rotation int = 0ÿ;

void setup()

{ Serial.begin(9600); // définit le port série sur 9600 pinMode(powerDownPin, OUTPUT);


digitalWrite(powerDown, LOW); // gyroscope pas en mode hors tension }

void loop()
{ rotationRate
= analogRead(inputPin); Serial.print("le taux de // lit la sortie du gyroscope
rotation est "); Serial.println(taux de rotation);
retard(100); }
// attend 100ms pour la prochaine lecture

Discussion
Cette esquisse définit le powerDownPin sur LOW pour faire fonctionner le gyroscope en mode normal (vous pouvez
éliminer ce code de la configuration si vous avez câblé la broche PD sur Gnd).

Les broches d'entrée analogiques peuvent être utilisées comme broches numériques (mais pas l'inverse).
L'entrée analogique 0 est la broche numérique 14ÿ; l'entrée analogique 1 est la broche numérique 15, et
ainsi de suite.

Le code de boucle lit la valeur du gyroscope sur la broche analogique 0 et l'affiche sur le moniteur série.

6.15 Détection de rotation à l'aide d'un gyroscope | 207


Machine Translated by Google

6.16 Sens de détection


Problème
Vous voulez que votre croquis détermine la direction à partir d'une boussole électronique.

Solution
Cette recette utilise le module boussole HM55B de Parallax (#29123). La Figure 6-17 montre les
connexions :

/*
L'esquisse
HM55bCompass utilise le protocole série 'software SPI' mis en œuvre à l'aide des fonctions de bit
Arduino (voir le chapitre 3) imprime l'angle de la boussole sur le moniteur série */

const entier enablePin = 2ÿ;


const int clockPin = 3ÿ; const
int dataPin = 4;

// codes de commande (de la fiche technique


HM55B) octet const COMMAND_LENGTH = 4ÿ; //le nombre de bits dans une commande //
réinitialise l'octet const
RESET_COMMAND = B0000ÿ; octet const MEASURE_COMMAND de la puce
= B1000ÿ; // démarre une
mesure const byte READ_DATA_COMMAND = B1100; // lit les données et termine l'octet
const de l'indicateur MEASUREMENT_READY = B1100ÿ; // valeur renvoyée lorsque la
mesure est terminée

angle intérieurÿ;

void setup()

{ Serial.begin(9600);
pinMode(enablePin, OUTPUT);
pinMode(horlogePin, SORTIE);
pinMode(dataPin, INPUT);
réinitialiser(); // réinitialiser le module boussole }

void loop()

{ startMeasurement();
retard(40); // attend que les données soient prêtes if
(readStatus()==MEASUREMENT_READY); // vérifie si les données sont prêtes { angle
= readMeasurement(); Serial.print("Angle = "); Serial.println(angle); // angle d'impression }
delay(100); } // lire la mesure et calculer l'angle

208 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

void reset()

{ pinMode(dataPin, OUTPUT);
digitalWrite(enablePin, LOW);
sortie série (RESET_COMMAND,
COMMAND_LENGTH); digitalWrite(enablePin,
HIGH); }

void startMeasurement()
{ pinMode(dataPin,
OUTPUT); digitalWrite(enablePin,
LOW);
serialOut(MESURE_COMMANDE,
COMMANDE_LONGUEUR); digitalWrite(enablePin,
HIGH); }

int readStatus()
{ int result = 0;
pinMode(dataPin,
OUTPUT); digitalWrite(enablePin,
LOW); sortie série
(READ_DATA_COMMAND, COMMAND_LENGTH);
résultat = serialIn(4); retourner le résultatÿ; // retourne
le statut }

int readMeasurement()
{ int X_Data = 0ÿ; int
Y_Data = 0ÿ; int
calcAngle = 0ÿ;

X_Data = serialIn(11); // Intensité du champ en X


Y_Data = serialIn(11); // et direction Y
digitalWrite(enablePin, HIGH); // désélectionne la puce
*
calcAngle = atan2(-Y_Data , X_Data) / M_PI if(calcAngle 180ÿ; // l'angle est atan(-y/x)
< 0)
calcAngle = calcAngle + 360ÿ; // angle de 0 à 259 au lieu de plus/moins 180
return calcAngleÿ; }

void serialOut(int value, int numberOfBits) { for(int i


= numberOfBits; i > 0; i--) // décale le MSB en
premier { digitalWrite(clockPin, LOW); si(bitRead(valeur, i-1) == 1)

digitalWrite(dataPin, HIGH); sinon


digitalWrite(dataPin, LOW);
digitalWrite(clockPin, HIGH); } }

int serialIn(int nombreDeBits) {

6.16 Sens de détection | 209


Machine Translated by Google

entier résultat = 0ÿ;

pinMode(dataPin, INPUT);
for(int i = numberOfBits; i > 0; i--) // obtient d'abord le MSB
{ digitalWrite(clockPin, HIGH); si (digitalRead(dataPin) == HIGH) résultat =
(résultat << 1) + 1ÿ; sinon résultat = (résultat << 1) + 0ÿ;
digitalWrite(clockPin, LOW); }

// ce qui suit convertit le résultat en un nombre négatif en complément à deux // si le bit le plus
significatif dans les données 11 bits est 1 if(bitRead(result, 11) == 1)

résultat = (B11111000 << 8) | résultat; // négation complément à deux

retourner le résultatÿ; }

Illustration 6-17. Connexions compas HM55B

210 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

Discussion
Le module boussole fournit des intensités de champ magnétique sur deux axes perpendiculaires (x et y).
Ces valeurs varient lorsque l'orientation de la boussole est modifiée par rapport au champ magnétique
terrestre (nord magnétique).

La fiche technique de l'appareil vous indique quelles valeurs envoyer pour réinitialiser la boussole ; vérifier
si une lecture valide est prête (si c'est le cas, il la transmettra).

L'esquisse utilise les fonctions serialIn() et serialOut() pour gérer les manipulations de broches qui
envoient et reçoivent des messages.

Le module boussole est initialisé dans un état connu dans la fonction reset() appelée depuis setup(). La
fonction startMeasurement() lance la mesure, et après un bref délai, la fonction readStatus() indique si les
données sont prêtes. Une valeur de 0 est renvoyée si la mesure n'est pas prête, ou 12 (binaire 1100) si la
boussole est prête à transmettre des données.

Onze bits de données sont lus dans les variables X_Data et Y_Data . Si vous utilisez un autre appareil,
vous devrez vérifier la fiche technique pour voir combien de bits et dans quel format les données sont
envoyées. X_Data et Y_Data stockent les relevés de champ magnétique et l'angle par rapport au nord
magnétique est calculé comme suit : Radians = arctan(-x/y)

Ceci est implémenté dans l'esquisse de la ligneÿ: angle


= 180 * (atan2(-1 * Y_Data , X_Data) / M_PI);

Pour qu'un servo suive la direction de la boussole sur les 180 premiers degrés, ajoutez ce qui suitÿ:

#include <Servo.h>
Servo monservoÿ;

dans la

configuration : myservo.attach(8);

et en boucle après calcul de l'angle :

angle = contrainte(angle, 0,180); // le servo n'est piloté que jusqu'à 180 degrés
myservo.write(angle);

6.17 Obtenir des entrées à partir d'une manette de jeu (PlayStation)

Problème
Vous souhaitez réagir aux positions du joystick ou aux pressions sur les boutons à partir d'un pavé de commande de jeu.

6.17 Obtenir des entrées à partir d'une manette de jeu (PlayStation) | 211
Machine Translated by Google

Solution
Cette recette utilise une manette Sony PlayStation 2 avec la bibliothèque PSX sur http://
www.arduino.cc/ playground/ Main/ PSXLibrary ; La figure 6-18 montre les connexions.

Figure 6-18. Prise de contrôleur PlayStation connectée à Arduino

L'esquisse utilise le moniteur série pour montrer quel bouton est enfoncéÿ:
/*
* Esquisse PSX
*

* Afficher les valeurs du joystick et des boutons


*
utilise la bibliothèque PSX écrite par Kevin Ahrendt *
http://www.arduino.cc/playground/Main/PSXLibrary */

#include <wProgram.h>
#include <Psx.h> // Inclut la bibliothèque PSX

Psx Psx; // Crée une instance de la librairie Psx


const int dataPin = 5ÿ; const
int cmndPin = 4ÿ; const entier
attPin = 3ÿ; const int clockPin
= 2ÿ; const int psxDelay =
50ÿ; // détermine le retard d'horloge en microsecondes

données entières non signées = 0ÿ; // les données stockent la réponse du contrôleur

void setup() { //
initialise la
bibliothèque Psx Psx.setupPins(dataPin,
cmndPin, attPin, clockPin, psxDelay); Série.begin(9600); // les résultats seront
affichés sur le moniteur série }

212 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

void loop()
{ data =
Psx.read(); // récupère les données du bouton du contrôleur psx

// vérifie les bits du bouton pour voir si un bouton est pressé if(data & psxLeft)

Serial.println("bouton gauche"); si
(données & psxDown)
Serial.println("bouton bas"); si (données
& psxRight)
Serial.println("bouton droit");
si (données & psxUp)
Serial.println("bouton haut"); si (données
& psxStrt)
Serial.println("bouton de démarrage"); si
(données & psxSlct)
Serial.println("bouton sélectionner");

retard(100); }

Discussion

Les contrôleurs de jeu fournissent des informations de différentes manières. Les contrôleurs les plus récents
contiennent des puces qui lisent les commutateurs et le joystick dans le contrôleur et communiquent les
informations à l'aide d'un protocole en fonction de la plate-forme de jeu. Les contrôleurs plus anciens sont
plus susceptibles de donner un accès direct aux commutateurs et aux joysticks en utilisant des connecteurs
avec de nombreuses connexions. La dernière vague de plates-formes de jeux utilise l'USB comme connexion.
Ceux-ci sont plus difficiles à utiliser avec Arduino.

Voir également

Recette 4.1ÿ; Recette 4.11

Protocole manette PlayStation : http:// www.gamesx.com/ controldata/ psxcont/ psxcont .htm

6.18 Accélération de lecture


Problème

Vous voulez réagir à l'accélérationÿ; par exemple, pour détecter quand quelque chose commence ou s'arrête
de bouger. Ou vous voulez détecter comment quelque chose est orienté par rapport à la surface de la Terre
(mesurer l'accélération due à la gravité).

6.18 Accélération de lecture | 213


Machine Translated by Google

Solution
Comme beaucoup de capteurs abordés dans ce chapitre, il existe un large choix d'appareils et
de méthodes de connexion. La recette 4.11 donnait un exemple de joystick virtuel utilisant
l'accéléromètre du nunchuck Wii pour suivre les mouvements de la main. La recette 13.2
contient plus d'informations sur l'utilisation de l'accéléromètre nunchuck Wii. La recette ici utilise
une sortie analogique proportionnelle à l'accélération. Les appareils appropriés incluent
l'ADXL203CE (SF SEN-00844), l'ADXL320 (SF SEN 00847) et le MMA7260Q (SF SEN00252)
- consultez le guide de sélection de l'accéléromètre SparkFun sur le site Web SparkFun pour plus d'informations.

La figure 6-19 montre les connexions pour les axes x et y d'un accéléromètre analogique.

Figure 6-19. Connexions pour les axes x et y d'un accéléromètre analogique

Vérifiez la fiche technique de votre appareil pour vous assurer que vous ne dépassez pas la tension
maximale. De nombreux accéléromètres sont conçus pour un fonctionnement en 3,3 V et peuvent être
endommagés s'ils sont connectés à la connexion d'alimentation 5 V sur une carte Arduino.

214 | Chapitre 6 : Obtention des données des capteurs


Machine Translated by Google

L'esquisse simple ici utilise l'ADXL320 pour afficher l'accélération sur les axes x et yÿ:

/*
accel sketch
simple sketch pour sortir des valeurs sur les axes x et y */

const int xPin = 0ÿ; // broches d'entrée


analogique const int yPin = 1ÿ;

void setup()

{ Serial.begin(9600); // notez la vitesse série plus élevée que d'habitude }

void loop()
{ int
xValeurÿ; // valeurs de l'accéléromètre stockées ici int yValueÿ;

xValeur = analogRead(xPin);
yValue = analogRead(yPin);

Serial.print("Valeur X = ");
Serial.println(xValue);

Serial.print("Valeur Y = ");
Serial.println(yValue);
retard(100);
}

Discussion
Vous pouvez utiliser les techniques des recettes précédentes pour extraire des informations des
lectures de l'accéléromètre. Vous devrez peut-être vérifier un seuil pour déterminer le mouvement.
Vous devrez peut-être faire la moyenne des valeurs comme dans l'exemple sonore pour obtenir
des valeurs utiles. Si l'accéléromètre lit horizontalement, vous pouvez utiliser les valeurs
directement pour calculer le mouvement. S'il lit verticalement, vous devrez prendre en compte les
effets de la gravité sur les valeurs. Ceci est similaire au décalage DC dans l'exemple audio, mais
cela peut être compliqué, car l'accéléromètre peut changer d'orientation de sorte que l'effet de la
gravité n'est pas une valeur constante pour chaque lecture.

Voir également

Guide de sélection SparkFun : http:// www.sparkfun.com/ commerce/ tutorial_info.php?tuto


rials_id=167

6.18 Accélération de lecture | 215


Machine Translated by Google
Machine Translated by Google

CHAPITRE 7

Sortie visuelle

7.0 Présentation
La sortie visuelle permet à l'Arduino de se montrer, et à cette fin, l'Arduino prend en charge une large gamme de dispositifs
LED. Avant de plonger dans les recettes de ce chapitre, nous aborderons les sorties numériques et analogiques Arduino.
Cette introduction sera un bon point de départ si vous n'êtes pas encore familiarisé avec l'utilisation des sorties numériques
et analogiques (digitalWrite et analogWrite).

Sortie numérique

Toutes les broches qui peuvent être utilisées pour l'entrée numérique peuvent également être utilisées pour la sortie numérique.
Le chapitre 5 a fourni un aperçu de la disposition des broches Arduinoÿ; vous voudrez peut-être consulter la section d'
introduction de ce chapitre si vous n'êtes pas familiarisé avec la connexion d'éléments aux broches Arduino.

La sortie numérique fait que la tension sur une broche est élevée (5 volts) ou basse (0 volt).
Utilisez la fonction digitalWrite(outputPin, value) pour activer ou désactiver quelque chose. La fonction a deux paramètres :
outputPin est la broche à contrôler et la valeur est soit HIGH (5 volts) soit LOW (0 volts).

Pour que la tension de la broche réponde à cette commande, la broche doit avoir été définie en mode sortie à l'aide de la
commande pinMode(outputPin, OUTPUT) . Le schéma de la recette 7.1 fournit un exemple d'utilisation de la sortie
numérique.

Sortie analogique

Analog fait référence aux niveaux qui peuvent être progressivement modifiés jusqu'à leur niveau maximum (pensez aux
gradateurs de lumière et aux commandes de volume). Arduino a une fonction analogWrite qui peut être utilisée pour
contrôler des choses telles que l'intensité d'une LED connectée à l'Arduino.

La fonction analogWrite n'est pas vraiment analogique, bien qu'elle puisse se comporter comme de l'analogique, comme
vous le verrez. analogWrite utilise une technique appelée modulation de largeur d'impulsion (PWM) qui émule un signal
analogique à l'aide d'impulsions numériques.

217
Machine Translated by Google

PWM fonctionne en faisant varier la proportion du temps d'activation et du temps d'arrêt des impulsions, comme
illustré à la Figure 7-1. La sortie de bas niveau est émulée en produisant des impulsions qui ne sont actives que
pendant une courte période. La sortie de niveau supérieur est émulée avec des impulsions plus actives que
désactivées. Lorsque les impulsions sont répétées assez rapidement (près de 500 fois par seconde sur Arduino), les
impulsions ne peuvent pas être détectées par les sens humains, et la sortie de choses telles que les LED semble
varier en douceur lorsque la fréquence d'impulsion est modifiée.

Illustration 7-1. Sortie PWM pour diverses valeurs analogWrite

Arduino a un nombre limité de broches pouvant être utilisées pour la sortie analogique. Sur une carte standard, vous
pouvez utiliser les broches 3, 5, 6, 9, 10 et 11. Sur la carte Arduino Mega, vous pouvez utiliser les broches 2 à 13 pour
la sortie analogique. La plupart des recettes qui suivent utilisent des broches qui peuvent être utilisées à la fois pour
le numérique et l'analogique afin de minimiser le recâblage si vous souhaitez essayer différentes recettes. Si vous
souhaitez sélectionner différentes broches pour la sortie analogique, n'oubliez pas de choisir l'une des broches d'
écriture analogique prises en charge (les autres broches ne donneront aucune sortie).

Contrôle de la lumière Le

contrôle de la lumière à l'aide d'une sortie numérique ou analogique est une méthode polyvalente, efficace et largement
utilisée pour fournir une interaction avec l'utilisateur. Les LED simples, les matrices et les affichages numériques sont

218 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

couverts en détail dans les recettes de ce chapitre. Le texte LCD et les affichages graphiques nécessitent des
techniques différentes et sont traités au chapitre 11.

Spécifications des DEL

Une LED est un dispositif semi-conducteur (diode) avec deux conducteurs, une anode et une cathode.
Lorsque la tension à l'anode est plus positive que celle à la cathode (d'une quantité
appelée tension directe) , l'appareil émet de la lumière (photons). L'anode est généralement la
fil plus long, et il y a souvent un méplat sur le boîtier pour indiquer la cathode (voir
Illustration 7-2). La couleur de la LED et la valeur exacte de la tension directe dépendent du
construction de la diode.

Une LED rouge typique a une tension directe d'environ 1,8 volts. Si la tension sur l'anode
n'est pas 1,8 volts plus positif que la cathode, aucun courant ne traversera la LED
et aucune lumière ne sera produite. Lorsque la tension sur l'anode devient 1,8 volts de plus
positif que celui de la cathode, la LED « s'allume » (conduite) et devient effectivement un court-circuit. Vous devez
limiter le courant avec une résistance, sinon la LED le fera (plus tôt
ou plus tard) burn-out. La recette 7.1 vous montre comment calculer les valeurs de limitation de courant
résistances.

Vous devrez peut-être consulter une fiche technique de LED pour sélectionner la bonne LED pour votre application,
en particulier pour déterminer les valeurs de tension directe et de courant maximum.
Les tableaux 7-1 et 7-2 montrent les champs les plus importants que vous devez rechercher sur un tableau de données LED.
drap.

Tableau 7-1. Spécifications de la fiche technique cléÿ: notes maximales absolues

Paramètre symbole Notation Unités Commenter

Courant direct Si 25 mA Le courant continu maximum pour cette LED

Courant direct de crête (1/10 duty @ Si 160 mA Le courant pulsé maximum (donné ici pour un

1KHz) impulsion qui est 1/10 allumé et 9/10 éteint)

Tableau 7-2. Spécifications clés de la fiche techniqueÿ: caractéristiques électro-optiques

Paramètre symbole Notation Unités Commenter

Intensité lumineuse IV 2 mcd Si = 2 mA - luminosité avec courant 2 mA

IV 40 mcd Si = 20 mA - luminosité avec un courant de 20 mA

Angle de vue 120 Degrés L'angle du faisceau

Longueur d'onde 620 nm La longueur d'onde dominante ou maximale (couleur)

Tension directe Vf 1.8 Volt La tension aux bornes de la LED lorsqu'elle est allumée

Les broches Arduino peuvent fournir jusqu'à 40 mA de courant. C'est beaucoup pour une LED d'intensité moyenne
typique, mais pas assez pour piloter les LED à luminosité plus élevée ou plusieurs LED.
connecté à une seule broche. La recette 7.3 montre comment utiliser un transistor pour augmenter la
courant à travers la LED.

7.0 Présentation | 219


Machine Translated by Google

Les LED multicolores se composent de deux LED ou plus dans un seul boîtier physique. Ceux-ci peuvent avoir
plus de deux fils pour permettre un contrôle séparé des différentes couleurs. Il existe de nombreuses variantes
de boîtiers, vous devez donc consulter la fiche technique de votre LED pour déterminer comment connecter
les câbles.

Les LED multicolores à changement de couleur automatique avec puce intégrée ne peuvent
en aucun cas être contrôléesÿ; vous ne pouvez pas changer leurs couleurs depuis Arduino.
Étant donné que PWM allume et éteint rapidement l'alimentation, vous redémarrez
efficacement la puce intégrée plusieurs fois par seconde, de sorte que ces LED ne
conviennent pas non plus aux applications PWM.

Multiplexage

Les applications qui doivent contrôler de nombreuses LED peuvent utiliser une technique appelée multiplexage.
Le multiplexage fonctionne en commutant des groupes de LED (généralement disposés en lignes ou en
colonnes) en séquence. La recette 7.11 montre comment 32 LED individuelles (huit LED par chiffre, y compris
le point décimal) à quatre chiffres peuvent être pilotées avec seulement 12 broches. Huit broches pilotent un
segment de chiffres pour tous les chiffres et quatre broches sélectionnent le chiffre actif. Le fait de parcourir les
chiffres assez rapidement (au moins 25 fois par seconde) donne l'impression que les lumières restent allumées
au lieu de pulser, par le phénomène de persistance de la vision.

Charlieplexing utilise le multiplexage avec le fait que les LED ont une polarité (elles ne s'allument que lorsque
l'anode est plus positive que la cathode) pour basculer entre deux LED en inversant la polarité.

7.1 Connexion et utilisation des LED

Problème
Vous souhaitez contrôler une ou plusieurs LED et sélectionner la bonne résistance de limitation de courant afin
de ne pas endommager les LED.

Solution
Allumer et éteindre une LED est facile à faire avec Arduino, et certaines des recettes des chapitres précédents
ont inclus cette capacité (voir la recette 5.1 pour un exemple qui contrôle la LED intégrée sur la broche 13). La
recette ici fournit des conseils sur le choix et l'utilisation des LED externes. La figure 7-2 montre le câblage de
trois voyants, mais vous pouvez exécuter ce croquis avec seulement un ou deux.

220 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Illustration 7-2. Connexion de LED externes

Le symbole schématique de la cathode (la broche négative) est k, pas c. Le symbole


schématique c est utilisé pour un condensateur.

Le schéma suivant allume trois LED connectées aux broches 3, 5 et 6 en séquence pendant
une secondeÿ:
/*
Croquis des LED

Faites clignoter trois LED connectées chacune à une broche numérique différente */

const int firstLedPin = 3; const entier // choisir la broche pour chacune des LED
secondLedPin = 5ÿ; const int
thirdLedPin = 6;

void setup()

{ pinMode(firstLedPin, OUTPUT); // déclarer les broches LED comme


pinMode(secondLedPin, OUTPUT); sortie // déclarer les broches LED comme
pinMode(thirdLedPin, OUTPUT); } sortie // déclarer les broches LED comme sortie

void loop() { //
fait clignoter
chacune des LED pendant 1000 millisecondes (1 seconde) blinkLED(firstLedPin,
1000); LED clignotante (seconde LedPin, 1000)ÿ; clignotementLED(troisièmeLedPin,
1000); }

7.1 Connexion et utilisation des LED | 221


Machine Translated by Google

// fait clignoter la LED sur la broche donnée pendant la durée en


millisecondes void blinkLED(int pin, int duration) { digitalWrite(pin, HIGH);
retard (durée); digitalWrite (broche, BAS); retard (durée); }
// allume la LED

// éteint la LED

L'esquisse définit les broches connectées aux LED comme sortie dans la fonction de configuration . La fonction
de boucle appelle blinkLED pour faire clignoter la LED pour chacune des trois broches. blinkLED définit la broche
indiquée sur HIGH pendant une seconde (1 000 millisecondes).

Discussion
Étant donné que les anodes sont connectées aux broches Arduino et que les cathodes sont connectées à la
terre, les LED s'allument lorsque la broche passe au niveau HAUT et s'éteignent lorsque la broche est au niveau bas.
Si vous aviez connecté les LED dans l'autre sens (les cathodes aux broches et les anodes à la terre), les LED
s'allumeraient lorsque la broche passerait au niveau BAS (l'effet visuel s'inverserait - l'une des LED s'éteindrait
pendant une seconde les deux autres seraient allumés).

Les LED nécessitent une résistance en série pour contrôler le courant ou elles peuvent
rapidement s'éteindre. La LED intégrée sur la broche 13 a une résistance sur le circuit imprimé.
Les LED externes doivent être connectées via une résistance en série sur l'anode ou la
cathode.

Une résistance en série avec la LED est utilisée pour contrôler la quantité de courant qui circulera lorsque la LED

sera conductrice. Pour calculer la valeur de la résistance, vous devez connaître la tension d'alimentation d'entrée
(Vs, généralement 5 volts), la tension directe de la LED (Vf) et la quantité de courant (I) que vous souhaitez faire
passer à travers la LED.

La formule de la résistance en ohms (appelée loi d'Ohm) est : R = (Vs - Vf) / I

Par exemple, piloter une LED avec une tension directe de 1,8 volts avec 15 mA de courant en utilisant une
tension d'alimentation d'entrée de 5 volts utiliserait les valeurs suivantesÿ:

Vs = 5 (pour une carte Arduino 5V)


Vf = 1,8 (la tension directe de la LED)
I = 0,015 (1 milliampère [mA] équivaut à un millième d'ampère, donc 15 mA équivaut à 0,015 ampère)

La tension aux bornes de la LED lorsqu'elle est allumée (Vs - Vf) est de : 5 - 1,8, soit 3,2 volts Par

conséquent, le calcul pour la résistance série est : 3,2 / 0,015, soit 213 ohms

La valeur de 213 ohms n'est pas une valeur de résistance standard, vous pouvez donc l'arrondir à 220 ohms.

222 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

La résistance est représentée sur la figure 7-2 connectée entre la cathode et la masse, mais elle peut
être connectée de l'autre côté de la LED à la place (entre l'alimentation en tension et l'anode).

Les broches Arduino ont un courant maximum de 40 mA. Si votre LED a besoin de
plus de courant que cela, vous devez utiliser un transistor pour commuter la LED,
comme indiqué dans la recette 7.3.

Voir également

Recette 7.3

7.2 Réglage de la luminosité d'une LED


Problème
Vous souhaitez contrôler l'intensité d'une ou plusieurs LED à partir de votre croquis.

Solution
Connectez chaque LED à une sortie analogique (PWM). Utilisez le câblage illustré à la Figure 7-2.
L'esquisse fera passer la ou les LED de l'extinction à l'intensité maximale et de nouveau à l'extinction,
chaque cycle prenant environ cinq secondesÿ:
/*
* Croquis LedBrightness *
contrôle la luminosité des LED sur les ports de sortie analogiques */

const int firstLed = 3; const int // spécifiez la broche pour chacune des LED
secondLed = 5ÿ; const int
thirdLed = 6;

int luminosité = 0ÿ;


entier incrément = 1ÿ;

void setup() { //
les broches
pilotées par analogWrite n'ont pas besoin d'être déclarées comme sorties }

void loop()
{ if(luminosité
> 255) {

incrément = -1ÿ; // compte à rebours après avoir atteint 255

} sinon si(luminosité < 1)


{ incrément = 1ÿ; // compte
après être redescendu à 0

7.2 Réglage de la luminosité d'une LED | 223


Machine Translated by Google

} luminosité = luminosité + incrémentÿ; // incrémente (ou le signe de décrémentation est moins)

// écrit la valeur de luminosité sur les LEDs analogWrite(firstLed,


bright); analogWrite(secondLed, luminosité);
analogWrite(troisièmeLed, luminosité );

retard(10); // 10 ms pour chaque changement de pas signifie 2,55 secondes pour monter ou descendre en fondu }

Discussion
Ceci utilise le même câblage que l'esquisse précédente, mais ici les broches sont contrôlées en utilisant
analogWrite au lieu de digitalWrite. analogWrite utilise PWM pour contrôler l'alimentation de la LEDÿ; voir la
section d' introduction de ce chapitre pour plus d'informations sur la sortie analogique.

L'esquisse fait monter et descendre le niveau de lumière en augmentant (en fondu) ou en diminuant (en
fondu) la valeur de la variable de luminosité à chaque passage dans la boucle. Cette valeur est donnée à la
fonction analogWrite pour les trois LED connectées. La valeur minimale pour analogWrite est 0, ce qui
maintient la tension sur la broche à 0. La valeur maximale est 255, ce qui maintient la broche à 5 volts.

Lorsque la variable de luminosité atteint la valeur maximale, elle commence à diminuer, car le signe de l'
incrément passe de +1 à -1 (ajouter -1 à une valeur revient à soustraire 1 de cette valeur).

Voir également

L' introduction de ce chapitre décrit le fonctionnement de la sortie analogique Arduino.

7.3 Pilotage des LED haute puissance

Problème
Vous devez commuter ou contrôler l'intensité des LED qui nécessitent plus de puissance que les broches
Arduino ne peuvent en fournir. Les broches Arduino ne peuvent gérer que le courant jusqu'à 40 mA.

Solution
Utilisez un transistor pour allumer et éteindre le courant traversant les LED. Connectez le voyant comme
illustré à la Figure 7-3. Vous pouvez utiliser le même code que celui indiqué dans les recettes précédentes
(assurez-vous simplement que les broches connectées à la base du transistor correspondent au numéro de
broche utilisé dans votre croquis).

224 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Illustration 7-3. Utilisation de transistors pour piloter des LED à courant élevé

Discussion
Les LED peuvent avoir besoin d'une source d'alimentation séparée de l'Arduino si le courant total est
supérieur à quelques centaines de mA. Voir l' annexe C pour plus d'informations sur l'utilisation d'une
alimentation externe.

N'oubliez pas de connecter la masse de l'alimentation externe à la masse Arduino.

Le courant est autorisé à circuler du collecteur à l'émetteur lorsque le transistor est activé. Aucun
courant significatif ne circule lorsque le transistor est bloqué. L'Arduino peut allumer un transistor en
rendant la tension sur une broche HIGH avec digitalWrite. Une résistance est nécessaire entre la broche
et la base du transistor pour éviter que trop de courant ne circule - 1K ohms est une valeur typique (cela
fournit 5 mA de courant à la base du transistor). Voir l' annexe B pour des conseils sur la façon de lire
une fiche technique et de choisir et d'utiliser un transistor. Vous pouvez également utiliser des circuits
intégrés spécialisés tels que l'ULN2003A pour piloter plusieurs sorties. Ceux-ci contiennent sept pilotes
de sortie à courant élevé (0,5 A).

La résistance utilisée pour limiter le flux de courant à travers la LED est calculée en utilisant la technique
donnée dans la recette 7.1, mais vous devrez peut-être tenir compte du fait que la tension de la source
sera légèrement réduite en raison de la petite chute de tension à travers le transistor.

7.3 Pilotage des LED haute puissance | 225


Machine Translated by Google

Ce sera généralement moins de trois quarts de volt (la valeur réelle peut être trouvée en regardant la
tension de saturation collecteur-émetteurÿ; voir l' annexe B). Les LED à courant élevé (1 watt ou plus)
sont mieux pilotées à l'aide d'une source de courant constant (un circuit qui contrôle activement le
courant) pour gérer le courant à travers la LED.

Voir également

Référence Web pour les pilotes à courant constantÿ: http:// blog.makezine.com/ archive/ 2009/08/
constant_current_led_driver.html

7.4 Réglage de la couleur d'une LED


Problème

Vous souhaitez contrôler la couleur d'une LED RVB sous le contrôle du programme.

Solution

Les LED RVB ont des éléments rouges, verts et bleus dans un seul boîtier avec les anodes connectées
ensemble (appelées anode commune) ou les cathodes connectées ensemble (appelées cathode
commune). Utilisez le câblage de la Figure 7-4 pour l'anode commune (les anodes sont connectées
au +5 volts et les cathodes sont connectées aux broches). Utilisez la Fig ure 7-2 si vos LED RVB sont
à cathode commune.

Illustration 7-4. Connexions RVB (anode commune)

226 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Cette esquisse s'estompe en continu dans le spectre des couleurs en faisant varier l'intensité
des éléments rouges, verts et bleusÿ:
/*
*
Esquisse RGB_LEDs
* LED RVB pilotées à partir de ports de sortie analogiques
*/

const int redPin = 3; const int // choisir la broche pour chacune des LED
greenPin = 5; const int
bluePin = 6; const booléen
inverse = vraiÿ; // définit vrai si anode commune, faux si cathode commune

int couleur = 0ÿ; // une valeur de 0 à 255 représentant la teinte int R, G, B; //


les composants de couleur Rouge Vert et Bleu

void setup() { //
les broches
pilotées par analogWrite n'ont pas besoin d'être déclarées comme sorties }

void loop()
{ int luminosité
= 255ÿ; // 255 est la luminosité maximale hueToRGB (couleur,
luminosité); // appelez la fonction pour convertir la teinte en RVB // écrivez les valeurs
RVB sur les broches analogWrite(redPin, R); analogWrite(greenPin, G); analogWrite(bluePin,
B );

couleur+ // incrémente la couleur //


+ÿ; si(couleur >
255) couleur =
0ÿ; retard(10);
}

// fonction pour convertir une couleur en ses composants rouge, vert et bleu.

void hueToRGB(int teinte, int luminosité) {

entier non signé scaledHue = (teinte * 6);


segment int non signé = scaledHue / 256ÿ; // segment 0 à 5 autour de la roue chromatique

unsigned int segmentOffset = scaledHue - (segment * 256); // position dans le segment

complément entier non signé = 0ÿ;


int non signé précédent = (luminosité * ( 255 - segmentOffset)) / 256ÿ; entier non
signé suivant = (luminosité * segmentOffset) / 256ÿ;

7.4 Réglage de la couleur d'une LED | 227


Machine Translated by Google

si (inverser) {

luminosité = 255-luminositéÿ;
complément = 255ÿ; précédent =
255-précÿ; suivant = 255-suivantÿ; }

switch(segment ) { //
cas 0ÿ: rouge
R = luminositéÿ;
G = suivantÿ;
B = complémentÿ;
Pause;
cas 1: // jaune
R = précÿ;
G = luminositéÿ;
B = complémentÿ;
Pause; cas 2 :
// vert
R = complémentÿ;
G = luminositéÿ;
B=
suivantÿ;
Pause; cas 3 : // cyan
R = complémentÿ;
G = précÿ;
B = luminositéÿ;
Pause; cas 4 :
// bleu
R = suivantÿ;
G = complémentÿ;
B = luminositéÿ;
Pause; cas 5 : par
défaut : // magenta

R = luminositéÿ;
G = complémentÿ;
B = précÿ;
Pause; }

Discussion
La couleur d'une LED RVB est déterminée par l'intensité relative de ses éléments rouge,
vert et bleu. La fonction principale de l'esquisse (hueToRGB) gère la conversion d'une
valeur de teinte allant de 0 à 255 en une couleur correspondante allant du rouge au bleu.
Le spectre des couleurs visibles est souvent représenté à l'aide d'une roue chromatique
constituée des couleurs primaires et secondaires avec leurs dégradés intermédiaires. Les
rayons de la roue chromatique représentant les six couleurs primaires et secondaires sont
gérés par six déclarations de cas . Le code d'une instruction case est exécuté si la variable de segment

228 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

correspond au numéro de cas, et si c'est le cas, les valeurs RVB sont définies de manière appropriée pour chacun.
Le segment 0 est rouge, le segment 1 est jaune, le segment 2 est vert, etc.

Si vous souhaitez également régler la luminosité, vous pouvez réduire la valeur de la variable de luminosité . Ce
qui suit montre comment régler la luminosité avec une résistance variable ou un capteur connecté comme illustré
à la Figure 7-11 ou à la Figure 7-15ÿ:

int luminosité = map( analogRead(0),0,1023, 0, 255); // obtenir la luminosité du capteur


La valeur de la variable de luminosité va de 0 à 255 lorsque l'entrée analogique va de 0 à 1 023, ce qui fait que la
LED augmente la luminosité à mesure que la valeur augmente.

Voir également

Recette 2.16ÿ; Recette 13.1

7.5 Séquençage de plusieurs LEDÿ: création d'un graphique à barres

Problème
Vous voulez un graphique à barres LED qui allume les LED proportionnellement à une valeur dans votre croquis
ou à une valeur lue à partir d'un capteur.

Solution
Vous pouvez connecter les LED comme illustré à la Figure 7-2 (en utilisant des broches supplémentaires si vous
voulez plus de LED). La figure 7-5 montre six voyants connectés sur des broches consécutives.

Illustration 7-5. Six LED avec cathodes connectées aux broches Arduino

7.5 Séquençage de plusieurs LED : création d'un graphique à barres | 229


Machine Translated by Google

Le schéma suivant allume une série de voyants, le nombre étant proportionnel à la valeur d'un
capteur connecté à un port d'entrée analogique (voir Figure 7-11 ou Fig ure 7-15 pour voir comment
un capteur est connecté) :
/*
Croquis de bargraphe

Allume une série de LED proportionnelles à une valeur d'un capteur analogique.
Six LED sont contrôlées mais vous pouvez modifier le nombre de LED en modifiant la valeur
de NbrLED et en ajoutant les broches au tableau ledPins */

const int NbrDEL = 6ÿ;


const int ledPins[] = { 2, 3, 4, 5, 6, 7}ÿ; const entier
analogInPin = 0ÿ; // Broche d'entrée analogique connectée à la résistance variable const int
wait = 30ÿ;

// Échange les valeurs des deux constantes suivantes si les cathodes sont connectées à Gnd const
boolean LED_ON = LOW; const booléen LED_OFF = HIGHÿ;

int sensorValue = 0ÿ; int // valeur lue à partir du capteur //


ledLevel = 0ÿ; valeur du capteur convertie en "barres" de LED

void setup() { for


(int led = 0; led < NbrLEDs; led++)
{ pinMode(ledPins[led], OUTPUT); // rend toutes
les sorties des broches LED } }

void loop()
{ sensorValue = analogRead(analogInPin); // lit l'analogique dans la valeur ledLevel =
map(sensorValue, 0, 1023, 0, NbrLEDs); // mappe au nombre de LED pour (int led = 0; led < NbrLEDs;
led++) { if (led < ledLevel ) { digitalWrite(ledPins[led], LED_ON); } else { digitalWrite(ledPins[led],
LED_OFF); niveau: } } }

// active les broches inférieures au niveau

// désactiver les broches supérieures à la

Discussion
Les broches connectées aux LED sont maintenues dans le tableau ledPins. Pour modifier le nombre
de LED, vous pouvez ajouter (ou supprimer) des éléments de ce tableau, mais assurez-vous que la
variable NbrLEDs est identique au nombre d'éléments (qui doit être identique au nombre de broches).
Vous pouvez demander au compilateur de calculer la valeur de NbrLEDs pour vous en remplaçant
cette ligneÿ:

230 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

const int NbrDEL = 6ÿ;

avec cette ligne :

const int NbrLEDs = sizeof (ledPins) / sizof (ledPins [0]ÿ;

La fonction sizeof renvoie la taille (nombre d'octets) d'une variable, dans ce cas, le nombre d'octets dans
le tableau ledPins . Comme il s'agit d'un tableau d'entiers (avec deux octets par élément), le nombre total
d'octets dans le tableau est divisé par la taille d'un élément (sizeof(ledPins[0])) et cela donne le nombre
d'éléments.

La fonction de carte Arduino est utilisée pour calculer le nombre de LED qui doivent être allumées en
proportion de la valeur du capteur. Le code boucle à travers chaque LED, l'allumant si la valeur
proportionnelle du capteur est supérieure au numéro de LED. Par exemple, si la valeur du capteur est 0,
aucune broche n'est allumée ; si le capteur est à la moitié de la valeur, la moitié est allumée. Lorsque le
capteur est à la valeur maximale, toutes les LED sont allumées.

La figure 7-5 montre toutes les anodes connectées entre elles (appelées anode commune) et les cathodes
connectées aux brochesÿ; les broches doivent être BASSES pour que la LED s'allume. Si les LED ont les
anodes connectées aux broches (comme illustré à la Figure 7-2) et que les cathodes sont connectées
ensemble (appelées cathodes communes), la LED s'allume lorsque la broche passe au niveau HAUT.
L'esquisse de cette recette utilise les noms constants LED_ON et LED_OFF pour faciliter la sélection des
connexions d'anode commune ou de cathode commune. Pour modifier l'esquisse de la connexion
cathodique commune, permutez les valeurs de ces constantes comme suitÿ:
const booléen LED_ON = HIGHÿ; // HIGH est activé lors de l'utilisation d'une connexion cathodique
commune const booléen LED_OFF = LOWÿ;

Vous voudrez peut-être ralentir la décroissance (taux de changement) des lumièresÿ; par exemple, pour
émuler le mouvement de l'indicateur d'un sonomètre. Voici une variation sur le croquis qui désintègre
lentement les barres de LED lorsque le niveau baisse :
/*
Bargraphe LED - version Decay
*/

const int NbrLEDs = sizeof(ledPins) / sizof(ledPins[0]ÿ; const


int ledPins[] = { 2, 3, 4, 5, 6, 7}ÿ; const int analogInPin = 0ÿ; //
broche d'entrée analogique connectée à la variable résistance // augmenter cela réduit
= 10ÿ; le taux de décroissance de la valeur stockée const int decay

int sensorValue = 0ÿ; // valeur lue à partir du capteur //


int valeur stockée = la valeur stockée (décroissante) du
0ÿ; int ledLevel = 0ÿ; capteur // valeur convertie en 'barres' de LED

void setup()
{ for (int led = 0; led < NbrLEDs; led++)
{ pinMode(ledPins[led], OUTPUT); // rend
toutes les sorties des broches LED } }

7.5 Séquençage de plusieurs LED : création d'un graphique à barres | 231


Machine Translated by Google

void loop()
{ sensorValue = analogRead(analogInPin); // lit l'analogique dans la valeur valeur_stockée
= max(sensorValue, valeur_stockée); // n'utilise la valeur du capteur que si le ledLevel
supérieur = map(storedValue, 0, 1023, 0, NbrLEDs); // mappe au nombre de LED pour (int led
= 0; led < NbrLEDs; led++) { if (led < ledLevel ) {

digitalWrite(ledPins[led], HIGH); // active les broches inférieures au niveau } else


{ digitalWrite(ledPins[led], LOW); // désactive les broches supérieures au niveau } }
valeurstockée = valeurstockée - déclinÿ; retard(10); }

// décline la valeur //
attend 10 ms avant la prochaine boucle

La décroissance est gérée par la ligne qui utilise la fonction max . Cela renvoie soit la valeur du capteur, soit la valeur
dégradée stockée, selon la valeur la plus élevée. Si le capteur est supérieur à la valeur décroissante, celle-ci est
enregistrée dans la valeur mémorisée. Sinon, le niveau de storageValue est réduit par la décroissance constante à
chaque fois dans la boucle (fixée à 10 millisecondes par la fonction de retard ). L'augmentation de la valeur de la
constante de décroissance réduira le temps nécessaire aux LED pour s'éteindre complètement.

Voir également

Voir les recettes 12.1 et 12.2 si vous avez besoin d'une plus grande précision dans vos temps de décroissance. La
durée totale de la boucle est en fait supérieure à 10 millisecondes car il faut environ une milliseconde supplémentaire
pour exécuter le reste du code de la boucle.

La recette 3.6 explique la fonction max .

La recette 5.6 en dit plus sur la lecture d'un capteur avec la fonction analogRead .

La recette 5.7 décrit la fonction map .

7.6 Séquençage de plusieurs LED : création d'une séquence de


poursuite (Knight Rider)

Problème

Vous voulez allumer des LED dans une séquence de "chasing lights" (comme on le voit dans l'émission télévisée
Knight Rider).

232 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Solution
Vous pouvez utiliser la même connexion que celle illustrée à la Figure 7-5ÿ:

/* Knight Rider
*/

const int NbrDEL = 6ÿ;


const int ledPins[] = {2, 3, 4, 5, 6, 7}ÿ; const
entier attendre = 30ÿ;

void setup()
{ for (int led = 0; led < NbrLEDs; led++)
{ pinMode(ledPins[led], OUTPUT); } }

void loop()
{ for (int led = 0; led < NbrLEDs-1; led++)
{ digitalWrite(ledPins[led], HIGH); retarder
(attendre); digitalWrite(ledPins[led + 1],
HIGH); retarder (attendre);
digitalWrite(ledPins[led], LOW); retard
(attente * 2); } for (int led = NbrLEDs; led >
0; led--) { digitalWrite(ledPins[led], HIGH);
retarder (attendre); digitalWrite(ledPins[led -
1], HIGH); retarder (attendre);
digitalWrite(ledPins[led], LOW); retard (attente
* 2); } }

Discussion
Ce code est similaire au code de la recette 7.5, sauf que les broches sont activées et désactivées dans une
séquence fixe plutôt que de dépendre d'un niveau de capteur. Il y a deux boucles for ; le premier produit le motif
de gauche à droite en allumant des LED de gauche à droite. Cette boucle commence par la première LED (la
plus à gauche) et passe par les LED adjacentes jusqu'à ce qu'elle atteigne et illumine la LED la plus à droite. La
deuxième boucle for allume les LED de droite à gauche en commençant par la LED la plus à droite et en
décrémentant (en diminuant de un) la LED allumée jusqu'à ce qu'elle atteigne la première LED (la plus à droite).
La période de retard est définie par la variable d' attente et peut être choisie pour fournir l'apparence la plus
agréable.

7.6 Séquençage de plusieurs LED : création d'une séquence de poursuite (Knight Rider) | 233
Machine Translated by Google

7.7 Contrôle d'une matrice LED à l'aide du multiplexage

Problème
Vous avez une matrice de LED et souhaitez minimiser le nombre de broches Arduino nécessaires pour
allumer et éteindre les LED.

Solution
Ce schéma utilise une matrice LED de 64 LED avec des anodes connectées en rangées et des
cathodes en colonnes (comme dans le Futurlec LEDM88R). Les écrans LED bicolores peuvent être plus
faciles à obtenir, et vous pouvez piloter une seule des couleurs si c'est tout ce dont vous avez besoin.
La figure 7-6 montre les connexions :

/*
esquisse matriceMpx

Séquencez les LED à partir de la première colonne et ligne jusqu'à ce que toutes les LED soient allumées
Le multiplexage est utilisé pour contrôler 64 LED avec 16 broches */

const int columnPins[] = { 2, 3, 4, 5, 6, 7, 8, 9}ÿ; const int rowPins[]


= { 10,11,12,15,16,17,18,19}ÿ;

pixel entier = 0ÿ; int // 0 à 63 LED dans la matrice // valeur


niveau_colonne = 0ÿ; int de pixel convertie en colonne de LED // valeur de
rowLevel = 0ÿ; pixel convertie en ligne de LED

void setup() { for


(int i = 0; i < 8; i++)
{ pinMode(columnPins[i],
OUTPUT); // crée toutes les sorties des broches LED pinMode(rowPins[i], OUTPUT); } }

void loop() { pixel


= pixel + 1; si(pixel >
63) pixel = 0ÿ;

niveaucolonne = pixel / 8ÿ; // mappe au nombre de colonnes //


niveauligne = pixel % 8; for (int obtient la valeur fractionnaire
column = 0; column < 8; column++)
{ digitalWrite(columnPins[column], LOW); for(int row =
0; row < 8; row++) { if (columnLevel > column) // connecte cette colonne à Ground
{ digitalWrite(rowPins[row], HIGH); // connecte toutes
les LED de la rangée au +5 volts } else if (columnLevel
== column && rowLevel >= row)

234 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

{
digitalWrite(rowPins[row], HIGH);

}
else
{ digitalWrite(columnPins[column], LOW); // éteint toutes les LED de cette
ligne } delayMicroseconds(300); digitalWrite(rowPins[row], LOW); }
// le délai donne un temps de trame de 20 ms pour 64 LED
// éteint la LED

digitalWrite(columnPins[column], HIGH); // déconnecte cette colonne


du sol } }

Illustration 7-6. Une matrice LED connectée à 16 broches numériques

Les écrans à matrice LED n'ont pas de brochage standard, vous devez donc vérifier la fiche
technique de votre écran. Câblez les rangées d'anodes et les colonnes de cathodes comme
illustré à la Figure 7-13 ou à la Figure 7-14, mais utilisez les numéros de broches des DEL
indiqués dans votre fiche technique.

7.7 Contrôle d'une matrice LED à l'aide du multiplexage | 235


Machine Translated by Google

Discussion
La valeur de la résistance doit être choisie de manière à ce que le courant maximal traversant une broche ne
dépasse pas 40 mA. Étant donné que le courant pour un maximum de huit LED peut circuler à travers chaque
broche de colonne, le courant maximum pour chaque LED doit être d'un huitième de 40 mA, ou 5 mA. Chaque
LED dans une petite matrice rouge typique a une tension directe d'environ 1,8 volts. Le calcul de la résistance
qui donne 5 mA avec une tension directe de 1,8 volts donne une valeur de 680 ohms. Vérifiez votre fiche
technique pour trouver la tension directe de la matrice que vous souhaitez utiliser. Chaque colonne de la matrice
est connectée via la résistance série à une broche numérique. Lorsque la broche de colonne passe au niveau
bas et qu'une broche de ligne passe au niveau haut, la LED correspondante s'allume. Pour toutes les LED où la
broche de colonne est haute ou sa broche de ligne est basse, aucun courant ne circulera à travers la LED et elle
ne s'allumera pas.

La boucle for parcourt chaque ligne et colonne et allume des LED séquentielles jusqu'à ce que toutes les LED
soient allumées. La boucle commence par la première colonne et ligne et incrémente le compteur de lignes
jusqu'à ce que toutes les LED de cette ligne soient alluméesÿ; il passe ensuite à la colonne suivante, et ainsi de
suite, allumant une autre LED à chaque passage dans la boucle jusqu'à ce que toutes les LED soient allumées.

Vous pouvez contrôler le nombre de LED allumées proportionnellement à la valeur d'un capteur (voir la recette
5.6 pour connecter un capteur au port analogique) en effectuant les modifications suivantes
au croquis.

Commentez ou supprimez ces trois lignes au début de la boucleÿ:

pixel = pixel + 1ÿ;


si(pixel > 63) pixel
= 0ÿ;

Remplacez-les par les lignes suivantes qui lisent la valeur d'un capteur sur la broche 0 et l'associent à un nombre
de pixels allant de zéro à 63ÿ: // lire l'analogique en valeur // associer la valeur du capteur au pixel

int sensorValue = analogRead(0);


pixel = carte (valeur du capteur, 0, 1023, 0, 63);
(DIRIGÉ)

Vous pouvez tester cela avec une résistance variable connectée à la broche d'entrée analogique 0 connectée
comme illustré à la Figure 5-7 du Chapitre 5. Le nombre de LED allumées sera proportionnel au
valeur du capteur.

7.8 Affichage des images sur une matrice LED

Problème
Vous souhaitez afficher une ou plusieurs images sur une matrice LED, créant peut-être un effet d'animation en
alternant rapidement plusieurs images.

236 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Solution
Cette solution peut utiliser le même câblage que dans la recette 7.7. L'esquisse crée l'effet d'un
cœur qui bat en allumant brièvement des LED disposées en forme de cœur. Un petit cœur suivi
d'un cœur plus grand clignote à chaque battement de cœur (les images ressemblent à la Figure 7-7)ÿ:
/*
*
matrixMpxAnimation croquis
* anime deux images de cœur pour montrer un cœur battant */

// les images du cœur sont stockées sous forme de bitmaps - chaque bit correspond à une LED //
un 0 indique que la LED est éteinte, 1 est allumé byte bigHeart[] = {

B01100110,
B11111111,
B11111111,
B11111111,
B01111110,
B00111100,
B00011000,
B00000000}ÿ;

octet petitCoeur[] = {
B00000000,
B00000000,
B00010100,
B00111110,
B00111110,
B00011100,
B00001000,
B00000000}ÿ;

const int columnPins[] = { 2, 3, 4, 5, 6, 7, 8, 9}ÿ; const int rowPins[]


= { 10,11,12,15,16,17,18,19}ÿ;

void setup() { for


(int i = 0; i < 8; i++)
{ pinMode(rowPins[i], OUTPUT);
pinMode(columnPins[i], OUTPUT); // faire toutes les sorties des broches LED
digitalWrite(columnPins[i], HIGH); //
déconnecte les broches de colonne de Ground } }

void loop() { int


pulseDelay = 800 ; // millisecondes à attendre entre les battements

afficher(petitcoeur, 80); // affiche l'image du petit cœur pendant 100 ms //


afficher(groscoeur, 160); suivi du grand cœur pendant 200 ms // ne montre
retard(pulseDelay); } rien entre les battements

7.8 Affichage d'images sur une matrice LED | 237


Machine Translated by Google

// routine pour afficher une image d'une image stockée dans le tableau pointé par le paramètre
image. // la trame est répétée pendant la durée donnée en millisecondes void show( byte *
image, unsigned long duration) { unsigned long start = millis(); while (start + duration > millis())
a passé { for(int row = 0; row
colonne
< 8; <
row++)
8; colonne++)
{ digitalWrite(rowPins[row],
{ pixel booléen = bitRead(image[row],column);
HIGH); for(int colonne =
if(pixel == 1) { digitalWrite(columnPins[column], LOW); // connecte la colonne à Gnd }
delayMicroseconds(300); // un petit délai pour chaque //LED commence
digitalWrite(columnPins[column],
à chronométrer
HIGH); // déconnecte la colonne de Gnd } digitalWrite(rowPins[row], LOW);jusqu'à
l'animation // boucle } } } la période de durée

// connecte la ligne au +5 volts

// déconnecte les LED

Illustration 7-7. Les deux images du cœur affichées à chaque battement

Discussion
Les colonnes et les lignes sont multiplexées (commutées) comme dans la recette 7.7, mais ici la valeur
écrite dans la LED est basée sur les images stockées dans les tableaux bigHeart et smallHeart .
Chaque élément du tableau représente un pixel (une seule LED) et chaque ligne du tableau représente

238 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

une ligne dans la matrice. Une ligne se compose de huit bits représentés au format binaire (désigné par le B
majuscule au début de chaque ligne). Un bit de valeur 1 indique que la LED correspondante doit être
allumée ; un 0 signifie désactivé. L'effet d'animation est créé en basculant rapidement entre les tableaux.

La fonction de boucle attend un court instant (800 millisecondes) entre les battements, puis appelle la
fonction show , d'abord avec le tableau smallheart , puis suivi du tableau bigHeart . La fonction show parcourt
chaque élément dans toutes les lignes et colonnes, allumant la LED si le bit correspondant est 1. La fonction
bitRead (voir recette 2.20) est utilisée pour déterminer la valeur de chaque bit.

Un court délai de 300 microsecondes entre chaque pixel laisse le temps à l'œil de percevoir la LED. La
synchronisation est choisie pour permettre à chaque image de se répéter assez rapidement (50 fois par
seconde) pour que le clignotement ne soit pas visible.

Voici une variation qui modifie la fréquence à laquelle le cœur bat, en fonction de la valeur d'un capteur.
Vous pouvez tester cela en utilisant une résistance variable connectée à la broche d'entrée analogique 0,
comme indiqué dans la recette 5.6. Utilisez le câblage et le code indiqués précédemment, sauf remplacez la
fonction de boucle par ce codeÿ:

void loop()
{ sensorValue = analogRead(analogInPin); // lit l'analogique dans la valeur int pulseRate =
map(sensorValue,0,1023,40,240); // convertir en battements / minute int pulseDelay =
(60000 / pulseRate ); // millisecondes à attendre entre les battements

afficher(petitcoeur, 80); // affiche l'image du petit cœur pendant 100


afficher(groscoeur, 160); ms // suivi du grand cœur pendant 200 ms // ne
retard(pulseDelay); } montre rien entre les battements

Cette version calcule le délai entre les impulsions à l'aide de la fonction de carte (voir la recette 5.7) pour
convertir la valeur du capteur en battements par minute. Le calcul ne tient pas compte du temps nécessaire
pour afficher le cœur, mais vous pouvez soustraire 240 millisecondes (80 ms plus 160 ms pour les deux
images) si vous souhaitez un timing plus précis.

Voir également

Les recettes 12.1 et 12.2 fournissent plus d'informations sur la gestion du temps à l'aide de la fonction millis .

Voir les recettes 7.12 et 7.13 pour plus d'informations sur l'utilisation des registres à décalage pour piloter
les LED si vous souhaitez réduire le nombre de broches Arduino nécessaires pour piloter une matrice de LED.

7.9 Contrôler une matrice de LED : Charlieplexing


Problème

Vous avez une matrice de LED et vous souhaitez minimiser le nombre de broches nécessaires pour allumer
et éteindre l'une d'entre elles.

7.9 Contrôler une matrice de LED : Charlieplexing | 239


Machine Translated by Google

Solution
Charlieplexing est un type spécial de multiplexage qui augmente le nombre de LED pouvant
être pilotées par un groupe de broches. Ce croquis passe par six LED en utilisant seulement
trois broches (Figure 7-8 montre les connexions) :
/*
* Croquis de Charlieplexing
* allumez six LED en séquence qui sont connectées aux broches 2, 3 et 4 */

octet broches[] = {2,3,4}ÿ; // les broches qui sont connectées aux LED

// les deux lignes suivantes déduisent le nombre de broches et de LED du tableau ci-dessus
const int NUMBER_OF_PINS = sizeof(pins)/ sizeof(pins[0]);
const entier NUMBER_OF_LEDS = NUMBER_OF_PINS * (NUMBER_OF_PINS-1ÿ);

paires d'octets[NUMBER_OF_LEDS/2][2] = { {0,1}, {1,2}, {0,2} }ÿ; // mappe les broches aux LED

void setup() {

// rien n'est nécessaire ici


}

void loop()
{ for(int i=0; i < NUMBER_OF_LEDS; i++) {

lumièreLed(i); // allume chaque LED tour à tour


delay(1000);
}
}

// cette fonction allume la LED donnée, la première LED est 0 void


lightLed(int led) { // les quatre lignes suivantes convertissent le numéro
de LED en numéros de broches int indexA = pairs[led/2][0]; int indexB =
paires[led/2][1]ÿ; int brocheA = broches[indexA]ÿ; int brocheB =
broches[indexB]ÿ;

// éteint toutes les broches non connectées à la LED donnée


for(int i=0; i < NUMBER_OF_PINS; i++)
if( pins[i] != pinA && pins[i] != pinB) { // si cette pin
n'est pas l'une de nos pins pinMode(pins[i],
INPUT); // définit le mode pour entrer digitalWrite(pins[i],LOW); //
assurez-vous que le pull-up est désactivé
}
// allumez maintenant les broches pour la LED
donnée pinMode(pinA, OUTPUT); pinMode(brocheB,
SORTIE); si( led % 2 == 0) {

240 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

digitalWrite(brocheA,BAS);
digitalWrite(brocheB,ÉLEVÉ);
}
autre
{
digitalWrite(brocheB,BAS);
digitalWrite(brocheA,ÉLEVÉ);
}
}

Illustration 7-8. Six LED pilotées par trois broches à l'aide de Charlieplexing

Discussion
Le terme Charlieplexing vient de Charlie Allen (de Microchip Technology, Inc.),
qui a publié la méthode. La technique est basée sur le fait que les LED ne s'allument que
lorsqu'il est connecté dans le "bon sens" (avec l'anode plus positive que la cathode).
Voici le tableau indiquant le nombre de voyants (voir Figure 7-6) allumés pour le
combinaisons des trois broches. L est BAS, H est HAUT et i est le mode INPUT . Mettre une épingle dans
Le mode INPUT le déconnecte efficacement du circuitÿ:
Épingles LED
234 123456
JE VAIS 000000
LH je 100000
HL ii LH i 010000
HL 001000
000100
L je H 000010
H je L 000001

7.9 Contrôler une matrice de LED : Charlieplexing | 241


Machine Translated by Google

Vous pouvez doubler le nombre de LED à 12 en utilisant une seule broche de plus. Les six premières LED sont
connectées de la même manière que dans l'exemple précédent ; ajoutez les six DEL supplémentaires de façon à
ce que les connexions ressemblent à celles de la Figure 7-9.

Illustration 7-9. Charlieplexing utilisant quatre broches pour piloter 12 LED

Modifiez l'esquisse précédente en ajoutant la broche supplémentaire au tableau de brochesÿ:

byte pins[] = {2,3,4,5}ÿ; // les broches qui sont connectées aux LED

Ajoutez les entrées supplémentaires au tableau pairs afin qu'il se lise comme suitÿ:

paires d'octets[NUMBER_OF_LEDS/2][2] = { {0,1}, {1,2}, {0,2}, {2,3}, {1,3}, {0,3} }ÿ;

Tout le reste peut rester le même, donc la boucle passera par les 12 LED car le code détermine le nombre de
LED à partir du nombre d'entrées dans le
tableau de broches .

Étant donné que Charlieplexing fonctionne en contrôlant les broches Arduino de sorte qu'une seule LED soit
allumée à la fois, il est plus compliqué de créer l'impression d'allumer plusieurs LED. Mais vous pouvez allumer
plusieurs LED en utilisant une technique de multiplexage modifiée pour Charlieplexing.

Ce croquis crée un graphique à barres en allumant une séquence de LED en fonction de la valeur d'un capteur
connecté à la broche analogique 0ÿ:

octet broches[] = {2,3,4}ÿ;


const int NUMBER_OF_PINS = sizeof(pins)/ sizeof(pins[0]); const
entier NUMBER_OF_LEDS = NUMBER_OF_PINS* (NUMBER_OF_PINS-1ÿ);

paires d'octets[NUMBER_OF_LEDS/2][2] = { {0,1}, {1,2}, {0,2} }ÿ;

int ledStates = 0ÿ; // détient les états pour jusqu'à 15 LED


int refreshedLedÿ; // la LED qui se rafraîchit

void setup() {

// rien ici
}

242 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

void loop()
{ const int
analogInPin = 0; // Broche d'entrée analogique connectée à la résistance variable

// voici le code de la recette du bargraph int sensorValue


= analogRead(analogInPin); // lit l'analogique dans la valeur int ledLevel = map(sensorValue, 0, 1023,
0, NUMBER_OF_LEDS); // mappe vers le
nombre de LED
pour (int led = 0; led < NUMBER_OF_LEDS; led++) { if (led
< ledLevel ) { setState(led, HIGH); } else { setState(led,
LOW); } } ledRefresh();
// active les broches inférieures au niveau

// désactiver les broches supérieures au niveau

void setState( int led, état booléen) {

bitWrite(ledStates,led, état);
}

void ledRefresh() {

// actualise une LED différente à chaque appel. if( refreshedLed++


> NUMBER_OF_LEDS) // incrément à la LED suivante
actualiséLed = 0ÿ; // répétition à partir de la première LED si toutes ont été rafraichies

if( bitRead(ledStates, refreshedLed ) == HIGH)


lightLed( refreshedLed );
}

// cette fonction est identique à l'esquisse ci-dessus // elle


allume la LED donnée, la première LED est 0 void lightLed(int
led) { // les quatre lignes suivantes convertissent le numéro de
LED en numéros de broches int indexA = pairs[led/2 ][0]ÿ; int
indexB = paires[led/2][1]ÿ; int brocheA = broches[indexA]ÿ; int brocheB =
broches[indexB]ÿ;

// éteint toutes les broches non connectées à la LED donnée


for(int i=0; i < NUMBER_OF_PINS; i++)
if( pins[i] != pinA && pins[i] != pinB) { // si cette pin
n'est pas l'une de nos pins pinMode(pins[i],
INPUT); // définit le mode pour entrer digitalWrite(pins[i],LOW); //
assurez-vous que le pull-up est désactivé
}
// allumez maintenant les broches pour la LED
donnée pinMode(pinA, OUTPUT);

7.9 Contrôler une matrice de LED : Charlieplexing | 243


Machine Translated by Google

pinMode(brocheB, SORTIE);
si( led % 2 == 0) {

digitalWrite(brocheA,BAS);
digitalWrite(brocheB,ÉLEVÉ);

}
autre {
digitalWrite(brocheB,BAS);
digitalWrite(brocheA,ÉLEVÉ);

}}

Cette esquisse utilise la valeur des bits de la variable ledStates pour représenter l'état des LED (0 si
éteint, 1 si allumé). La fonction de rafraîchissement vérifie chaque bit et allume les LED pour chaque
bit défini sur 1. La fonction de rafraîchissement doit être appelée rapidement et à plusieurs reprises,
sinon les LED sembleront clignoter.

L'ajout de retards dans votre code peut interférer avec l'effet de «ÿpersistance de
la visionÿ» qui crée l'illusion qui masque le clignotement des LED.

Vous pouvez utiliser une interruption pour entretenir la fonction de rafraîchissement en arrière-plan
(sans avoir besoin d'appeler explicitement la fonction en boucle). Les interruptions de minuterie sont
couvertes au chapitre 18, mais voici un aperçu d'une approche pour utiliser une interruption pour
entretenir vos rafraîchissements de LED. Cela utilise une bibliothèque tierce appelée FrequencyTimer2
(disponible sur Arduino Playground) pour créer l'interruptionÿ: #include <FrequencyTimer2.h>

octet broches[] = {2,3,4,5}ÿ;


const int NUMBER_OF_PINS = sizeof(pins)/ sizeof(pins[0]);
const entier NUMBER_OF_LEDS = NUMBER_OF_PINS * (NUMBER_OF_PINS-1ÿ);

paires d'octets[NUMBER_OF_LEDS/2][2] = { {0,1}, {1,2}, {0,2} }ÿ;

int ledStates = 0ÿ; // détient les états pour jusqu'à 15 LED int
refreshedLedÿ; // la LED qui se rafraîchit

---

#include <FrequencyTimer2.h> // inclut cette bibliothèque pour gérer l'actualisation

octet broches[] = {2,3,4}ÿ;


const int NUMBER_OF_PINS = sizeof(pins)/ sizeof(pins[0]);
const entier NUMBER_OF_LEDS = NUMBER_OF_PINS * (NUMBER_OF_PINS-1ÿ);

paires d'octets[NUMBER_OF_LEDS/2][2] = { {0,1}, {1,2}, {0,2} }ÿ;

int ledStates = 0ÿ; // détient les états pour jusqu'à 15 LED int
refreshedLedÿ; // la LED qui se rafraîchit

244 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

void setup() {

FrequencyTimer2::setPeriod(20000/ NUMBER_OF_LEDS); // définit la période // la


ligne suivante indique à FrequencyTimer2 la fonction à appeler (ledRefresh)
FrequencyTimer2::setOnOverflow(ledRefresh);
FrequencyTimer2::enable(); }

void loop()
{ const int
analogInPin = 0; // Broche d'entrée analogique connectée à la résistance variable

// voici le code de la recette du bargraph int sensorValue


= analogRead(analogInPin); // lit l'analogique dans la valeur int ledLevel = map(sensorValue, 0,
1023, 0, NUMBER_OF_LEDS); // mappe vers le
nombre de LED
for (int led = 0; led < NUMBER_OF_LEDS; led++) { if (led
< ledLevel ) { setState(led, HIGH); } else { setState(led,
LOW); } } // la LED n'est plus rafraîchie en boucle, elle
est gérée par FrequencyTimer2// active les broches inférieures au niveau

// désactiver les broches supérieures au niveau

// le code restant est le même que l'exemple précédent

La bibliothèque FrequencyTimer2 a une période définie sur 1 666 microsecondes (20 ms divisé par 12, le
nombre de LED). La méthode FrequencyTimer2setOnOverflow obtient la fonction à appeler (ledRefresh)
chaque fois que le temporisateur « se déclenche ».

Voir également

Le chapitre 18 fournit plus d'informations sur les interruptions de minuterie.

7.10 Pilotage d'un affichage LED à 7 segments

Problème
Vous souhaitez afficher des chiffres à l'aide d'un afficheur numérique à 7 segments.

Solution
Le croquis suivant affiche les chiffres de zéro à neuf sur un affichage à un chiffre et à 7 segments. La figure
7-10 montre les connexions. La sortie est produite en activant des combinaisons de segments qui
représentent les chiffresÿ:
/*
*
Esquisse de sept segments

7.10 Pilotage d'un affichage LED à 7 segments | 245


Machine Translated by Google

* Affiche des chiffres allant de 0 à 9 sur un affichage à un chiffre


* Cet exemple compte les secondes de 0 à 9 */

// bits représentant les segments A à G (et le point décimal) pour les chiffres 0-9 const byte
numeral[10] = {
//ABCDEFG /dp
B11111100, // 0
B01100000, // 1
B11011010, // 2
B11110010, // 3
B01100110, // 4
B10110110, // 5
B00111110, // 6
B11100000, // 7
B11111110, // 8
B11100110, // 9 }ÿ;

// broches pour la virgule décimale et chaque


segment // dp,G,F,E,D,C,B,A const=int segmentPins[8];
{ 5,9,8,7,6,4,3,2}

void setup()
{ for(int i=0; i
< 8; i++)
{ pinMode(segmentPins[i],
OUTPUT); // définit le segment et les broches DP sur la sortie } }

void loop()
{ for(int i=0; i
<= 10; i++) { showDigit(i);
retard(1000); } // la dernière
valeur si i vaut 10 et cela
désactivera l'affichage
delay(2000); // pause de deux
secondes avec l'affichage éteint }

// Affiche un nombre de 0 à 9 sur un affichage à 7 segments // toute valeur


non comprise entre 0 et 9 désactive l'affichage void showDigit( int number)
{ boolean isBitSet;

for(int segment = 1; segment < 8; segment++)


{ if( nombre < 0 || nombre > 9){ isBitSet = 0; // désactive
tous les segments } else{

246 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

// isBitSet sera vrai si le bit donné est 1


isBitSet = bitRead(numeral[number], segment); }
estBitSet = ! estBitSetÿ; // supprimer cette ligne si
affichage cathodique commun digitalWrite( segmentPins[segment],
isBitSet); } }

Illustration 7-10. Connecter un afficheur 7 segments

Discussion
Les segments à éclairer pour chaque chiffre sont contenus dans le tableau appelé chiffre. Il
y a un octet par chiffre où chaque bit de l'octet représente l'un des sept segments (ou le
point décimal).
Le tableau appelé segmentPins contient les broches associées à chaque segment. La
fonction showDigit vérifie que le nombre est compris entre zéro et 9 et, s'il est valide,
examine chaque bit de segment et active le segment si le bit est défini (égal à 1). Voir la
recette 3.12 pour plus d'informations sur la fonction bitRead .

7.10 Pilotage d'un affichage LED à 7 segments | 247


Machine Translated by Google

Comme mentionné dans la recette 7.4, une broche est définie sur HIGH lors de l'activation d'un segment sur
un affichage à cathode commune, et elle est définie sur LOW lors de l'activation d'un segment sur un
affichage à anode commune. Le code ici est pour un affichage d'anode commun, il inverse donc la valeur
(définit 0 sur 1 et 1 sur 0) comme suitÿ:

estBitSet = ! estBitSetÿ; // supprimer cette ligne si affichage à cathode commune

Le ! est l'opérateur de négation — voir recette 2.20. Si votre écran est un écran à cathode commune (toutes
les cathodes sont connectées ensembleÿ; consultez la fiche technique si vous n'êtes pas sûr), vous pouvez
supprimer cette ligne.

7.11 Pilotage des affichages LED multichiffres à 7 segments : multiplexage

Problème
Vous souhaitez afficher des nombres à l'aide d'un affichage à 7 segments affichant deux chiffres ou plus.

Solution
Les affichages multichiffres à 7 segments utilisent généralement le multiplexage. Dans les recettes
précédentes, des lignes et des colonnes multiplexées de LED étaient connectées ensemble pour former un
réseauÿ; ici, les segments correspondants de chaque chiffre sont connectés ensemble (voir Figure 7-11) :
/*
*
Esquisse SevenSegmentMpx
* Affiche des nombres allant de 0 à 9999 sur un affichage à quatre chiffres
* Cet exemple affiche la valeur d'un capteur connecté à une entrée analogique */

// bits représentant les segments A à G (et le point décimal) pour les chiffres 0-9 const int
numeral[10] = {
//ABCDEFG /dp
B11111100, // 0
B01100000, // 1
B11011010, // 2
B11110010, // 3
B01100110, // 4
B10110110, // 5
B00111110, // 6
B11100000, // 7
B11111110, // 8
B11100110, // 9 }ÿ;

// broches pour le point décimal et chaque segment


// dp,G,F,E,D,C,B,A
const int segmentPins[] = { 4,7,8,6,5,3,2,9}ÿ;

const int nbrDigits= 4; // le nombre de chiffres dans l'affichage LED

// creuser 1 2 3 4
const int digitPins[nbrDigits] = { 10,11,12,13}ÿ;

248 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

void setup()
{ for(int i=0; i
< 8; i++)
pinMode(segmentPins[i], OUTPUT); // définit le segment et les broches DP sur la sortie

for(int i=0; i < nbrDigits; i++)


pinMode(digitPins[i], OUTPUT);
}

void loop()
{ int value =
analogRead(0);
showNumber(valeur); }

void showNumber( int number)


{ if(number == 0) showDigit( 0,
nbrDigits-1)ÿ; // affiche 0 dans
le chiffre le plus à droite else { // affiche la valeur correspondant à chaque
chiffre // le chiffre le plus à gauche est 0, le plus à droite est un de moins que
le nombre de places for( int digit = nbrDigits-1; digit >= 0; digit --) { si(nombre
> 0) {

showDigit( nombre % 10, chiffre) ;


nombre = nombre / 10ÿ;

}}}}

// Affiche le nombre donné sur un affichage à 7 segments à la position de chiffre


donnée void showDigit( int number, int digit) { digitalWrite( digitPins[digit], HIGH );
for(int segment = 1; segment < 8; segment++) { boolean isBitSet =
bitRead(numeral[number], segment); // isBitSet sera vrai si le bit donné est 1 isBitSet
= ! estBitSetÿ; // supprimer cette ligne si affichage cathodique commun
digitalWrite( segmentPins[segment], isBitSet); } retard(5); digitalWrite( digitPins[digit],
LOW ); }

7.11 Pilotage des affichages LED multichiffres à 7 segments : multiplexage | 249


Machine Translated by Google

Illustration 7-11. Connexion d'un affichage multichiffres à 7 segments (LTC-2623)

Discussion
Cette esquisse a une fonction showDigit similaire à celle décrite dans la recette 7.10. Ici, la fonction
reçoit le chiffre et la place du chiffre. La logique pour allumer les segments pour correspondre au
chiffre est la même, mais en plus, le code met la broche correspondant au chiffre à la place HIGH,
donc seul ce chiffre sera écrit (voir les explications précédentes sur le multiplexage).

7.12 Pilotage d'affichages LED à 7 segments et à plusieurs chiffres à

l'aide des registres à décalage MAX7221

Problème
Vous souhaitez contrôler plusieurs affichages à 7 segments, mais vous souhaitez minimiser le nombre
de broches Arduino requises.

Solution
Cette solution utilise la puce de pilote de LED MAX7221 populaire pour contrôler les écrans à cathode
commune à quatre chiffres, tels que le Lite-On LTC-4727JR (Digi-Key 160-1551-5-ND).
Le MAX7221 fournit une solution plus simple que la recette 7.11, car il gère le multiplexage et le
décodage des chiffres dans le matériel.

Ce croquis affichera un nombre compris entre zéro et 9ÿ999 (la figure 7-12 montre les connexions)ÿ:

250 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

/*
Max7221_chiffres
*/

#include <SPI.h> // Bibliothèque Arduino SPI introduite dans la version 0019 d'Arduino

const int esclaveSelect = 10ÿ; //broche utilisée pour activer l'esclave actif

const entier nombreDeChiffres = 2ÿ; // changez-les pour qu'ils correspondent au nombre de chiffres
câblés const int maxCount
= 99ÿ;

nombre entier = 0ÿ;

void setup()

{ Serial.begin(9600);
SPI.begin(); // initialise SPI
pinMode(slaveSelect, OUTPUT);
digitalWrite(esclaveSelect,BAS); //select slave // prépare le
7221 pour afficher des données à 7 segments - voir la fiche technique
sendCommand(12,1); // mode normal (le mode par défaut est le mode d'arrêt);
envoieCommand(15,0); // Afficher le test de sendCommand(10,8); // définit une
intensité moyenne (la plage est de 0 à 15) sendCommand(11,numberOfDigits); //
Commande de limite de balayage de 7221 chiffres sendCommand(9,255); //
commande de décodage, utilisez des chiffres standard à 7 segments
digitalWrite(slaveSelect,HIGH); //désélectionner l'esclave }

void loop() { //
affiche un
numéro du port série terminé par le caractère de fin de ligne if(Serial.available()) {

char ch = Serial.read(); if( ch ==


'\n') { displayNumber(number);
nombre = 0ÿ; } sinon nombre =
(nombre * 10) + ch - '0'ÿ; //
voir le chapitre 4 pour plus de
détails

}}

// fonction pour afficher jusqu'à quatre chiffres sur un affichage à 7 segments void
displayNumber( int number) { for(int i = 0; i < numberOfDigits; i++) { byte character
= number % 10; // récupère la valeur de la décade la plus à droite if(number == 0
&& i > 0)

caractère = 0xfÿ; // le 7221 effacera les segments lors de la réception de la valeur // envoie le
numéro de chiffre comme commande, le premier chiffre est la commande 1

7.12 Pilotage d'affichages LED à 7 segments et à plusieurs chiffres à l'aide des registres à décalage MAX7221 | 251
Machine Translated by Google

sendCommand(numberOfDigits-i, caractère);
nombre = nombre / 10ÿ; } }

void sendCommand (commande int, valeur int)


{ digitalWrite (slaveSelect, LOW); //chip select
is active low //2-byte data transfer to the 7221 SPI.transfer(command);
SPI.transfer(valeur); digitalWrite(slaveSelect,HIGH); // libère la
puce, signale la fin du transfert }

Illustration 7-12. MAX7221 pilotant un affichage à 7 segments à cathode commune à plusieurs chiffres

Solution
Cette recette utilise la communication Arduino SPI pour communiquer avec la puce MAX7221. Le
chapitre 13 couvre SPI plus en détail, et la recette 13.8 explique le code spécifique SPI utilisé.

Cette esquisse affiche un nombre si jusqu'à quatre chiffres sont reçus sur le port série—voir Chapitre
4 pour une explication du code série en boucle. La fonction displayNumber extrait la valeur de chaque
chiffre, en commençant par le chiffre le plus à droite, vers le MAX7221 à l'aide de la fonction
sendCommand qui envoie les valeurs au MAX7221.

Le câblage illustré utilise un affichage à quatre chiffres et 7 segments, mais vous pouvez utiliser des
affichages à un ou deux chiffres jusqu'à huit chiffres. Lors de la combinaison de plusieurs écrans,
chaque broche de segment correspondante doit être connectée ensemble. (La recette 13.8 montre les
connexions pour un affichage commun à deux chiffres.)

252 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Les puces MAX72xx sont conçues pour les écrans cathodiques courants. L'anode de chaque
segment est disponible sur une broche séparée, et les cathodes de tous les segments pour
chaque chiffre sont connectées ensemble.

7.13 Contrôle d'un réseau de LED à l'aide des registres à


décalage MAX72xx

Problème
Vous avez un réseau de LED 8x8 à contrôler et vous souhaitez minimiser le nombre de broches Arduino
requises.

Solution
Comme dans la recette 7.12, vous pouvez utiliser un registre à décalage pour réduire le nombre de
broches nécessaires pour contrôler une matrice LED. Cette solution utilise la puce de pilote de LED
MAX7219 ou MAX7221 populaire pour fournir cette capacité. L'esquisse utilise la bibliothèque de matrices
distribuée avec Arduino, mais elle utilise des broches Arduino différentes de celles de l'exemple d'esquisse
Arduino. Pour exécuter le code suivant, connectez votre Arduino, votre matrice et votre MAX72xx comme
illustré à la Figure 7-13.

Illustration 7-13. MAX72xx pilotant une matrice de LED 8x8

7.13 Contrôle d'un réseau de LED à l'aide des registres à décalage MAX72xx | 253
Machine Translated by Google

Cette esquisse est basée sur la bibliothèque Arduino hello_matrix de Nicholas Zambetti, seul le numéro
de broche a été modifié pour être cohérent avec le câblage utilisé ailleurs dans ce chapitreÿ:

#include <Sprite.h>
#include <Matrice.h>

// Bonjour Matrix //
par Nicholas Zambetti <http://www.zambetti.com>

// Démonstration de l'utilisation de la bibliothèque Matrix


// Pour les contrôleurs matriciels LED MAX7219
// Clignote le visage accueillant à l'écran

const int loadPin = 2ÿ; const


int clockPin = 3ÿ; const int
dataPin = 4;

Matrix myMatrix = Matrix(dataPin, clockPin, loadPin); // crée une nouvelle instance Matrix

void setup() { }

void loop()

{ maMatrice.clear(); // efface l'affichage

retard(1000);

// tourne quelques pixels sur


myMatrix.write(1, 5, HIGH);
maMatrice.write(2, 2, HIGH);
maMatrice.write(2, 6, HIGH);
maMatrix.write(3, 6, HIGH);
maMatrix.write(4, 6, HIGH);
maMatrix.write(5, 2, HIGH);
maMatrice.write(5, 6, HIGH);
maMatrix.write(6, 5, HIGH);

retard(1000); }

Discussion
Une matrice est créée en passant des numéros de broches pour les broches de données, de
chargement et d'horloge. loop utilise la méthode write pour activer les pixels ; la méthode clar désactive
les pixels. write a trois paramètres : les deux premiers identifient la colonne et la ligne (x et y) d'une
LED et le troisième paramètre (HIGH ou LOW) allume ou éteint la LED.

254 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Les numéros de broches indiqués ici correspondent aux LED vertes de la matrice bicolore 8x8
disponible auprès de ces fournisseursÿ:

SparkFun : COM-00681
NKC Électronique Numéro d'article : COM-0006

La résistance (marquée R1 dans la Figure 7-13) est utilisée pour contrôler le courant maximum qui
sera utilisé pour piloter une LED. La fiche technique du MAX72xx contient un tableau indiquant une plage
de valeurs (voir Tableau 7-3).

Tableau 7-3. Tableau des valeurs de résistance (de la fiche technique du MAX72xx)

Tension directe LED

Courant 1.5V 2.0V 2.5V 3.0V 3.5V

40mA 12 kÿ 12 kÿ 11 kÿ 10 kÿ 10 kÿ

30 mA 18 kÿ 17 kÿ 16 kÿ 15 kÿ 14 kÿ

20mA 30 kÿ 28 kÿ 26 kÿ 24 kÿ 22 kÿ

10 mA 68 kÿ 64 kÿ 60 kÿ 56 kÿ 51 kÿ

La LED verte dans la matrice de LED illustrée à la Figure 7-13 a une tension directe de 2,0
volts et un courant direct de 20 mA. Le tableau 7-3 indique 28K ohms, mais pour ajouter un peu
marge de sécurité, une résistance de 30K ou 33K serait un choix approprié. Les condensateurs
(0,1 uf et 10 uf) sont nécessaires pour éviter la génération de pointes de bruit lorsque le
Les voyants sont allumés et éteints—voir "Utilisation de condensateurs pour le découplage" à la page 593
dans l' annexe C si vous n'êtes pas familiarisé avec la connexion des condensateurs de découplage.

Voir également

Fiche technique MAX72xx : http:// pdfserv.maxim-ic.com/ en/ ds/ MAX7219-MAX7221.pdf

7.14 Augmentation du nombre de sorties analogiques à l'aide de PWM


Puces d'extension (TLC5940)

Problème
Vous voulez avoir un contrôle individuel de l'intensité de plus de LED qu'Arduino ne peut
support (6 sur une carte standard et 12 sur la Mega).

Solution
La puce TLC5940 pilote jusqu'à 16 LED en utilisant seulement cinq broches de données. La figure 7-14 montre
les connexions. Ce sketch est basé sur l'excellente bibliothèque Tlc5940 écrite par Alex Leone
(acleone@gmail.com). Vous pouvez télécharger la bibliothèque à partir de http:// code.google
.com/ p/ tlc5940arduino/ÿ:

7.14 Augmentation du nombre de sorties analogiques à l'aide de puces d'extension PWM (TLC5940) | 255
Machine Translated by Google

/*
* Croquis TLC
* Créez un effet de type Knight Rider sur les LED branchées sur toutes les sorties TLC *
cette version suppose un TLC avec 16 LED */

#include "Tlc5940.h"

void setup()
{ Tlc.init(); //
initialise la bibliothèque TLC }

void loop()
{ int direction
= 1; int intensité =
4095ÿ; // une intensité de 0 à 4095, la pleine luminosité est de 4095 int dim = intensité / 4; //
1/4 la valeur assombrit la LED pour (int channel = 0; channel < 16; channel += direction) { //
les commandes TLC suivantes définissent les valeurs à écrire par la méthode de mise à jour
Tlc.clear(); // éteint toutes les LED if (channel == 0) { direction = 1; } else { Tlc.set(channel -
1, dim); // définit l'intensité de la LED précédente }

Tlc.set(canal, intensité); // pleine intensité sur cette LED si (canal < 16){

Tlc.set(canal + 1, dim); // définit la LED suivante sur dim } else


{ direction = -1; }

Tlc.update(); // cette méthode envoie des données aux puces TLC pour modifier le délai des
LED (75); } }

Discussion
Cette esquisse parcourt chaque canal (LED), réglant la LED précédente sur faible, le
canal actuel sur pleine intensité et le canal suivant sur faible. Les LED sont contrôlées
par quelques méthodes de base.
La méthode Tlc.init initialise les fonctions Tlc avant toute autre fonction.

256 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Image 7-14. Seize LED pilotées par PWM externe

Les fonctions suivantes ne prennent effet qu'après l'appel de la méthode update() :


Tlc.clear
Éteint tous les canaux

Tlc.set
Définit l'intensité pour le canal donné à une valeur donnée
Tlc.setAll
Définit tous les canaux sur une valeur donnée

Tlc.update
Envoie les modifications de l'une des commandes précédentes à la puce TLC

Plus de fonctions sont disponibles dans la bibliothèque ; voir le lien vers la référence à la fin de cette
recette.

La résistance 2K entre la broche TLC 20 (Iref) et Gnd laissera environ 20 mA à travers chaque LED.
Vous pouvez calculer la valeur de résistance R pour un courant différent (en milliampères) à l'aide
de la formule R = 40 000 / mA. R est de 1 ohm et le calcul ne dépend pas de la tension de
commande de la LED.

Si vous voulez que les LED s'éteignent lorsque l'Arduino est réinitialisé, mettez une résistance de
pull-up (10K) entre +5V et BLANK (broche 23 du TLC et broche 10 de l'Arduino).

7.14 Augmentation du nombre de sorties analogiques à l'aide de puces d'extension PWM (TLC5940) | 257
Machine Translated by Google

Voici une variante qui utilise une valeur de capteur pour régler l'intensité maximale de la LED. Vous pouvez tester
cela à l'aide d'une résistance variable connectée comme illustré à la Figure 7-11 ou à la Figure 7-15ÿ:
#include "Tlc5940.h"

const int sensorPin = 0ÿ; // connecte le capteur à l'entrée analogique 0

void setup()
{ Tlc.init(); //
initialise la bibliothèque TLC }

void loop()
{ int direction
= 1; int sensorValue
= analogRead(0); // récupère la valeur du capteur int intensité =
map(sensorValue, 0,1023, 0, 4095); // carte à la plage TLC int dim = intensité / 4ÿ; //
1/4 la valeur assombrit la LED pour (int channel = 0; channel < NUM_TLCS 16;
*
channel += direction) { // les commandes TLC suivantes écrire
définissent
par la méthode
les valeurs
de mise
à à
jour Tlc.clear(); // éteint toutes les LED if (channel == 0) { direction = 1; } else
{ Tlc.set(channel - 1, dim); // définit l'intensité de la LED précédente }

Tlc.set(canal, intensité); // pleine intensité sur cette LED if (channel !=


NUM_TLCS * 16 - 1) { Tlc.set(channel
suivante sur
+ 1,dim
dim);
} else
// définit
{ direction
la LED
= -1; }

Tlc.update(); // cette méthode envoie des données aux puces TLC pour modifier le délai des
LED (75); } }

Cette version permet également plusieurs puces TLC si vous souhaitez piloter plus de 16 LED.
Pour ce faire, connectez les puces TLC en "guirlande" - connectez le Sout (broche 17) du premier TLC au Sin
(broche 26) du suivant. Le Sin (broche 26) de la première puce TLC est connecté à la broche Arduino 11, comme
illustré à la Figure 7-14.

Les broches suivantes doivent être connectées ensemble lors de la connexion en guirlande des puces TLCÿ:

• Broche Arduino 9 à XLAT (broche 24) de chaque TLC •

Broche Arduino 10 à BLANK (broche 23) de chaque TLC • Broche

Arduino 13 à SCLK (broche 25) de chaque TLC

Chaque TLC a besoin de sa propre résistance entre Iref (broche 20) et Gnd.

258 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

Vous devez modifier la valeur de la constante NUM_TLCS définie dans la bibliothèque Tlc5940 pour qu'elle
corresponde au nombre de puces que vous avez câblées.

Voir également

Rendez-vous sur http:// code.google.com/ p/ tlc5940arduino/ pour télécharger cette bibliothèque et accéder à
sa documentation.

7.15 Utilisation d'un indicateur analogique comme affichage

Problème

Vous souhaitez contrôler le pointeur d'un indicateur de panneau analogique à partir de votre croquis. Les
lectures fluctuantes sont plus faciles à interpréter sur un compteur analogique, et les compteurs analogiques
ajoutent un look rétro cool à un projet.

Solution

Connectez le compteur via une résistance en série (5K ohms pour le compteur typique de 1 mA) et connectez-
le à une sortie analogique (PWM) (voir Figure 7-15).

Image 7-15. Piloter un compteur analogique

7.15 Utilisation d'un indicateur analogique comme affichage | 259


Machine Translated by Google

Le mouvement du pointeur correspond à la position d'un pot (résistance variable) :


/*
* Esquisse AnalogMeter
* Pilote un compteur analogique via une broche Arduino PWM
* Le niveau du compteur est contrôlé par une résistance variable sur une broche d'entrée analogique */

const entier analogInPin = 0ÿ; // Broche d'entrée analogique connectée à la résistance variable const int
analogMeterPin = 9ÿ; // Broche de sortie analogique se connectant au compteur

int sensorValue = 0ÿ; int // valeur lue depuis le pot // valeur


outputValue = 0ÿ; sortie vers le PWM (sortie analogique)

void setup() { //
rien dans setup }

void loop()
{ sensorValue
= analogRead(analogInPin); // lit l'analogique dans la valeur outputValue = map(sensorValue, 0, 1023,
0, 255); // mappe à la plage de la sortie analogique analogWrite(analogMeterPin, outputValue); }

// écrit la valeur de la sortie analogique

Discussion
Dans cette variante de la recette 7.2, la sortie Arduino analogWrite pilote un indicateur de panneau.
Les indicateurs de panneau sont généralement beaucoup plus sensibles que les LEDÿ; une résistance
doit être connectée entre la sortie Arduino et le compteur pour faire chuter le courant au niveau du compteur.

La valeur de la résistance série dépend de la sensibilité du compteur ; 5K ohms donnent une déviation à
pleine échelle avec un mètre de 1 mA. Vous pouvez utiliser des résistances de 4,7K, car elles sont plus
faciles à obtenir que 5K, bien que vous deviez probablement réduire la valeur maximale donnée à
analogWrite à 240 environ. Voici comment vous pouvez modifier la plage dans la fonction de carte si vous
utilisez une résistance de 4,7ÿK ohms avec un mètre de 1ÿmAÿ:
outputValue = map(sensorValue, 0, 1023, 0, 240); // mapper à la plage du mètre

Si votre compteur a une sensibilité différente de 1 mA, vous devrez utiliser une résistance série de valeur
différente. La valeur de la résistance en ohms est : Résistance = 5 000 / mA

Ainsi, un mètre de 500 microampères (0,5 mA) correspond à 5 000 / 0,5, soit 10 000 (10K) ohms.

Certains compteurs excédentaires ont déjà une résistance série interne - vous devrez peut-être faire des
essais pour déterminer la valeur correcte de la résistance, mais veillez à ne pas appliquer trop de tension
à votre compteur.

Voir également

Recette 7.2

260 | Chapitre 7 : Sortie visuelle


Machine Translated by Google

CHAPITRE 8

Sortie physique

8.0 Présentation
Vous pouvez faire bouger les choses en contrôlant les moteurs avec Arduino. Différents types de moteurs
conviennent à différentes applications, et ce chapitre montre comment Arduino peut piloter de nombreux types
de moteurs différents.

Contrôle de mouvement à l'aide de

servos Les servos vous permettent de contrôler avec précision les mouvements physiques car ils se déplacent
généralement vers une position au lieu de tourner en permanence. Ils sont idéaux pour faire tourner quelque
chose sur une plage de 0 à 180 degrés. Les servos sont faciles à connecter et à contrôler car le pilote du moteur
est intégré au servo.

Les servos contiennent un petit moteur relié par des engrenages à un arbre de sortie. L'arbre de sortie entraîne
un bras d'asservissement et est également connecté à un potentiomètre pour fournir un retour de position à un
circuit de commande interne (voir Figure 8-1).

Vous pouvez obtenir des servos à rotation continue dont le retour de position est déconnecté afin que vous
puissiez demander au servo de tourner en continu dans le sens des aiguilles d'une montre et dans le sens
inverse des aiguilles d'une montre avec un certain contrôle sur la vitesse. Ceux-ci fonctionnent un peu comme
les moteurs à balais couverts dans la recette 8.3, sauf que les servos à rotation continue utilisent le code de la
bibliothèque servo au lieu de analogWrite.

Les servos réagissent aux changements de durée d'une impulsion. Une courte impulsion de 1 ms ou moins fera
tourner le servo à un extrême ; une durée d'impulsion d'environ 2 ms fera tourner le servo à l'autre extrême (voir
Figure 8-2). Les impulsions comprises entre ces valeurs feront tourner le servo dans une position proportionnelle
à la largeur d'impulsion. Il n'y a pas de norme pour la relation exacte entre les impulsions et la position, et vous
devrez peut-être bricoler les commandes de votre croquis pour ajuster la plage de vos servos.

261
Machine Translated by Google

Illustration 8-1. Éléments à l'intérieur d'un servo de loisir

Bien que la durée de l'impulsion soit modulée (contrôlée), les servos nécessitent des impulsions
différentes de la sortie de modulation de largeur d'impulsion (PWM) d' analogWrite. Vous pouvez
endommager un servo de loisir en le connectant à la sortie d' analogWrite - utilisez plutôt la
bibliothèque Servo.

Solénoïdes et relais Bien que

la plupart des moteurs produisent un mouvement rotatif, un solénoïde produit un mouvement linéaire lorsqu'il
est alimenté. Un solénoïde a un noyau métallique qui est déplacé par un champ magnétique qui est créé lorsque
le courant passe à travers une bobine. Un relais mécanique est un type de solénoïde qui connecte ou déconnecte
des contacts électriques (c'est un solénoïde actionnant un interrupteur).
Les relais sont contrôlés comme des solénoïdes. Les relais et les solénoïdes, comme la plupart des moteurs,
nécessitent plus de courant qu'une broche Arduino ne peut fournir en toute sécurité, et les recettes de ce
chapitre montrent comment vous pouvez utiliser un transistor ou un circuit externe pour piloter ces appareils.

Moteurs à balais et sans balais


La plupart des moteurs à courant continu (CC) à faible coût sont de simples dispositifs avec deux fils connectés
à des balais (contacts) qui contrôlent le champ magnétique des bobines qui entraînent un noyau métallique
(induit). Le sens de rotation peut être inversé en inversant la polarité de la tension sur les contacts. Les moteurs
à courant continu sont disponibles dans de nombreuses tailles différentes, mais même les plus petits (comme
les moteurs à vibration utilisés dans les téléphones portables) nécessitent un transistor ou une autre commande
externe pour fournir un courant adéquat. Les recettes qui suivent montrent comment contrôler les moteurs à
l'aide d'un transistor ou d'un circuit de contrôle externe appelé pont en H.

262 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-2. Relation entre la largeur d'impulsion et l'angle d'asservissementÿ; le bras de sortie du servo se déplace
proportionnellement lorsque la largeur d'impulsion augmente de 1 ms à 2 ms

La principale caractéristique dans le choix d'un moteur est le couple. Le couple détermine la quantité de travail
que le moteur peut faire. En règle générale, les moteurs à couple élevé sont plus gros et plus lourds et
consomment plus de courant que les moteurs à couple inférieur.

Les moteurs sans balais sont généralement plus puissants et efficaces pour une taille donnée que les moteurs
à balais, mais ils nécessitent un contrôle électronique plus compliqué. Lorsque les performances d'un moteur
sans balais sont souhaitées, des composants appelés régulateurs de vitesse électroniques destinés à une
utilisation de radiocommande de loisir peuvent être facilement contrôlés par Arduino car ils sont contrôlés un
peu comme un servomoteur.

Moteurs pas à pas Les

moteurs pas à pas sont des moteurs qui tournent d'un certain nombre de degrés en réponse à des impulsions
de commande. Le nombre de degrés dans chaque pas dépend du moteur, allant d'un ou deux degrés par pas
à 30 degrés ou plus.

Deux types de steppers sont couramment utilisés avec Arduino : bipolaire (généralement avec quatre fils
attachés à deux bobines) et unipolaire (cinq ou six fils attachés à deux bobines). Les fils supplémentaires
dans un stepper unipolaire sont connectés en interne au centre des bobines (dans la version à cinq fils,
chaque bobine a une prise centrale et les deux prises centrales sont connectées ensemble). Les recettes
couvrant les steppers bipolaires et unipolaires ont des schémas illustrant ces connexions.

8.0 Présentation | 263


Machine Translated by Google

Barre latérale de dépannage


La cause la plus courante de problèmes lors de la connexion d'appareils nécessitant une
alimentation externe est de ne pas connecter toutes les masses ensemble. Votre masse
Arduino doit être connectée à la masse de l'alimentation externe et aux masses des
appareils externes alimentés.

8.1 Contrôle de la position d'un servo


Problème

Vous souhaitez contrôler la position d'un servo à l'aide d'un angle calculé dans votre croquis.
Par exemple, vous voulez qu'un capteur sur un robot se balance sur un arc ou se déplace vers une position que
vous sélectionnez.

Solution

Utilisez la bibliothèque Servo distribuée avec Arduino. Connectez l'alimentation du servo et la masse à une
alimentation appropriée (un seul servo de loisir peut généralement être alimenté à partir de la ligne Arduino 5V). Les
versions récentes de la bibliothèque vous permettent de connecter les câbles de signal servo à n'importe quelle
broche numérique Arduino.

Voici l'exemple de sketch Sweep distribué avec Arduino ; La figure 8-3 montre le
Connexions:

#include <Servo.h>

Servo monservoÿ; // crée un objet servo pour contrôler un servo

angle entier = 0ÿ; // variable pour stocker la position du servo

void setup()

{ myservo.attach(9); // attache le servo sur la broche 10 à l'objet servo }

void loop()
{ for(angle =
0; angle < 180; angle += 1) // va de 0 degrés à 180 degrés { // par pas de 1 degré // dit au servo d'aller à
la position dans la variable 'angle' myservo.write(angle);d'asservissement
retard(20); // attend 20ms entre
} for(angle lesangle
= 180; commandes
>= 1;
retard(20); } } angle -= 1) // passe de 180 degrés à 0 degrés { myservo.write(pos);

// indique au servo d'aller en position dans la variable 'pos' //


attend 20 ms entre les commandes d'asservissement

264 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-3. Connexion d'un servo pour le test avec l'exemple de croquis Sweep

Discussion
Cet exemple balaie le servo entre 0 et 180 degrés. Vous devrez peut-être demander à la bibliothèque
d'ajuster les positions minimale et maximale afin d'obtenir l'amplitude de mouvement souhaitée. L'appel de
Servo.attach avec des arguments facultatifs pour les positions minimale et maximale ajustera le mouvementÿ:

monservo.attach(9,1000,2000 ); // utilisez la broche 9, réglez min à 1000us, max à 2000us

Étant donné que les servos typiques répondent aux impulsions mesurées en microsecondes et non en
degrés, les arguments suivant le numéro de broche informent la bibliothèque Servo du nombre de
microsecondes à utiliser lorsque 0 degré ou 180 degrés sont demandés. Tous les servos ne se déplacent
pas sur une plage complète de 180 degrés, vous devrez donc peut-être expérimenter avec le vôtre pour
obtenir la plage souhaitée.

Les paramètres de servo.attach(pin, min, max) sont les suivantsÿ:


épingler

Le numéro de broche auquel le servo est attaché (doit être 9 ou 10) min

(facultatif)
La largeur d'impulsion, en microsecondes, correspondant à l'angle minimum (0 degré) sur le servo
(par défaut à 544)

maximum (facultatif)
La largeur d'impulsion, en microsecondes, correspondant à l'angle maximum (180 degrés) sur le
servo (par défaut à 2 400)

Les besoins en puissance varient en fonction du servo et du couple nécessaire pour faire tourner l'arbre.

8.1 Contrôle de la position d'un servo | 265


Machine Translated by Google

Vous pouvez avoir besoin d'une source externe de 5 ou 6 volts lors de la connexion de
plusieurs servos. Quatre piles AA fonctionnent bien si vous souhaitez utiliser la batterie.
N'oubliez pas que vous devez connecter la masse de la source d'alimentation externe à
la masse Arduino.

8.2 Contrôler un ou deux servos avec un potentiomètre


ou un capteur

Problème
Vous souhaitez contrôler le sens de rotation et la vitesse d'un ou deux servos avec un potentiomètre.
Par exemple, vous souhaitez contrôler le panoramique et l'inclinaison d'une caméra ou d'un capteur
connecté aux servos. Cette recette peut fonctionner avec n'importe quelle tension variable d'un capteur
pouvant être lu à partir d'une entrée analogique.

Solution
La même bibliothèque peut être utilisée que dans la recette 8.1, avec l'ajout d'un code pour lire la
tension sur un potentiomètre. Cette valeur est mise à l'échelle de manière à ce que la position du
potentiomètre (de 0 à 1023) corresponde à une valeur comprise entre 0 et 180 degrés. La seule
différence dans le câblage est l'ajout du potentiomètre ; voir Figure 8-4ÿ:
#include <Servo.h>

Servo monservoÿ; // crée un objet servo pour contrôler un servo

entier potpin = 0ÿ; // broche analogique utilisée pour connecter le


analogique intpotentiomètre
val; // variable pour lire la valeur de la broche

void setup()

{ myservo.attach(9); // attache le servo sur la broche 9 à l'objet servo }

void loop()
{ val =
analogRead(potpin); val = // lit la valeur du potentiomètre // le met à
carte(val, 0, 1023, 0, 179); l'échelle pour l'utiliser avec le servo // règle
myservo.write(val); retard(15); } la position sur la valeur mise à l'échelle //
attend que le servo y arrive

266 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-4. Contrôler un servo avec un potentiomètre

Discussion
Tout ce qui peut être lu à partir de analogRead (voir chapitre 5 et chapitre 6) peut être utilisé -
par exemple, les recettes du gyroscope et de l'accéléromètre du chapitre 6 peuvent être utilisées
pour que l'angle du servo soit contrôlé par le lacet du gyroscope ou l'angle de l'accéléromètre.

8.3 Contrôle de la vitesse des servos à rotation continue


Problème
Vous souhaitez contrôler le sens de rotation et la vitesse des servos modifiés pour une rotation
continue. Par exemple, vous utilisez deux servomoteurs à rotation continue pour alimenter un
robot et vous souhaitez que la vitesse et la direction soient contrôlées par votre croquis.

Solution
Les servos à rotation continue sont une forme de moteur à engrenages réduits avec réglage de
la vitesse avant et arrière. Le contrôle des servos à rotation continue est similaire aux servos
normaux. Le servo tourne dans une direction lorsque l'angle est augmenté de 90 degrés ; il
tourne dans l'autre sens lorsque l'angle est diminué de 90 degrés. La direction réelle vers l'avant
ou vers l'arrière dépend de la façon dont vous avez attaché les servos. La figure 8-5 montre les
connexions pour contrôler deux servos.

Cet exemple balaie les servos de 90 à 180 degrés, donc si les servos étaient connectés aux
roues, le véhicule avancerait à un rythme lentement croissant, puis ralentirait

8.3 Contrôle de la vitesse des servos à rotation continue | 267


Machine Translated by Google

Illustration 8-5. Contrôler deux servos

jusqu'à un arrêt. Comme le code d'asservissement est en boucle, cela continuera tant qu'il
y aura du courantÿ:
#include <Servo.h>

Servo myservoLeftÿ; // crée un objet servo pour contrôler un servo


Servo myservoDroitÿ; // crée un objet servo pour contrôler un servo

entier pos = 0ÿ; // variable pour stocker la position du servo

void setup()

{ myservoLeft.attach(9); // attache le servo gauche sur la broche 9 à l'objet servo


myservoRight.attach(10); // attache le servo droit sur la broche 10 à l'objet servo }

void loop()
{ for(angle =
90; angle < 180; angle += 1) // passe de 90 à 180 degrés { // par pas de 1 degré // 90 degrés
est arrêté myservoLeft.write(angle); // tourne lemyservoRight.write(180-angle);
servo à la vitesse donnée par 'angle'
// aller dans la
direction opposée

retard(20); } // attend 20ÿms entre les commandes d'asservissement


for(angle =
180; angle >= 90; angle -= 1) // passe de 180 à 90 degrés { myservoLeft.write(angle);
myservoRight.write(180-angle); // autre servo va dans la direction opposée } }
// tourne à une vitesse donnée par 'angle'

268 | Chapitre 8 : Sortie physique


Machine Translated by Google

Discussion
Vous pouvez utiliser un code similaire pour la rotation continue et les servos normaux, mais sachez que
les servos à rotation continue peuvent ne pas s'arrêter de tourner lors de l'écriture d'exactement 90 degrés.
Certains servos ont un petit potentiomètre que vous pouvez régler pour régler cela, ou vous pouvez
ajouter ou soustraire quelques degrés pour arrêter le servo. Par exemple, si le servo gauche arrête de
tourner à 92 degrés, vous pouvez modifier les lignes qui écrivent sur les servos comme suit :
myservoLeft.write(angle+TRIM); // déclarer int TRIM=2ÿ; au début du croquis

8.4 Contrôle des servos depuis le port série


Problème
Vous souhaitez fournir des commandes pour contrôler les servos à partir du port série. Peut-être souhaitez-
vous contrôler les servos à partir d'un programme exécuté sur votre ordinateur.

Solution
Vous pouvez utiliser un logiciel pour contrôler les servos. Cela a l'avantage que n'importe quel nombre de
servos peut être pris en charge. Cependant, votre esquisse doit constamment s'occuper de rafraîchir la
position du servo, de sorte que la logique peut se compliquer à mesure que le nombre de servos augmente
si votre projet doit effectuer de nombreuses autres tâches.

Cette recette pilote quatre servos selon les commandes reçues sur le port série. Les commandes sont de
la forme suivante :

• 180a écrit 180 pour asservir a

• 90b écrit 90 sur servo b


• 0c écrit 0 sur servo c

• 17d écrit 17 sur servo d

Voici le croquis qui pilote quatre servos connectés sur les broches 7 à 10ÿ:
#include <Servo.h> // la bibliothèque servo

#define SERVOS 4 // le nombre de servos int


servoPins[SERVOS] = {7,8,9,10}ÿ; // servos sur les broches 7 à 10

Servo monservo[SERVOS]ÿ;

void setup()

{ Serial.begin(9600); for(int
i=0; i < SERVOS; i++)
monservo[i].attach(servoPins[i]);
}

boucle vide ()

8.4 Contrôle des servos depuis le port série | 269


Machine Translated by Google

{ serviceSerial(); }

// serviceSerial vérifie le port série et met à jour la position avec les données reçues // il attend des
données servo sous la formeÿ: // "180a" écrit 180 sur servo a // "90b écrit 90 sur servo b void
serviceSerial() { static int pos = 0ÿ;

if (Serial.available()) { char ch =
Serial.read();

si(ch >= '0' && ch <= '9') * 10 + // est-ce que ch est un


ch - '0'; pos = pos nombreÿ? // oui, accumulez la valeur
else if(ch >= 'a' && ch <= 'a'+ SERVOS) // est-ce que ch est une lettre pour nos servosÿ? // oui,
monservo[ch - 'a'].write(pos); enregistre la position dans le tableau de positions

}}

Discussion
La connexion des servos est similaire aux recettes précédentes. Chaque fil de ligne d'asservissement est
connecté à une broche numérique. Toutes les masses d'asservissement sont connectées à la masse Arduino. Les
lignes d'alimentation des servos sont connectées ensemble et vous aurez peut-être besoin d'une source
d'alimentation externe de 5 V ou 6 V si vos servos nécessitent plus de courant que l'alimentation Arduino ne peut en fournir.

Un tableau nommé myservo (voir recette 2.4) est utilisé pour contenir les références des quatre servos.
Une boucle for dans la configuration attache chaque servo du tableau à des broches consécutives définies dans le
tableau servoPins .

Si le caractère reçu de serial est un chiffre (le caractère sera supérieur ou égal à zéro et inférieur ou égal à 9), sa
valeur est accumulée dans la variable pos. Si le caractère est la lettre a, la position est écrite sur le premier servo
du tableau (le servo connecté à la broche 7). Les lettres b, c et d contrôlent les servos suivants.

Voir également

Voir le chapitre 4 pour plus d'informations sur la gestion des valeurs reçues en série.

270 | Chapitre 8 : Sortie physique


Machine Translated by Google

8.5 Conduire un moteur sans balais (à l'aide d'un contrôleur de vitesse Hobby)

Problème
Vous avez un moteur brushless hobby et vous souhaitez contrôler sa vitesse.

Solution
Cette esquisse utilise le même code que la recette 8.2. Le câblage est similaire, sauf pour le
variateur de vitesse et le moteur. Les moteurs sans balais ont trois enroulements et ceux-ci doivent
être connectés en suivant les instructions de votre régulateur de vitesse (voir Figure 8-6).

Illustration 8-6. Raccordement d'un régulateur de vitesse électronique

Discussion
Consultez la documentation de votre variateur de vitesse pour vous assurer qu'il est adapté à votre
moteur brushless et pour vérifier le câblage. Les moteurs sans balais ont trois connexions pour les
trois fils du moteur et deux connexions pour l'alimentation. De nombreux contrôleurs de vitesse
fournissent une alimentation sur la broche centrale du connecteur de servo. Sauf si vous souhaitez
alimenter la carte Arduino depuis le variateur de vitesse, vous devez déconnecter ou couper ce fil central.

Si votre contrôleur de vitesse a une fonction qui fournit une alimentation 5V aux servos et autres
appareils (appelé circuit d'éliminateur de batterie ou BEC en abrégé), vous devez déconnecter ce fil lors
de la connexion de l'Arduino au contrôleur de vitesse (voir Figure 8-6).

8.5 Conduire un moteur sans balais (à l'aide d'un contrôleur de vitesse Hobby) | 271
Machine Translated by Google

8.6 Contrôle des solénoïdes et des relais

Problème
Vous voulez activer un solénoïde ou un relais sous contrôle de programme. Les solénoïdes sont des électro-
aimants qui convertissent l'énergie électrique en mouvement mécanique. Un relais électromagnétique est un
interrupteur activé par un solénoïde.

Solution
La plupart des solénoïdes nécessitent plus de puissance qu'une broche Arduino ne peut fournir, donc un
transistor est utilisé pour commuter le courant nécessaire pour activer un solénoïde. L'activation du
solénoïde est obtenue en utilisant digitalWrite pour régler la broche HIGH.

Ce schéma active un transistor connecté comme illustré à la figure 8-7. Le solénoïde sera activé pendant une
seconde toutes les heuresÿ:

solénoïde intPin = 2ÿ; // Solénoïde connecté au transistor sur la broche 2

void setup()

{ pinMode(ledPin, OUTPUT); }

void loop()
{ // intervalle
= intervalle de
digitalWrite(solenoidPin, 60 minutes
HIGH); // active= le
1000
délai* 60
du *solénoïde
60 ;
(1000); // attend une seconde digitalWrite(ledPin, LOW); // désactive
le solénoïde // attend une heure de retard (intervalle); }

Discussion
Le choix du transistor dépend de la quantité de courant nécessaire pour activer le solénoïde ou le relais. La fiche
technique peut le spécifier en milliampères (mA) ou en tant que résistance de la bobine. Pour trouver le courant
nécessaire à votre solénoïde ou relais, divisez la tension de la bobine par sa résistance en ohms. Par exemple,
un relais 12V avec une bobine de 185 ohms consomme 65 mA : 12 (volts) / 185 (ohms) = 0,065 ampères, soit 65
mA.

Les petits transistors tels que le 2N2222 sont suffisants pour les solénoïdes nécessitant jusqu'à quelques
centaines de milliampères. Les solénoïdes plus grands nécessiteront un transistor de puissance plus élevée,
comme le TIP102/TIP120 ou similaire. Il existe de nombreuses alternatives de transistors appropriées; voir
l'annexe B pour obtenir de l'aide sur la lecture d'une fiche technique et le choix des transistors.

Le but de la diode est d'empêcher la force électromotrice inverse de la bobine d'endommager le transistor (la
force électromotrice inverse est une tension produite lorsque le courant à travers une bobine est commuté

272 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-7. Piloter un solénoïde avec un transistor

désactivé). La polarité de la diode est importante ; il y a une bande colorée indiquant la cathode -
celle-ci doit être connectée à l'alimentation positive du solénoïde.

Les relais électromagnétiques sont activés comme les solénoïdes. Un relais spécial appelé relais à
semi-conducteurs (SSR) possède une électronique interne qui peut être pilotée directement à partir
d'une broche Arduino sans avoir besoin du transistor. Consultez la fiche technique de votre relais
pour connaître la tension et le courant dont il a besoinÿ; tout ce qui dépasse 40 mA à 5 volts
nécessitera un circuit tel que celui illustré à la Figure 8-7.

8.7 Faire vibrer un objet


Problème
Vous voulez que quelque chose vibre sous le contrôle d'Arduino. Par exemple, vous voulez que votre
projet tremble pendant une seconde chaque minute.

Solution
Connectez un moteur vibrant comme illustré à la Figure 8-8.

8.7 Faire vibrer un objet | 273


Machine Translated by Google

Figure 8-8. Connexion d'un moteur vibrant

Le schéma suivant activera le moteur de vibration pendant une seconde chaque minuteÿ:
/*
* Croquis vibreur
* Vibrer pendant une seconde chaque minute
*
*/

const int motorPin = 3ÿ; // Le transistor du moteur de vibration est connecté à la broche 3

void setup()

{ pinMode(motorPin, OUTPUT); }

void loop()

{ digitalWrite(motorPin, HIGH); //délai de


vibration(1000); // retarde une seconde
digitalWrite(motorPin, LOW); // arrête le délai de vibration
(59000); // attend 59 secondes. }

Discussion
Cette recette utilise un moteur conçu pour vibrer, comme le SparkFun ROB-08449. Si vous avez un
ancien téléphone portable dont vous n'avez plus besoin, il peut contenir de minuscules moteurs de
vibration qui conviendraient. Les moteurs vibrants nécessitent plus de puissance qu'une broche Arduino
ne peut fournir, donc un transistor est utilisé pour allumer et éteindre le courant du moteur. Presque
tous les transistors NPN peuvent être utilisés ; La figure 8-3 montre le 2N2222 commun (consultez le
site Web de ce livre pour obtenir des informations sur ce fournisseur et sur les autres composants
utilisés). Une résistance de 1 kilohm relie la broche de sortie à la base du transistorÿ; la valeur n'est pas
critique, et vous pouvez utiliser des valeurs jusqu'à 4,7 kilohm environ (la résistance empêche trop de courant de circuler

274 | Chapitre 8 : Sortie physique


Machine Translated by Google

via la broche de sortie). La diode absorbe (ou amortit - on l'appelle parfois une diode d'amortissement)
les tensions produites par les enroulements du moteur lors de sa rotation. Le condensateur absorbe
les pointes de tension produites lorsque les balais (contacts reliant le courant électrique aux
enroulements du moteur) s'ouvrent et se ferment. La résistance de 33 ohms est nécessaire pour
limiter la quantité de courant circulant dans le moteur.

Cette esquisse définit la broche de sortie HIGH pendant une seconde (1 000 millisecondes) puis
attend 59 secondes. Le transistor s'allumera (conduira) lorsque la broche est HAUTE, permettant au
courant de circuler à travers le moteur.
Voici une variante de ce sketch qui utilise un capteur pour faire vibrer le moteur. Le câblage est
similaire à celui illustré à la Figure 8-3, avec l'ajout d'une cellule photoélectrique connectée à la
broche analogique 0 (voir recette 1.6)ÿ:
/*
* Esquisse Vibrate_Photocellule
* Vibrer lorsque le capteur photo détecte la lumière au-dessus du niveau ambiant
*
*/

const int motorPin = 3ÿ; // le transistor du moteur de vibration est connecté à la broche 3 const int
sensorPin = 0ÿ; // Photodétecteur connecté à l'entrée analogique 0 // niveau de lumière ambiante
const int seuilMarge = 100ÿ; // combien au-dessus
(calibré
de dans
la température
la configuration)
ambianteint nécessaire
sensorAmbient
pour=vibrer
0ÿ;

void setup()

{ pinMode(motorPin, OUTPUT);
capteurAmbient = analogRead(capteurPin); // obtient le niveau d'éclairage au
démarrageÿ; }

void loop()
{ int
sensorValue = analogRead(sensorPin);
if( sensorValue > sensorAmbient + thresholdMargin) {

digitalWrite(motorPin, HIGH); //vibrer

}
autre {
digitalWrite(motorPin, LOW); // arrête de vibrer

}}

Ici, la broche de sortie est allumée lorsqu'une lumière brille sur la cellule photoélectrique. Lorsque
l'esquisse démarre, le niveau de lumière d'arrière-plan sur le capteur est lu et stocké dans la variable
sensorAmbient. Les niveaux de lumière lus en boucle qui sont plus élevés activeront le moteur de
vibration.

8.7 Faire vibrer un objet | 275


Machine Translated by Google

8.8 Entraînement d'un moteur à balais à l'aide d'un transistor

Problème
Vous voulez allumer et éteindre un moteur. Vous voudrez peut-être contrôler sa vitesse. Le moteur n'a
besoin de tourner que dans un sens.

Solution
Ce croquis allume et éteint le moteur et contrôle sa vitesse à partir des commandes reçues sur le port
série (Figure 8-9 montre les connexions)ÿ:
/*
* Croquis SimpleBrushed
* les commandes du port série contrôlent la vitesse du
moteur * les chiffres '0' à '9' sont valides où '0' est désactivé, '9' est la vitesse
maximale */

const int motorPins = 3ÿ; // le pilote du moteur est connecté à la broche 3

void setup()

{ Serial.begin(9600); }

void loop()
{ if
(Serial.available()) { char ch =
Serial.read();

if(ch >= '0' && ch <= '9') { int // est-ce que ch est un nombreÿ?

speed = map(ch, '0', '9', 0,


255); analogWrite(3, vitesse);
Serial.println(vitesse); } else
{ Serial.print("Caractère inattendu ");
Serial.println(ch); } } }

Discussion
Cette recette est similaire à la recette 8.7 ; la différence est que analogWrite est utilisé pour contrôler la
vitesse du moteur. Voir « Sortie analogique » à la page 217 au chapitre 7 pour plus d'informations sur
l'écriture analogique et la modulation de largeur d'impulsion (PWM).

276 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-9. Conduire un moteur à balais

8.9 Contrôle de la direction d'un moteur à


balais avec un pont en H
Problème
Vous souhaitez contrôler la direction d'un moteur à balais, par exemple, vous souhaitez faire tourner un
moteur dans un sens ou dans l'autre à partir des commandes du port série.

Solution
Un pont en H peut contrôler deux moteurs à balais. La figure 8-10 montre les connexions du circuit intégré
de pont en H L293Dÿ; vous pouvez également utiliser le SN754410 qui a la même disposition des brochesÿ:
/*
* Esquisse Brushed_H_Bridge_simple
* les commandes du port série contrôlent la direction du
moteur * + ou - définissent la direction, toute autre touche arrête le
moteur */

const in1Pin = 5ÿ; // Broches d'entrée H-Bridge const


int in2Pin = 4;

void setup()

{ Serial.begin(9600);
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
Serial.println("+ - pour définir la direction, toute autre touche arrête le moteur"); }

8.9 Contrôle de la direction d'un moteur à balais avec un pont en H | 277


Machine Translated by Google

void loop()
{ if
(Serial.available()) { char
ch = Serial.read(); if (ch
== '+') { Serial.println("CW");
digitalWrite(in1Pin,LOW);
digitalWrite(in2Pin,HIGH); }
sinon si (ch == '-')
{ Serial.println("CCW");
écriture numérique (in1Pin,
HIGH); digitalWrite(in2Pin,LOW); }
else { Serial.print("Arrêter le
moteur");
digitalWrite(in1Pin,LOW);
digitalWrite(in2Pin,LOW); } } }

Illustration 8-10. Connexion de deux moteurs à balais à l'aide d'un pont en H L293D

278 | Chapitre 8 : Sortie physique


Machine Translated by Google

Discussion
Le tableau 8-1 montre comment les valeurs de l'entrée H-Bridge affectent le moteur. Dans le croquis
dans la solution de cette recette, un seul moteur est contrôlé à l'aide des broches IN1 et IN2ÿ; la
La broche EN est HAUTE en permanence car elle est connectée au +5V.

Tableau 8-1. Table logique pour H-Bridge

AU EN 1 EN 2 Une fonction

HAUT BAS HAUT Tourne dans le sens des aiguilles d'une montre

ÉLEVÉ ÉLEVÉ MEUGLER


Tourner dans le sens antihoraire

HAUT BAS MEUGLER Arrêt du moteur

ÉLEVÉ ÉLEVÉ HAUT Arrêt du moteur

MEUGLER Ignoré Arrêt du moteur ignoré

La figure 8-5 montre comment un deuxième moteur peut être connecté. Les commandes d'esquisse suivantes
les deux moteurs ensemble :

/*
* Esquisse Brushed_H_Bridge_simple2
* Les commandes du port série contrôlent la direction du moteur
* + ou - régler la direction, toute autre touche arrête les moteurs
*/

const in1Pin = 5ÿ; // Broches d'entrée H-Bridge


const in2Pin = 4ÿ;

const entier in3Pin = 3ÿ; // Goupilles H-Bridge pour deuxième moteur


const in4Pin = 2ÿ;

void setup()
{
Série.begin(9600);
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
pinMode(in3Pin, OUTPUT);
pinMode(in4Pin, OUTPUT);
Serial.println("+ - définit la direction des moteurs, toute autre touche arrête les moteurs");
}

boucle vide ()
{
si (série.disponible()) {
char ch = Serial.read();
si (ch == '+')

8.9 Contrôle de la direction d'un moteur à balais avec un pont en H | 279


Machine Translated by Google

{ Serial.println("CW"); //
premier moteur
digitalWrite(in1Pin,LOW);
digitalWrite(in2Pin,HIGH); //
deuxième moteur
digitalWrite(in3Pin,LOW);
digitalWrite(in4Pin,HIGH); }
sinon si (ch == '-')
{ Serial.println("CCW"); écriture
numérique (in1Pin, HIGH);
digitalWrite(in2Pin,LOW);

digitalWrite(in3Pin,HIGH);
digitalWrite(in4Pin,LOW); }
else { Serial.print("Arrêter les
moteurs");
digitalWrite(in1Pin,LOW);
digitalWrite(in2Pin,LOW);
digitalWrite(in3Pin,LOW);
digitalWrite(in4Pin,LOW); } } }

8.10 Contrôle de la direction et de la vitesse d'un moteur à


balais avec un pont en H

Problème
Vous souhaitez contrôler la direction et la vitesse d'un moteur à balais. Cela étend les fonctionnalités
de la recette 8.9 en contrôlant à la fois la direction et la vitesse du moteur via des commandes
depuis le port série.

Solution
Connectez un moteur à balais aux broches de sortie du pont en H, comme illustré à la Figure 8-11.

280 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-11. Connexion d'un moteur à balais à l'aide d'analogWrite pour le contrôle de la vitesse

Cette esquisse utilise les commandes du moniteur série pour contrôler la vitesse et
la direction du moteur. L'envoi de "0" arrêtera le moteur et les chiffres "1" à "9"
contrôleront la vitesse. L'envoi de "+" et "-" définira la direction du moteurÿ:
/*
* Croquis Brushed_H_Bridge
* les commandes du port série contrôlent la vitesse et la direction du
moteur * les chiffres '0' à '9' sont valides où '0' est désactivé, '9' est la vitesse
maximale * + ou - définit la direction */

const int enPin = 5ÿ; // H-Bridge active la broche


const int in1Pin = 7; // Broches d'entrée H-Bridge
const int in2Pin = 4;

void setup()

{ Serial.begin(9600);
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
Serial.println("Vitesse (0-9) ou + - pour définir la direction"); }

void loop()
{ if
(Serial.available()) { char ch =
Serial.read();

8.10 Contrôle de la direction et de la vitesse d'un moteur à balais avec un pont en H | 281
Machine Translated by Google

if(ch >= '0' && ch <= '9') // est-ce que ch est un nombreÿ?

{ int speed = map(ch, '0',


'9', 0, 255); analogWrite(enPin, vitesse);
Serial.println(vitesse); } sinon si (ch ==
'+') { Serial.println("CW");
digitalWrite(in1Pin,LOW);
digitalWrite(in2Pin,HIGH); } sinon si (ch
== '-') { Serial.println("CCW"); écriture
numérique (in1Pin, HIGH);
digitalWrite(in2Pin,LOW); } else
{ Serial.print("Caractère inattendu ");
Serial.println(ch); } } }

Discussion
Cette recette est similaire à la recette 8.9, dans laquelle la direction du moteur est contrôlée par les
niveaux sur les broches IN1 et IN2. Mais en plus, la vitesse est contrôlée par la valeur analogWrite sur
la broche EN (voir le chapitre 7 pour plus d'informations sur PWM). L'écriture d'une valeur de 0 arrêtera
le moteurÿ; écrire 255 fera tourner le moteur à plein régime. La vitesse du moteur variera
proportionnellement aux valeurs comprises dans cette plage.

8.11 Utilisation de capteurs pour contrôler la direction et la


vitesse des moteurs à balais (pont en H L293)

Problème
Vous souhaitez contrôler la direction et la vitesse des moteurs à balais avec le retour des capteurs. Par
exemple, vous voulez que deux photocapteurs contrôlent la vitesse et la direction du moteur pour
amener un robot à se déplacer vers un faisceau de lumière.

Solution
Cette solution utilise des connexions de moteur similaires à celles illustrées à la Figure 8-10, mais avec
l'ajout de deux résistances dépendantes de la lumière, comme illustré à la Figure 8-12.

282 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-12. Deux moteurs contrôlés à l'aide de capteurs

Le croquis surveille le niveau de lumière sur les capteurs et entraîne les moteurs à se diriger vers le
capteur détectant le niveau de lumière le plus lumineuxÿ:
/*
* L'esquisse Brushed_H_Bridge_Direction
*
utilise des capteurs photo pour contrôler la direction du moteur
* le robot se déplace dans la direction d'une lumière */

int leftPins[] = {5,7,4}ÿ; // sur la broche pour PWM, deux broches pour le sens du moteur int
rightPins[] = {6,3,2}ÿ;

const int LeftSensorPin = 0ÿ; // broches analogiques avec capteurs const


int rightSensorPin = 1;

int sensorThreshold = 0ÿ; int // doit avoir autant de lumière sur un capteur pour se déplacer //
regarde = 0; le nombre de tentatives pour tourner et trouver de la lumière

void setup()
{ for(int i=1; i <
3; i++) { pinMode(leftPins[i],
OUTPUT); pinMode(rightPins[i],
OUTPUT); } }

void loop()
{ int leftVal =
analogRead(leftSensorPin);

8.11 Utilisation de capteurs pour contrôler la direction et la vitesse des moteurs à balais (L293 H-Bridge) | 283
Machine Translated by Google

int rightVal = analogRead(rightSensorPin);


if(sensorThreshold == 0) // les capteurs ont-ils été calibrés ?
sensorThreshold = (leftVal + rightVal) / 2ÿ; // non, calibrer les capteurs

if( leftVal < sensorThreshold && rightVal < sensorThreshold) { if(looks


< 4) // limite le nombre de regards consécutifs { lookAround(); regarde
= regarde + 1; } } autre

{ // s'il y a suffisamment de lumière pour avancer


setSpeed(rightPins, map(rightVal,0,1023, 0,255));
setSpeed(leftPins, map(leftVal,0,1023,0,255)); regarde =
0; // réinitialiser le compteur de regards } }

void lookAround()
{ // rotation à
gauche pendant une demi-seconde
setSpeed(leftPins, -127 );
setSpeed(rightPins, 127 ); retard
(500); setSpeed(rightPins, 0 );
setSpeed(leftPins, 127 ); }

void setSpeed(int pins[], int speed )


{ if(speed < 0) { digitalWrite(pins[1],HIGH);
digitalWrite(broches[2],BAS); vitesse =
-vitesseÿ; } else { digitalWrite(pins[1],LOW);
digitalWrite(broches[2],HIGH); }
analogWrite(broches[0], vitesse); }

Discussion
Ce croquis contrôle la vitesse de deux moteurs en réponse à la quantité de lumière détectée par
deux photocellules. Les photocellules sont disposées de manière à ce qu'une augmentation de la
lumière d'un côté augmente la vitesse du moteur de l'autre côté. Cela amène le robot à se tourner
vers le côté avec la lumière la plus brillante. La lumière qui brille également sur les deux cellules rend le

284 | Chapitre 8 : Sortie physique


Machine Translated by Google

le robot avance en ligne droite. Une lumière insuffisante oblige le robot à s'arrêter et à regarder autour de lui
pour voir s'il y a une source de lumière provenant d'une autre direction.

La lumière est détectée par les entrées analogiques 0 et 1 (voir recette 6.2). Lorsque le programme démarre,
la lumière ambiante est mesurée et ce seuil est utilisé pour déterminer le niveau de lumière minimum nécessaire
pour déplacer le robot. Lorsque la lumière tombe en dessous du seuil, la fonction lookAround est appelée pour
faire pivoter le robot afin de rechercher plus de lumière.

La vitesse du moteur est contrôlée dans la fonction setSpeed . Deux broches sont utilisées pour contrôler la
direction de chaque moteur et avec une autre broche pour contrôler la vitesse. Les numéros de broches sont
conservés dans les tableaux leftPins et rightPins . La première broche de chaque tableau est la broche de
vitesseÿ; les deux autres broches sont pour la direction.

Une alternative au L293 est le Toshiba FB6612FNG. Cela peut être utilisé dans n'importe laquelle des recettes
montrant le L293D. La figure 8-13 montre le câblage du FB6612 tel qu'il est utilisé sur la carte de dérivation
Pololu (SparkFun ROB-09402).

Illustration 8-13. Câblage H-Bridge pour la carte de dérivation Pololu

Vous pouvez réduire le nombre de broches nécessaires en ajoutant du matériel supplémentaire pour contrôler
les broches de direction. Cela se fait en utilisant une seule broche par moteur pour la direction, avec un
transistor ou une porte logique pour inverser le niveau sur l'autre entrée H-Bridge. Vous pouvez trouver des
schémas de circuit pour cela dans le wiki Arduino, mais si vous voulez quelque chose de déjà câblé, vous
pouvez utiliser un blindage H-Bridge tel que le blindage de commande de moteur Freeduino (NKC

8.11 Utilisation de capteurs pour contrôler la direction et la vitesse des moteurs à balais (L293 H-Bridge) | 285
Machine Translated by Google

Electronics ARD-0015) ou l'Ardumoto de SparkFun (DEV-09213). Ces blindages se branchent


directement sur Arduino et ne nécessitent que des connexions à l'alimentation et aux bobinages du
moteur.
Voici le croquis révisé pour le bouclier Ardumoto :

/*
* L'esquisse Brushed_H_Ardumoto
*
utilise des capteurs photo pour contrôler la direction du moteur
* le robot se déplace dans la direction d'une lumière
*/

int leftPins[] = {10,12}ÿ; // une broche pour PWM, une broche pour la direction du moteur int
rightPins[] = {11,13}ÿ;

const int LeftSensorPin = 0ÿ; // broches analogiques avec capteurs const


int rightSensorPin = 1;

int sensorThreshold = 0ÿ; int // doit avoir autant de lumière sur un capteur pour se déplacer //
regarde = 0; le nombre de tentatives pour tourner et trouver de la lumière

void setup()

{ pinMode(leftPins[1], OUTPUT);
pinMode(rightPins[1], OUTPUT);
Série.begin(9600); }

Les fonctions loop et lookAround sont identiques au sketch précédent. setSpeed a moins de code car le
matériel sur le blindage permet à une seule broche de contrôler la direction du moteurÿ: void setSpeed(int
pins[], int speed ) { if(speed < 0) { digitalWrite(pins[1],HIGH); vitesse = -vitesseÿ; } else
{ digitalWrite(pins[1],LOW); } analogWrite(broches[0], vitesse); }

Les affectations des broches pour le blindage Freeduino sont les


suivantesÿ: int leftPins[] = {10,13}ÿ; // PWM, Direction int rightPins[]
= {9,12}ÿ; // PWM, direction

Si vous avez un bouclier différent, vous devrez consulter la fiche technique et vous assurer que les
valeurs du croquis correspondent aux broches utilisées pour le PWM et la direction.

286 | Chapitre 8 : Sortie physique


Machine Translated by Google

Voir également

La fiche technique de la carte Pololu : http:// www.pololu.com/ file/ 0J86/ TB6612FNG.pdf La page produit

du shield Freeduino : http:// www.nkcelectronics.com/ freeduino-arduino-motor-control -shield-kit.html

La page produit du shield Ardumoto : http:// www.sparkfun.com/ commerce/ prod uct_info.php?


products_id=9213

8.12 Pilotage d'un moteur pas à pas bipolaire

Problème

Vous avez un moteur pas à pas bipolaire (quatre fils) et vous souhaitez le faire passer sous contrôle de
programme à l'aide d'un H-Bridge.

Solution

Cette esquisse fait avancer le moteur en réponse aux commandes série. Une valeur numérique suivie
d'un + avance dans une directionÿ; a - étapes dans l'autre. Par exemple, 24+ fait passer un moteur à 24
pas d'un tour complet dans un sens, et 12- pas d'un demi-tour dans l'autre sens. La figure 8-14 montre
les connexions à un moteur pas à pas bipolaire à quatre fils utilisant le pont en H L293ÿ:

/*
* Croquis pas à pas_bipolaire
*
*
stepper est contrôlé depuis le port série. une
* '-'
valeur numérique suivie de '+' ou fait avancermoteur
le
*
*
* http://www.arduino.cc/en/Reference/Stepper */

#include <Stepper.h>

// changez ceci en nombre de pas sur votre moteur #define


STEPS 24

// crée une instance de la classe stepper, en spécifiant // le


nombre de pas du moteur et les broches auxquelles il est //
attaché
Pas à pas (ÉTAPES, 2, 3, 4, 5);

int pas = 0ÿ;

void setup()
{ // règle la
vitesse du moteur à 30 RPM

8.12 Commande d'un moteur pas à pas bipolaire | 287


Machine Translated by Google

stepper.setSpeed(30);
Série.begin(9600); }

void loop() { if

(Serial.available()) { char ch =
Serial.read();

si(ch >= '0' && ch <= '9'){ * 10 + // est-ce que ch est un


sinon si(ch == '+'){ch - '0'; pas = pas } nombreÿ? // oui, accumule la valeur

stepper.step(steps); pas
= 0ÿ; } sinon if(ch == '-')
{ stepper.step(steps * -1);
pas = 0ÿ; } } }

Illustration 8-14. Moteur pas à pas bipolaire à quatre fils utilisant le pont en H L293

Discussion
Si votre stepper nécessite un courant supérieur à celui que le L293 peut fournir (600 mA pour le
L293D), vous pouvez utiliser la puce SN754410 qui gère jusqu'à 1 ampère. Pour un courant jusqu'à
2 ampères, vous pouvez utiliser la puce L298. Le L298 peut utiliser le même schéma que celui illustré
dans la solution de cette recette, et il doit être connecté comme indiqué à la Figure 8-15.

288 | Chapitre 8 : Sortie physique


Machine Translated by Google

Illustration 8-15. Stepper unipolaire avec L298

Un moyen simple de connecter un L298 à Arduino consiste à utiliser le shield SparkFun Ardumoto
(DEV-09213). Cela se branche sur une carte Arduino et ne nécessite qu'une connexion externe aux
enroulements du moteurÿ; l'alimentation du moteur provient de la broche Arduino Vin (entrée de
tension externe). In1/2 est contrôlé par la broche 12 et ENA est la broche 10. In3/4 est connecté à la
broche 13 et ENB est sur la broche 11. Apportez les modifications suivantes au code pour utiliser le
schéma précédent avec Ardumoto : Stepper stepper(STEPS , 12,13); int pas = 0ÿ;

En configurationÿ:

pinMode(10,
SORTIE); digitalWrite(10, BAS); //
enable A // règle la vitesse du moteur à
30 tr/min stepper.setSpeed(30);
Série.begin(9600); pinMode(11, SORTIE);
digitalWrite(11, BAS); // active B

Le code de la boucle est le même que le sketch précédent.

8.12 Commande d'un moteur pas à pas bipolaire | 289


Machine Translated by Google

8.13 Commande d'un moteur pas à pas bipolaire (à l'aide de l'EasyDriver


Planche)

Problème
Vous avez un moteur pas à pas bipolaire (quatre fils) et vous voulez le faire passer sous le programme
contrôle à l'aide de la carte EasyDriver.

Solution
Cette solution est similaire à la recette 8.12, mais elle utilise la populaire carte EasyDriver.
La figure 8-16 montre les connexions.

Illustration 8-16. Connexion de la carte EasyDriver

L'esquisse suivante contrôle la direction et le nombre de pas à partir du port série. contrairement à
le code de la recette 8.12, il ne nécessite pas la bibliothèque stepper, car l'EasyDriver
La carte gère le contrôle des bobines du moteur dans le matérielÿ:

/*
*
Esquisse Stepper_Easystepper
*
*
stepper est contrôlé depuis le port série.
* '-'
une valeur numérique suivie de '+' ou fait avancer le moteur

290 | Chapitre 8 : Sortie physique


Machine Translated by Google

*
*/

const int dirPin = 2; const


int stepPin = 3ÿ;

vitesse entière = // vitesse souhaitée en pas par seconde //


100ÿ; int pas = 0ÿ; le nombre de pas à faire

void setup()

{ pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
Série.begin(9600); }

void loop()
{ if
(Serial.available()) { char ch =
Serial.read();

si(ch >= '0' && ch <= '9'){ * 10 + // est-ce que ch est un


else if(ch == '+'){ ch - '0'; pas
pas(pas); = pas
pas = } nombreÿ? // oui, accumule la valeur
0ÿ; } sinon if(ch == '-'){ step(-steps);
pas = 0ÿ; } sinon if(ch == 's'){ vitesse
= étapesÿ; Serial.print("Régler la
vitesse sur "); Serial.println(steps);
pas = 0ÿ; } } }

void step(int steps) { int


stepDelay = 1000 /
speed; //délai en ms pour la vitesse donnée en pas par seconde int stepsLeftÿ;

// détermine la direction selon que steps_to_mode est + ou - if (steps > 0)


{ digitalWrite(dirPin, HIGH); étapesLeft = étapesÿ; } if (steps < 0)
{ digitalWrite(dirPin, LOW);

8.13 Commande d'un moteur pas à pas bipolaire (à l'aide de la carte EasyDriver) | 291
Machine Translated by Google

étapesLeft =
-étapesÿ; } // décrémente
le nombre de pas, en déplaçant un pas à chaque fois while(stepsLeft
> 0) { digitalWrite(stepPin,HIGH); retardMicrosecondes(1);
digitalWrite(stepPin,LOW); retard(stepDelay); // décrémente les pas
à gauche stepsLeft--; } }

Discussion
La carte EasyDriver est alimentée par les broches marquées «ÿM+ÿ» et «ÿGndÿ» (illustrées en haut à
droite de la Figure 8-16). La carte fonctionne avec des tensions comprises entre 8 volts et 30 volts ; vérifiez
les spécifications de votre moteur pas à pas pour la tension de fonctionnement correcte. Si vous utilisez
un stepper 5V, vous devez fournir 5 volts aux broches marquées "Gnd" et "+5V" (ces broches sont en bas
à gauche de la carte EasyDriver) et couper le cavalier sur le circuit imprimé marqué "APWR " (ceci
déconnecte le régulateur embarqué et alimente le moteur et la carte EasyDriver à partir d'une alimentation
externe 5V).

Vous pouvez réduire la consommation de courant lorsque le moteur ne marche pas en connectant la
broche Enable à une sortie numérique de réserve et en réglant cette sortie HIGH pour désactiver la sortie
(une valeur LOW active la sortie).

Les options de pas à pas sont sélectionnées en connectant les broches MS1 et MS2 à +5V (HIGH) ou
Gnd (LOW), comme indiqué dans le Tableau 8-2. Les options par défaut avec la carte connectée comme
illustré à la Figure 8-16 utiliseront une résolution de huitième étape (MS1 et MS2 sont HIGH, Reset est
HIGH et Enable est LOW).

Tableau 8-2. Options de micro-pas

Résolution MS1 MS2

Pas complet MEUGLER MEUGLER

Demi-pas HAUT BAS

Quart de pas BAS HAUT

Huitième étape ÉLEVÉ ÉLEVÉ

Vous pouvez modifier le code pour que la valeur de la vitesse détermine les tours par seconde comme
suit :

// utilise ce qui suit pour la vitesse donnée en


RPM int speed = 100; //RPM vitesse
int stepsPerRevolution
souhaitée en
= 200; // cette ligne définit les étapes pour une révolution

292 | Chapitre 8 : Sortie physique


Machine Translated by Google

Modifiez la fonction d'étape de sorte que la première ligne soit la suivanteÿ:

int stepDelay = 60L * 1000L / stepsPerRevolution / speedÿ; // vitesse en RPM

Tout le reste peut rester le même, mais maintenant la commande de vitesse que vous envoyez sera le RPM
du moteur quand il marche.

8.14 Commande d'un moteur pas à pas unipolaire (ULN2003A)

Problème
Vous avez un moteur pas à pas unipolaire (cinq ou six fils) et vous souhaitez le contrôler à l'aide d'une puce
de pilote Darlington ULN2003A.

Solution
Connectez un moteur pas à pas unipolaire comme illustré à la Figure 8-17. La connexion + V va à une
alimentation électrique adaptée à la tension et au courant nécessaires à votre moteur.

Illustration 8-17. Stepper unipolaire connecté à l'aide du pilote ULN2003

8.14 Commande d'un moteur pas à pas unipolaire (ULN2003A) | 293

Vous aimerez peut-être aussi