Programmazione Arduino: guida completa agli sketch
Una guida pratica per imparare a programmare Arduino partendo dalle basi: struttura di uno sketch, variabili, condizioni, cicli, operatori, input e output, comunicazione seriale, gestione del tempo e principali funzioni del linguaggio.
Non è necessario imparare tutto a memoria. Il modo migliore per apprendere la programmazione Arduino è leggere i concetti fondamentali e metterli subito in pratica modificando piccoli sketch già funzionanti.
- Introduzione alla programmazione Arduino
- Come si progetta un programma
- Struttura di uno sketch Arduino
- Ortografia, grammatica e sintassi
- Parole chiave
- Variabili e array
- Istruzioni di controllo
- Operatori
- Librerie e funzioni
- Funzioni di input e output
- Comunicazione seriale
- Funzioni di tempo
- Funzioni matematiche
- Numeri casuali
- Riepilogo finale
🧠 Introduzione alla programmazione Arduino
Un programma Arduino viene comunemente chiamato sketch.
Lo sketch contiene tutte le istruzioni che il microcontrollore deve eseguire per leggere sensori, prendere decisioni e controllare dispositivi come LED, relè, motori, display e moduli di comunicazione.
Arduino utilizza un ambiente di programmazione basato sul C/C++, arricchito da funzioni e librerie che rendono molto più semplice l’utilizzo dell’hardware.
Nelle vecchie guide si trova spesso il termine Wiring per indicare il linguaggio di Arduino. Storicamente Wiring ha avuto un ruolo importante nello sviluppo dell’ambiente Arduino, ma oggi per un tutorial moderno è più corretto parlare di C/C++ e delle API Arduino.
Per scrivere e caricare gli sketch è possibile utilizzare Arduino IDE 2.
Nell’IDE possiamo:
- scrivere il codice;
- controllarne la sintassi;
- compilarlo;
- caricarlo sulla scheda;
- visualizzare dati tramite Monitor Seriale;
- installare librerie e supporto per nuove schede.
Puoi approfondire l’uso dell’ambiente di sviluppo nella nostra guida:
👉 Guida ad Arduino IDE e agli sketch
Parti da programmi molto semplici, come Blink. Leggi il codice, caricalo sulla scheda, modifica un valore, osserva cosa cambia e ripeti l’esperimento. È molto più efficace della sola memorizzazione teorica.
🧩 Come si progetta un programma
Un programma è una sequenza di istruzioni che il microcontrollore esegue secondo una logica precisa.
Prima di iniziare a scrivere codice è utile dividere il problema in piccoli blocchi.
1. Acquisizione dei dati
Determina quali informazioni devono essere lette.
Ad esempio:
- temperatura;
- distanza;
- pressione di un pulsante;
- luminosità;
- movimento.
2. Elaborazione e decisione
Una volta ottenuti i dati bisogna stabilire cosa deve fare Arduino.
Ad esempio:
if (temperatura > 30) {
// attiva la ventola
}
3. Controllo degli attuatori
Infine Arduino può agire su uno o più dispositivi:
- LED;
- buzzer;
- motori;
- servo;
- relè;
- display.
Esempio: misurare una distanza
Consideriamo un sensore HC-SR04 con:
- TRIG collegato al pin 2;
- ECHO collegato al pin 3;
- VCC a 5V;
- GND a GND.
float cm = 0;
void misurazioneDistanza() {
digitalWrite(2, LOW);
delayMicroseconds(2);
digitalWrite(2, HIGH);
delayMicroseconds(10);
digitalWrite(2, LOW);
cm = pulseIn(3, HIGH) / 58.0;
}
void comunicazioneDistanza() {
Serial.print(cm);
Serial.println(" cm");
}
void setup() {
Serial.begin(9600);
pinMode(2, OUTPUT);
pinMode(3, INPUT);
}
void loop() {
misurazioneDistanza();
comunicazioneDistanza();
delay(2000);
}
Anche senza conoscere ogni istruzione, possiamo già riconoscere:
- una variabile;
- due funzioni personalizzate;
setup();loop();- commenti;
- parentesi graffe che delimitano i blocchi.
🏗️ Struttura di uno sketch Arduino
Quasi ogni programma Arduino contiene almeno due funzioni fondamentali:
- setup()
- loop()
// Dichiarazioni globali
void setup() {
// istruzioni eseguite una sola volta
}
void loop() {
// istruzioni ripetute continuamente
}
void setup()
Viene eseguito una sola volta, quando Arduino viene acceso o resettato.
Viene normalmente utilizzato per:
- configurare i pin;
- avviare la comunicazione seriale;
- inizializzare display e sensori;
- impostare lo stato iniziale del sistema.
void loop()
Dopo aver completato setup(),
Arduino esegue loop()
continuamente finché la scheda rimane alimentata.
✍️ Ortografia, grammatica e sintassi
Il compilatore richiede una sintassi precisa. Anche un piccolo errore può impedire la compilazione.
Punto e virgola
Molte istruzioni terminano con:
;
Esempio:
int led = 13;
digitalWrite(led, HIGH);
Parentesi graffe
Le parentesi:
{
}
delimitano un blocco di istruzioni.
Commenti
Commento su una sola riga:
// questo è un commento
Commento su più righe:
/*
Questo è
un commento
multiriga
*/
Usa l’indentazione e i commenti. Un programma ben formattato è molto più facile da leggere, correggere e modificare anche dopo mesi.
🔑 Parole chiave fondamentali
| Parola | Significato |
|---|---|
HIGH |
Livello logico alto. |
LOW |
Livello logico basso. |
INPUT |
Configura un pin come ingresso. |
OUTPUT |
Configura un pin come uscita. |
INPUT_PULLUP |
Ingresso con resistenza pull-up interna attiva. |
true |
Valore booleano vero. |
false |
Valore booleano falso. |
📦 Variabili
Una variabile è un’area di memoria utilizzata per memorizzare un valore.
Esempio:
int temperatura = 25;
In questo caso:
intè il tipo;temperaturaè il nome;25è il valore iniziale.
Tipi di dato comuni
| Tipo | Utilizzo tipico |
|---|---|
bool |
Vero/falso. |
byte |
Interi piccoli senza segno. |
char |
Caratteri. |
int |
Numeri interi. |
unsigned int |
Interi senza segno. |
long |
Interi più grandi. |
unsigned long |
Valori positivi grandi, molto usato con millis(). |
float |
Numeri con parte decimale. |
Le dimensioni di alcuni tipi, come int,
possono cambiare passando da Arduino UNO
ad altre famiglie di microcontrollori.
Evita quindi di considerare universali
le dimensioni tipiche dell’ATmega328P.
Variabili globali e locali
Una variabile dichiarata fuori dalle funzioni può essere utilizzata in più parti dello sketch.
int led = 13;
void setup() {
}
void loop() {
}
Una variabile dichiarata dentro una funzione è invece normalmente visibile solo all’interno del relativo blocco.
Array
Un array raccoglie più elementi dello stesso tipo.
int valori[4] = {10, 25, 50, 100};
L’indice parte da 0.
valori[0]→ 10valori[1]→ 25valori[2]→ 50valori[3]→ 100
#define e const
Possiamo creare una costante simbolica con:
#define LED_PIN 5
In molti casi moderni è però preferibile utilizzare una costante tipizzata:
const int LED_PIN = 5;
🔀 Istruzioni di controllo
if
Esegue un blocco soltanto se una condizione è vera.
if (temperatura > 30) {
digitalWrite(ventola, HIGH);
}
if…else
if (temperatura > 30) {
digitalWrite(ventola, HIGH);
}
else {
digitalWrite(ventola, LOW);
}
a = 10; assegna il valore 10.
a == 10 verifica se a contiene il valore 10.
for
Il ciclo for è utile quando sappiamo
quante volte vogliamo ripetere un’operazione.
for (int i = 0; i < 10; i++) {
Serial.println(i);
}
while
Ripete il blocco finché la condizione rimane vera.
while (sensore < 500) {
sensore = analogRead(A0);
}
do…while
È simile a while, ma il blocco viene
eseguito almeno una volta.
do {
sensore = analogRead(A0);
} while (sensore < 500);
switch…case
È utile quando dobbiamo scegliere tra diversi casi in base allo stesso valore.
switch (modalita) {
case 1:
digitalWrite(LED_BUILTIN, HIGH);
break;
case 2:
digitalWrite(LED_BUILTIN, LOW);
break;
default:
break;
}
break
Interrompe un ciclo oppure termina un ramo
di uno switch.
continue
Salta il resto dell’iterazione corrente e passa alla successiva.
➗ Operatori
Operatori matematici
| Operatore | Operazione |
|---|---|
+ | Addizione |
- | Sottrazione |
* | Moltiplicazione |
/ | Divisione |
% | Resto della divisione |
Operatori di confronto
==uguale!=diverso<minore>maggiore<=minore o uguale>=maggiore o uguale
Operatori booleani
&&AND||OR!NOT
Esempio:
if (temperatura > 30 && umidita > 70) {
// entrambe le condizioni sono vere
}
Operatori di incremento
i++;
i--;
i += 5;
i -= 5;
🧩 Librerie e funzioni
Una funzione è un blocco di codice che svolge un compito specifico.
Arduino mette a disposizione numerose funzioni già pronte, ad esempio:
digitalWrite()digitalRead()analogRead()delay()millis()
Possiamo anche creare funzioni personalizzate.
void accendiLed() {
digitalWrite(LED_BUILTIN, HIGH);
}
e richiamarle con:
accendiLed();
Librerie
Le librerie aggiungono funzionalità allo sketch.
Esempio:
#include <Servo.h>
Con una libreria possiamo controllare componenti complessi senza dover riscrivere da zero tutto il protocollo di comunicazione.
🔌 Funzioni di INPUT e OUTPUT
pinMode()
Configura il funzionamento di un pin.
pinMode(8, OUTPUT);
pinMode(2, INPUT);
digitalWrite()
Imposta un’uscita digitale.
digitalWrite(8, HIGH);
digitalWrite(8, LOW);
digitalRead()
Legge lo stato di un ingresso digitale.
int stato = digitalRead(2);
analogRead()
Legge un ingresso analogico.
Su Arduino UNO R3 con ATmega328P il convertitore ADC è a 10 bit e produce normalmente valori da:
0 a 1023
int valore = analogRead(A0);
analogWrite()
Sulle classiche schede AVR come Arduino UNO,
analogWrite() viene normalmente utilizzato
per generare PWM.
analogWrite(9, 128);
Un valore di 128 corrisponde indicativamente a un duty cycle del 50%.
Risoluzione ADC, pin PWM e comportamento di alcune funzioni possono cambiare tra UNO R3, UNO R4, Nano, Mega, ESP32 e altre piattaforme. Controlla sempre la documentazione della scheda utilizzata.
💬 Comunicazione seriale
La comunicazione seriale permette lo scambio di dati tra Arduino e il computer.
Serial.begin()
Serial.begin(9600);
Imposta la velocità della comunicazione.
Serial.print()
Serial.print("Temperatura: ");
Serial.print(temperatura);
Serial.println()
Funziona come Serial.print(),
ma termina la riga.
Serial.println("Arduino avviato");
Serial.available()
Verifica se sono disponibili dati ricevuti.
if (Serial.available() > 0) {
char dato = Serial.read();
}
Serial.read()
Legge un byte ricevuto.
char comando = Serial.read();
⏱️ Funzioni di tempo
delay()
Ferma l’esecuzione dello sketch per il numero indicato di millisecondi.
delay(1000);
equivale a una pausa di un secondo.
Durante il delay il normale flusso dello sketch rimane fermo. Nei progetti più complessi è spesso preferibile usare millis().
delayMicroseconds()
delayMicroseconds(10);
Introduce una pausa espressa in microsecondi.
millis()
Restituisce il numero di millisecondi trascorsi dall’avvio dello sketch.
unsigned long adesso = millis();
Esempio senza delay()
const int ledPin = LED_BUILTIN;
unsigned long precedente = 0;
const unsigned long intervallo = 1000;
bool statoLed = false;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
unsigned long adesso = millis();
if (adesso - precedente >= intervallo) {
precedente = adesso;
statoLed = !statoLed;
digitalWrite(ledPin, statoLed);
}
}
Permette di eseguire operazioni periodiche senza bloccare completamente lo sketch. È uno dei concetti più importanti per passare dai progetti base a programmi Arduino più evoluti.
📐 Funzioni matematiche
Arduino mette a disposizione diverse funzioni utili.
min()
int minimo = min(a, b);
max()
int massimo = max(a, b);
abs()
int valore = abs(numero);
constrain()
Limita un valore entro un intervallo.
valore = constrain(valore, 0, 255);
map()
Converte un valore da un intervallo a un altro.
int pwm = map(sensore, 0, 1023, 0, 255);
È molto utile per trasformare una lettura analogica in un valore PWM.
pow() e sqrt()
float quadrato = pow(numero, 2);
float radice = sqrt(numero);
🎲 Numeri casuali
random()
Genera valori pseudo-casuali.
long numero = random(0, 10);
Il risultato può andare da 0 a 9.
randomSeed()
Permette di inizializzare il generatore pseudo-casuale.
randomSeed(analogRead(A0));
Questa tecnica viene spesso utilizzata con un ingresso analogico lasciato non collegato, anche se non rappresenta una sorgente casuale crittograficamente sicura.
🧠 Alcune buone pratiche
- usa nomi di variabili comprensibili;
- indenta correttamente il codice;
- commenta i passaggi non evidenti;
- evita numeri “magici” ripetuti nel codice;
- dividi programmi lunghi in funzioni;
- controlla sempre i valori restituiti dai sensori;
- usa
millis()quando non vuoi bloccare lo sketch; - mantieni separata la logica di lettura, decisione e azione.
Un sistema domotico, un robot o una stazione meteo non sono altro che molti piccoli problemi risolti separatamente e poi collegati tra loro.
📋 Riepilogo: i concetti fondamentali
🛠️ Ambiente di sviluppo
Arduino IDE permette di scrivere, compilare e caricare gli sketch sulla scheda.
🏗️ Struttura
Le due funzioni fondamentali sono:
setup()→ eseguita una volta;loop()→ ripetuta continuamente.
📦 Variabili
Conservano i dati utilizzati dal programma.
Tra i tipi più comuni troviamo:
- bool;
- byte;
- int;
- long;
- float;
- char.
🔀 Controllo del programma
if / elseforwhiledo...whileswitch / casebreakcontinue
⚡ Input e output
pinMode()digitalWrite()digitalRead()analogRead()analogWrite()
💬 Comunicazione seriale
Serial.begin()Serial.print()Serial.println()Serial.available()Serial.read()
⏱️ Tempo
delay()delayMicroseconds()millis()
Non cercare di memorizzare tutte le istruzioni. Impara invece a capire la logica di un programma, a leggere la documentazione e a dividere un problema complesso in piccoli blocchi. Quando questo meccanismo diventa naturale, programmare Arduino diventa molto più semplice.
🚀 Cosa studiare dopo
Dopo aver compreso questi concetti puoi passare a progetti sempre più avanzati:
- sensori analogici e digitali;
- display LCD e OLED;
- servo e motori DC;
- interrupt;
- I2C, SPI e UART;
- Bluetooth;
- WiFi e IoT;
- ESP32.
La programmazione diventa davvero naturale quando la teoria viene applicata continuamente a circuiti e progetti reali.

