Programmation Arduino : bases, variables, boucles et fonctions
Programmation Arduino pour débutants : setup et loop, int, long, byte, dépassement, const, #define, if-else, switch-case, boucles, tableaux, fonctions avec LED.
La programmation Arduino consiste à dire à une carte Arduino quoi faire en langage C/C++ : tu écris quelle LED s'allume et quand, ce qui se passe quand on appuie sur un bouton et comment interpréter le nombre envoyé par un capteur, et la carte répète ces instructions des milliers de fois par seconde. Bonne nouvelle : presque tous les programmes que tu verras, du clignotement d'une LED à la voiture robot, sont construits avec les mêmes dix briques de base environ. Ce sont setup() et loop(), les variables, les constantes, les opérateurs, if-else, switch-case, les boucles for et while, les tableaux et les fonctions.
Dans ce guide, tu vas découvrir ces briques une par une, chacune avec un vrai exemple de LED ou de bouton-poussoir. Tous les exemples tournent sur le même circuit simple et ont été compilés et testés pour l'Arduino Uno. Les points où les débutants bloquent le plus souvent, à savoir le dépassement des variables, la confusion entre = et ==, un break oublié et un compteur qui repart à zéro à chaque tour, sont expliqués à part. Dans les dernières parties, tu verras aussi comment la même logique fonctionne sur l'ESP32 et à quoi elle ressemble en MicroPython sur le Raspberry Pi Pico.

