Bases · 20 min de lecture

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.

Carte Arduino Uno et ses broches numériques
Arduino Uno : tous les exemples de cet article utilisent un bouton-poussoir sur la broche D2 et six LED sur les broches D8–D13. Grâce à la LED intégrée sur D13, les premiers exemples ne demandent même aucun câble.

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ègleBonne écritureSi tu ne la respectes pas
Chaque instruction se termine par un point-virguledigitalWrite(13, HIGH);expected ';' before '}' token
Majuscules et minuscules comptentpinMode(13, OUTPUT);'pinmode' was not declared in this scope
Les blocs de code sont entre accoladesvoid loop() { ... }Chaque { doit avoir sa }
Commentaire sur une ligne// cette ligne ne s'exécute pasLes 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 ?.

ComposantArduino UnoESP32Raspberry Pi Pico
6 LED (chacune avec 220 Ω, cathode au GND)D8, D9, D10, D11, D12, D13GPIO 18, 19, 21, 22, 23, 25GP14, GP13, GP12, GP11, GP10, GP9
Bouton-poussoir (autre patte au GND)D2GPIO 4GP2
LED de la carteD13 (la LED marquée L)GPIO 2 (la plupart des DevKit)GP25 ("LED" sur le Pico W)
Vitesse du port série9600 bauds115200 baudsShell de Thonny
Ne branche jamais une LED sans résistance : la LED comme la broche de l'Arduino peuvent être endommagées. Si tu utilises deux pattes du même côté en plantant le bouton sur la plaque d'essai, elles sont peut-être déjà reliées à l'intérieur et le bouton se comporte comme s'il n'était jamais appuyé ; utiliser les pattes en diagonale est donc le plus sûr. Tu peux retrouver les numéros de broches de ta carte dans l'outil Pinout.

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.

Arduino (C++)
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 ç.

TypeTaille sur UnoPlage de valeursUsage typique
bool1 octettrue ou falseLa LED est-elle allumée, le bouton a-t-il été appuyé
byte1 octet0 – 255Numéro de broche, luminosité PWM
char1 octet-128 – 127Un seul caractère : 'A'
int2 octets-32 768 – 32 767Compteurs, résultat d'analogRead()
unsigned int2 octets0 – 65 535Nombres positifs uniquement
long4 octets-2 147 483 648 – 2 147 483 647Grands nombres entiers
unsigned long4 octets0 – 4 294 967 295Mesure du temps avec millis()
float4 octetsEnviron ±3,4 × 10^38, précision de 6–7 chiffresTempérature, tension, moyennes
double4 octets (identique à float sur Uno)Identique à float8 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 :

Arduino (C++)
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 codeRésultat sur UnoRésultat sur ESP32 et PicoPourquoi ?
a = 32767 + 1-3276832768int fait 2 octets sur l'Uno, 4 octets sur les autres
60 * 1000-553660000Les constantes sont d'abord calculées en int
60 * 1000L6000060000Le suffixe L fait passer le calcul en long
5 / 22.002.00La division de deux entiers donne un entier
5 / 2.02.502.50Si 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().

Dans l'Arduino IDE, ouvre Fichier > Préférences et règle les Avertissements du compilateur (Compiler warnings) sur "Plus" ou "Tous". Ainsi, quand tu écris une expression qui déborde comme 60 * 1000, le compilateur affiche l'avertissement integer overflow in expression et tu repères l'erreur avant même que le code n'arrive sur la carte.

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.

Arduino (C++)
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}
Si tu écris #define LED_PIN 13;, le point-virgule fait partie de la valeur et la ligne pinMode(LED_PIN, OUTPUT) devient pinMode(13;, OUTPUT). Le compilateur affiche expected ')' before ';' token ; la note in expansion of macro 'LED_PIN' en dessous montre que le problème apparaît là où la constante est utilisée, mais la ligne à corriger est bien celle du #define. Écrire #define LED_PIN = 13 provoque aussi une erreur : expected primary-expression before '=' token.

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 :

GroupeOpérateurSignificationExemple
Arithmétique+ - * /Les quatre opérationsx = 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 1i++;
Comparaison== != < > <= >=Le résultat est true ou falseif (x >= 10)
Logique&& || !ET, OU, NONif (a && !b)
Conditionnel? :if-else abrégéx > 0 ? HIGH : LOW
Bit à bit& | ^ ~ << >>Agit sur les bits d'un nombre1 << 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 :

Arduino (C++)
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 :

Arduino (C++)
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".

