ARDUINO : bien débuter
Voici un article que j'aurais dû écrire il y a longtemps. En effet, je constate souvent que la majeure partie des débutants ne connaissent même pas les bases essentielles du développement sur cette plateforme.
Certains se contentent d'acheter une carte et de rechercher sur le WEB un projet qui correspond à leurs attentes, sans apprendre les bases du langage. Ce n'est pas la bonne méthode.
Ce tutoriel n'a pas la prétention d'être exhaustif, mais il met en avant certains points importants, donne des conseils et permettra d'éviter certains pièges. Certains points généralement absents des tutoriels courants sont présentés ici.
Sa lecture est relativement longue, surtout si l'on clique sur les liens proposés. Il ne s'agit pas de tout assimiler d'une seule traite, mais conserver ce document sous le coude comme pense-bête pour y revenir en cas de besoin est une bonne chose.
Les points suivants sont abordés :
- les différentes cartes
- l'alimentation
- les périphériques
- le prototypage
- la réalisation finale
- le logiciel (IDE, drivers)
- le moniteur série
- le code (variables, conditions, boucles, fonctions, macros, structures, pointeurs, etc.)
- les librairies ou bibliothèques
- trucs et astuces (entrées numériques, analogiques, communication série, le temps, réseau, etc.).
1. Les cartes
Il existe différentes cartes, qui correspondent chacune à un besoin. Elles comportent souvent les composants suivants :
- un microcontrôleur
- un oscillateur
- un connecteur USB (ou pas)
- un convertisseur USB / série (ou pas)
- un connecteur d'alimentation (ou pas)
- un régulateur de tension
- des connecteurs d'entrée / sortie
- une LED sur l'alimentation
- une LED réservée à l'utilisateur
Le microcontrôleur exécute les instructions du logiciel (code) écrit par l'utilisateur. Ce logiciel est souvent appelé sketch dans le monde ARDUINO, et il est écrit le plus souvent en C ou C++.
Le microcontrôleur intègre différents types de mémoire :
- mémoire programme (FLASH)
- mémoire de travail volatile (RAM)
- mémoire de stockage permanent de données (EEPROM)
L'oscillateur est une horloge utilisée pour cadencer l'exécution du logiciel.
Le connecteur USB permet l'alimentation de la carte en 5V, la programmation du microcontrôleur, et d'autres usages, grâce au convertisseur USB.
Le connecteur d'alimentation, un JACK 5.5x2.1 généralement, permet d'alimenter la carte sous une tension comprise entre 6.5V et 20V. Il est présent sur certaines cartes (UNO, MEGA, LEONARDO).
Le régulateur de tension abaisse la tension d'alimentation pour l'adapter au microcontrôleur, le plus généralement 5V, ou 3.3V dans certains cas.
Les connecteurs d'entrée / sortie permettent de raccorder différents types de périphériques (capteurs, boutons, LEDs, modules, etc.).
Sur ces connecteurs on trouve également plusieurs broches d'alimentation :
- VIN ou RAW : alimentation 6.5V - 20V (équivalent au JACK de la UNO)
- VCC : alimentation 5V ou 3.3V (entrée ou sortie)
- sortie 3.3V
- GND
Avant de démarrer, il est indispensable de bien comprendre les différents modes d'alimentation de ces cartes (voir plus loin : 1.4. L'alimentation).
1.1. Les cartes ATMEGA328P
Les cartes équipées d'un microcontrôleur ATMEGA328P ont en commun les caractéristiques suivantes :
- alimentation 5V (plus rarement 3.3V)
- oscillateur 16MHz
- 32 KB de mémoire FLASH pour le code
- 2 KB de mémoire RAM pour les données volatiles
- 1 KB de mémoire EEPROM pour les données non volatiles
- 14 entrée / sorties digitales
- 6 entrées analogiques
32 KO de mémoire est une quantité ridiculement faible par rapport à la taille de celle d'un ordinateur du type PC, mais on peut faire énormément de choses tout de même, et cela suffit à la majorité des applications.
1.1.1. La UNO
ARDUINO UNO R3 officielle |
C'est la carte la plus connue, mais il en existe différentes versions. La carte officielle est équipée d'un microcontrôleur ATMEGA328P 28 pattes DIL (Dual In Line).
ARDUINO UNO clone |
La carte UNO dite "clone", que l'on trouve le plus souvent chez les revendeurs chinois, est équipée d'un ATMEGA328P 28 pattes SMD (Surface Mount Device).
Quelle sont les différences ?
Pratiquement aucune si ce n'est le convertisseur USB :
- un microcontrôleur ATMEGA16U2 pour la carte officielle
- un convertisseur CH340 pour la carte clone
Cette carte est assez peu adaptée à une réalisation finalisée, sauf si l'on utilise des modules vendus sous forme de cartes dites "shield", enfichées directement sur les connecteurs de la UNO :
Shield Ethernet W5100 |
Shield communication radio RFM69 |
Shield de pilotage moteur |
Mais sachez toutefois que ces cartes sont difficilement empilables à l'infini, car rien ne dit qu'elles n'utilisent pas les même entrées / sortie de la UNO. Souvent il est plus prudent de se limiter à une seule carte, à moins de bien étudier le schéma.
1.1.2. La NANO
C'est une version miniature de la UNO, équipée d'un ATMEGA328P SMD et d'un connecteur mini-USB. Elle possède 2 entrées analogiques supplémentaires (A6 et A7).Comme pour la UNO, il existe deux versions, officielle et clone avec un convertisseur USB différent :
- un convertisseur FT232RL pour la carte officielle
- un convertisseur CH340 pour la carte clone
1.1.3. La PRO MINI
La PRO MINI est une carte qui ne possède pas de connecteur USB ni de convertisseur USB. Elle est plutôt réservée aux utilisateurs avertis qui désirent développer des systèmes à basse consommation, alimentés sur batterie.Elle existe en deux versions :
- 16MHz 5V
- 8MHz 3.3V
Cet article peut être utile :
Pour la programmer il faudra lui ajouter un convertisseur USB :
Voir ici pour plus de détails :
ARDUINO PRO MINI & basse consommation
1.2. La carte ATMEGA2560
Les cartes équipées d'un microcontrôleur ATMEGA2560 ont en commun les caractéristiques suivantes :
- alimentation 5V
- oscillateur 16MHz
- 256 KB de mémoire FLASH pour le code
- 8 KB de mémoire RAM pour les données volatiles
- 4 KB de mémoire EEPROM pour les données non volatiles
- 54 entrée / sorties digitales
- 16 entrées analogiques
Comme pour la UNO, il existe deux versions, qui se distinguent par leur convertisseur USB :
- un microcontrôleur ATMEGA16U2 pour la carte officielle
- un convertisseur CH340 pour la carte clone
Ces cartes seront nécessaires uniquement dans les cas extrêmes :
- serveur WEB avec stockage sur carte SD et communication par Ethernet
- projets avec écran TFT grand format
- etc.
1.3. Les cartes diverses
Il existe bien entendu d'autres cartes :
- ARDUINO LEONARDO
- ARDUINO MICRO
- ARDUINO DUE
- etc.
Sans oublier les cartes à base d'ESP8266 ou ESP32 qui possèdent un contrôleur WIFI, et éventuellement un écran OLED, ou un contrôleur de charge de batterie :
ESP32 Devkit C |
HELTEC WiFi Kit 32 |
WEMOS D1 LOLIN32 |
Le but de cet article n'est pas de les énumérer toutes, mais de s'initier à la manipulation des plus courantes.
1.4. L'alimentation
Si un montage simple peut être alimenté avec un simple bloc secteur USB ou JACK, d'autres nécessiteront une alimentation plus conséquente, ou une batterie.
J'ai déjà écrit quelques articles sur ce sujet. Le premier est très important :
ARDUINO : l'alimentation (VCC, VIN, etc.)
Alimentation par batterie + panneaux solaires
Alimenter un ARDUINO sur Pile ou Batterie
Consommation d'une carte ARDUINO, ESP8266 ou ESP32
L'alimentation est un sujet sérieux à ne pas sous estimer.
1.5. Les périphériques
En général, lorsque l'on réalise un projet, on a besoin de dispositifs divers :
- boutons
- potentiomètre
- capteurs
- LEDs
- afficheurs
- etc.
Si un bouton, un potentiomètre ou une LED peuvent se passer de librairie pour être utilisés, la majorité des capteurs ou afficheurs, plus complexes, ne pourront s'en passer.
Un conseil : avant d'acheter quoi que ce soit, ne foncez pas tête baissée et vérifiez qu'il existe une librairie adaptée, spécialement s'il s'agit d'un afficheur TFT (dans ce cas vérifiez également que le vendeur indique bien de quel contrôleur l'écran est équipé).
1.5.1. Les kits
Faut-il acheter un kit comprenant un ARDUINO et différents composants ?
Je dirais non, car souvent les capteurs livrés ne sont pas des modèles très performants, et la plupart ne serviront à rien et vous resteront sur les bras.
Par contre il est intéressant d'acheter un kit de résistances 1/4W :
Jeu de résistances film métallique 1% |
On
peut éventuellement compléter par quelques diodes (1N4148, 1N4004),
condensateurs (10nF, 100nF, 10µF), transistors (BC547, 2N2222, 2N2907, 2N3904,
2N3906).
1.5.2. Les bus
Un ARDUINO possède deux bus, I2C et SPI.
Le bus I2C permet de connecter plusieurs composants ou modules sur deux fils SDA (data) et SCL (clock). L'adressage est logiciel et chaque composant possède son adresse propre. Certains composants permettent le choix entre plusieurs adresses différentes, grâce à une ou plusieurs broches spéciales, afin d'éviter que deux composants aient la même adresse.
Le bus SPI permet de connecter plusieurs composants ou modules sur quatre fils : MISO (Master Input Slave Output), MOSI (Master Output Slave Input), CLK (clock) et CS (chip select). L'adressage est physique, il faudra prévoir une broche CS par composant. Il est souvent utilisé sur les composants de stockage ou d'échange de données (SD, mémoire FLASH, carte Ethernet), et certains petits écrans TFT.
Ces bus permettent d'économiser des broches d'entrée / sortie. Par exemple il est possible de contrôler un clavier matriciel 16 touches avec un MCP23008 (expander 8 bits I2C), avec simplement 2 entrées / sorties au lieu de 8.
Un afficheur LCD monopolise 6 entrées / sorties de l'ARDUINO. Avec un contrôleur I2C PCF8574, 2 suffiront.
Les organes de commande sont très nombreux :
- boutons
- interrupteurs
- commutateurs rotatifs
- encodeurs rotatifs
- claviers matriciels
- télécommandes
- etc.
1.5.2.1. Encodeur rotatif
Peu de personnes pensent à utiliser un encodeur rotatif :
Voir cet exemple :
1.5.3.2. Télécommande infra-rouge
Penser également à la télécommande infra-rouge. Le module TSOP4838 est un récepteur capable de comprendre les code de la majeure partie des télécommandes du marché (NEC, SONY, SAMSUNG, etc.) :
Il nécessite une librairie nommée IRREMOTE, installable depuis l'IDE.
Voir cet exemple :
Télécommande de Relais par Infra-Rouge
1.5.3.3. Clavier matriciel
Un clavier matriciel peut être utilisé pour concevoir des IHM (Interface Homme Machine) simples. En général il est nécessaire de lui adjoindre un écran pour le côté visuel (menu, affichage de données).
Même si des librairies existent, elles ne sont pas vraiment à la portée d'un débutant :
https://github.com/neu-rah/ArduinoMenu
J'ai à ce jour implémenté deux projets à base de clavier matriciel :
ARDUINO : Micro-irrigation Automatisée
Minuterie pour Insoleuse de PCB
1.5.3.4. Ecran TFT tactile
C'est en général le premier réflexe, lorsque l'on a une IHM élaborée à concevoir. Ici aussi, il s'agit d'une tâche complexe, difficilement accessible aux débutants.
Il existe des écrans intelligents : le Nextion est le plus connu. Un logiciel permet de dessiner l'interface graphique : https://nextion.tech/nextion-editor/
1.5.3.5. Interface WEB
Depuis pas mal d'années les interfaces WEB se sont invitées à la table des logiciels embarqués. Il s'agit à mon sens de la solution idéale pour concevoir une IHM complexe.
En effet, il est souvent plus intuitif d'utiliser un dispositif comme un navigateur ou un smartphone pour communiquer avec un système embarqué. Cela nécessite bien sûr du matériel adéquat (ESP8266, ESP32), et des connaissances (HTML, JAVASCRIPT) mais l'investissement est rentable.
Voici quelques exemples concrets :
Serveur ESP32 : implémentation
ARDUINO + Ethernet ou ESP32 : comparons
Un logger analogique et digital (version WEB)
1.5.4. Les capteurs
Il existe une foule de capteurs :
- température
- humidité
- pression
- lumière
- poids
- présence
- distance
- anémomètre
- gyroscope
- courant
- etc.
J'ai déjà écrit des article sur certains :
Les capteurs de température, humidité, pression & luminosité
Capteur de présence : le HC-SR501 sous 3.3V, 3.7V et 5V
Un thermomètre MYSENSORS sur batterie
Un thermomètre / hygromètre MYSENSORS sur batterie
Un thermomètre MYSENSORS pour freezer
Banc de Mesure de Consommation
Il est important de consulter la datasheet du composant ou du module capteur, ne serait-ce que pour vérifier qu'il correspond au besoin. Attention, certains capteurs s'alimentent en 5V, d'autres en 3.3V.
Un capteur de température ou de luminosité I2C peut être alimenté par la sortie 3.3V d'un ARDUINO, et le dialogue I2C peut se faire en 5V. Cela ne pose pas de problème.
1.5.5. La commande de puissance
La commande de charges de puissance ne se fait pas directement à l'aide d'une sortie de l'ARDUINO, comme on le voit parfois. Une sortie d'ARDUINO est limitée à 20mA, tout juste assez pour allumer une LED courante.
En fonction du type de charge (lampe, moteur, pompe, etc.) de la tension nécessaire (5V, 12V, 24V, 230V, etc.) et de la puissance à fournir, l'organe de commande sera différent.
Il faut tenir compte aussi de l'utilisation prévue. On n'utilisera pas un relais lorsque la fréquence de commutation est élevée.
Anecdote : j'ai déjà vu quelques amateurs allumer avec des relais 15 rubans de LEDS sur un escalier. Soyons sérieux, imaginez le bruit infernal que ce montage va produire ! Des transistors MOSFET feront ce travail en silence, et on pourra de plus régler la luminosité en utilisant une technique appelée PWM.
1.5.5.1. Relais
Module relais |
Un relais peut être utilisé pour commander tous types de charges, en courant continu comme alternatif. Souvent ces modules sont limités à 250V et 10A, mais il n'est pas interdit de commander un contacteur plus puissant avec un relais :
Contacteur Legrand 25A |
Un contacteur est préférable lorsqu'il s'agit d'alimenter un gros moteur ou une pompe 230V. Commander ce type de charge avec un petit module relais 10A est assez déconseillé. Les contacts n'ont pas une résistance suffisante et pourraient rester collés, ou plutôt soudés, à cause des arcs électriques importants générés par la charge inductive.
Il existe des modules relais comportant jusqu'à 16 relais, mais il faut savoir que chaque relais, lorsque la bobine est alimentée, consomme environ 75mA. Si plusieurs relais peuvent être commandés simultanément, cette consommation sera doublée, triplée, etc. Prévoir une alimentation conséquente.
Également, alimenter un module à 1 ou 2 relais à l'aide de la broche 5V d'un ARDUINO alimenté par sa broche VIN est acceptable (tout va dépendre de la tension sur VIN). Au delà de 2 relais, le courant disponible est trop faible. Prévoir une alimentation 5V et alimenter l'ARDUINO (broche 5V) et les relais en parallèle est pratiquement une obligation.
Lorsque l'on manipule du 230V on doit prendre des précautions, en particulier ne pas toucher les parties haute tension (contacts, bornier de sortie), ni le dessous du module.
Il n'est pas obligatoire d'utiliser un module comme ci-dessus, bien qu'il présente pas mal d'avantages. On peut parfaitement utiliser un relais nu :
Relais nu |
Attention : ce genre de relais ne se commande pas avec une sortie ARDUINO, car son courant de bobine est d'environ 70mA. Il faut lui ajouter une électronique de commande.
Plus de détails ici :
Piloter un relais. Transistor unipolaire ou bipolaire ?
Piloter des Relais ou des MOSFEts à l'aide d'un Module MCP23008 ou MCP23017
1.5.5.2. Dimmer
Dimmer |
Ces modules permettent d'alimenter une charge 230V (ampoule, moteur, etc.) avec une tension variable.
Ces modules se commandent en PWM et sont équipés d'optocoupleurs, ce qui isole l'ARDUINO du 230V.
Comme avec un relais, lorsque l'on manipule du 230V on doit prendre des précautions, en
particulier ne pas toucher les parties haute tension (triac, optocoupleurs, bornier
de sortie), ni le dessous du module.
Attention : toutes les ampoules 230V ne sont pas utilisables avec un dimmer, spécialement celles équipées de LEDs. Également, seuls les moteurs universels à balais peuvent être commandés de cette manière.
1.5.5.3. MOSFET
MOSFET AOD4184 |
Un transistor MOSFET ne pourra commuter que des charges en courant continu et basse tension (5V, 12V, 24V, etc.). Ce type de dispositif est intéressant par exemple pour commander des LEDs de puissance, ou un moteur à courant continu.
Attention, la plupart des modules du commerce (IRF520 par exemple) acceptent difficilement une commande en 5V. Il faut faire attention à ce que l'on appelle la tension VGSth, et choisir des modèles "Logic Level". Éviter les séries IRFxxx.
Voir ici pour plus d'explications :
Lorsque l'on a besoin de plusieurs canaux, il n'est pas inintéressant de fabriquer son propre module :
Piloter des Relais ou des MOSFEts à l'aide d'un Module MCP23008 ou MCP23017
1.5.5.4. Commande de moteur
Lorsque l'on a besoin d'un moteur il est impensable d'acheter un modèle dont le vendeur ne précise pas certaines caractéristiques :
- tension de fonctionnement
- courant maximal consommé
- vitesse en tours / minute
- couple
Je veux bien accorder que le courant consommé dépendra en grande partie de la charge mécanique, mais ce n'est pas une raison pour faire l'impasse sur l'essentiel.
Eviter d'acheter un produit pour lequel le vendeur n'a aucun renseignement à fournir à part "moteur 6V" ou "moteur 12V", et que la datasheet est introuvable.
Module L293D |
On utilisera un driver de moteur de ce type pour piloter un moteur à courant continu, lorsque l'on désire le faire tourner dans les deux sens, et faire varier sa vitesse. Le L293D peut débiter 600mA. Il n'est pas le seul du marché :
- L9110S : 1 moteur, 800mA
- L298 : 2 moteurs, 4A
- TB6612FNG : 2 moteurs, 1A
- VNH7070BASTR : 1 moteur, 15A
Il existe des moteurs continus avec réducteur mécanique de vitesse (engrenages), appelés moto-réducteurs. La réduction de vitesse permet également d'augmenter le couple.
Les tutoriels sur le pilotage de moteurs sont nombreux :
https://arduino103.blogspot.com/2011/06/controle-moteur-dc-via-l293d-h-bridge.html
http://gilles.thebault.free.fr/spip.php?article41
1.5.5.5. Servomoteur
Servomoteur |
Un servomoteur permet d'effectuer une rotation de 0° à 180°, avec positionnement angulaire. Il ne nécessite aucune électronique de puissance, et se pilote simplement avec une sortie digitale PWM.
Il faut bien connaître les caractéristiques de la charge mécanique afin de faire un choix judicieux (le couple en particulier).
Attention, certains modèles vendus sous la dénomination servomoteur 360° ne permettent pas le positionnement angulaire. Ce sont simplement des moteurs continus avec réducteur de vitesse, dont la vitesse est réglable.
Le pilotage d'un servomoteur est on ne peut plus simple. La librairie Servo est faite pour cela. Et il existe de nombreux tutoriels :
https://www.carnetdumaker.net/articles/controler-un-servomoteur-avec-une-carte-arduino-genuino/
1.5.5.6. Moteur pas à pas
Module A4988 |
Ce type de module permet de piloter un moteur pas à pas. Je vous conseille de fortement vous documenter avant d'attaquer pareil sujet. Il existe différents types de moteurs (unipolaire, bipolaire) et il ne s'agit pas de se lancer tête baissée, et d'acheter n'importe quel moteur en croyant qu'on pourra facilement le piloter avec le module driver X ou Y.
Il existe beaucoup de tutoriels. Ne pas hésiter à y consacrer du temps :
http://dansetrad.fr/Orgue_de_barbarie/Elec/Action/PasAPas/
1.5.6. L'affichage
1.5.6.1. La LED
La LED est une diode. Elle comporte une borne + (anode) et une borne - (cathode). L'anode est souvent la broche la plus longue.
Trop de débutants relient
une LED directement à une sortie de l'ARDUINO. Une résistance de
limitation de courant est indispensable, car une sortie ARDUINO est
limitée théoriquement à 20mA (40mA grand maxi, ce qui pourrait être fatal pour
certaines LEDs) :
En utilisant le montage de gauche, la LED s'allumera en envoyant un niveau haut sur la sortie D4. En utilisant le montage de droite, la LED s'allumera en envoyant un niveau bas sur la sortie D5
Suivant la luminosité désirée la résistance pourra avoir une valeur de 330Ω, 1KΩ, ou même 10KΩ si la LED est performante.
Ne pas oublier que la carte ARDUINO possède déjà une LED, sur la sortie D13 (ou LED_BUILTIN).
Quand on a besoin de plusieurs LEDs accolées, il existe des blocs (bargraph) :
1.5.6.2. La LED de puissance
Il existe un grand nombre de LEDs de puissance. Elles sont disponibles sous forme de composants unitaires ou de rubans, en 5V ou 12V :
Ruban de LEDs 12V 5630 |
Attention : ces LEDs ne se pilotent pas avec une sortie de l'ARDUINO. Comme pour un relais, il faut leur associer une électronique de puissance, un MOSFET par exemple, comme sur ce projet :
Un éclairage d'escalier à LEDs
1.5.6.3. La LED intelligente
Une LED de puissance intelligente peut être commandée par une sortie de l'ARDUINO, la WS2812 :
Module WS2812 |
Module 8 LEDs WS2812 |
Ruban WS2812 |
Matrice WS2812 |
Ces LEDs RGB (couleur) possèdent 3 fils (5V, GND, DIN), on peut les chaîner, et elles sont disponibles sous forme de modules à une LED, de blocs de 8 LEDs, de rubans, de matrices ou d'anneaux. La commande réclame peu de courant. L'intensité et la couleur sont réglables.
Elles sont adressables, c'est à dire que l'on pourra allumer une LED parmi N sur un ruban.
Attention : le courant consommé par chaque LED peut aller jusqu'à 60mA (luminosité maximale). Si le nombre de LEDs est important une alimentation conséquente est à prévoir.
LEDs APA102 |
Les LEDs APA102 ou SK9822 sont encore plus intelligentes que les WS2812. D'une part elles fonctionnent sur bus SPI, plus rapide, d'autre part elles possèdent un registre de luminosité.
En d'autres termes à partir du moment où la demande d'allumage des LEDs a été envoyée (couleurs, luminosité), le microcontrôleur n'a pas besoin de renouveler cette demande en permanence comme avec une WS2812. Le circuit de contrôle de chaque LED mémorise les données de couleur et luminosité et gère la LED de manière autonome. L'ARDUINO pourra sans problème être occupé à d'autres tâches.
Si le nombre de LEDs est important les APA102 ou SK9822 sont préférables.
1.5.6.4. Afficheurs matriciels
Afficheur 4 blocs MAX7219 |
Ces afficheurs sont équipés de 64 LEDs par bloc, adressables une à une.
J'en parle ici :
1.5.6.5. Les écrans
On voit trop de projets équipés d'un écran LCD comme celui-ci :
Ils ne sont pas très simples à utiliser (beaucoup de débutants s'y cassent les dents), ils fonctionnent mal sous 3.3V, et ils sont gros et moches. Je conseille plutôt d'utiliser de petits écrans OLED :Ils sont beaucoup plus simples à utiliser, et permettent l'affichage de logos, de caractères de tailles différentes, et même de caractères accentués (encore faut-il choisir la bonne police).
J'en parle ici :
Afficheur OLED SSD1306 : comparons
Certaines cartes ESP32 sont équipées d'écrans OLED :
HELTEC-WIFI-KIT-32 |
https://riton-duino.blogspot.com/2021/06/esp32-heltec-wifi-kit-32.html
Pour les besoins d'affichage de grande taille, penser aux écrans TFT :
Plus d'informations ici :
LED, LCD, TFT et ARDUINO (et autres VFD, NIXIE)
Cet article parle aussi d'afficheurs à 7 segments à LED ou LCD, et de bien d'autres sujets.
1.5.7. Le son
Lorsque l'on désire produire des sons avec un ARDUINO, on a le choix entre différentes solutions.
S'il s'agit de produire un signal d'avertissement, un buzzer peut suffire :
S'il s'agit de sons plus élaborés (musique ou messages vocaux), un petit lecteur MP3 est la solution la plus abordable :
Cet article peut aider :
Faire du bruit avec un ARDUINO
1.5.8. Les connecteurs
Les interconnexions entre cartes peuvent être réalisées à l'aide de fils soudés, mais également à l'aide de connecteurs :
Je vous renvoie à cet article :
Les connecteurs pour cartes électroniques
1.6. Le prototypage
Le développement d'un projet passe par une phase importante : le prototype.
Cet article donne beaucoup d'informations utiles pour réaliser un prototype réussi :
ARDUINO : prototypage amélioré sur breadboard
L'essentiel est de s'équiper d'une breadboard et de fils DUPONT pour les raccordements :
Une carte NANO ou PRO MINI peut être directement enfichée sur la breadboard, ainsi que pas mal de modules équipés de broches mâles. Une UNO ou MEGA sera posée à côté de la breadboard.
1.7. La réalisation finale
La réalisation finale d'un projet peut difficilement être faite sur une breadboard avec des fils DUPONT. La fiabilité serait douteuse. Dans la majorité des cas il sera nécessaire de passer par une étape de finalisation.
On peut utiliser une plaquette à pastilles et souder dessus les composants et modules :
On imagine mal une carte UNO ou MEGA sur une plaquette à pastilles. On privilégiera pour cet usage la NANO ou la PRO MINI, ou d'autres cartes équipées de broches mâles.
Plus de détails ici :
Développement électronique ARDUINO (voir le paragraphe 8.7. Le montage sur plaquette à pastilles)
Ce projet a été entièrement réalisé sur plaquette à pastilles :
Alimentation 3.7V (dessus) |
Alimentation 3.7V (dessous) |
Mais cela commence à faire beaucoup pour un débutant.
2. Le logiciel
2.1. L'IDE ARDUINO
L'IDE ARDUINO est le logiciel qui va permettre d'écrire le programme, appelé sketch. Il est installable à partir de cette page :
https://www.arduino.cc/en/software
Je déconseille totalement l'installation à partir d'autres sources, en particulier Microsoft Store !
L'IDE s'installe sur PC, Windows, LINUX et même MAC.
Il existe deux versions Windows :
- une version installable par un logiciel d'installation .EXE, qui installera l'IDE dans le répertoire "Program Files".
- une version sous forme de fichier .ZIP, que l'on décompressera dans son espace personnel. Il sera possible par ce moyen d'installer plusieurs versions.
2.2. Les drivers USB
Pour programmer la carte, nous allons avoir besoin de communiquer avec elle à travers un cordon USB.
Tout d'abord, les utilisateurs de LINUX seront exemptés de cette tâche, car les drivers nécessaires font déjà partie de l'OS.
Pour les autres, si vous avez opté pour l'installation à partir d'un fichier ZIP, il va falloir installer un driver adapté. Pour cela il est impératif de savoir de quel type de convertisseur USB est équipée la carte ARDUINO :
- ATMEGA16U2
- FT232RL
- CH340
- etc.
Concernant les deux premiers, on peut se référer à cette documentation :
https://www.locoduino.org/spip.php?article15
Si la carte est équipée d'un convertisseur CH340, ce qui est le cas de la majorité des modèles clone chinois, le driver se trouve ici :
http://www.wch.cn/download/ch341ser_exe.html
Si l'on possède un convertisseur USB séparé pour une utilisation avec une PRO MINI, on peut lire cet article :
Les convertisseurs USB / série (voir le paragraphe : 2. Les drivers)
A partir du moment où les drivers sont installés, dans le menu Outils / Port de l'IDE, on verra apparaître un port série pour chaque carte connectée à l'ordinateur.
Si aucun port n'est visible au branchement de la carte, ce n'est pas la peine d'aller plus loin. Trop d'amateurs réinstallent l'IDE, ce qui n'apporte rien.
Cet article peut être utile :
ARDUINO : problèmes de téléversement
Classiquement la première manipulation que l'on effectue est lancer l'IDE et de charger l'exemple Blink à l'aide du menu "Fichiers / Exemples / 01.Basics / Blink".
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Ensuite il faut cliquer sur l'icône Téléverser ou taper CTRL-U pour charger l'exemple dans la carte.
Les cartes sont en général vendues avec cet exemple pré-chargé. Si vous voulez être certains que toute la chaîne fonctionne, remplacez les délais dans le code :
delay(1000);
Par :
delay(200);
Si la LED clignote plus rapidement, c'est que tout fonctionne.
2.3. Le terminal ou moniteur série
Le moniteur série est un outil indispensable au développement d'un logiciel. C'est pour cette raison que je le présente en premier.
un article sur le sujet :
2.4. Le code
Tout d'abord, tordons le cou à une idée très répandue. Il n'y a pas de langage ARDUINO à proprement parler. Le code s'écrit en C ou en C++, rien de plus. La syntaxe est rigoureusement identique.
La seule différence entre un programme C classique et un programme C ARDUINO est la suivante :
void loop() {
En programmation C ARDUINO, la fonction setup() est exécutée au démarrage, une seule fois, et permet d'initialiser des entrées / sorties, des librairies. La fonction loop() est exécutée en boucle, répétitivement, à l'infini. Il n'y a donc jamais d'arrêt.
En réalité, la fonction main() existe, mais elle se trouve dans la librairie ARDUINO, ce n'est pas à vous de l'écrire :
int main(void)
{
init();
initVariant();
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
Ecrire du code C ou C++ ne se fait pas sans connaissances. La formation est une étape indispensable, sans laquelle on ne pourra en aucun cas développer un projet, ou modifier un projet existant pour l'adapter à ses besoins.
On voit beaucoup trop de demandes sur les forums comme celle-ci :J'ai trouvé un code sur le WEB, mais il ne fait pas vraiment ce que je veux, pourriez-vous m'aider à le modifier pour qu'il fasse ceci ou cela ?
Non, il y peu de chances que les intervenants d'un forum fassent le travail à votre place.
Il existe de nombreux tutoriels ARDUINO. En général, il faut être prêt a y consacrer une semaine, en écrivant des exemples.
D'autres tutoriels sont plus généralistes, et présentent seulement le langage C :
https://openclassrooms.com/fr/courses/19980-apprenez-a-programmer-en-c
Sachez toutefois que le code standard C utilise des fonctions pas forcément présentes sur ARDUINO. Un tutoriel spécifique ARDUINO est préférable, surtout si l'on est débutant.
Nous allons tout de même parler de quelques détails.
2.4.1. Les commentaires
2.4.2. Les accolades et parenthèses
Source de nombreux problèmes chez les débutants, elles vont toujours par paires.
void setup() // 2 parenthères
{ // accolade ouvrante
Serial.begin(115200); // 2 parenthères
Serial.println("Serial test"); // 2 parenthèses
} // accolade fermante
void loop() // deux parenthèses
{ // accolade ouvrante
if (Serial.available()) { // 4 parenthèses + accolade ouvrante
char c = Serial.read(); // 2 parenthèses
Serial.print("char reçu: "); // 2 parenthèses
Serial.println(c); // 2 parenthèses
} // accolade fermante
} // accolade fermante
Si par exemple la dernière parenthèse est oubliée le compilateur affichera :
expected '}' at end of input
Dans l'IDE, la combinaison CTRL-T permet d'indenter le code, c'est à dire d'ajouter des espaces en début de ligne, en fonction du niveau d'imbrication des instructions.
A utiliser sans modération !
2.4.3. Le point-virgule
Le point-virgule termine une ligne de code.
Erreur souvent commise :
if (condition == true);
var = 1;
Ou :
if (condition == true); {
var = 1;
}
La première ligne est traduite par : si la condition est vraie, ne rien faire, à cause du point-virgule. Donc la seconde ligne sera toujours exécutée.
La syntaxe correcte est :
if (condition == true)
var = 1;
Ou :
if (condition == true) {
var = 1;
}
Comme on le voit ici, une condition n'est pas forcément suivie d'une instruction ou d'une suite d'instructions entre accolades. S'il n'y a qu'une instruction à exécuter, les accolades peuvent être omises. Par contre je recommande vivement d'utiliser systématiquement les accolades, pour la bonne raison que si l'on ajoute une instruction à exécuter après la condition, on peut oublier d'ajouter les accolades. Si elles sont déjà présentes, cela facilite les choses.
2.4.4. Les variables
En C les variables sont typées, contrairement à d'autres langages. Elles peuvent être numériques (int, long, float) ou textuelles (char, char[]).
Piège courant : une variable flottante utilise le point comme séparateur entre partie entière et décimales, et non pas la virgule :
float f = 12.34; // correct
float f = 12,34; // incorrect
2.4.4.1. Portée
En C une variable peut avoir une portée locale ou globale.
int i; // variable globale
int func(void)
{
for (i = 0 ; i < 10 ; i++) {
print("i=");
println(i);
}
return i;
}
Dans ce premier cas, i est une variable globale. Elle est visible de partout dans le sketch. Elle occupe en permanence 2 octets en mémoire RAM.
int func(void)
{
int i; // variable locale
for (i = 0 ; i < 10 ; i++) {
print("i=");
println(i);
}
return i;
}
Dans ce deuxième cas, i est une variable locale. Elle n'est visible que dans la fonction func(). Elle occupe 2 octets en mémoire RAM, mais sera détruite en sortie de fonction, donc la mémoire qu'elle occupe est temporaire, ce qui est plus économique.
Il est possible de déclarer une variable et de lui affecter une valeur :
int i = 100;
Par contre, pour une variable global ou statique il est inutile de l'initialiser à ZÉRO :
int i = 0; // inutile
int i; // OK
Au démarrage, toutes les variables globales et statiques sont initialisées à ZERO, sauf bien sûr celles auxquelles on a affecté une valeur.
2.4.4.2. Variables en FLASH
Un autre moyen de ne pas gaspiller la mémoire RAM est de placer des variables, surtout des messages, en mémoire FLASH :
println("ceci est un message en RAM");
println(F("ceci est un message en FLASH"));
https://www.arduino.cc/reference/en/language/variables/utilities/progmem/
2.4.4.3. Constantes
Une variable peut être constante, c'est à dire que son contenu ne pourra pas être modifié par le code :
const int var = 22;
La valeur de cette variable sera conservée indéfiniment. Si l'on essaie de la modifier par programmation, le compilateur affichera un message d'erreur.
2.4.5. Les macros et directives
Il existe une catégorie particulière de constantes, en général peu décrites dans les tutoriels :
#define YELLOW 0xFFE0
Ceci n'est pas une variable. Elle n'occupe aucune place en mémoire. Simplement, le compilateur (ou plutôt son préprocesseur) remplacera YELLOW par 0xFFE0 à chaque fois qu'il rencontrera ce mot.
On peut faire une foule de choses avec des macros :
#define log Serial.print
#define logln Serial.println
A chaque fois que l'on appellera la fonction log() ou logln() le préprocesseur remplacera par Serial.print() ou Serial.println().
Comme précédemment, si DEBUG est définie, à chaque fois que l'on appellera la fonction log() ou logln() le préprocesseur remplacera par Serial.print() ou Serial.println().
Si l'on met la ligne en commentaires :
A chaque fois que l'on appellera la fonction log() ou logln() le préprocesseur remplacera par rien du tout, donc aucune fonction ne sera appelée.
Il est possible également d'écrire du code tenant compte de la plateforme :
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
Les constantes ESP32 et ESP8266 sont définies dans les librairies de l'IDE. On peut donc écrire un code comportant des parties spécifiques à chaque plateforme. Ensuite il suffira de choisir la bonne carte dans le menu "Outils / Type de Carte" pour que la compilation se fasse avec le code correspondant.
D'autres constantes existent :
__AVR__ : définie pour un microcontrôleur AVR
__AVR_ATmega2560__ : définie pour un microcontrôleur ATMEGA2560
__AVR_ATmega32U4__ : définie pour un microcontrôleur ATMEGA32U4
Il existe des constantes prédéfinies à usage général :
__FILE__: représente le nom du fichier source.
__DATE__: représente la date de la compilation.
__TIME__: représente l'heure de la compilation.
Je conseille la lecture de cet article :
https://openclassrooms.com/fr/courses/19980-apprenez-a-programmer-en-c/15954-le-preprocesseur
Le langage C fait la distinction entre char (caractère) et chaîne de caractères.
'a' et "a" ne sont pas équivalents. 'a' est un caractère, tandis que "a" est une chaîne de caractères comportant un seul char.
char s1[] = "abcdef";
Une chaîne de caractères C est terminée par un caractère NUL, donc la chaîne ci-dessus occupe 7 octets et non 6. Ce caractère NUL est utilisé par pas mal de
fonctions comme terminateur (caractère de fin de chaîne).
Il existe différents moyens de déclarer une chaîne de caractères (tableau de char) :
char s1[] = "abcdef";
char *s2 = "abcdef";
char s1[] = "abcdef";
char *s2 = "abcdef";
s1 = "ghijk"; // invalide
s2 = "ghijk"; // correct
La variable s2 est un pointeur, qui contient l'adresse de la chaîne "abcdef".
La première expression est invalide. On ne peut pas simplement changer la valeur d'une chaîne de caractères comme cela. La deuxième est valide, car elle ne met en jeu qu'une affectation de pointeur.
La première expression doit s'écrire comme ceci :
char s1[] = "abcdef";
strcpy(s1, "ghijk");
Quand on a affaire à une chaîne de caractères, on utilise la fonction strcpy() pour faire une recopie. Attention, la longueur de la nouvelle chaîne ne doit pas être supérieure à l'ancienne, sinon on risque des problèmes de débordement.
On peut pré-dimensionner une chaîne, afin d'éviter cela :
char s1[20] = "abcdef"; // la chaîne de 6 caractères est contenue dans un espace de 20 octets
Il existe également une fonction qui permet de copier une chaîne en limitant la longueur : strncpy().
char s1[] = "abcdef";
char *s2 = "abcdef";
s1[0] = 'g';
s2[0] = 'g'
Enfin, dans les deux cas, l'appel d'une fonction acceptant un pointeur de char en paramètre se fera de la même façon :
char s1[] = "abcdef";
char *s2 = "abcdef";
Serial.println(s1);
Serial.println(s2);
Ces deux appels produiront le même résultat.
Comment compare t-on deux chaînes de caractères ?
On voit beaucoup de comparaisons de ce type :
char s[] = "chaîne";
if (s == "blabla") { // NON OK
// instructions
}
char s[] = "chaîne";
if (strcmp(s, "blabla") == 0) {
// instructions
}
strcmp() retourne 0 si les chaînes sont identiques. Il existe également une autre fonction, strncmp(), qui compare uniquement les n premiers caractères.
String s = "chaîne";
if (s == "blabla") { // OK
// instructions
}
Dans ce cas, s est une String C++. L'opérateur == ou != sont redéfinis par la classe String pour faire une comparaison de contenu.
Attention, la classe String est plutôt déconseillée sur ARDUINO (voir plus bas).
Toutes ces notions sont importantes. Il vaut mieux s'exercer.
2.4.7. Les tableaux
Nous avons vu qu'une C string est un tableau de variables de type char. Un tableau peut stocker d'autres types de variables.
Il est important de connaître les tableaux. Les débutants ignorent souvent jusqu'à leur existence.
Erreur souvent commise : les tableaux en C / C++ démarrent à l'index ZÉRO, et non pas UN comme dans certains langages :
A noter :
NSAMPLE définit le nombre d'échantillons. Cette constante est utilisée partout où cela est nécessaire :
- dimensionnement du tableau
- vérification que l'on a atteint la fin du tableau
- parcours du tableau pour faire la moyenne
Cette méthode est bien plus rationnelle que l'utilisation directe d'une valeur (20). Si l'on veut changer le nombre d'échantillons, il suffit de changer la valeur de NSAMPLES.
L'utilisation de millis() sera détaillée au paragraphe 2.6.4.2 millis().
2.4.8. String
On voit beaucoup trop de tutoriels montrant des exemples utilisant des objets C++ String. Je déconseille totalement, sauf sur ESP8266 ou ESP32.
Plus de détails ici :
ARDUINO : la fragmentation mémoire
J'explique également dans ce document comment utiliser les tableaux de char (ou C strings).
2.4.9. OU et ET logique
Si l'on doit tester plusieurs conditions on utilise && ou ||, et non pas & et | comme on le voit parfois.
if (condition1 == true && condition2 == true) { // ET logique
// instructions
}
if (condition1 == true || condition2 == true) { // OU logique
// instructions
}
Les premières choses à apprendre en C sont les déclarations de variables et les opérateurs. C'est indispensable.
2.4.10. condition ou boucle
On entend trop de débutants parler de boucle quand le mot condition serait plus approprié.
Les conditions : if, else, else if, switch
Les boucles : while, do while, for
Encore une fois, formez-vous, cela évitera les confusions et vous serez plus à même de vous faire comprendre sur les forums.
2.4.11. switch()
L'instruction switch() est un bon moyen d'éviter une suite de conditions if + else.
if (valeur == 1) {
// instructions
}
else if (valeur == 2) {
// instructions
}
else if (valeur == 3) {
// instructions
}
else {
// instructions
}
Ces lignes peuvent être remplacées par :
switch (valeur) {
case 1:
// instructions
break;
case 2:
// instructions
break;
case 3:
// instructions
break;
default:
// instructions
break;
}
Cette écriture est autrement plus claire et élégante ! Mais elle ne fonctionne qu'avec une valeur entière.
Lorsque l'on cherche à évaluer une chaîne de caractères, il faut précéder comme suit :
char s[] = "chaîne";
if (strcmp(s, "blabla") == 0) {
// instructions
}
else if (strcmp(s, "coucou") == 0) {
// instructions
}
else if (strcmp(s, "bonjour") == 0) {
// instructions
}
else {
// instructions
}
2.4.12. Les fonctions
Beaucoup de débutants appellent une fonction une "void". Appelons un chat un
chat, et utilisons la bonne terminologie. Une fonction est une
fonction, elle peut être void (ne pas retourner de valeur) ou non (retourner une valeur) :
void func1(void)
{
// ne retourne pas de valeur
}
int func2(void)
{
// retourne une valeur
return 0;
}
Une fonction void s'appelle comme ceci :
func1();
Une fonction retournant une valeur s'appelle comme ceci :
Bien entendu la variable recevant la valeur retournée doit être du même type que la valeur retournée par la fonction.
Un piège commun :
char *func(void)
{
char val[] = "abcdef";
return val;
}
La variable locale val est détruite en sortie de fonction. Le code appelant risque de récupérer une valeur totalement erratique, et le programme peut planter.
On doit utiliser une variable dite statique dans ce cas.
char *func(void)
{
static char val[] = "abcdef";
return val;
}
2.4.13. Les structures
On peut regrouper des variables de différents types dans une structure. Ici par exemple nous regroupons les caractéristiques de différentes personnes dans un tableau de structures :
Il est possible, comme pour toute variable, de déclarer une structure tout en lui affectant des valeurs :
Nous pouvons accéder aux différents éléments ainsi :
persons[0].name : le nom de la première personne
persons[0].size : la taille de la première personne
persons[0].age : l'âge de la première personne
Nous voyons donc que l'accès aux différents éléments de la structure se fait à l'aide du point.
Parcourons la liste :
A noter :
Le nom de la personne est présent dans la structure sous forme de pointeur. Cela évite de pré-dimensionner la variable name, car les noms peuvent être courts ou très longs. On évite ainsi un gaspillage de mémoire.
La variable npersons contient le nombre de lignes du tableau. Sa valeur est calculée lors de la compilation en divisant la taille totale du tableau par la taille de la structure. On obtient donc le nombre de structures dans le tableau.
2.4.14. Les pointeurs
Nous allons terminer par un point obscur pour la plupart : les pointeurs.
Dans l'exemple précédent nous avons utilisé un pointeur (name). Ce pointeur contient l'adresse d'une chaîne de caractère (le nom d'une personne).
Mais on peut aussi utiliser un pointeur sur n'importe quel type de variable :
int *p = &i;
Serial.println(i);
Serial.println(*p);
Que veulent dire ces quelques lignes ?
i est un entier.
p est un pointeur sur un entier (int *). On lui affecte l'adresse de i grâce à l'opérateur &.
On affiche i.
On affiche ensuite le contenu de la variable pointée par p grâce à l'opérateur *.
Les deux lignes affichent strictement la même valeur.
On peut aller plus loin avec les pointeurs sur les structures. En reprenant l'exemple du paragraphe précédent :
Serial.begin(115200);
for (int n = 0 ; n < npersons ; n++) {
Serial.print(n);
printPerson(&persons[n]);
}
}
void printPerson(struct person *p)
{
Serial.print(": ");
Serial.print(p->name);
Serial.print("; size=");
Serial.print(p->size);
Serial.print("; age=");
Serial.println(p->age);
}
Ici nous avons créé une fonction printPerson() qui permet l'affichage des caractéristiques d'une personne. Elle accepte un paramètre du type struct person *, c'est à dire un pointeur sur une structure du type person.
La fonction accède cette fois-ci aux différents éléments de la structure à l'aide de la flèche : ->
La fonction setup() quand à elle, appelle la fonction printPerson() en lui passant en paramètre l'adresse de la nième structure du tableau : &persons[n].
2.5. Les librairies ou bibliothèques
ARDUINO a un avantage indéniable par rapport à d'autres plateformes (PIC, MSP430, etc.) : la disponibilité de nombreuses librairies écrites par des développeurs chevronnés, qui évitent d'avoir à écrire soi-même le code de gestion de pas mal de modules et composants. Il serait dommage de se priver du travail accompli.
On peut dans un premier temps explorer le gestionnaire de bibliothèques, à l'aide du menu "Outils / Gérer les bibliothèques" :
Utiliser la zone "Filtrez votre recherche" pour rechercher un module, ou un composant particulier, puis installer la librairie adéquate.
Généralement, chaque librairie est accompagnée d'exemples, et je conseille vivement d'en essayer au moins un, ne serait ce que pour vérifier que les branchements sont corrects, et que la librairie correspond au besoin.
Il est nécessaire de redémarrer l'IDE après installation d'une librairie pour voir apparaître les exemples dans le menu "Fichier / exemples".
Dans certains cas, la recherche dans le gestionnaire de bibliothèques ne donne rien et on devra faire une recherche sur le WEB et récupérer un fichier ZIP que l'on installera à la main dans le répertoire libraries de l'IDE.
2.6. Trucs et astuces
J'ai regroupé ici quelques notions de base que trop de débutants ignorent, et également quelques pièges à éviter.
2.6.1. Entrées / sorties numériques
Pour manipuler les entrées / sorties numériques, il convient de se documenter sur les fonctions pinMode(), digitalRead(), digitalWrite().
2.6.1.1. Tension
Attention : une carte ARDUINO ne supporte pas plus de 5V sur une entrée digitale, et 3.3V pour certains modèles (DUE, PRO MINI 3.3V 8MHz). Si l'on désire appliquer une tension supérieure il conviendra de la réduire en utilisant un pont diviseur :
2.6.1.2. Isolation galvanique
Si l'on désire une isolation galvanique entre la source de tension et l'entrée de l'ARDUINO on peut utiliser un optocoupleur. En effet, la source de tension peut être dangereuse, et l'on n'a pas forcément envie de soumettre l'ARDUINO, et surtout les personnes qui manipulent l'ARDUINO, à cette tension :
Par exemple ce montage permet de détecter la présence du secteur grâce à un optocoupleur. Lorsque le secteur est présent la LED de l'optocoupleur est allumée et le transistor conduit. La sortie OUT est à ZÉRO. Lorsque le secteur est absent la LED de l'optocoupleur est éteinte et le transistor est bloqué. La sortie OUT est à UN.
Le condensateur C1 provoque une chute de tension dite capacitive, sans dégagement de chaleur.
La résistance R2 peut être remplacée par une résistance de PULLUP de l'ARDUINO. Voir paragraphe 2.6.1.5. PULLUP & PULLDOWN.
2.6.1.3. Courant
Attention également au courant disponible. Une sortie ARDUINO ne peut fournir que 20mA (grand maxi 40mA), et la somme des courants de sortie ne doit pas excéder 200mA au total (y compris pour la carte ARDUINO MEGA), sous peine de destruction du microcontrôleur.
Cela veut dire que si l'on envisage d'allumer un certain nombre de LEDs avec 20mA dans chacune, on ne pourra en allumer au grand maximum 10 simultanément. Si les besoins sont supérieurs, beaucoup de solutions existent, l'ULN2803 par exemple.
2.6.1.4. Nombre d'entrées / sorties
Un ATMEGA328P possède 14 entrées / sorties numériques. Les 2 premières D0 et D1 sont réservées au contrôleur USB, et il est assez déconseillé de les utiliser comme entrée / sortie, ou pour communiquer avec un module (BlueTooth par exemple) car cela pourrait poser des problèmes lors du chargement du sketch sur la carte, et le moniteur série deviendrait inutilisable.
Si l'on a besoin d'une ligne série supplémentaire il existe une possibilité de transformer 2 entrées / sorties quelconques d'un ARDUINO en liaison série : SoftwareSerial.
A savoir : les 6 entrées analogiques A0 à A5 sont également disponibles en tant qu'entrées / Sorties numériques. Il suffit de le demander :
pinMode(A0, OUTPUT);
pinMode(A1, INPUT);
Ensuite on pourra lire et écrire comme s'il s'agissait d'une vraie entrée / sortie numérique :
digitalWrite(A0, HIGH);
int val = digitalRead(A1);
Le poussoir SW1 est relié à l'entrée D2. Une résistance de PULLUP R1 fixe l'entrée à 5V (HIGH) lorsque le poussoir est relâché.
Le poussoir SW2 est relié à l'entrée D3. Une résistance de PULLDOWN R2 fixe l'entrée à GND (LOW) lorsque le poussoir est relâché.
Ces résistances permettent d'éviter que l'entrée soit électromagnétiquement parasitée et bascule sans cesse de HIGH à LOW au repos. On dit souvent : une entrée en l'air se comporte comme une antenne.
L'ARDUINO possède des résistances de PULLUP internes qui permettent de se passer de résistance physique. Elles sont activables par logiciel :
pinMode(2, INPUT_PULLUP);
On pourra ainsi relier directement le bouton entre entrée et GND, et l'entrée passera à LOW quand le bouton sera appuyé :
if (digitalRead(2) == LOW) {
// traitement de l'appui
}
L'ARDUINO ne possède pas de résistances de PULLDOWN internes, mais certains microcontrôleurs le proposent.
2.6.1.6. Anti-rebond
Un bouton, lorsqu'il est appuyé ou relâché, provoque plusieurs rebonds, et l'entrée de l'ARDUINO passera plusieurs fois à HIGH et LOW.
Pour éviter cela il suffit d'installer un petit condensateur de 100nF en parallèle sur le bouton :
La valeur du condensateur dépendra de la qualité du bouton. Plus le nombre de rebonds est important plus la valeur sera élevée.Une solution logicielle existe :
https://github.com/thomasfredericks/Bounce2
2.6.1.7. Le PWMLa technique PWM est souvent employée pour régler la luminosité d'une LED, ou la vitesse d'un moteur continu :
En faisant varier le rapport cyclique, la tension moyenne varie, ainsi que la luminosité de la LED, la vitesse du moteur, ou le positionnement d'un servomoteur.
Pour activer le PWM sur une sortie numérique, il convient de se documenter sur la fonction analogWrite().
Cette documentation précise quelles sont les sorties utilisables en PWM en fonction de la carte.
6 sorties sont disponibles sur une UNO, NANO, PRO MINI : 3, 5, 6, 9, 10, 11
Un article plus complet :
https://www.locoduino.org/spip.php?article47
2.6.2. Entrées analogiques
2.6.2.1. Mesure de tensionUne entrée analogique permet de mesurer une tension. Pour lire une entrée analogique, il convient de se documenter sur la fonction analogRead(), et éventuellement analogReference().
Sur un ARDUINO équipé d'un ATMEGA328P, la tension de référence peut être choisie, comme l'indique la documentation de analogReference() :
- DEFAULT : 5V (ou 3.3V pour une PRO MINI). La mesure sera fortement dépendante de la valeur exacte de la tension d'alimentation
- INTERNAL : 1.1V. La mesure sera indépendante de la tension d'alimentation mais cela nécessite de connaître la valeur exacte de cette tension de 1.1V, qui est précise à 10% près. Elle peut être mesurée sur la broche AREF
- EXTERNAL : une référence externe (TL431 (1%), ou mieux LM4040 : 0.1%) peut être utilisée pour plus de précision et de stabilité en température. Il existe de nombreux tutoriels
Pour mesurer une tension on procède comme ceci :
#define VREF 4.95 // valeur exacte sur AREF
// code de mesure (dans la fonction loop() par exemple)
unsigned int adc = analogRead(0); // mesure sur A0
float voltage = adc * VREF / 1023; // 1023 car l'ADC est un 10 bits (1024 points)
On obtiendra ainsi une mesure en volts.
Attention : sur ses entrées analogiques, une carte ARDUINO ne supportera pas une tension supérieure à sa tension d'alimentation. Deuxièmement elle devra également être inférieure à la référence de tension choisie, sinon, l'ADC mesurera une valeur de 1023.
Dans le cas d'une entrée analogique, on utilisera de préférence des résistances de précision 1%.
Attention : si l'on désire lire plusieurs entrées, il y a certaines précautions à prendre :
ARDUINO : les performances de l'ADC
Il n'y a pas que l'ARDUINO qui soit capable de mesurer une tension. D'autre microcontrôleurs sont plus performants dans ce domaine :
2.6.2.2. Mesure de courant continu
Une entrée ADC peut également servir à mesurer un courant, à l'aide d'une résistance shunt :
Sur ce montage de pilotage de moteur, la résistance shunt R1 de 1Ω provoque une chute de tension de 1V pour un courant moteur de 1A . Il suffit de mesurer la tension aux bornes de la résistance pour savoir quel est le courant consommé par le moteur.
Il sera nécessaire de se documenter sur la loi d'Ohm :
U = RI
I = U / R
Le courant passant dans une résistance de 1Ω est donc de 1A si la tension mesurée à ses bornes est de 1V.
2.6.2.3. Mesure de courant continu avec un INA226
Pour mesurer un courant continu avec précision l'INA226 est particulièrement intéressant :
Sa précision de 16 bits est largement supérieure à celle de l'ADC ARDUINO. Généralement le shunt soudé sur la carte est un 10mΩ (marquage R010). Le courant maximal mesurable sera de 8A. Avec un shunt de 100mΩ (marquage R100) il sera de 800mA.
L'INA226 est capable également de mesurer une tension : 36V maximum.
J'en parle ici :
https://riton-duino.blogspot.com/search?q=ina226
Il y a d'autres solutions :
INA138 et MAX4372 : Current Monitoring
2.6.2.4. Mesure de courant alternatif
La mesure de courant alternatif ne peut pas être effectuée directement avec un ARDUINO. Il existe deux moyens principaux :
Capteur de courant ACS712 |
Ce capteur fonctionne par effet HALL. On trouve beaucoup de tutoriels :
https://wiki.mchobby.be/index.php?title=SENSEUR-COURANT-ACS712
Transformateur de courant SCT013 |
Ce capteur est un transformateur de courant. Il fonctionne comme une pince ampèremétrique. Voici un tutoriel sur le sujet :
Sur ce schéma on voit une résistance de charge du transformateur (33Ω), dite "Burden". Attention, certains transformateurs du commerce sont déjà équipés de cette résistance, d'autres non.
2.6.3. Communication série
Le port USB de l'ARDUINO ne sert pas seulement au chargement du code sur la carte et afficher des informations sur le moniteur série. On peut l'utiliser également pour communiquer avec un logiciel tournant sur le PC.
Chargeons ce petit exemple :
void setup()
{
Serial.begin(115200);
Serial.println("Serial test");
}
void loop() {
if (Serial.available()) {
char c = Serial.read();
Serial.print("char reçu: ");
Serial.println(c);
}
}
Ce sketch affiche les caractères envoyés par le moniteur série (entrer les caractères dans la zone de texte du haut, puis cliquer sur "Envoyer" ou la touche RETURN du clavier :
Serial test
char reçu: e
char reçu: f
char reçu: d
char reçu: f
char reçu: s
char reçu: d
char reçu:
char reçu:
char reçu: q
char reçu: s
char reçu: d
char reçu:
char reçu:
Ici j'ai tapé efdfsd RETURN, puis qsd RETURN. On voit deux lignes vides à la fin de chaque mot entré. Il s'agit des caractères RETURN (\r) et NELINE (\n), car dans la liste de choix "Fin de ligne" du moniteur série (en bas à droite), j'ai choisi "Les deux, NL et CR".
Bien entendu on peut envoyer ces caractères à l'ARDUINO avec un programme tournant sur le PC, ou une carte RASPBERRY PI, écrit en PYTHON et PYSERIAL, par exemple.
Si l'on préfère éviter de monopoliser le port USB de l'ARDUINO, il existe une possibilité de transformer 2 entrées / sorties quelconques d'un ARDUINO en liaison série : SoftwareSerial.
Lorsque l'on a besoin d'une solution fiable de transfert de données, une solution logicielle appelée protocole est nécessaire :
2.6.4. Le tempsIl existe différents moyens d'introduire une notion de temps dans un programme :
2.6.4.1 delay(), delayMicroseconds()
Ces deux fonctions laissent s'écouler un temps en millisecondes ou microsecondes.
L'exemple basique Blink :
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
La LED de la carte clignote, une seconde allumée, une seconde éteinte.
2.6.4.2 millis()
Cette fonction retourne le temps écoulé en millisecondes depuis le démarrage.
Cet exemple BlinkWithoutDelay fait la même chose que le précédent :
int ledState = LOW;
unsigned long previousMillis = 0;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(LED_BUILTIN, ledState);
}
// autres instructions
}
Quelle est la différence ? La fonction loop(), dans le deuxième cas, ne sera pas bloquée pendant l'exécution de delay(), et pourra exécuter d'autres instructions. On parle d'exécution non bloquante.
2.6.4.3 RTC
Jusqu'ici nous avons vu le moyen d'utiliser le temps relatif. Dans certains cas on aura besoin de beaucoup plus : l'heure et la date.
Pour cela, il sera nécessaire d'utiliser un circuit dit RTC (Real Time Clock). Je déconseille les circuits du type DS1307, peu précis. Le DS3231 apportera une précision bien supérieure et une compensation en température :
Je conseille l'utilisation de la librairie RTCLIB, installable depuis l'IDE.
Dans l'exemple DS3231 de la librairie, on voit ces lignes dans la fonction setup() :
if (rtc.lostPower()) {
Serial.println("RTC lost power, lets set the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
Ces lignes permettent d'ajuster la date et l'heure à celles de la compilation du sketch. La méthode lostPower() permet de savoir si le circuit vient d'être démarré pour la première fois. Si la pile est en place, l'heure ne sera ajustée qu'une seule fois.
Si l'on veut ajuster la date et l'heure à la demande, il faudra imaginer une solution plus souple (boutons, encodeur rotatif, télécommande, écran tactile, etc.).
2.6.4.4 NTP
Le Protocole NTP (Network Time Protocol) permet de récupérer l'heure par le réseau. Il est réservé aux cartes possédant une interface WIFI ou celles équipées d'une carte Ethernet.
2.6.5. La communication en réseau
Il existe différents moyens de communiquer en réseau avec un ARDUINO :
- carte Ethernet (filaire)
- NRF24L01 (radio 2.4GHz)
- ESP8266 ou ESP32 (WIFI)
Souvent il y a confusion entre NRF24L01 et WIFI, qui utilisent tous deux la bande de fréquence 2.4GHz. Le WIFI permet de communiquer à l'aide des protocoles standards utilisés sur Internet (TCP, UDP, etc.), ce que ne permet pas le NRF24L01.
Voir la table des matières : Communication
Fuyez les architectures du type ARDUINO + ESP8266, ou les cartes dites "UNO WIFI". Un ESP8266 seul, ou mieux, un ESP32 vous fera gagner beaucoup de temps de codage, grâce à leurs librairies très élaborées et leur système de fichier FLASH (spiffs, littlefs), dans lequel on pourra stocker des fichiers HTML, des images, etc.
Penser également au BlueTooth, qui permet une communication point à point (un ARDUINO avec module BlueTooth, ou un ESP32, avec un smartphone).
2.6.6. Pas assez d'entrées / sorties numériques ?
Parfois, un ARDUINO ne possède pas assez d'entrées / sorties pour le projet en vue. Et l'on a pas forcément envie de s'encombrer d'une carte MEGA.
Cet article vous dira comment en ajouter :
https://riton-duino.blogspot.com/2019/02/les-extensions-de-gpios-de-larduino.html
Ceci aussi valable pour les ESP8266 et ESP32, à condition de choisir un module capable d'être alimenté sous 3.3V (c'est majoritairement le cas des expanders).
2.6.7. Pas assez d'entrées / sorties analogiques ?
Si l'on a besoin d'entrées analogiques supplémentaires, un ADC sera nécessaire, un module ADS1115 (4 canaux sur bus I2C) par exemple, que l'on peut trouver facilement :
ADS1115 (16 bits) |
L'ADS1115 est un ADC 16bits, il offre une plus grande précision que l'ADC de l'ARDUINO (10bits).
2.6.8. Pas assez de mémoire ?
Tout d'abord il ne faut pas espérer augmenter la quantité de mémoire réservée au code. Dans ce cas, seul un processeur possédant plus de mémoire FLASH pourra nous venir en aide.
On est souvent tenté d'ajouter une carte mémoire SD ou microSD à un ARDUINO lorsque l'on a besoin de stocker de grandes quantité de données. La fiabilité n'est pas toujours au rendez-vous. Tout dépend de la SD. Il convient d'en essayer plusieurs.
Pour un de mes projets, un serveur WEB, une Kingston SDHC 4Gb produisait des défauts aléatoires : fichier non trouvé, présence de caractères étranges lors de lectures. Avec une Sandisk Extreme SDHC le résultat s'est très nettement amélioré.
La SD n'est pas la seule solution. Souvent, une mémoire FLASH SPI de quelques Mo sera plus que suffisante.
Et il existe des modules, tout aussi faciles à raccorder qu'un module SD :
Module W25Q128 (16 Mo) |
J'en parle ici :
ARDUINO : Stockage en Flash SPI
2.6.9. Besoin d'une vraie sortie analogique ?
Comme on l'a vu plus haut, la technique PWM permet de faire varier la luminosité d'une LED par exemple. Mais le signal qu'elle reçoit n'est pas une tension continue :
La luminosité est perçue comme étant continue car la rétine a une inertie importante.
Si l'on a besoin d'une vraie tension continue on peut utiliser trois solutions :
- un signal PWM + un filtrage RC (résistance + condensateur)
- un potentiomètre numérique (un AD8400 par exemple)
- un DAC
Un filtrage par réseau RC aura une inertie importante et sera peu réactif. Un potentiomètre numérique revient assez cher. Un DAC est très bon marché.
Sur un ARDUINO, il est possible d'en ajouter un sur le bus I2C :
Module DAC 12 bits MCP4725 |
Voir ce projet : Alimentation 3.7V Numérique
A savoir : l'ESP32 possède un DAC.
2.6.10. Interruptions et notions avancées
Ces sujets débordent un peu du cadre "comment bien débuter". Il est difficilement accessible aux débutants.
J'ai préféré les regrouper dans un article à part :
3. Matériel
Lorsque l'on désire aller un peu plus loin que le simple assemblage de cartes et de modules, il est nécessaire de posséder un peu de matériel.
3.1. Alimentation
Si l'on désire réaliser des montages avec de la puissance, une alimentation réglable peut être utile pendant la phase de prototypage :
Alimentation 5-30V 5A |
Ensuite, la réalisation finale pourra adopter une alimentation fixe :
Bloc secteur 5V 1A USB |
Alimentation secteur 5V 3W pour PCB |
Alimentation secteur 12V 25W |
Si l'on envisage de laisser une alimentation secteur branchée 24H/24, un modèle de qualité s'impose :
3.2. Multimètre
Ne pas hésiter à faire l'acquisition d'un multimètre, qui permettra de mesurer tensions, courants, résistances, condensateurs, etc.
Cet article en parle :
3.3. Ampèremètre USB
Un ampèremètre USB permet de mesurer la tension USB et surtout le courant consommé par une carte ARDUINO.3.4. Testeur
Ce petit testeur de composants permet beaucoup de choses pour un prix ridicule :
Plus de détails ici :
Testeur de composants : le GM328
3.5. Fer à souder
Pour ceux qui désirent réaliser des projets plus aboutis et finalisés, un fer à souder sera indispensable :
Je vous renvoie à cet article :
Fer à Souder : recommandations
4. Liens utiles
https://zestedesavoir.com/tutoriels/686/arduino-premiers-pas-en-informatique-embarquee/
Le forum ARDUINO en français, où l'on pourra poser des questions :
https://forum.arduino.cc/c/international/francais/49
5. Conclusion
J'espère avoir aidé certains débutants à se mettre en selle, ou les avoir motivés pour tenter un premier contact.
Ce blog comporte une table des matières. Il ne faut pas hésiter à la parcourir.
Cordialement
Henri
Bonjour, je tombe depuis quelques jours dans le milieu "Arduino" et je viens de voir votre blog très impressionnant. Je suis lunetier et travaille sur des machines 5 axes. Je cherche à réaliser un détecteur de lumiere qui pourrait m'envoyer un SMS. quand une machine est en défaut une led clignote et je me dis que si je recevais un SMS à son clignotement je pourrais intervenir plus rapidement. Pourrieez vous m'aider. Merci. Lucien
RépondreSupprimerIl serait plus facile d'échanger, poster du code, des images, etc. sur le forum ARDUINO.
Supprimerhttps://forum.arduino.cc/c/international/francais/49
A bientôt.
OK MERCI
SupprimerBonjour
RépondreSupprimerje débute avec arduino et il ne fait aucun doute que votre blog me sera d 'une grande aide. Merci à vous pour le boulot effectué!
Merci. Il n'y a qu'à se servir.
SupprimerBravo pour votre post vraiment très complet.
RépondreSupprimerMerci pour l'appréciation.
SupprimerBonjour, merci pour ces infos... Dans quoi me suis je lancé !!!
RépondreSupprimer