Comandi Arduino: elenco con sintassi, esempi ed errori comuni
Comandi Arduino spiegati: pinMode, digitalWrite, analogRead, analogWrite, millis, Serial, map, tone, pulseIn e attachInterrupt con esempi ed errori comuni.
I comandi Arduino sono funzioni già pronte che dicono alla scheda cosa fare: pinMode() trasforma un pin in uscita, digitalWrite() accende un LED, analogRead() legge un sensore e Serial.println() invia un messaggio al computer. La maggior parte degli sketch Arduino non è altro che una ventina di comandi di base combinati in modi diversi. Quando hai capito bene questi comandi e il loro significato, puoi leggere qualsiasi codice, dal LED che lampeggia alla macchina robot, e scrivere il tuo progetto da zero.
In questa guida abbiamo raccolto i comandi Arduino più usati in quattro gruppi: ingresso e uscita, tempo, matematica e comunicazione. Per ogni comando trovi la sintassi, il significato dei parametri, un breve esempio che si compila e funziona su un Arduino Uno e l'errore che i principianti fanno più spesso. Nelle ultime sezioni vedremo anche come gli stessi comandi si comportano in modo diverso sull'ESP32 e quali sono i loro equivalenti MicroPython sul Raspberry Pi Pico.

Che cos'è un comando Arduino e come viene eseguito uno sketch?
Il codice Arduino si basa sul C/C++; quasi tutto quello che chiamiamo «comandi» sono in realtà funzioni che il core Arduino ti mette a disposizione già pronte. Una funzione riceve dei parametri tra parentesi (per esempio il numero di un pin e un valore) e alcune restituiscono un risultato: digitalRead() ti dà lo stato di un pin, millis() il tempo trascorso. Ogni sketch Arduino ha due funzioni obbligatorie: setup() viene eseguita una sola volta all'accensione o al reset della scheda, poi loop() si ripete all'infinito. Le preparazioni come l'impostazione dei pin e Serial.begin() vanno in setup(), mentre ciò che deve accadere di continuo va in loop().
1// Her Arduino programı bu iki fonksiyondan oluşur / Every Arduino sketch has these two functions
2void setup() {
3 // Açılışta ya da resetten sonra bir kez çalışır / Runs once at power-up or after reset
4 pinMode(13, OUTPUT); // dahili LED pini çıkış / built-in LED pin as output
5}
6
7void loop() {
8 // Sonsuza kadar tekrar eder / Repeats forever
9 digitalWrite(13, HIGH); // LED'i yak / turn the LED on
10 delay(500); // 500 ms bekle / wait 500 ms
11 digitalWrite(13, LOW); // LED'i söndür / turn the LED off
12 delay(500);
13}Tenere a mente tre regole fin dall'inizio ti evita molti errori di compilazione: i comandi distinguono tra maiuscole e minuscole (se scrivi digitalwrite ottieni l'errore «'digitalwrite' was not declared in this scope»), ogni istruzione termina con un punto e virgola e i testi vanno tra virgolette doppie, mentre i singoli caratteri tra apici. Per i tipi di variabili e le strutture come if e for, dai un'occhiata alle basi della programmazione Arduino.
Elenco dei comandi Arduino: tabelle per categoria
Le quattro tabelle qui sotto riassumono quasi tutti i comandi che userai nei progetti di tutti i giorni. Il primo gruppo sono i comandi di ingresso e uscita: stabiliscono il ruolo di un pin, gli applicano una tensione o ne leggono un valore. I numeri dei pin della tua scheda li trovi nello strumento Pinout.
| Comando | Sintassi | A cosa serve | Esempio |
|---|---|---|---|
| pinMode | pinMode(pin, modalità) | Imposta un pin come ingresso o uscita | pinMode(13, OUTPUT); |
| digitalWrite | digitalWrite(pin, valore) | Porta un pin a HIGH (5 V) o LOW (0 V) | digitalWrite(13, HIGH); |
| digitalRead | digitalRead(pin) | Legge se un pin è HIGH o LOW | int b = digitalRead(2); |
| analogRead | analogRead(pin) | Converte una tensione di 0–5 V in un numero da 0 a 1023 | int v = analogRead(A0); |
| analogWrite | analogWrite(pin, valore) | Genera un segnale PWM da 0 a 255 | analogWrite(9, 128); |
| analogReference | analogReference(tipo) | Sceglie la tensione di riferimento di analogRead | analogReference(INTERNAL); |
| tone / noTone | tone(pin, frequenza, durata) | Produce un suono con un'onda quadra; noTone lo ferma | tone(8, 440, 500); |
| pulseIn | pulseIn(pin, valore, timeout) | Misura la durata di un impulso in µs | pulseIn(10, HIGH, 30000); |
| shiftOut | shiftOut(pinDati, pinClock, ordine, byte) | Invia un byte bit per bit (per esempio a un 74HC595) | shiftOut(11, 12, MSBFIRST, 255); |
| attachInterrupt | attachInterrupt(interrupt, funzione, modalità) | Chiama una funzione appena un pin cambia | attachInterrupt(digitalPinToInterrupt(2), say, FALLING); |
Il secondo gruppo sono i comandi di tempo. Capire la differenza tra delay(), che aspetta, e millis() e micros(), che misurano il tempo, è la chiave per scrivere uno sketch che funzioni in modo fluido.
| Comando | Sintassi | A cosa serve | Attenzione |
|---|---|---|---|
| delay | delay(ms) | Aspetta i millisecondi indicati | Durante l'attesa il programma si ferma |
| delayMicroseconds | delayMicroseconds(us) | Aspetta qualche microsecondo | Preciso tra 3 e 16383 µs |
| millis | millis() | Restituisce i millisecondi dall'avvio | unsigned long; va in overflow dopo circa 49,7 giorni |
| micros | micros() | Restituisce i microsecondi dall'avvio | Sull'Uno avanza a passi di 4 µs, overflow dopo circa 70 minuti |
Il terzo gruppo sono i comandi di matematica: servono a convertire la lettura di un sensore in un altro intervallo, a limitarla o a generare un numero casuale. Il quarto gruppo, i comandi di comunicazione, permette alla scheda di scambiare dati con il computer e con altri dispositivi.
| Comando | Sintassi | A cosa serve | Risultato di esempio |
|---|---|---|---|
| map | map(x, daMin, daMax, aMin, aMax) | Riporta un intervallo su un altro | map(512, 0, 1023, 0, 255) → 127 |
| constrain | constrain(x, minimo, massimo) | Mantiene un valore tra due limiti | constrain(300, 0, 255) → 255 |
| min / max | min(a, b) / max(a, b) | Restituisce il minore o il maggiore | min(7, 3) → 3 |
| abs | abs(x) | Valore assoluto | abs(-12) → 12 |
| pow / sqrt / sq | pow(base, esponente), sqrt(x), sq(x) | Potenza, radice quadrata, quadrato | pow(2, 10) → 1024.0 |
| random | random(min, max) | Intero casuale (max escluso) | random(1, 7) → da 1 a 6 |
| randomSeed | randomSeed(seme) | Cambia il punto di partenza della sequenza casuale | randomSeed(analogRead(A3)); |
| Comando | A cosa serve | Esempio |
|---|---|---|
| Serial.begin(velocità) | Apre la porta seriale alla velocità in baud indicata | Serial.begin(9600); |
| Serial.print(dato) | Stampa il dato e resta sulla stessa riga | Serial.print(temperatura); |
| Serial.println(dato) | Stampa il dato e va a capo | Serial.println("Ciao"); |
| Serial.available() | Restituisce il numero di byte in attesa di lettura | if (Serial.available() > 0) |
| Serial.read() | Legge un byte, restituisce -1 se non ci sono dati | char c = Serial.read(); |
| Serial.readStringUntil(c) | Legge il testo fino a un certo carattere | String s = Serial.readStringUntil('\n'); |
| Serial.parseInt() | Estrae un intero dal testo ricevuto | int n = Serial.parseInt(); |
| Serial.write(byte) | Invia un byte grezzo | Serial.write(65); // 'A' |
| Wire.begin() | Avvia il bus I2C (Wire.h) | Wire.begin(); |
| SPI.begin() | Avvia il bus SPI (SPI.h) | SPI.begin(); |
pinMode(): stabilire il ruolo di un pin
pinMode(pin, modalità) indica se un pin digitale è un ingresso o un'uscita e di solito si scrive una sola volta in setup(). Le modalità sono tre: OUTPUT rende il pin un'uscita (per pilotare un LED, un buzzer o un relè), INPUT lo rende un ingresso ad alta impedenza (per circuiti con una resistenza di pull-up o pull-down esterna) e INPUT_PULLUP lo rende un ingresso collegando a 5 V una resistenza interna di circa 20–50 kΩ. Anche i pin analogici (A0–A5) possono essere usati come pin digitali con pinMode; per esempio, pinMode(A0, OUTPUT) è un comando valido.
digitalWrite() e digitalRead(): uscita e ingresso digitale
digitalWrite(pin, HIGH) porta un pin di uscita a 5 V sull'Uno e digitalWrite(pin, LOW) lo porta a 0 V. Prelevare fino a 20 mA da un pin è sicuro (il limite assoluto è 40 mA); collega sempre il LED con una resistenza, il cui valore puoi trovare con il calcolatore della resistenza per LED. digitalRead(pin) controlla la tensione sul pin e restituisce HIGH o LOW; sull'Uno, a grandi linee, tutto ciò che supera 3 V conta come HIGH e ciò che sta sotto 1,5 V come LOW. Nell'esempio seguente il LED integrato si accende quando premi il pulsante collegato a D2:
1const int BUTON_PIN = 2; // buton: bir ucu D2, diğer ucu GND / button: one leg to D2, the other to GND
2const int LED_PIN = 13; // dahili LED / built-in LED
3
4void setup() {
5 pinMode(BUTON_PIN, INPUT_PULLUP); // dahili pull-up direnci açık / internal pull-up resistor enabled
6 pinMode(LED_PIN, OUTPUT);
7}
8
9void loop() {
10 int durum = digitalRead(BUTON_PIN); // HIGH ya da LOW döner / returns HIGH or LOW
11 if (durum == LOW) { // pull-up ile basılı = LOW / with pull-up, pressed = LOW
12 digitalWrite(LED_PIN, HIGH);
13 } else {
14 digitalWrite(LED_PIN, LOW);
15 }
16}Con INPUT_PULLUP la logica si inverte: con il pulsante rilasciato il pin legge HIGH grazie alla resistenza interna, quando lo premi legge LOW perché viene collegato a GND. Se colleghi il pulsante senza resistenza in modalità INPUT, il pin resta flottante e digitalRead() restituisce valori a caso; persino avvicinare la mano può cambiare il risultato. Per il rimbalzo del pulsante e i modi corretti di collegarlo, leggi come collegare un pulsante ad Arduino.
analogRead() e analogWrite(): lettura analogica e PWM
analogRead(pin) usa un convertitore a 10 bit (ADC) per trasformare una tensione tra 0 e 5 V sui pin A0–A5 in un numero da 0 a 1023. Una lettura richiede circa 100 µs, quindi puoi fare circa 10.000 letture al secondo. Per convertire il numero in tensione si usa valore × 5,0 / 1023; una lettura di 512, per esempio, corrisponde a circa 2,5 V. La tensione di riferimento si cambia con analogReference(): l'opzione INTERNAL usa il riferimento interno da 1,1 V dell'Uno e migliora la risoluzione con le tensioni piccole. Tutti i dettagli su risoluzione e riferimento sono in ADC e conversione analogico-digitale.
Nonostante il nome, analogWrite(pin, valore) non produce una vera tensione analogica. Accende e spegne il pin molto velocemente per creare un segnale PWM: 0 significa sempre spento, 255 sempre acceso e 127 acceso più o meno per metà del tempo. È da questa media che un LED ci appare a mezza luminosità e un motore gira lentamente. Sull'Uno solo i pin 3, 5, 6, 9, 10 e 11, segnati con ~ sulla scheda, forniscono il PWM; la frequenza è di 490 Hz sulla maggior parte dei pin e di 980 Hz sui pin 5 e 6. analogWrite() imposta da sola il pin come uscita, quindi pinMode non è obbligatorio. Il codice qui sotto regola la luminosità di un LED con un potenziometro e scrive la lettura insieme alla tensione nel Monitor seriale; per i dettagli su duty cycle e frequenza leggi Che cos'è il PWM?.
1const int POT_PIN = A0; // potansiyometrenin orta bacağı / potentiometer wiper
2const int LED_PIN = 9; // ~9 PWM pini + 220 ohm direnç / ~9 PWM pin + 220 ohm resistor
3
4void setup() {
5 Serial.begin(9600);
6}
7
8void loop() {
9 int ham = analogRead(POT_PIN); // 0-1023 arası / between 0 and 1023
10 float volt = ham * (5.0 / 1023.0); // sayıyı gerilime çevir / convert the reading to volts
11 analogWrite(LED_PIN, ham / 4); // 0-1023 -> 0-255 PWM parlaklığı / 0-1023 -> 0-255 PWM brightness
12
13 Serial.print(F("Ham / raw: "));
14 Serial.print(ham);
15 Serial.print(F(" Gerilim / voltage: "));
16 Serial.print(volt, 2); // 2 ondalık basamak / 2 decimal places
17 Serial.println(F(" V"));
18 delay(200);
19}delay(), millis() e micros(): comandi di tempo
delay(ms) aspetta i millisecondi indicati e nel frattempo nessun'altra riga di loop() viene eseguita; delay(1000) è una pausa completa di un secondo. Per attese brevi nell'ordine dei microsecondi c'è delayMicroseconds(), preciso tra 3 e 16383 µs. millis(), invece, non aspetta: restituisce il tempo trascorso dall'avvio della scheda, in millisecondi. Salva sempre il risultato in una variabile di tipo unsigned long: se usi int, sull'Uno il valore va in overflow appena supera 32.767, cioè dopo circa 33 secondi, e la temporizzazione salta. millis() torna a zero circa ogni 49,7 giorni; il metodo della sottrazione qui sotto continua a funzionare correttamente anche con questo overflow.
1const int LED_PIN = 13;
2const unsigned long ARALIK = 500; // yanıp sönme aralığı (ms) / blink interval (ms)
3unsigned long oncekiZaman = 0; // son değişim anı / time of the last toggle
4
5void setup() {
6 pinMode(LED_PIN, OUTPUT);
7}
8
9void loop() {
10 unsigned long simdi = millis();
11 if (simdi - oncekiZaman >= ARALIK) { // taşmada da doğru çalışır / safe across overflow
12 oncekiZaman = simdi;
13 digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // LED'i tersine çevir / toggle the LED
14 }
15 // Burada buton, sensör ve ekran işleri de yapılabilir / button, sensor and display tasks can run here
16}Con questo schema loop() non si ferma mai: mentre il LED continua a lampeggiare puoi leggere un pulsante, misurare un sensore e aggiornare un display nello stesso ciclo. micros() funziona allo stesso modo in microsecondi; sull'Uno avanza a passi di 4 µs e va in overflow dopo circa 70 minuti. Spieghiamo in dettaglio come eseguire più attività insieme in Arduino millis() invece di delay().
Serial.begin(), Serial.print() e Serial.read(): comunicazione seriale
I comandi Serial permettono ad Arduino di parlare con il computer tramite il cavo USB e sono il tuo strumento di debug più importante. Serial.begin(9600) apre la porta seriale a 9600 bit al secondo; se la velocità del Monitor seriale non coincide, vedrai caratteri strani sullo schermo. Serial.print() stampa il dato e resta sulla stessa riga, mentre Serial.println() va a capo dopo la stampa. Con un secondo parametro scegli il formato: Serial.print(78, HEX) stampa «4E», Serial.print(78, BIN) stampa «1001110» e Serial.print(3.14159, 3) mostra «3.142» (i numeri decimali hanno per impostazione predefinita 2 cifre dopo la virgola). Scrivere i testi fissi dentro F("...") fa risparmiare spazio nei 2 KB di RAM dell'Uno.
Per leggere dati, prima controlli con Serial.available() se ci sono byte in attesa nel buffer; il buffer di ricezione dell'Uno è di 64 byte. Serial.read() prende un solo byte da questo buffer e restituisce -1 se non c'è niente da leggere. Il codice seguente accende e spegne il LED con i caratteri 1 e 0 che invii dal Monitor seriale:
1const int LED_PIN = 13;
2
3void setup() {
4 Serial.begin(9600); // Seri Monitör de 9600 olmalı / Serial Monitor must be 9600 too
5 pinMode(LED_PIN, OUTPUT);
6 Serial.println(F("1: LED açık / on, 0: LED kapalı / off"));
7}
8
9void loop() {
10 if (Serial.available() > 0) { // tamponda bayt var mı? / any bytes waiting?
11 char c = Serial.read(); // ilk baytı al / read the first byte
12 if (c == '1') { // '1' karakteri, 1 sayısı değil / the character '1', not the number 1
13 digitalWrite(LED_PIN, HIGH);
14 Serial.println(F("LED açık / on"));
15 } else if (c == '0') {
16 digitalWrite(LED_PIN, LOW);
17 Serial.println(F("LED kapalı / off"));
18 }
19 // '\n' ve '\r' gibi diğer karakterler atlanır / other characters such as '\n' and '\r' are ignored
20 }
21}Nota che il confronto si fa con '1' (tra apici, quindi un carattere): l'1 che digiti sulla tastiera corrisponde al numero 49 nella tabella ASCII, per questo la condizione c == 1 non è mai vera. Per numeri di più cifre puoi usare Serial.parseInt(), e per leggere una riga intera Serial.readStringUntil('\n'). Per le impostazioni di fine riga del Monitor seriale, la velocità in baud e il Plotter seriale, leggi come usare il Monitor seriale di Arduino.
map() e constrain(): riscalare e limitare i valori
map(valore, daMin, daMax, aMin, aMax) sposta un numero da un intervallo a un altro in modo proporzionale. La formula che c'è dietro è: (x − daMin) × (aMax − aMin) / (daMax − daMin) + aMin. Per esempio, map(512, 0, 1023, 0, 255) restituisce 127 e non 127,6, perché map() lavora solo con numeri interi e scarta la parte decimale. Invertendo l'intervallo di destinazione ottieni una relazione inversa: map(x, 0, 1023, 255, 0). map() non limita il risultato; se l'ingresso esce dall'intervallo indicato, anche l'uscita ne esce. Per questo di solito si usa insieme a constrain(x, minimo, massimo).
1const int LDR_PIN = A0; // LDR + 10k gerilim bölücü / LDR + 10k voltage divider
2const int LED_PIN = 9; // ~9 PWM pini / ~9 PWM pin
3
4void setup() {
5 pinMode(LED_PIN, OUTPUT);
6}
7
8void loop() {
9 int isik = analogRead(LDR_PIN); // odada ölçülen aralık ~200-800 / measured range in the room ~200-800
10 int pwm = map(isik, 200, 800, 255, 0); // karanlıkta parlak, aydınlıkta sönük / bright in the dark, dim in the light
11 pwm = constrain(pwm, 0, 255); // aralık dışı değerleri kes / clip out-of-range values
12 analogWrite(LED_PIN, pwm);
13 delay(20);
14}In questo esempio l'LDR dà valori tra 200 e 800 nella stanza. Se di notte la lettura scende a 100, map() calcola 297; senza constrain(), analogWrite() riceverebbe questo valore fuori dall'intervallo 0–255. Sull'Uno un valore del genere dà risultati diversi e inattesi a seconda del pin: sui pin 3, 5, 6 e 11, che usano timer a 8 bit, 297 va in overflow e si comporta come 41, quindi il LED quasi si spegne al buio completo invece di brillare al massimo. Dato che constrain(), min(), max() e abs() sull'Uno sono definite come macro, non mettere x++ né altre chiamate di funzione tra le parentesi: l'espressione può essere valutata più volte e dare risultati inattesi. Per il collegamento dell'LDR leggi sensore di luce LDR.
tone() e noTone(): produrre suoni con un buzzer
tone(pin, frequenza, durata) genera su un pin un'onda quadra con duty cycle del 50% e fa suonare a quella frequenza un buzzer passivo o un piccolo altoparlante. La durata è in millisecondi ed è facoltativa; senza di essa il suono continua finché non chiami noTone(pin). Un dettaglio importante: tone() non aspetta, avvia il suono e passa subito alla riga successiva. Per suonare note una dopo l'altra ti serve quindi, dopo ogni chiamata a tone(), un delay() lungo almeno quanto la nota, altrimenti sentirai solo l'ultima.
1const int BUZZER_PIN = 8; // pasif buzzer'ın + ucu / passive buzzer + leg
2
3void setup() {
4 int notalar[] = {262, 294, 330, 349, 392}; // Do Re Mi Fa Sol (Hz) / C D E F G (Hz)
5 for (int i = 0; i < 5; i++) {
6 tone(BUZZER_PIN, notalar[i], 200); // 200 ms çal / play for 200 ms
7 delay(250); // tone() beklemez, sen bekle / tone() does not wait, so you do
8 }
9 noTone(BUZZER_PIN); // sesi kapat / stop the sound
10}
11
12void loop() {
13}- Limiti di frequenza: Sull'Uno non si possono generare toni sotto i 31 Hz e il limite superiore è 65.535 Hz; con un buzzer l'intervallo utile va all'incirca da 100 a 5000 Hz.
- Un suono alla volta: Solo un pin alla volta può emettere un tono; per suonare su un altro pin devi prima fermare quello precedente con noTone().
- Conflitto con il PWM: Sull'Uno tone() usa il Timer2, quindi mentre suona analogWrite() sui pin 3 e 11 non funziona correttamente.
- Buzzer attivo: Avendo un oscillatore proprio, la sua frequenza non si può cambiare con tone(); basta accenderlo e spegnerlo con digitalWrite(). Le differenze sono spiegate in Che cos'è un buzzer?.
pulseIn(): misurare la durata di un impulso
pulseIn(pin, HIGH) aspetta che il pin diventi HIGH, misura per quanto tempo resta HIGH e restituisce il risultato in microsecondi; può misurare impulsi da 10 µs a 3 minuti. L'uso più noto è il sensore di distanza a ultrasuoni HC-SR04: il sensore fornisce un impulso lungo quanto il tempo che il suono impiega ad andare e tornare. Il suono viaggia nell'aria a circa 343 m/s, cioè 0,0343 cm/µs; dato che il percorso è di andata e ritorno, distanza = durata × 0,0343 / 2.
1const int TRIG_PIN = 9;
2const int ECHO_PIN = 10;
3
4void setup() {
5 Serial.begin(9600);
6 pinMode(TRIG_PIN, OUTPUT);
7 pinMode(ECHO_PIN, INPUT);
8}
9
10void loop() {
11 digitalWrite(TRIG_PIN, LOW);
12 delayMicroseconds(2);
13 digitalWrite(TRIG_PIN, HIGH); // 10 µs tetik darbesi / 10 µs trigger pulse
14 delayMicroseconds(10);
15 digitalWrite(TRIG_PIN, LOW);
16
17 unsigned long sure = pulseIn(ECHO_PIN, HIGH, 30000UL); // en fazla 30 ms bekle / wait at most 30 ms
18 if (sure == 0) {
19 Serial.println(F("Menzil dışı / out of range"));
20 } else {
21 float mesafe = sure * 0.0343 / 2.0; // ses hızı 343 m/s, gidiş-dönüş / speed of sound 343 m/s, round trip
22 Serial.print(mesafe, 1);
23 Serial.println(F(" cm"));
24 }
25 delay(100);
26}Il terzo parametro, il timeout, è molto importante. Se manca, pulseIn() aspetta 1 secondo quando non arriva nessun impulso e restituisce 0; se il cavo del sensore si stacca, l'intero programma si blocca per un secondo a ogni ciclo. Un timeout di 30000 µs corrisponde a circa 5 metri, sufficienti per i 4 metri di portata dell'HC-SR04. Per il collegamento e la precisione del sensore leggi sensore di distanza HC-SR04.
attachInterrupt(): reagire all'istante con gli interrupt
attachInterrupt(digitalPinToInterrupt(pin), funzione, modalità) esegue la funzione indicata nell'istante in cui un pin cambia, qualunque cosa stia facendo loop() in quel momento. Questa funzione si chiama routine di servizio dell'interrupt (ISR). La modalità può assumere quattro valori: RISING scatta nel passaggio da LOW a HIGH, FALLING nel passaggio da HIGH a LOW, CHANGE a ogni cambiamento e LOW finché il pin resta LOW. Su Uno e Nano solo i pin D2 e D3 possono generare interrupt in questo modo; sul Mega si possono usare i pin 2, 3, 18, 19, 20 e 21. È l'ideale per non perdere un encoder che gira veloce, gli impulsi di un anemometro o una pressione molto breve del pulsante.
1const int BUTON_PIN = 2; // Uno'da kesme pinleri: 2 ve 3 / interrupt pins on the Uno: 2 and 3
2volatile unsigned long sayac = 0; // ISR'de değişen değişken volatile olmalı / variables changed in an ISR must be volatile
3
4void say() { // kesme fonksiyonu (ISR): kısa tut / interrupt service routine: keep it short
5 sayac++;
6}
7
8void setup() {
9 Serial.begin(9600);
10 pinMode(BUTON_PIN, INPUT_PULLUP);
11 attachInterrupt(digitalPinToInterrupt(BUTON_PIN), say, FALLING); // HIGH'dan LOW'a geçişte / on a HIGH-to-LOW edge
12}
13
14void loop() {
15 noInterrupts(); // 4 baytlık değeri güvenle kopyala / copy the 4-byte value safely
16 unsigned long kopya = sayac;
17 interrupts();
18
19 Serial.print(F("Basma sayısı / presses: "));
20 Serial.println(kopya);
21 delay(500);
22}random() e randomSeed(): generare numeri casuali
random(max) restituisce un intero casuale tra 0 e max−1, e random(min, max) uno tra min e max−1; il limite superiore non è compreso nel risultato. Per questo, per un dado da 1 a 6 si scrive random(1, 7). Arduino non produce una vera casualità: calcola una sequenza di numeri con una formula fissa, quindi se non chiami randomSeed() vedrai gli stessi numeri nello stesso ordine a ogni avvio della scheda. Usare come seme il rumore di un pin analogico non collegato risolve il problema nella pratica:
1void setup() {
2 Serial.begin(9600);
3 randomSeed(analogRead(A3)); // boştaki A3 pininin gürültüsü / noise from the unconnected A3 pin
4}
5
6void loop() {
7 int zar = random(1, 7); // 1-6 arası; üst sınır dahil değil / 1 to 6; the upper bound is exclusive
8 Serial.print(F("Zar / dice: "));
9 Serial.println(zar);
10 delay(1000);
11}Comandi Arduino sull'ESP32: a cosa fare attenzione
L'ESP32 si programma nell'IDE Arduino con gli stessi comandi, e la maggior parte del codice di questo articolo funziona subito cambiando i numeri dei pin. Ma dato che l'hardware è diverso, alcuni comandi si comportano in un altro modo. La differenza più importante è la tensione: i pin dell'ESP32 lavorano a 3,3 V, digitalWrite(pin, HIGH) fornisce 3,3 V e non bisogna collegare segnali a 5 V direttamente ai pin. Per conoscere meglio la scheda leggi Che cos'è l'ESP32?.
| Comando | Arduino Uno | ESP32 |
|---|---|---|
| digitalWrite(pin, HIGH) | 5 V | 3,3 V |
| analogRead() | 10 bit, 0–1023, A0–A5 | 12 bit, 0–4095; con il Wi-Fi attivo solo i pin ADC1 (GPIO 32–39) |
| analogWrite() | Solo i pin ~ (3, 5, 6, 9, 10, 11), 490/980 Hz | Quasi ogni GPIO in grado di fare da uscita; frequenza con ledcAttach(pin, frequenza, risoluzione) |
| attachInterrupt() | Solo D2 e D3 | Tutti i GPIO; alla ISR si aggiunge IRAM_ATTR |
| tone() | Usa il Timer2 e disturba il PWM su 3 e 11 | Funziona con l'hardware LEDC |
| Serial.begin() | Di solito 9600 | Di solito 115200 (anche i messaggi di avvio usano questa velocità) |
| delay() | Tiene il processore completamente in attesa | Cede il tempo a FreeRTOS; il Wi-Fi continua a funzionare in background |
1const int POT_PIN = 34; // ADC1 pini, Wi-Fi açıkken de okur / ADC1 pin, works with Wi-Fi on
2const int LED_PIN = 2; // çoğu DevKit'te dahili LED / onboard LED on most DevKits
3const int BUTON_PIN = 4; // butonun diğer ucu GND / other button leg to GND
4
5volatile bool basildi = false;
6
7void IRAM_ATTR butonISR() { // ESP32'de ISR IRAM'e yerleşmeli / on the ESP32 the ISR should live in IRAM
8 basildi = true;
9}
10
11void setup() {
12 Serial.begin(115200);
13 pinMode(BUTON_PIN, INPUT_PULLUP);
14 attachInterrupt(digitalPinToInterrupt(BUTON_PIN), butonISR, FALLING); // her GPIO kesme destekler / every GPIO supports interrupts
15}
16
17void loop() {
18 int ham = analogRead(POT_PIN); // 0-4095 (12 bit)
19 analogWrite(LED_PIN, map(ham, 0, 4095, 0, 255)); // 8 bit PWM / 8-bit PWM
20 if (basildi) {
21 basildi = false;
22 Serial.println("Butona basıldı / button pressed");
23 }
24 Serial.println(ham);
25 delay(200);
26}Poiché sull'ESP32 analogRead() restituisce valori da 0 a 4095, anche l'intervallo di map() cambia di conseguenza. IRAM_ATTR davanti alla ISR colloca il codice nella memoria interna veloce; se manca, in alcune situazioni la scheda può riavviarsi con un «Guru Meditation Error». Le letture analogiche dell'ESP32 non sono lineari vicino agli estremi (intorno a 0 V e a 3,3 V); se ti serve una misura più precisa, la funzione analogReadMilliVolts() restituisce un valore calibrato in millivolt.
Raspberry Pi Pico: gli equivalenti MicroPython dei comandi Arduino
Se programmi il Raspberry Pi Pico con l'IDE Arduino (core arduino-pico), tutti i comandi di questo articolo funzionano con lo stesso nome; analogRead() restituisce 10 bit per impostazione predefinita e analogWrite() genera un PWM a 1 kHz. Il Pico però si usa soprattutto con MicroPython. Lì i comandi si scrivono con oggetti dei moduli machine e time; la logica è la stessa, cambia solo la sintassi. Anche i pin del Pico lavorano a 3,3 V e gli ingressi analogici sono i pin GP26, GP27 e GP28. Per cominciare leggi Che cos'è il Raspberry Pi Pico?.
| Comando Arduino | Equivalente MicroPython | Nota |
|---|---|---|
| pinMode(15, OUTPUT) | led = Pin(15, Pin.OUT) | L'oggetto Pin si crea una volta sola |
| pinMode(14, INPUT_PULLUP) | btn = Pin(14, Pin.IN, Pin.PULL_UP) | Resistenza di pull-up interna |
| digitalWrite(15, HIGH) | led.value(1) | Va bene anche led.on() |
| digitalRead(14) | btn.value() | Restituisce 0 o 1 |
| analogRead(A0) | ADC(26).read_u16() | Restituisce da 0 a 65535 |
| analogWrite(15, 128) | PWM(Pin(15)).duty_u16(32768) | Duty cycle da 0 a 65535 |
| delay(500) | time.sleep_ms(500) | Va bene anche time.sleep(0.5) |
| millis() | time.ticks_ms() | Per le differenze, time.ticks_diff() |
| Serial.println(x) | print(x) | Compare nella shell di Thonny |
| tone(pin, 440) | pwm.freq(440) e pwm.duty_u16(32768) | Per zittirlo, duty_u16(0) |
| pulseIn(pin, HIGH, 30000) | machine.time_pulse_us(pin, 1, 30000) | In caso di timeout restituisce un valore negativo |
| attachInterrupt(...) | btn.irq(trigger=Pin.IRQ_FALLING, handler=f) | f riceve l'oggetto pin come parametro |
| random(1, 7) | random.randint(1, 6) | Il limite superiore è compreso |
| map() / constrain() | Non sono incluse, le scrivi tu | Per constrain: min(max(x, 0), 255) |
1from machine import Pin, ADC, PWM
2import time
3
4led = PWM(Pin(15)) # pinMode + analogWrite karşılığı / pinMode + analogWrite equivalent
5led.freq(1000) # 1 kHz PWM
6buton = Pin(14, Pin.IN, Pin.PULL_UP) # INPUT_PULLUP karşılığı / INPUT_PULLUP equivalent
7pot = ADC(26) # GP26 = ADC0
8
9def map_deger(x, giris_min, giris_max, cikis_min, cikis_max): # Arduino map() karşılığı / Arduino map() equivalent
10 return (x - giris_min) * (cikis_max - cikis_min) // (giris_max - giris_min) + cikis_min
11
12onceki = time.ticks_ms() # millis() karşılığı / millis() equivalent
13while True:
14 ham = pot.read_u16() # 0-65535 (analogRead)
15 led.duty_u16(ham) # parlaklık / brightness (analogWrite)
16 if buton.value() == 0: # digitalRead; basılı = 0 / pressed = 0
17 print("Butona basıldı / button pressed")
18 if time.ticks_diff(time.ticks_ms(), onceki) >= 1000: # saniyede bir / once a second
19 onceki = time.ticks_ms()
20 print("Yüzde / percent:", map_deger(ham, 0, 65535, 0, 100))
21 time.sleep_ms(50) # delay(50)Come vedi nella tabella, in MicroPython random.randint(1, 6) comprende il limite superiore e dà lo stesso risultato di random(1, 7) su Arduino; time.ticks_diff() garantisce la stessa sicurezza contro l'overflow della sottrazione con millis(). Sono proprio queste piccole differenze a creare più confusione quando si passa da una piattaforma all'altra. Per gli altri comandi di base di MicroPython dai un'occhiata alle basi di MicroPython.
Idee di progetto con questi comandi
- Semaforo: Accendi tre LED in sequenza con pinMode(), digitalWrite() e delay(); lo spieghiamo passo passo in semaforo con Arduino.
- Dado elettronico: Genera un numero da 1 a 6 con random() e, quando premi il pulsante, mostra il risultato con i LED o su un display a 7 segmenti.
- Sensore di parcheggio: Misura la distanza con pulseIn(), trasformala in un intervallo di bip con map() ed emetti un avviso sonoro con tone().
- Luce notturna automatica: Leggi la luce con analogRead() e regola la luminosità di analogWrite() con map() e constrain().
- Telecomando via porta seriale: Controlla un LED, un relè o un servomotore con i comandi inviati dal computer tramite Serial.read().
- Test dei riflessi: Accendi un LED in un momento casuale con random() e misura il tuo tempo di reazione al millisecondo con attachInterrupt() e millis().
Errori comuni e come risolverli
| Errore | Sintomo | Soluzione |
|---|---|---|
| pinMode() dimenticato | Il LED è molto fioco o non si accende | Scrivi pinMode(pin, OUTPUT) in setup() |
| Pulsante senza resistenza in modalità INPUT | digitalRead() restituisce 0 e 1 a caso | Usa INPUT_PULLUP; premuto si legge LOW |
| Errore di battitura nel nome del comando | 'digitalwrite' was not declared in this scope | Attenzione a maiuscole e minuscole: digitalWrite |
| Velocità in baud diversa | Caratteri strani nel Monitor seriale | Imposta il Monitor seriale alla stessa velocità di Serial.begin() |
| analogWrite() su un pin senza PWM | Il LED è solo acceso al massimo o spento | Usa un pin segnato con ~ (3, 5, 6, 9, 10, 11) |
| millis() salvato in un int | La temporizzazione salta dopo circa 33 secondi | Usa unsigned long |
| Dado con random(1, 6) | Il 6 non esce mai | Scrivi random(1, 7); il limite superiore è escluso |
| Aspettarsi decimali da map() | Il risultato è sempre intero e le piccole variazioni si perdono | Se serve, scrivi una tua formula con float |
| pulseIn() senza timeout | Senza sensore ogni ciclo si blocca per 1 secondo | Passa 30000 come terzo parametro |
| delay() o Serial dentro una ISR | Il programma si blocca o si comporta in modo strano | Nella ISR cambia solo un flag volatile |
I comandi di questo articolo sono i mattoni della maggior parte dei progetti che realizzerai con Arduino; il resto sono per lo più funzioni aggiuntive fornite dalle librerie. Provare ogni comando una volta nel suo piccolo circuito e vedere il risultato nel Monitor seriale ti fa imparare molto meglio che studiarli a memoria. Nell'app BlueGrays trovi, passo passo e con schemi elettrici e codice commentato, progetti che usano questi comandi, come accendere un LED, controllare un LED con un pulsante, misurare la luce con un LDR, regolare la frequenza di un buzzer, misurare la distanza con l'HC-SR04 e un progetto del dado.
Domande frequenti
Quali sono i comandi Arduino più usati?
I più frequenti sono pinMode(), digitalWrite(), digitalRead(), analogRead(), analogWrite(), delay(), millis(), Serial.begin() e Serial.println(). Se aggiungi map() per riscalare i valori, tone() per i suoni, pulseIn() per i sensori di distanza e attachInterrupt() per gli interrupt, puoi scrivere quasi tutti i tuoi progetti da principiante.
In che linguaggio si scrivono i comandi Arduino?
Il codice Arduino si basa su C e C++; il core Arduino aggiunge al linguaggio funzioni già pronte come pinMode() e digitalWrite(). I comandi sono in inglese, distinguono tra maiuscole e minuscole e ogni istruzione termina con un punto e virgola. ESP32 e Raspberry Pi Pico, se preferisci, si possono programmare anche in MicroPython.
Che differenza c'è tra digitalWrite e analogWrite?
digitalWrite() porta un pin in uno di due soli stati: HIGH (5 V sull'Uno) o LOW (0 V). analogWrite() accende e spegne il pin molto velocemente per creare un segnale PWM da 0 a 255, con cui puoi regolare la luminosità di un LED o la velocità di un motore. Sull'Uno analogWrite() funziona solo sui pin segnati con ~.
Cosa significano void setup e void loop?
setup() è la funzione che viene eseguita una volta all'accensione o al reset della scheda; qui vanno le preparazioni come pinMode() e Serial.begin(). loop() è la funzione che si ripete all'infinito dopo la fine di setup(). Il void davanti indica che queste funzioni non restituiscono alcun valore.
Che differenza c'è tra Serial.print e Serial.println?
Serial.print() stampa il dato e lascia il cursore sulla stessa riga, così il dato successivo compare subito accanto. Serial.println() dopo la stampa invia i caratteri di fine riga (\r\n), quindi il dato successivo inizia su una nuova riga. Per mostrare più valori affiancati su una riga si usa prima print() e alla fine println().
A cosa serve la funzione map di Arduino?
map() converte un numero da un intervallo a un altro in modo proporzionale; per esempio trasforma il valore 0–1023 di analogRead() nell'intervallo 0–255 per analogWrite() o in 0–180 gradi per un servo. Lavora solo con interi e non limita il risultato, quindi è consigliabile usarla insieme a constrain() per gestire gli ingressi fuori intervallo.
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
LED lampeggiante
Progetto di input di base che accende e spegne un singolo LED a determinati intervalli con Arduino. Insegna l'uso delle funzioni digitalWrite e delay.

Accendere un LED con un pulsante (Push)
Progetto di controllo istantaneo (push) che accende il LED quando il pulsante viene premuto e lo spegne quando viene rilasciato. Insegna l'uso della lettura dei pulsanti e dell'espressione condizional

Misurare l'intensità luminosa con LDR
Progetto che misura l'intensità della luce ambientale con un sensore LDR e la visualizza su un monitor seriale. Insegna le basi della lettura dei sensori analogici e della comunicazione seriale.

Impostazione della frequenza con cicalino
Progetto interattivo con 4 pulsanti che possono aumentare e diminuire la frequenza del cicalino, accenderlo e spegnerlo. Insegna la lettura multipla dei pulsanti e il controllo variabile.

HC-SR04 Misura della distanza (display seriale)
Il sensore a ultrasuoni HC-SR04 misura la distanza e visualizza il risultato in cm sul monitor seriale. Insegna il principio del calcolo della distanza con l'onda sonora.

Effetto Supercar a velocità regolabile
Progetto con potenziometro in grado di regolare in tempo reale la velocità dell'animazione LED Supercar. Combina ingresso analogico e controllo bidirezionale ad anello.

Funzionamento del servomotore con potenziometro
Progetto che controlla il servomotore in tempo reale convertendo il valore del potenziometro nell'intervallo 0-180°. insegna la funzione map() e l'integrazione analogico-servo.

Progetto Dadi
Progetto di dado che genera un numero casuale tra 1 e 6 a ogni pressione del pulsante e lo visualizza su un display a 7 segmenti. Grazie al meccanismo di rimbalzo, viene prodotto un unico risultato co