Écrire if (mode = 2) est l'erreur classique : cette ligne ne compare rien, elle affecte 2 à mode, et comme le résultat n'est pas nul, la condition est toujours vraie. Autre bug sournois : un point-virgule juste après la parenthèse, comme dans if (x == 5);. Le if se termine alors par une instruction vide et le bloc en dessous s'exécute à chaque fois, quelle que soit la condition.

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.

Arduino (C++)
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.

Si tu définis une variable dans un case, place le code de ce case entre accolades : case 1: { byte step = 3; ... break; }. Sans accolades, l'Uno compile avec un simple avertissement, mais l'ESP32 s'arrête sur l'erreur jump to case label et le code ne compile pas du tout.

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).

BoucleQuand la condition est-elle vérifiée ?Quand l'utiliser ?Exemple
forAvant chaque tourQuand le nombre de répétitions est connufor (int i = 0; i < 6; i++)
whileAvant chaque tourPour attendre qu'un événement se produisewhile (digitalRead(2) == HIGH)
do-whileAprès chaque tourQuand elle doit s'exécuter au moins une foisdo { ... } 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 :

Arduino (C++)
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.

La boucle for (byte i = 0; i < 256; i++) ne se termine jamais : un byte contient au maximum 255, donc i repasse à 0 avant d'atteindre 256 et la condition reste toujours vraie. De la même manière, une boucle while qui attend une condition qui n'arrive jamais, par exemple un capteur dont le fil s'est débranché, bloque le programme pour de bon.

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 :

Arduino (C++)
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.

Arduino (C++)
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.

Arduino (C++)
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.

Garde tes variables aussi locales que possible : static pour les compteurs dont une seule fonction a besoin, globale pour les valeurs partagées par plusieurs fonctions. La ligne Global variables use … bytes of dynamic memory affichée par l'IDE après la compilation indique la RAM occupée par tes variables globales. Sur l'Uno, un comportement instable peut apparaître au-delà de 75 pour cent ; tu trouveras des solutions dans le guide mémoire insuffisante sur 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 ?.

Arduino (C++)
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.

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)
NotionArduino (C++)MicroPython
Partie exécutée une foissetup()Le code avant la ligne while True:
Partie répétée sans finloop()while True:
Variableint x = 5;x = 5
Constanteconst int PIN = 2;PIN = const(2) (from micropython import const)
Conditionif / else if / elseif / elif / else
Choix multipleswitch-caseSuite de if / elif
Boucle de comptagefor (int i = 0; i < 6; i++)for i in range(6):
Tableaubyte a[] = {1, 2, 3};a = [1, 2, 3]
Fonctionvoid 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

ErreurSymptômeSolution
Utiliser = dans une comparaisonLe bloc if s'exécute toujoursUtilise == pour comparer
Mettre ; ou = sur la ligne #defineexpected ')' before ';' tokenÉcris #define LED_PIN 13
Mal écrire une commande'pinmode' was not declared in this scopeFais attention aux majuscules, comme dans pinMode
Lettre accentuée dans un nom de variablestray '\303' in programN'utilise que des lettres sans accent, des chiffres et _
Calculer 60 * 1000 en intLe résultat vaut -5536Écris 60 * 1000L ou 60000UL
Stocker millis() dans un intLa temporisation déraille après 32 secondesUtilise unsigned long
Division entière5 / 2 donne 2Écris 5 / 2.0 ou convertis en float
Oublier break à la fin d'un caseLe case suivant s'exécute aussiTermine chaque case par break
Écrire en dehors d'un tableauValeurs aléatoires, plantagesGarde l'indice entre 0 et le nombre d'éléments - 1
Déclarer un compteur en localLe compteur reste toujours à 1Rends-le global ou static
Quand tu obtiens une erreur de compilation, lis seulement la première ligne d'erreur et corrige-la ; la plupart des erreurs des lignes suivantes en sont des conséquences. La signification des messages est expliquée dans le guide erreurs de compilation Arduino. Si tu n'as pas de carte sous la main, tu peux aussi essayer le code dans une simulation Tinkercad.

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.

Voir tous les projets
Clignotement d'une LED
#1Débutant

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

4.6(179)
978
Allumer une LED avec un bouton-poussoir (Push)
#9Débutant

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

4.9(112)
198
Allumer et éteindre une LED avec un bouton
#10Débutant

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

4.8(100)
162
Chenillard K2000 à LED
#6Intermédiaire

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 à

4.8(104)
196
Feu de circulation
#3Débutant

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

4.8(129)
367
ESP32 Contrôle de LED avec bouton poussoir (Push)
#104Débutant

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.

4.6(36)
55
Raspberry Pi Pico Bouton Toggle LED (GP14 + GP2)
#156Débutant
Premium

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.

0.0(0)
9
Projet de dé électronique
#79Intermédiaire
Premium

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

5.0(48)
67