Qu'est-ce que la programmation Arduino et quel langage utilise-t-elle ?
Le code Arduino repose sur le C++ ; il n'existe pas de "langage Arduino" à part. Le cœur Arduino ajoute au C++ des fonctions toutes prêtes comme pinMode(), digitalWrite() et delay(). Le fichier que tu écris s'appelle un sketch (ou croquis) et porte l'extension .ino. Quand tu cliques sur Vérifier, l'Arduino IDE ajoute en haut du fichier l'en-tête Arduino.h et génère lui-même les déclarations des fonctions, puis le compilateur transforme le code en langage machine que le processeur comprend. Le bouton Téléverser envoie ensuite ce résultat par USB au bootloader de la carte. Si tu n'as pas encore installé l'IDE, commence par le guide installer Arduino IDE.
Quelques règles de base s'appliquent quand tu écris du code. Les apprendre dès le départ fait disparaître la moitié des erreurs de compilation que tu verrais sinon pendant tes premiers jours :
| Règle | Bonne écriture | Si tu ne la respectes pas |
|---|---|---|
| Chaque instruction se termine par un point-virgule | digitalWrite(13, HIGH); | expected ';' before '}' token |
| Majuscules et minuscules comptent | pinMode(13, OUTPUT); | 'pinmode' was not declared in this scope |
| Les blocs de code sont entre accolades | void loop() { ... } | Chaque { doit avoir sa } |
| Commentaire sur une ligne | // cette ligne ne s'exécute pas | Les commentaires ne sont pas compilés, ils servent à expliquer |
| Commentaire sur plusieurs lignes | /* ... */ | Sans fermeture, tout ce qui suit devient un commentaire |
| Texte entre guillemets doubles, un caractère entre guillemets simples | "Bonjour" et 'A' | Mélanger les guillemets donne une mauvaise valeur ou une erreur |
Le circuit utilisé dans les exemples
Tous les exemples tournent sur un seul circuit. Branche six LED sur les broches D8–D13, chacune avec une résistance de 220 Ω ; la patte courte (cathode) de chaque LED va au GND. Tu peux vérifier la valeur de la résistance pour ta LED avec le calculateur de résistance pour LED. Relie une patte du bouton-poussoir à D2 et la patte opposée en diagonale au GND. Comme le code utilise INPUT_PULLUP, aucune résistance externe n'est nécessaire : la broche lit HIGH quand le bouton est relâché et LOW quand il est appuyé. Pour plus de détails, consulte brancher un bouton-poussoir sur Arduino et qu'est-ce qu'une LED ?.
| Composant | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| 6 LED (chacune avec 220 Ω, cathode au GND) | D8, D9, D10, D11, D12, D13 | GPIO 18, 19, 21, 22, 23, 25 | GP14, GP13, GP12, GP11, GP10, GP9 |
| Bouton-poussoir (autre patte au GND) | D2 | GPIO 4 | GP2 |
| LED de la carte | D13 (la LED marquée L) | GPIO 2 (la plupart des DevKit) | GP25 ("LED" sur le Pico W) |
| Vitesse du port série | 9600 bauds | 115200 bauds | Shell de Thonny |
setup() et loop() : le squelette de tout programme
Tout sketch Arduino comporte deux fonctions obligatoires. setup() ne s'exécute qu'une seule fois, à la mise sous tension de la carte ou quand on appuie sur le bouton reset ; on y place les préparatifs comme la configuration des broches et Serial.begin(). loop() se répète ensuite indéfiniment une fois setup() terminé. En coulisses, le cœur Arduino possède une fonction main() cachée : elle prépare d'abord le matériel, appelle setup() une fois, puis appelle loop() encore et encore dans une boucle infinie. La zone en haut du fichier, en dehors de ces deux fonctions, est la zone globale ; on y définit les constantes et les variables qui doivent être accessibles partout.
1// 1) Global alan: sabitler ve değişkenler / Global area: constants and variables
2const int LED_PIN = 13; // dahili LED / built-in LED
3unsigned long passCount = 0; // loop() kaç kez döndü / how many times loop() has run
4
5// 2) setup(): açılışta bir kez çalışır / runs once at power-up or reset
6void setup() {
7 pinMode(LED_PIN, OUTPUT);
8 Serial.begin(9600);
9 Serial.println("setup() bitti / setup() done");
10}
11
12// 3) loop(): sonsuza kadar tekrar eder / repeats forever
13void loop() {
14 passCount++; // her turda 1 artır / add 1 on every pass
15 Serial.print("Tur / Pass: ");
16 Serial.println(passCount);
17
18 digitalWrite(LED_PIN, HIGH); // LED'i yak / LED on
19 delay(500); // 500 ms bekle / wait 500 ms
20 digitalWrite(LED_PIN, LOW); // LED'i söndür / LED off
21 delay(500);
22}Téléverse le code et ouvre le moniteur série à 9600 bauds : tu verras une fois "setup() done", puis un numéro de tour qui augmente chaque seconde, pendant que la LED intégrée clignote au même rythme. Les deux delay(500) dans loop() allongent chaque tour à environ une seconde ; une loop() sans attente ni affichage série peut tourner des centaines de milliers de fois par seconde sur un Uno. Pour tirer le meilleur du moniteur série, jette un œil au guide Arduino Serial Monitor.
Variables et types de données : int, long, float, bool, byte
Une variable est une boîte nommée dans la mémoire qui garde une valeur. Pour la définir, tu écris d'abord son type, puis son nom, et si tu veux une valeur de départ, par exemple int counter = 0;. Le type détermine combien d'octets occupe la boîte et quelle plage de nombres elle peut contenir. L'Arduino Uno n'a que 2 Ko de RAM, donc choisir le bon type compte. Les noms de variables commencent par une lettre ou un tiret bas et ne peuvent contenir ni espaces ni lettres accentuées comme é, è ou ç.
| Type | Taille sur Uno | Plage de valeurs | Usage typique |
|---|---|---|---|
| bool | 1 octet | true ou false | La LED est-elle allumée, le bouton a-t-il été appuyé |
| byte | 1 octet | 0 – 255 | Numéro de broche, luminosité PWM |
| char | 1 octet | -128 – 127 | Un seul caractère : 'A' |
| int | 2 octets | -32 768 – 32 767 | Compteurs, résultat d'analogRead() |
| unsigned int | 2 octets | 0 – 65 535 | Nombres positifs uniquement |
| long | 4 octets | -2 147 483 648 – 2 147 483 647 | Grands nombres entiers |
| unsigned long | 4 octets | 0 – 4 294 967 295 | Mesure du temps avec millis() |
| float | 4 octets | Environ ±3,4 × 10^38, précision de 6–7 chiffres | Température, tension, moyennes |
| double | 4 octets (identique à float sur Uno) | Identique à float | 8 octets sur l'ESP32 |
Quelques règles pratiques t'éviteront bien des soucis. analogRead() renvoie un nombre de 0 à 1023, un int suffit donc. millis(), en revanche, renvoie un unsigned long ; si tu stockes le temps dans une variable int, la valeur déborde au bout de 32,7 secondes et ta temporisation ne fonctionne plus. Sur l'Uno, les calculs en float sont faits par logiciel : ils sont plus lents que les calculs sur les entiers, et au-delà de 6–7 chiffres le résultat n'est plus fiable ; ne compare donc jamais deux float avec ==. Si tu veux un type dont la taille reste la même sur toutes les cartes, utilise ceux qui portent leur taille dans le nom, comme uint8_t, int16_t et uint32_t.
Dépassement (overflow) : que se passe-t-il quand une variable dépasse sa limite ?
Si tu essaies de stocker un nombre plus grand que ce que son type peut contenir, l'Arduino ne signale aucune erreur ; le nombre repart du début, comme le compteur kilométrique d'une voiture. Sur l'Uno, un int contient au maximum 32 767, et si tu ajoutes 1 il devient -32 768. Un byte passe de 255 à 0. Un piège plus sournois concerne les calculs avec des constantes : une expression comme 60 * 1000 est d'abord calculée en int et déborde, même si le résultat est rangé dans une variable long. Le sketch ci-dessous affiche tous ces cas dans le moniteur série, et sa loop() montre un dépassement de byte sur une LED :
1const int LED_PIN = 9; // PWM destekli pin (~9) / PWM-capable pin (~9)
2byte brightness = 0; // byte: 0-255
3
4void setup() {
5 pinMode(LED_PIN, OUTPUT);
6 Serial.begin(9600);
7
8 int a = 32767; // Uno'da int'in en büyük değeri / largest int on an Uno
9 a = a + 1; // taşma: -32768 olur / overflow: becomes -32768
10 Serial.println(a);
11
12 long wrong = 60 * 1000; // int ile hesaplanır, taşar: -5536 / computed as int, overflows: -5536
13 long right = 60 * 1000L; // L eki hesabı long yapar: 60000 / the L suffix makes it long math: 60000
14 Serial.println(wrong);
15 Serial.println(right);
16
17 float half = 5 / 2; // tam sayı bölmesi: 2.00 / integer division: 2.00
18 float half2 = 5 / 2.0; // ondalıklı bölme: 2.50 / floating-point division: 2.50
19 Serial.println(half);
20 Serial.println(half2);
21}
22
23void loop() {
24 analogWrite(LED_PIN, brightness); // parlaklığı uygula / apply the brightness
25 brightness++; // 255'ten sonra 0'a döner / wraps to 0 after 255
26 delay(10);
27}| Ligne de code | Résultat sur Uno | Résultat sur ESP32 et Pico | Pourquoi ? |
|---|---|---|---|
| a = 32767 + 1 | -32768 | 32768 | int fait 2 octets sur l'Uno, 4 octets sur les autres |
| 60 * 1000 | -5536 | 60000 | Les constantes sont d'abord calculées en int |
| 60 * 1000L | 60000 | 60000 | Le suffixe L fait passer le calcul en long |
| 5 / 2 | 2.00 | 2.00 | La division de deux entiers donne un entier |
| 5 / 2.0 | 2.50 | 2.50 | Si un nombre a une virgule, le résultat aussi |
Observe la LED sur D9 : sa luminosité monte lentement de 0 à 255, puis la ligne brightness++ transforme la valeur en 0 au lieu de 256 et la LED s'éteint d'un coup. C'est la façon la plus simple de voir un dépassement de tes propres yeux. D9 fait partie des broches PWM de l'Uno marquées d'un ~, c'est pourquoi analogWrite() y fonctionne ; le PWM est expliqué en détail dans qu'est-ce que le PWM ?. Le retour à zéro de millis() après environ 49,7 jours est lui aussi un dépassement, sans conséquence dans un code bien écrit ; tu verras comment l'écrire dans le guide millis() au lieu de delay().
const et #define : des valeurs qui ne changent jamais
Pour les nombres qui ne changent pas pendant l'exécution du programme, comme les numéros de broches ou les seuils, il existe deux façons de leur donner un nom. Une constante définie avec const a un type, respecte les règles de portée, et si tu essaies de la modifier par erreur, le compilateur t'arrête avec assignment of read-only variable 'LED_PIN'. #define, lui, est une directive du préprocesseur : avant la compilation, il remplace chaque BUTTON_PIN du code par 2. Il n'a pas de type, et la ligne ne prend ni point-virgule ni signe égal. Pour des nombres simples, aucun des deux n'occupe de RAM, car le compilateur place la valeur directement dans le code. Aujourd'hui on préfère const, et écrire le nom des constantes en MAJUSCULES est une habitude courante. L'exemple ci-dessous utilise les deux : la LED reste allumée tant que tu appuies sur le bouton.
1#define BUTTON_PIN 2 // önişlemci: derlemeden önce metin değişimi / preprocessor: text swap before compiling
2const int LED_PIN = 13; // tipi olan, salt okunur sabit / typed, read-only constant
3
4void setup() {
5 pinMode(LED_PIN, OUTPUT);
6 pinMode(BUTTON_PIN, INPUT_PULLUP); // dahili pull-up: basılınca LOW / internal pull-up: LOW when pressed
7}
8
9void loop() {
10 if (digitalRead(BUTTON_PIN) == LOW) { // buton basılı mı? / is the button pressed?
11 digitalWrite(LED_PIN, HIGH); // evet: LED yanar / yes: LED on
12 } else {
13 digitalWrite(LED_PIN, LOW); // hayır: LED söner / no: LED off
14 }
15}Les opérateurs : arithmétiques, de comparaison et logiques
Les opérateurs permettent de calculer avec les variables, de les comparer et de combiner des conditions. Presque tous ceux que tu utiliseras dans tes projets de tous les jours sont dans ce tableau :
| Groupe | Opérateur | Signification | Exemple |
|---|---|---|---|
| Arithmétique | + - * / | Les quatre opérations | x = a * 2; |
| Reste | % | Reste d'une division (entiers uniquement) | 7 % 3 donne 1 |
| Affectation | = += -= *= /= | Affecter, ajouter, retirer… | total += 5; |
| Incrément, décrément | ++ -- | Ajouter 1 ou retirer 1 | i++; |
| Comparaison | == != < > <= >= | Le résultat est true ou false | if (x >= 10) |
| Logique | && || ! | ET, OU, NON | if (a && !b) |
| Conditionnel | ? : | if-else abrégé | x > 0 ? HIGH : LOW |
| Bit à bit | & | ^ ~ << >> | Agit sur les bits d'un nombre | 1 << 3 donne 8 |
Les deux paires les plus souvent confondues sont = et == ainsi que & et &&. Un seul signe égal affecte une valeur, deux signes comparent. Un seul & travaille sur les bits des nombres, tandis que && demande si les deux conditions sont vraies. Tu peux essayer les tables de vérité de ET, OU et NON dans l'outil portes logiques, et les opérateurs bit à bit sont détaillés dans le guide systèmes de numération et opérations sur les bits. L'exemple ci-dessous compte combien de fois le bouton a été appuyé et allume la LED après un nombre impair d'appuis :
1const int LED_PIN = 13;
2const int BUTTON_PIN = 2;
3
4int presses = 0; // toplam basış sayısı / total number of presses
5bool lastPressed = false; // önceki turdaki durum / state on the previous pass
6
7void setup() {
8 pinMode(LED_PIN, OUTPUT);
9 pinMode(BUTTON_PIN, INPUT_PULLUP);
10 Serial.begin(9600);
11}
12
13void loop() {
14 bool pressed = (digitalRead(BUTTON_PIN) == LOW); // karşılaştırma: true ya da false / comparison: true or false
15
16 if (pressed && !lastPressed) { // şimdi basılı VE önceden değildi: yeni basış / pressed now AND not before: new press
17 presses++; // 1 artır / increment by 1
18 Serial.print("Basış / Presses: ");
19 Serial.println(presses);
20 delay(50); // basit debounce / simple debounce
21 }
22 lastPressed = pressed;
23
24 // Kalan (%) ile tek mi çift mi? / odd or even using the remainder (%)
25 digitalWrite(LED_PIN, (presses % 2 == 1) ? HIGH : LOW);
26}L'astuce, c'est la condition pressed && !lastPressed : elle signifie "appuyé maintenant ET pas appuyé au tour précédent". Ainsi, le nombre n'augmente pas tant que tu maintiens le bouton et chaque appui n'est compté qu'une fois. presses % 2 donne le reste de la division du nombre par 2 : 1 pour les nombres impairs, 0 pour les pairs. L'opérateur ? : de la dernière ligne choisit alors HIGH ou LOW selon ce résultat.
if, else if et else : prendre des décisions
if exécute le code entre accolades quand la condition entre parenthèses est vraie. Si elle est fausse, c'est le bloc else qui s'exécute, s'il existe. Quand il te faut plus de choix, tu ajoutes else if entre les deux. Les conditions sont vérifiées de haut en bas, et dès que le bloc de la première condition vraie a été exécuté, les autres sont ignorées. En C++, toute valeur différente de zéro est considérée comme vraie : if (counter) signifie donc "si le compteur n'est pas nul". Nous avons déjà vu un exemple simple de if-else dans la partie sur const. Écrivons maintenant un programme qui distingue un appui court d'un appui long :
1const int LED_PIN = 13;
2const int BUTTON_PIN = 2;
3
4void setup() {
5 pinMode(LED_PIN, OUTPUT);
6 pinMode(BUTTON_PIN, INPUT_PULLUP);
7 Serial.begin(9600);
8}
9
10void loop() {
11 if (digitalRead(BUTTON_PIN) == LOW) { // basıldı / pressed
12 unsigned long start = millis();
13 while (digitalRead(BUTTON_PIN) == LOW) { // bırakılana kadar bekle / wait until released
14 }
15 unsigned long held = millis() - start; // basılı kalma süresi (ms) / hold time (ms)
16
17 if (held < 50) {
18 return; // 50 ms'den kısa: parazit, yok say / under 50 ms: bounce, ignore
19 } else if (held < 1000) {
20 digitalWrite(LED_PIN, HIGH); // kısa basış: LED yak / short press: LED on
21 Serial.println("Kısa basış / Short press");
22 } else {
23 digitalWrite(LED_PIN, LOW); // uzun basış: LED söndür / long press: LED off
24 Serial.println("Uzun basış / Long press");
25 }
26 }
27}Dès que le bouton est appuyé, le code note l'instant avec millis(), attend dans une boucle while que le bouton soit relâché et calcule le temps écoulé. Les appuis de moins de 50 ms sont considérés comme du bruit dû au rebond mécanique du bouton, et return termine ce tour de loop() plus tôt. Un appui de moins d'une seconde allume la LED, un appui plus long l'éteint. L'ordre des conditions compte : si tu avais placé le test held < 1000 en premier, un parasite de 30 ms compterait aussi comme un "appui court".
switch-case : choisir parmi plusieurs cas
Si tu dois faire beaucoup de choses différentes selon la valeur d'une variable, switch-case est plus lisible qu'une longue suite de else if. switch compare la valeur entre parenthèses à chaque étiquette case et commence l'exécution à celle qui correspond. Tu dois terminer chaque case par break ; sinon le programme continue et exécute aussi le code du case suivant. Si aucun case ne correspond, c'est le bloc default qui s'exécute. switch ne fonctionne qu'avec des types entiers comme int, byte, char et enum ; pour un String, un float ou des plages comme "entre 10 et 20", il te faut if. Dans l'exemple ci-dessous, chaque appui fait passer la lampe au mode suivant : éteinte, allumée, clignotement lent, clignotement rapide.
1const int LED_PIN = 13;
2const int BUTTON_PIN = 2;
3
4byte mode = 0; // 0 kapalı, 1 açık, 2 yavaş, 3 hızlı / 0 off, 1 on, 2 slow, 3 fast
5bool lastPressed = false;
6
7void setup() {
8 pinMode(LED_PIN, OUTPUT);
9 pinMode(BUTTON_PIN, INPUT_PULLUP);
10}
11
12void loop() {
13 bool pressed = (digitalRead(BUTTON_PIN) == LOW);
14 if (pressed && !lastPressed) {
15 mode = (mode + 1) % 4; // 0 → 1 → 2 → 3 → 0
16 delay(50); // basit debounce / simple debounce
17 }
18 lastPressed = pressed;
19
20 switch (mode) {
21 case 0: // kapalı / off
22 digitalWrite(LED_PIN, LOW);
23 break;
24 case 1: // sürekli açık / always on
25 digitalWrite(LED_PIN, HIGH);
26 break;
27 case 2: // 500 ms'de bir değiş / toggle every 500 ms
28 digitalWrite(LED_PIN, (millis() / 500) % 2 ? HIGH : LOW);
29 break;
30 case 3: // 100 ms'de bir değiş / toggle every 100 ms
31 digitalWrite(LED_PIN, (millis() / 100) % 2 ? HIGH : LOW);
32 break;
33 default: // beklenmeyen değer: başa dön / unexpected value: reset
34 mode = 0;
35 break;
36 }
37}La ligne mode = (mode + 1) % 4 fait passer le mode par 0, 1, 2, 3 puis, grâce à l'opérateur %, le remet à 0 quand il atteint 4. Remarque qu'on n'utilise pas delay() pour clignoter : l'expression (millis() / 500) % 2 alterne entre 0 et 1 toutes les 500 ms, donc le bouton réagit à tout moment pendant que la LED clignote. La version plus élaborée de cette approche par modes s'appelle une machine à états ; tu verras comment l'utiliser dans des projets comme des feux tricolores et des menus dans le guide machine à états avec Arduino.
Les boucles for, while et do-while
Les boucles exécutent un bloc de code encore et encore. Les parenthèses d'une boucle for comportent trois parties : le départ (int i = 0), la condition pour continuer (i < 6) et le pas après chaque tour (i++). for est idéale quand tu sais combien de fois répéter. while continue tant que sa condition est vraie et la vérifie avant chaque tour ; elle convient aux attentes dont tu ne connais pas la durée à l'avance. do-while vérifie la condition à la fin et s'exécute donc toujours au moins une fois. Dans une boucle, break en sort immédiatement et continue saute la fin du tour en cours pour passer au suivant. Comme loop() est déjà une boucle infinie, tu n'as généralement pas besoin d'y écrire while (true).
| Boucle | Quand la condition est-elle vérifiée ? | Quand l'utiliser ? | Exemple |
|---|---|---|---|
| for | Avant chaque tour | Quand le nombre de répétitions est connu | for (int i = 0; i < 6; i++) |
| while | Avant chaque tour | Pour attendre qu'un événement se produise | while (digitalRead(2) == HIGH) |
| do-while | Après chaque tour | Quand elle doit s'exécuter au moins une fois | do { ... } while (x < 10); |
L'exemple ci-dessous crée un effet K2000 avec six LED. La boucle for de setup() passe les six broches en sortie en une seule ligne, et la boucle while de loop() attend que le bouton soit appuyé. Tant que tu maintiens le bouton, la lumière va de D8 à D13 puis revient :
1const int FIRST_LED = 8; // ilk LED pini / first LED pin
2const int LAST_LED = 13; // son LED pini / last LED pin
3const int BUTTON_PIN = 2;
4
5void setup() {
6 for (int pin = FIRST_LED; pin <= LAST_LED; pin++) {
7 pinMode(pin, OUTPUT); // 6 pini tek döngüyle çıkış yap / make 6 pins outputs with one loop
8 }
9 pinMode(BUTTON_PIN, INPUT_PULLUP);
10}
11
12void loop() {
13 while (digitalRead(BUTTON_PIN) == HIGH) {
14 // butona basılana kadar burada bekle / wait here until the button is pressed
15 }
16
17 for (int pin = FIRST_LED; pin <= LAST_LED; pin++) { // ileri: 8 → 13 / forward: 8 → 13
18 digitalWrite(pin, HIGH);
19 delay(80);
20 digitalWrite(pin, LOW);
21 }
22 for (int pin = LAST_LED - 1; pin > FIRST_LED; pin--) { // geri: 12 → 9 / back: 12 → 9
23 digitalWrite(pin, HIGH);
24 delay(80);
25 digitalWrite(pin, LOW);
26 }
27}Faire démarrer la boucle de retour à LAST_LED - 1 et la faire tourner seulement tant que la broche est supérieure à FIRST_LED est un choix délibéré : les LED des extrémités ne s'allument pas deux fois de suite et le mouvement reste fluide. Pour régler la vitesse, créer un effet de remplissage et d'autres motifs, consulte le guide chenillard et effet K2000 avec Arduino.
Les tableaux (array) : plusieurs valeurs sous un seul nom
Un tableau range plusieurs valeurs du même type, dans l'ordre, sous un seul nom. La ligne const byte LEDS[] = {8, 9, 10, 11, 12, 13}; crée un tableau de six éléments. On accède aux éléments avec des crochets, et on compte à partir de 0 : LEDS[0] vaut 8 et LEDS[5] vaut 13. La taille d'un tableau ne peut plus changer une fois défini. Si tu laisses sizeof(LEDS) / sizeof(LEDS[0]) calculer le nombre d'éléments au lieu de l'écrire à la main, tes boucles s'adaptent toutes seules quand tu ajoutes une broche au tableau. Un indice hors du tableau, comme LEDS[6], ne provoque aucune erreur ; il lit ou abîme une autre variable en mémoire. Assure-toi donc que l'indice reste entre 0 et le nombre d'éléments moins un. L'exemple ci-dessous transforme les six LED en dé électronique :
1const byte LEDS[] = {8, 9, 10, 11, 12, 13}; // LED pinleri / LED pins
2const byte LED_COUNT = sizeof(LEDS) / sizeof(LEDS[0]); // eleman sayısı: 6 / number of elements: 6
3const byte BUTTON_PIN = 2;
4
5void setup() {
6 for (byte i = 0; i < LED_COUNT; i++) { // indeks 0'dan başlar / index starts at 0
7 pinMode(LEDS[i], OUTPUT);
8 }
9 pinMode(BUTTON_PIN, INPUT_PULLUP);
10 randomSeed(analogRead(A0)); // boştaki A0'ın gürültüsüyle tohumla / seed from noise on the unconnected A0
11}
12
13void loop() {
14 if (digitalRead(BUTTON_PIN) == LOW) {
15 byte dice = random(1, 7); // 1 ile 6 arası / between 1 and 6
16 for (byte i = 0; i < LED_COUNT; i++) {
17 digitalWrite(LEDS[i], (i < dice) ? HIGH : LOW); // ilk 'dice' kadar LED yanar / the first 'dice' LEDs light up
18 }
19 delay(300); // basılı tutarsan zar dönmeye devam eder / keeps rolling while held
20 }
21}random(1, 7) produit un nombre de 1 à 6, car la borne supérieure n'est pas incluse dans le résultat. Autant de LED s'allument : si le dé donne 4, les quatre LED de LEDS[0] à LEDS[3] s'allument. La ligne randomSeed(analogRead(A0)) utilise comme valeur de départ le bruit électrique de la broche A0 laissée en l'air ; sans elle, la carte produirait la même suite de nombres à chaque mise sous tension. Autre avantage des tableaux : si tu déplaces les LED sur d'autres broches, il suffit de modifier la première ligne.
Écrire des fonctions : découper le code en morceaux
Si tu fais la même tâche à plusieurs endroits du programme, transforme-la en fonction. Une fonction se compose d'un type de retour, d'un nom, de paramètres entre parenthèses et d'un corps entre accolades. Les fonctions qui ne renvoient rien sont de type void ; celles qui renvoient une valeur la rendent avec return. Les paramètres sont passés par copie : modifier un paramètre dans la fonction ne modifie pas la variable à l'endroit de l'appel. L'Arduino IDE génère lui-même les déclarations des fonctions des fichiers .ino, tu peux donc aussi écrire une fonction sous loop(). Dans les fichiers .cpp ou avec PlatformIO, en revanche, tu dois déclarer une fonction avant de l'utiliser. Donne à tes fonctions des noms qui disent ce qu'elles font, comme blinkLed ou isPressed.
1const byte LED_PIN = 13;
2const byte BUTTON_PIN = 2;
3
4// Değer döndürmeyen (void) fonksiyon / function that returns nothing (void)
5void blinkLed(byte pin, byte times, int ms) {
6 for (byte i = 0; i < times; i++) {
7 digitalWrite(pin, HIGH);
8 delay(ms);
9 digitalWrite(pin, LOW);
10 delay(ms);
11 }
12}
13
14// bool döndüren fonksiyon / function that returns a bool
15bool isPressed(byte pin) {
16 return digitalRead(pin) == LOW; // INPUT_PULLUP: basılı = LOW / pressed = LOW
17}
18
19void setup() {
20 pinMode(LED_PIN, OUTPUT);
21 pinMode(BUTTON_PIN, INPUT_PULLUP);
22 blinkLed(LED_PIN, 3, 100); // açılışta 3 hızlı yanıp sönme / 3 quick blinks at start-up
23}
24
25void loop() {
26 if (isPressed(BUTTON_PIN)) {
27 blinkLed(LED_PIN, 2, 250); // basınca 2 yavaş yanıp sönme / 2 slow blinks per press
28 }
29}blinkLed() reçoit en paramètres la broche, le nombre de clignotements et la vitesse, tu peux donc réutiliser la même fonction pour une autre LED et une autre vitesse. isPressed() renvoie un bool et garde à un seul endroit la logique "appuyé = LOW" d'INPUT_PULLUP ; si un jour tu câbles le bouton autrement, tu ne changes que cette ligne. Le delay() à l'intérieur de la fonction bloque quand même le programme. Pour des fonctions qui font plusieurs choses à la fois, il faut une temporisation basée sur millis().
Variables globales, locales et static
L'endroit où une variable est visible s'appelle sa portée. Les variables globales, définies en dehors des fonctions, vivent pendant tout le programme et peuvent être lues et modifiées de partout. Les variables locales, définies dans une fonction ou un bloc entre accolades, sont recréées à chaque exécution de ce bloc et disparaissent à sa fin. C'est de là que vient la plainte la plus fréquente des débutants : "mon compteur reste toujours à 1". Si tu places static devant une variable locale, elle ne prend sa valeur de départ que la première fois et garde sa valeur d'un tour à l'autre, tout en restant visible uniquement dans cette fonction.
1const byte LED_PIN = 13;
2const byte BUTTON_PIN = 2;
3
4int globalCount = 0; // global: her yerden görünür, değerini korur / global: visible everywhere, keeps its value
5
6void setup() {
7 pinMode(LED_PIN, OUTPUT);
8 pinMode(BUTTON_PIN, INPUT_PULLUP);
9 Serial.begin(9600);
10}
11
12void loop() {
13 int localCount = 0; // yerel: her turda yeniden 0 olur / local: back to 0 on every pass
14 static int staticCount = 0; // static yerel: değerini korur, yalnız burada görünür / static local: keeps its value, visible only here
15
16 if (digitalRead(BUTTON_PIN) == LOW) {
17 globalCount++;
18 localCount++;
19 staticCount++;
20 Serial.print(globalCount);
21 Serial.print(' ');
22 Serial.print(localCount);
23 Serial.print(' ');
24 Serial.println(staticCount); // 3. basışta: 3 1 3 / on the 3rd press: 3 1 3
25 digitalWrite(LED_PIN, (staticCount % 2) ? HIGH : LOW);
26 delay(300);
27 }
28}Quand tu appuies trois fois sur le bouton, le moniteur série affiche les lignes 1 1 1, 2 1 2 et 3 1 3 : les compteurs global et static continuent d'augmenter, tandis que le compteur local reste toujours à 1, car il repart de 0 à chaque tour de loop(). Si tu définis une variable locale portant le même nom qu'une globale, la locale masque la globale et, dans cette fonction, tu ne touches jamais à la variable globale. Les variables globales modifiées par une fonction d'interruption (ISR) doivent en plus être déclarées volatile ; tu trouveras les détails dans le guide interruptions Arduino.
Programmer l'ESP32 avec Arduino : même langage, autres tailles
Quand tu programmes l'ESP32 avec l'Arduino IDE, tu utilises le même langage C++ et les mêmes commandes, mais il y a quelques différences. Comme l'ESP32 est un processeur 32 bits, int fait 4 octets et contient des valeurs de -2 147 483 648 à 2 147 483 647 ; le calcul 32767 + 1 de l'exemple de dépassement donne donc 32768. double fait 8 octets, analogRead() renvoie des valeurs de 0 à 4095 et les broches fonctionnent en 3,3 V. Serial.printf() permet un affichage formaté. random() utilise par défaut le générateur matériel de nombres aléatoires, la ligne randomSeed() est donc inutile. Le programme ci-dessous réunit tout ce que tu as appris dans cet article : un tableau, une fonction, switch-case et un bouton qui change de mode. Pour les caractéristiques générales de la carte, consulte qu'est-ce que l'ESP32 ?.
1// ESP32: aynı dil, farklı pinler / ESP32: same language, different pins
2const byte LEDS[] = {18, 19, 21, 22, 23, 25}; // güvenli GPIO'lar / safe GPIOs
3const byte LED_COUNT = sizeof(LEDS) / sizeof(LEDS[0]);
4const byte BUTTON_PIN = 4; // diğer bacağı GND'ye / other leg to GND
5
6byte mode = 0; // 0 kapalı, 1 yürüyen ışık, 2 hepsi yanıp söner / 0 off, 1 chaser, 2 all blink
7bool lastPressed = false;
8
9void setAll(bool on) {
10 for (byte i = 0; i < LED_COUNT; i++) {
11 digitalWrite(LEDS[i], on ? HIGH : LOW);
12 }
13}
14
15void setup() {
16 Serial.begin(115200);
17 for (byte i = 0; i < LED_COUNT; i++) {
18 pinMode(LEDS[i], OUTPUT);
19 }
20 pinMode(BUTTON_PIN, INPUT_PULLUP);
21 Serial.printf("int = %d bayt / bytes\n", (int)sizeof(int)); // ESP32'de 4 / 4 on the ESP32
22
23 int a = 32767;
24 a = a + 1;
25 Serial.println(a); // ESP32'de 32768, taşma yok / 32768 on the ESP32, no overflow
26}
27
28void loop() {
29 bool pressed = (digitalRead(BUTTON_PIN) == LOW);
30 if (pressed && !lastPressed) {
31 mode = (mode + 1) % 3; // 0 → 1 → 2 → 0
32 delay(50);
33 }
34 lastPressed = pressed;
35
36 switch (mode) {
37 case 0:
38 setAll(false);
39 break;
40 case 1: { // case içinde değişken için süslü parantez / braces for a variable inside a case
41 byte step = (millis() / 120) % LED_COUNT; // sıradaki LED / LED whose turn it is
42 for (byte i = 0; i < LED_COUNT; i++) {
43 digitalWrite(LEDS[i], (i == step) ? HIGH : LOW);
44 }
45 break;
46 }
47 case 2:
48 setAll((millis() / 300) % 2); // 300 ms'de bir hepsi / all of them every 300 ms
49 break;
50 }
51}Pour faire tourner ce programme sur un Uno, il suffit de remplacer le tableau LEDS par {8, 9, 10, 11, 12, 13}, de mettre BUTTON_PIN à 2 et de remplacer la ligne Serial.printf(), qui n'existe pas sur l'Uno, par Serial.print(). C'est exactement l'intérêt de définir les numéros de broches sous forme de constantes et de tableaux en haut du fichier. Remarque aussi que le bloc case 1 est entre accolades ; comme la variable step y est définie, ces accolades sont obligatoires sur l'ESP32.
Raspberry Pi Pico : la même logique en MicroPython
Tu peux programmer le Raspberry Pi Pico en C++ en ajoutant le paquet de cartes RP2040 à l'Arduino IDE ; le code de cet article fonctionne alors dès que tu changes les numéros de broches, et int fait là aussi 4 octets. Le Pico s'utilise toutefois le plus souvent avec MicroPython. En Python, on n'écrit pas le type des variables, les blocs sont définis par l'indentation au lieu des accolades, il n'y a pas de point-virgule en fin de ligne et les entiers ne débordent pas : ils grandissent autant que nécessaire. Le code ci-dessous est la version MicroPython du dé électronique. Pour l'installation, consulte qu'est-ce que le Raspberry Pi Pico ?, et pour les détails du langage, les bases de MicroPython.
1from machine import Pin
2import time, random
3
4leds = [Pin(n, Pin.OUT) for n in (14, 13, 12, 11, 10, 9)] # liste = dizi / list = array
5button = Pin(2, Pin.IN, Pin.PULL_UP) # basılınca 0 / reads 0 when pressed
6
7def show(count): # fonksiyon / function
8 for i, led in enumerate(leds): # for döngüsü / for loop
9 led.value(1 if i < count else 0)
10
11show(0) # setup() karşılığı: bir kez çalışır / like setup(): runs once
12while True: # loop() karşılığı / like loop()
13 if button.value() == 0: # buton basılı mı? / is the button pressed?
14 show(random.randint(1, 6)) # 1-6 arası zar at / roll a number from 1 to 6
15 time.sleep_ms(300)| Notion | Arduino (C++) | MicroPython |
|---|---|---|
| Partie exécutée une fois | setup() | Le code avant la ligne while True: |
| Partie répétée sans fin | loop() | while True: |
| Variable | int x = 5; | x = 5 |
| Constante | const int PIN = 2; | PIN = const(2) (from micropython import const) |
| Condition | if / else if / else | if / elif / else |
| Choix multiple | switch-case | Suite de if / elif |
| Boucle de comptage | for (int i = 0; i < 6; i++) | for i in range(6): |
| Tableau | byte a[] = {1, 2, 3}; | a = [1, 2, 3] |
| Fonction | void blink(int pin) { ... } | def blink(pin): |
| Logique | && || ! | and or not |
| Commentaire | // commentaire | # commentaire |
Idées de projets avec ces bases
- Feu tricolore : construis un carrefour avec bouton piéton grâce aux constantes, à delay() et à if ; le guide pas à pas se trouve dans feu tricolore avec Arduino.
- K2000 et chenillard : crée des dizaines de motifs lumineux différents avec une boucle for et un tableau.
- Dé électronique : fais passer le dé à 6 LED sur un afficheur 7 segments avec un tableau, random() et une fonction ; pour cela, consulte le guide afficheur 7 segments.
- Test de réflexes : allume une LED à un moment aléatoire et mesure avec un unsigned long et millis() la rapidité avec laquelle tu appuies sur le bouton.
- Lampe à modes : éteinte, fixe, respiration et flash depuis un seul bouton avec switch-case ; pour une version en couleur, jette un œil à utiliser une LED RGB.
- Serrure à code : range les touches appuyées dans un tableau et compare-les au code enregistré ; les détails sont dans le guide clavier matriciel avec Arduino.
Erreurs fréquentes et solutions
| Erreur | Symptôme | Solution |
|---|---|---|
| Utiliser = dans une comparaison | Le bloc if s'exécute toujours | Utilise == pour comparer |
| Mettre ; ou = sur la ligne #define | expected ')' before ';' token | Écris #define LED_PIN 13 |
| Mal écrire une commande | 'pinmode' was not declared in this scope | Fais attention aux majuscules, comme dans pinMode |
| Lettre accentuée dans un nom de variable | stray '\303' in program | N'utilise que des lettres sans accent, des chiffres et _ |
| Calculer 60 * 1000 en int | Le résultat vaut -5536 | Écris 60 * 1000L ou 60000UL |
| Stocker millis() dans un int | La temporisation déraille après 32 secondes | Utilise unsigned long |
| Division entière | 5 / 2 donne 2 | Écris 5 / 2.0 ou convertis en float |
| Oublier break à la fin d'un case | Le case suivant s'exécute aussi | Termine chaque case par break |
| Écrire en dehors d'un tableau | Valeurs aléatoires, plantages | Garde l'indice entre 0 et le nombre d'éléments - 1 |
| Déclarer un compteur en local | Le compteur reste toujours à 1 | Rends-le global ou static |
Une fois ces briques maîtrisées, l'étape suivante consiste à connaître les commandes les plus utilisées : la liste des commandes Arduino explique tout, de pinMode() à attachInterrupt(), avec des exemples. Dans l'application BlueGrays, tu trouveras aussi des projets comme le clignotement d'une LED, le contrôle d'une LED par bouton, le K2000, un feu tricolore et un dé, pas à pas avec schémas de câblage et code prêt à l'emploi, pour essayer sur un vrai circuit chaque structure apprise ici.
Questions fréquentes
Quel langage de programmation utilise Arduino ?
Le code Arduino repose sur le C++. Le cœur Arduino ajoute au langage des fonctions toutes prêtes comme pinMode(), digitalWrite() et delay(), et le code s'écrit dans des fichiers à l'extension .ino. Des cartes comme l'ESP32 et le Raspberry Pi Pico peuvent aussi se programmer en MicroPython si tu préfères.
Par où commencer pour apprendre la programmation Arduino ?
Installe d'abord l'Arduino IDE et téléverse l'exemple Blink, qui fait clignoter la LED intégrée. Essaie ensuite, dans l'ordre, setup() et loop(), les variables, if-else, les boucles, les tableaux et les fonctions, chacun avec un circuit à LED ou à bouton. Utiliser chaque nouvelle notion dans un petit projet la fait retenir bien mieux qu'une simple lecture.
Quelle est la différence entre int et long sur Arduino ?
Sur l'Arduino Uno, un int fait 2 octets et contient des nombres de -32 768 à 32 767, alors qu'un long fait 4 octets et va jusqu'à environ ±2,1 milliards. Un nombre qui dépasse cette limite repart du début sans erreur, c'est pourquoi on utilise long ou unsigned long pour de grandes valeurs comme millis(). Sur l'ESP32 et le Pico, int fait lui aussi 4 octets.
Quelle est la différence entre const et #define sur Arduino ?
Une constante définie avec const a un type, respecte la portée, et le compilateur signale une erreur si tu essaies de la modifier. #define est un remplacement de texte fait avant la compilation ; il n'a pas de type et provoque des erreurs inattendues si on le termine par un point-virgule. Pour des nombres simples, aucun des deux n'occupe de RAM, mais on préfère généralement const, plus sûr.
Quelle est la différence entre une boucle for et une boucle while sur Arduino ?
La boucle for réunit sur une ligne le départ, la condition et le pas ; on l'utilise quand on connaît le nombre de répétitions, par exemple pour allumer six LED l'une après l'autre. La boucle while ne vérifie qu'une condition et continue tant qu'elle est vraie ; elle convient aux situations de durée inconnue, comme attendre l'appui sur un bouton.
Peut-on programmer Arduino en Python ?
Les cartes 8 bits comme l'Arduino Uno ne peuvent pas exécuter Python, elles se programment donc en C++. L'ESP32 et le Raspberry Pi Pico, eux, peuvent se programmer en MicroPython. Un programme Python qui tourne sur ton ordinateur peut aussi piloter un Uno de façon indirecte en communiquant avec lui par le port série.
Projets à réaliser après cet article
Voir tous les projets
Clignotement d'une LED
Le tout premier bonjour de l'électronique : allumer et éteindre une seule LED. L'Arduino allume et éteint la LED à intervalles très courts, la lumière clignote donc rapidement. Tu vois de la façon la

Allumer une LED avec un bouton-poussoir (Push)
Comme une sonnette : la lumière reste allumée tant que tu appuies et s'éteint quand tu relâches. L'Arduino surveille le bouton en permanence ; tant qu'il est enfoncé la LED est allumée, et dès que tu

Allumer et éteindre une LED avec un bouton
Un appui et la lumière s'allume, un deuxième et elle s'éteint, exactement comme l'interrupteur de ta chambre. L'Arduino remarque chaque appui et fait passer la LED à l'état inverse, en attendant un co

Chenillard K2000 à LED
Le fameux balayage lumineux : un point de lumière glisse d'un bout à l'autre de six LED, puis revient. L'Arduino allume chaque LED un dixième de seconde avant de passer à la suivante, fait demi-tour à

Feu de circulation
Une copie miniature du feu tricolore que tu vois chaque jour dans la rue. Le rouge reste allumé deux secondes, l'orange brille un court instant, le vert reste deux secondes, puis on revient au rouge e

ESP32 Contrôle de LED avec bouton poussoir (Push)
La LED s'allume lorsque le bouton est enfoncé et s'éteint lorsqu'il est relâché. Montre comment la broche d'entrée numérique de l'ESP32 et la résistance pull-up interne sont utilisées. Grâce au mode INPUT_PULLUP, aucune résistance externe n'est nécessaire.

Raspberry Pi Pico Bouton Toggle LED (GP14 + GP2)
Bouton + LED — niveau supérieur ! 🔁 Contrairement à #155, pas besoin de maintenir le bouton. Appuie et relâche → LED allumée. Réappuie → LED éteinte (toggle). Même circuit que #155, mais grande différence de code. Apprends edge detection, state tracking et debounce.

Projet de dé électronique
Fini les dés perdus pendant les jeux de société : à chaque appui sur le bouton, un nombre au hasard de 1 à 6 s'affiche sur l'afficheur 7 segments. Chaque appui donne un seul résultat, qui s'écrit auss
Autres articles
Application BlueGrays
Réalise ce montage pas à pas sur ton téléphone
Schéma, code et liste des composants sur un seul écran. Plus de 160 projets Arduino, ESP32 et Pico à réaliser.
Scanne avec ton téléphone
Pointe l’appareil photo vers le code : la boutique d’applications de ton téléphone s’ouvre.
ou ouvre la boutique

