Skip to content

Progettazione e Sviluppo con Arduino

Questa sezione copre la progettazione e lo sviluppo con Arduino, dalla lettura di sensori al controllo di attuatori, fino all’interfacciamento con Raspberry Pi via seriale e nRF24.


Arduino è una piattaforma elettronica open-source basata su microcontrollori (ATmega328P su Arduino Uno). Serve per creare progetti interattivi che leggono dati da sensori e controllano attuatori.

ModelloMCUPin digitaliPin analogiciUso tipico
Uno R3ATmega328P (16 MHz)14 (6 PWM)6Progetti didattici e prototipi
NanoATmega328P (16 MHz)14 (6 PWM)8Progetti compatti
Mega 2560ATmega2560 (16 MHz)54 (15 PWM)16Progetti complessi
LeonardoATmega32U4 (16 MHz)20 (7 PWM)12HID (tastiera/mouse)

Arduino Uno Rev3

Piedinatura Arduino Uno

Fonte: Arduino Store — UNO Rev3

Legenda:

  • ~ = pin con uscita PWM
  • D0-D13 = pin digitali
  • A0-A5 = pin analogici (anche I²C su A4=SDA, A5=SCL)
  • TX/RX = seriale hardware (collegata alla USB)

  1. Scarica l’IDE da arduino.cc
  2. Installa e avvia
  3. Collega Arduino via USB
  4. Seleziona la scheda: Strumenti → Scheda → Arduino Uno
  5. Seleziona la porta: Strumenti → Porta → COMx (Windows) o /dev/ttyACMx (Linux)
  1. Installa VS Code
  2. Installa l’estensione PlatformIO IDE
  3. Crea un nuovo progetto: PIO Home → New Project
  4. Seleziona scheda: Arduino Uno
  5. Scrivi il codice in src/main.cpp
  6. Compila: ✔️ (spunta in basso) o Ctrl+Alt+B
  7. Carica: → (freccia) o Ctrl+Alt+U

Su Arduino non c’è un vero debugger hardware come GDB. Si usa Serial.print():

int valore = analogRead(A0);
Serial.print("Valore sensore: ");
Serial.println(valore);
delay(100);

Apri il Monitor Seriale (IDE: Ctrl+Shift+M, PlatformIO: icona plug) per vedere l’output.


La breadboard permette di prototipare circuiti senza saldature.

Breadboard con collegamenti

┌─────────────┬───────┬───────┬─ ... ┬───────┐
(+) │ 1 │ 2 │ 3 │ ... │ 30 │ = binocoli orizzontali
├─────┼─────┼─────┼─────┼─────┤
│ │ │ │ │ │
├─────┼─────┼─────┼─────┼─────┤
(-) │ 1 │ 2 │ 3 │ ... │ 30 │
└─────────────┴───────┴───────┴─ ... ┴───────┘
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│a│b│c│d│e│f│g│h│i│j│ ... │a│b│c│d│e│f│g│h│i│j│
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
│ │ │ │ │ │ │ │ │ │ │ ... │ │ │ │ │ │ │ │ │ │ ← righe collegate
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
│ │ │ │ │ │ │ │ │ │ │ ... │ │ │ │ │ │ │ │ │ │
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
───┴─── ───┴───
binocoli binocoli
(+) / (-) (E / F)

Regole base:

  • I binocoli laterali (rosso/blu) sono collegati verticalmente: usali per alimentazione (rosso = 5V/Vcc, blu = GND)
  • Le righe interne (a-j) sono collegate orizzontalmente in gruppi di 5
  • Il ponticello centrale separa le due metà: nessuna connessione tra E e F

Collegamenti tipici:

┌─ LED ─────────────────────────────┐
│ Anodo (+) → a1 Catodo (-) → a5 │
│ Resistenza 220Ω da b1 a binocolo GND │
│ Filo da D13 a a1 (LED+) │
└────────────────────────────────────────┘

const int PIN_POT = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int valore = analogRead(PIN_POT);
float tensione = valore * (5.0 / 1023.0);
Serial.print("Valore: ");
Serial.print(valore);
Serial.print(" Tensione: ");
Serial.print(tensione);
Serial.println(" V");
delay(200);
}

Schema di montaggio:

Schema potenziometro

Circuito:

5V ──┐
┌┴┐
│ │ Potenziometro 10kΩ
│ │
└┬┘
├── A0 (lettura analogica 0-1023)
GND ─┘
const int PIN_BOTTONE = 7;
void setup() {
pinMode(PIN_BOTTONE, INPUT_PULLUP); // Attiva resistenza interna di pull-up
Serial.begin(9600);
}
void loop() {
int stato = digitalRead(PIN_BOTTONE);
if (stato == LOW) { // Premuto (LOW perché usiamo INPUT_PULLUP)
Serial.println("Bottone premuto!");
delay(300); // Debounce semplice
}
}

Schema di montaggio:

Schema pulsante

Circuito:

5V ──┐
┌┤│ Pulsante
│││
└┤│
└── D7 (con INPUT_PULLUP, non serve resistenza esterna)
GND ─┘
const int PIN_TEMP = A1;
void setup() {
Serial.begin(9600);
}
void loop() {
int valore = analogRead(PIN_TEMP);
// TMP36: 10mV per °C, offset 0.5V = 50°C
float tensione = valore * (5.0 / 1023.0);
float temperatura = (tensione - 0.5) * 100.0;
Serial.print("Temperatura: ");
Serial.print(temperatura);
Serial.println(" °C");
delay(1000);
}

Schema di montaggio:

Schema LM35

Circuito:

TMP36
┌─┐
│ │
│ │
─┬─
┌─┼─┐
│ │ │
5V A1 GND
const int PIN_TRIG = 9;
const int PIN_ECHO = 10;
void setup() {
pinMode(PIN_TRIG, OUTPUT);
pinMode(PIN_ECHO, INPUT);
Serial.begin(9600);
}
void loop() {
// Invia impulso ultrasonico
digitalWrite(PIN_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(PIN_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(PIN_TRIG, LOW);
// Misura il tempo di ritorno
long durata = pulseIn(PIN_ECHO, HIGH);
// Calcola distanza: velocità suono ≈ 343 m/s = 0.0343 cm/μs
// Distanza = durata / 2 * 0.0343
float distanza = durata * 0.0343 / 2.0;
Serial.print("Distanza: ");
Serial.print(distanza);
Serial.println(" cm");
delay(500);
}

Schema di montaggio:

Schema HC-SR04

Circuito HC-SR04:

HC-SR04
┌──────────┐
│ VCC TRIG │
│ ECHO GND │
└──────────┘
│ │ │ │
5V GND D9 D10
TRIG ECHO
SensoreTipoPinFunzione
PotenziometroAnalogicoA0analogRead() → 0-1023
LDR (fotoresistenza)AnalogicoA0analogRead() → luce/ombra
LM35 / TMP36AnalogicoA1analogRead() → °C
PulsanteDigitaleD7digitalRead() → LOW/HIGH
HC-SR04DigitaleD9, D10pulseIn() → cm
DHT11/DHT22DigitaleD2Libreria DHT → °C, umidità
PIR (movimento)DigitaleD8digitalRead() → movimento

Schema di montaggio:

Schema LED

const int PIN_LED = 13;
void setup() {
pinMode(PIN_LED, OUTPUT);
}
void loop() {
digitalWrite(PIN_LED, HIGH); // Accendi
delay(500);
digitalWrite(PIN_LED, LOW); // Spegni
delay(500);
}
const int PIN_LED = 9; // Deve essere un pin ~PWM
void setup() {
pinMode(PIN_LED, OUTPUT);
}
void loop() {
for (int luminosita = 0; luminosita <= 255; luminosita++) {
analogWrite(PIN_LED, luminosita);
delay(5);
}
for (int luminosita = 255; luminosita >= 0; luminosita--) {
analogWrite(PIN_LED, luminosita);
delay(5);
}
}

Schema di montaggio:

Schema LED PWM

Circuito con resistenza:

D9 (PWM) ──┬──┐
│ │ 220Ω
│ │
│ └── Anodo (+)
│ LED
└────── Catodo (-)
GND

Schema di montaggio:

Schema servomotore

#include <Servo.h>
Servo mioServo;
const int PIN_SERVO = 9;
void setup() {
mioServo.attach(PIN_SERVO);
}
void loop() {
mioServo.write(0); // 0 gradi
delay(1000);
mioServo.write(90); // 90 gradi
delay(1000);
mioServo.write(180); // 180 gradi
delay(1000);
}

Collegamento servomotore:

SG90
┌───┐
│ │
╱ ╲ ╱ ╲
│ │ │
────┬───
│ │ │
GND 5V Segnale
D9 (PWM)

Schema di montaggio:

Schema L298N

const int PIN_ENA = 9; // PWM velocità
const int PIN_IN1 = 8;
const int PIN_IN2 = 7;
void setup() {
pinMode(PIN_ENA, OUTPUT);
pinMode(PIN_IN1, OUTPUT);
pinMode(PIN_IN2, OUTPUT);
}
void loop() {
// Avanti a 1/2 velocità
digitalWrite(PIN_IN1, HIGH);
digitalWrite(PIN_IN2, LOW);
analogWrite(PIN_ENA, 128);
delay(2000);
// Stop
analogWrite(PIN_ENA, 0);
delay(1000);
// Indietro a piena velocità
digitalWrite(PIN_IN1, LOW);
digitalWrite(PIN_IN2, HIGH);
analogWrite(PIN_ENA, 255);
delay(2000);
// Stop
analogWrite(PIN_ENA, 0);
delay(1000);
}

Schema L298N:

Arduino L298N
─────── ─────
D9 ────────────────────────── ENA (PWM velocità A)
D8 ────────────────────────── IN1
D7 ────────────────────────── IN2
5V ────────────────────────── +5V
GND ────────────────────────── GND
┌────────┴────────┐
12V (batteria) Motore DC
AttuatorePinControllo
LEDD13 (o qualunque)digitalWrite(LED, HIGH/LOW)
LED PWMD3, D5, D6, D9, D10, D11analogWrite(pin, 0-255)
ServomotoreD9servo.write(0-180°)
Motor DC (L298N)ENA+IN1+IN2digitalWrite(IN1, IN2), analogWrite(ENA)
BuzzerD8tone(pin, frequenza) / noTone(pin)
RelayD12digitalWrite(RELAY, HIGH/LOW)

La comunicazione seriale (UART) è il metodo più semplice e versatile per far comunicare Arduino con un PC, un Raspberry Pi, sensori seriali (GPS, RFID) o un secondo Arduino. Utilizza due linee dati (TX e RX) oltre alla massa comune (GND).

L’UART (Universal Asynchronous Receiver-Transmitter) trasmette i dati un bit alla volta a una velocità concordata detta baud rate (es. 9600, 115200). La comunicazione è asincrona: non c’è un segnale di clock separato, quindi entrambi i dispositivi devono usare la stessa velocità.

┌─────────────────┐ ┌─────────────────┐
│ │ TX ───→ RX │
│ Arduino │ RX ←─── TX │ PC / Altro
│ │ GND ──── GND │
└─────────────────┘ └─────────────────┘
(D1=TX, D0=RX)
Frame di un byte (9600 baud, 8N1):
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│START│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │STOP │
│ bit │ bit │ bit │ bit │ bit │ bit │ bit │ bit │ bit │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
8 bit di dato (LSB first) ± eventuale parità

Importante:

  • Il collegamento è incrociato (TX→RX, RX→TX)
  • Con il cavo USB, la conversione seriale-USB è gestita dal chip FTDI/CH340G sulla scheda Arduino
  • Massa comune (GND collegato) sempre necessaria

Baud rateUtilizzo tipicoMax distanza (appross.)
300GPS vecchi, dispositivi lenti~1000 m
1200Modem, dispositivi industriali~500 m
9600Default Arduino, debug, sensori~100 m
57600Trasferimento dati veloce~10 m
115200GPS moderni, Bluetooth HC-05/HC-06~5 m
250000Comunicazione rapida tra moduli~1 m

Regola: Serial.begin(9600) è il valore più sicuro per iniziare. Per aumentare la velocità, assicurati che entrambi i dispositivi supportino il baud rate scelto.


Serial Monitor Arduino

Il Monitor Seriale (Ctrl+Shift+M) permette di:

  • Visualizzare i dati inviati da Arduino
  • Inviare comandi da tastiera ad Arduino
  • Selezionare il baud rate (in basso a destra)
  • Scegliere terminazione riga (\n, \r\n, ecc.)

Consiglio: usa lo Serial Plotter (Ctrl+Shift+L) per visualizzare graficamente i dati numerici in tempo reale (es. andamento temperatura).


Il caso più comune: stampare messaggi di debug per capire cosa sta succedendo nel programma.

#define DEBUG
void setup() {
Serial.begin(9600);
Serial.println("Sistema avviato!");
Serial.print("Timestamp (ms): ");
Serial.println(millis());
}
void loop() {
int sensore = analogRead(A0);
#ifdef DEBUG
Serial.print("[DEBUG] A0 = ");
Serial.print(sensore);
Serial.print(" Tensione = ");
Serial.print(sensore * (5.0 / 1023.0));
Serial.println(" V");
#endif
delay(500);
}

Caso d’uso 2 — Invio dati strutturati (CSV)

Section titled “Caso d’uso 2 — Invio dati strutturati (CSV)”

Utile per registrare dati su PC e importarli in Excel o fogli di calcolo.

void setup() {
Serial.begin(9600);
// Intestazione CSV (stampata una volta sola)
Serial.println("timestamp,temperatura,umidita,luminosita");
}
void loop() {
unsigned long t = millis();
float temp = 20.0 + random(-50, 50) / 10.0; // Simula TMP36
float hum = 50.0 + random(-20, 20) / 10.0;
int luce = analogRead(A0);
// Dati in formato CSV
Serial.print(t);
Serial.print(",");
Serial.print(temp, 1);
Serial.print(",");
Serial.print(hum, 1);
Serial.print(",");
Serial.println(luce);
delay(1000);
}

Su PC: un programma Python o Node.js può leggere la seriale e salvare i dati in un file CSV.


Caso d’uso 3 — Invio dati in formato JSON

Section titled “Caso d’uso 3 — Invio dati in formato JSON”

Perfetto per interfacciarsi con applicazioni web o Node.js.

void setup() {
Serial.begin(9600);
}
void loop() {
float temp = 20.0 + random(-50, 50) / 10.0;
float hum = 50.0 + random(-20, 20) / 10.0;
// Output JSON compatto
Serial.print("{\"t\":");
Serial.print(temp, 1);
Serial.print(",\"h\":");
Serial.print(hum, 1);
Serial.println("}");
delay(2000);
}

Output:

{"t":22.3,"h":48.7}
{"t":22.1,"h":49.2}

Caso d’uso 4 — Ricezione comandi (parsing)

Section titled “Caso d’uso 4 — Ricezione comandi (parsing)”

Arduino ascolta comandi testuali dal PC e reagisce di conseguenza.

const int PIN_LED = 13;
const int PIN_LED2 = 12;
void setup() {
Serial.begin(9600);
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_LED2, OUTPUT);
Serial.println("Pronto. Comandi: LED1 ON, LED1 OFF, LED2 ON, LED2 OFF, STATO");
}
void loop() {
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
cmd.toUpperCase();
if (cmd == "LED1 ON") {
digitalWrite(PIN_LED, HIGH);
Serial.println("LED1 acceso");
} else if (cmd == "LED1 OFF") {
digitalWrite(PIN_LED, LOW);
Serial.println("LED1 spento");
} else if (cmd == "LED2 ON") {
digitalWrite(PIN_LED2, HIGH);
Serial.println("LED2 acceso");
} else if (cmd == "LED2 OFF") {
digitalWrite(PIN_LED2, LOW);
Serial.println("LED2 spento");
} else if (cmd == "STATO") {
Serial.print("LED1: ");
Serial.println(digitalRead(PIN_LED) ? "ON" : "OFF");
Serial.print("LED2: ");
Serial.println(digitalRead(PIN_LED2) ? "ON" : "OFF");
} else if (cmd == "HELP") {
Serial.println("Comandi: LED1 ON, LED1 OFF, LED2 ON, LED2 OFF, STATO");
} else {
Serial.print("Comando sconosciuto: ");
Serial.println(cmd);
}
}
}

Caso d’uso 5 — Lettura sensore seriale (GPS NMEA)

Section titled “Caso d’uso 5 — Lettura sensore seriale (GPS NMEA)”

Molti sensori comunicano direttamente via seriale, come i moduli GPS (Neo-6M, Neo-8M).

Collegamento:

┌───────────┐ ┌─────────────┐
│ GPS │ TX ───→ RX (D2) │
│ Neo-6M │ RX ←─── TX (D3) │
│ │ GND ──── GND │
└───────────┘ └─────────────┘
Arduino (SoftwareSerial)
#include <SoftwareSerial.h>
// Crea una seconda porta seriale sui pin D2 (RX) e D3 (TX)
SoftwareSerial gps(2, 3); // RX, TX
void setup() {
Serial.begin(9600); // Seriale principale (USB → PC)
gps.begin(9600); // Seriale software (GPS)
Serial.println("Lettura GPS...");
}
void loop() {
if (gps.available() > 0) {
char c = gps.read();
// Inoltra al PC per elaborazione
Serial.write(c);
}
// Invia comando al GPS (es. configurazione)
if (Serial.available() > 0) {
gps.write(Serial.read());
}
}

Nota: I moduli GPS inviano frasi NMEA (es. $GPGGA,123519,4807.038,N,...) che possono essere parse per estrarre latitudine, longitudine, altitudine e orario.


Caso d’uso 6 — Comunicazione tra due Arduino (UART)

Section titled “Caso d’uso 6 — Comunicazione tra due Arduino (UART)”

Due Arduino possono comunicare direttamente via seriale.

Schema collegamento:

┌─────────────────┐ ┌─────────────────┐
│ Arduino #1 │ │ Arduino #2 │
│ │ │ │
│ TX (D1) ───────┼─────────┼── RX (D0) │
│ RX (D0) ───────┼─────────┼── TX (D1) │
│ GND ───────┼─────────┼── GND │
└─────────────────┘ └─────────────────┘
(master) (slave)

Arduino #1 (trasmettitore):

int contatore = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.print("CIAO_");
Serial.println(contatore);
contatore++;
delay(1000);
}

Arduino #2 (ricevitore):

void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
String msg = Serial.readStringUntil('\n');
msg.trim();
Serial.print("Ricevuto: ");
Serial.println(msg);
// Accendi LED a ogni messaggio
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
}

Caso d’uso 7 — Serial Plotter: visualizzazione grafica

Section titled “Caso d’uso 7 — Serial Plotter: visualizzazione grafica”

Lo Serial Plotter dell’IDE Arduino (Ctrl+Shift+L) permette di vedere i dati numerici in tempo reale.

void setup() {
Serial.begin(9600);
}
void loop() {
int pot = analogRead(A0); // 0-1023
int luce = analogRead(A1); // LDR
float temp = analogRead(A2) * (5.0 / 1023.0 - 0.5) * 100.0;
// Serial Plotter accetta valori separati da spazio o virgola
Serial.print(pot);
Serial.print(" ");
Serial.print(luce);
Serial.print(" ");
Serial.println(temp);
delay(100);
}

Lo Serial Plotter disegna automaticamente una curva per ogni valore numerico stampato su una riga. Ideale per vedere l’andamento di sensori in tempo reale.


FunzioneDescrizione
Serial.begin(speed)Avvia la seriale con baud rate speed
Serial.print(val)Stampa il valore come testo
Serial.println(val)Stampa il valore con newline (\n)
Serial.write(byte)Invia un byte grezzo (0-255)
Serial.available()Restituisce il numero di byte in arrivo
Serial.read()Legge un byte (restituisce -1 se nessun dato)
Serial.readString()Legge tutti i byte disponibili come stringa
Serial.readStringUntil(c)Legge fino al carattere c
Serial.parseInt()Legge il prossimo intero
Serial.parseFloat()Legge il prossimo float
Serial.flush()Attende che tutti i dati in uscita siano trasmessi
Serial.setTimeout(t)Imposta il timeout in ms per le funzioni di parse

Uso di SoftwareSerial (pin seriali aggiuntivi)

Section titled “Uso di SoftwareSerial (pin seriali aggiuntivi)”

Arduino Uno ha una sola porta seriale hardware (D0=RX, D1=TX). La libreria SoftwareSerial permette di crearne altre su qualsiasi pin digitale.

#include <SoftwareSerial.h>
// Crea una seriale software su pin 10 (RX) e 11 (TX)
SoftwareSerial mySerial(10, 11);
void setup() {
Serial.begin(9600); // Seriale USB (PC)
mySerial.begin(9600); // Seriale software (es. GPS, Bluetooth)
mySerial.println("Modulo connesso!");
}
void loop() {
// Bridge: inoltra dati tra PC e modulo
if (mySerial.available()) {
Serial.write(mySerial.read());
}
if (Serial.available()) {
mySerial.write(Serial.read());
}
}

Limitazione: SoftwareSerial non può inviare e ricevere contemporaneamente ad alta velocità. Per più porte seriali simultanee, usa Arduino Mega (ha 4 UART hardware).


Tabella comparativa: Seriale vs altre interfacce

Section titled “Tabella comparativa: Seriale vs altre interfacce”
CaratteristicaUART (Seriale)I²CSPI
Numero fili2 (+ GND)2 (SDA+SCL)4 (MOSI+MISO+SCK+SS)
VelocitàFino a 2 MbpsFino a 3.4 MHzFino a 10 MHz
DispositiviPunto-puntoMulti-masterMulti-slave
ComplessitàMolto sempliceMediaMedia
Tipico usoDebug, GPS, Bluetooth, PCSensori (LCD, BME280)SD card, nRF24, display

ErroreCausaSoluzione
Caratteri strani sul monitorBaud rate diverso tra Arduino e MonitorStessa velocità su entrambi
Niente sul monitorArduino in reset continuo o porta sbagliataVerifica porta e alimentazione
Dati saltati o corrottiBuffer overflow o baudrate troppo altoRiduci baudrate o aumenta delay
Serial non funziona se uso pin D0/D1Quei pin sono usati dalla seriale USBEvita di usarli come I/O generico
SoftwareSerial non riceve beneInterferenza con interrupt timerUsa baudrate ≤ 57600

7. Interfacciamento via Seriale con Raspberry Pi

Section titled “7. Interfacciamento via Seriale con Raspberry Pi”

Arduino collegato a Raspberry Pi via USB

┌──────────┐ ┌──────────────┐
│ Arduino │ USB │ Raspberry │
│ Uno │═══════════════════│ Pi 4/5 │
└──────────┘ └──────────────┘

Cavo USB-A → microUSB (o USB-C). Il Raspberry rileva Arduino come /dev/ttyACM0 o /dev/ttyUSB0.

import serial
import time
# Configurazione porta seriale
ser = serial.Serial(
port='/dev/ttyACM0',
baudrate=9600,
timeout=1
)
time.sleep(2) # Attendi reset Arduino
try:
while True:
if ser.in_waiting > 0:
linea = ser.readline().decode('utf-8').strip()
print(f"Arduino dice: {linea}")
except KeyboardInterrupt:
print("Chiusura...")
ser.close()
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
time.sleep(2)
while True:
comando = input("Comando (ACCENDI/SPEGNI): ").strip()
ser.write((comando + "\n").encode())
risposta = ser.readline().decode().strip()
print(f"Risposta: {risposta}")

Esempio completo: sensore + Python + logging

Section titled “Esempio completo: sensore + Python + logging”

Arduino (lettura temperatura su richiesta):

const int PIN_TEMP = A1;
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd == "TEMPERATURA") {
int valore = analogRead(PIN_TEMP);
float tensione = valore * (5.0 / 1023.0);
float temp = (tensione - 0.5) * 100.0;
Serial.print(temp);
Serial.println(" C");
}
}
}

Raspberry (Python con logging CSV):

import serial
import time
import csv
from datetime import datetime
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
time.sleep(2)
with open('temperature.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['timestamp', 'temperatura'])
try:
while True:
ser.write(b"TEMPERATURA\n")
risposta = ser.readline().decode().strip()
if risposta:
timestamp = datetime.now().isoformat()
writer.writerow([timestamp, risposta])
f.flush()
print(f"{timestamp}{risposta}")
time.sleep(60) # Leggi ogni minuto
except KeyboardInterrupt:
ser.close()
print("Logging terminato.")

Il modulo nRF24L01 permette comunicazione wireless tra Arduino e Raspberry (o tra due Arduino) a 2.4 GHz, con portata fino a 100m (modello +PA+LNA).

nRF24L01
┌───────────┐
│ 1 2 3 │
│ 4 5 6 │
│ 7 │
└───────────┘
1 = GND 5 = MOSI
2 = VCC (3.3V) 6 = SCK
3 = CE 7 = CSN
4 = CS (alcuni modelli: IRQ = 8)
nRF24L01Arduino Uno
GNDGND
VCC3.3V (mai 5V!)
CED9
CSND10
MOSID11
SCKD13
MISOD12

Schema pratico:

nRF24L01 Arduino Uno
──────── ──────────
VCC ───────────────────── 3.3V
GND ───────────────────── GND
CE ───────────────────── D9
CSN ───────────────────── D10
MOSI ──────────────────── D11
MISO ──────────────────── D12
SCK ───────────────────── D13
Aggiungi un condensatore 10µF tra 3.3V e GND (vicino al modulo)
per stabilizzare l'alimentazione!
nRF24L01Raspberry Pi (GPIO)
GNDGND (pin 6)
VCC3.3V (pin 1)
CEGPIO22 (pin 15)
CSNGPIO8 / CE0 (pin 24)
MOSIGPIO10 / MOSI (pin 19)
MISOGPIO9 / MISO (pin 21)
SCKGPIO11 / SCLK (pin 23)
┌─────────────────────────────────────┐
│ Raspberry Pi 40-pin │
├─────────────────────────────────────┤
│ 1 3.3V ── nRF24 VCC 2 5V │
│ 3 SDA 4 5V │
│ 5 SCL 6 GND ←───┤
│ 7 GPIO4 8 GPIO14 │
│ 9 GND 10 GPIO15 │
│ 11 GPIO17 12 GPIO18 │
│ 13 GPIO27 │ 14 GND │
│ 15 GPIO22 ←── CE 16 GPIO23 │
│ 17 3.3V 18 GPIO24 │
│ 19 MOSI ←───────┐ 20 GND │
│ 21 MISO ←───────┤ 22 GPIO25 │
│ 23 SCK ←────────┤ 24 CE0 ←────┤ CSN
│ 25 GND 26 CE1 │
└─────────────────────────────────────┘

Arduino (Library Manager):

  1. Apri Strumenti → Gestione librerie
  2. Cerca “RF24” di TMRh20
  3. Installa

Raspberry Pi:

Terminal window
# Abilita SPI
sudo raspi-config
# → Interface Options → SPI → Enable
# Installa libreria
pip install pyrf24
# Verifica
python3 -c "import pyrf24; print('OK')"

Codice Arduino — trasmettitore (invia temperatura)

Section titled “Codice Arduino — trasmettitore (invia temperatura)”
#include <SPI.h>
#include <RF24.h>
RF24 radio(9, 10); // CE, CSN
const byte indirizzo[6] = "NODO1";
const int PIN_TEMP = A1;
void setup() {
Serial.begin(9600);
if (!radio.begin()) {
Serial.println("Modulo nRF24 non rilevato!");
while (1);
}
radio.openWritingPipe(indirizzo);
radio.setPALevel(RF24_PA_LOW); // Massima potenza: RF24_PA_MAX
radio.setDataRate(RF24_250KBPS); // Bassa velocità = più portata
radio.stopListening();
Serial.println("Trasmettitore nRF24 pronto");
}
void loop() {
int valore = analogRead(PIN_TEMP);
float tensione = valore * (5.0 / 1023.0);
float temperatura = (tensione - 0.5) * 100.0;
bool successo = radio.write(&temperatura, sizeof(temperatura));
if (successo) {
Serial.print("Inviato: ");
Serial.print(temperatura);
Serial.println(" °C");
} else {
Serial.println("Invio fallito!");
}
delay(2000);
}
import pyrf24
import time
# Configurazione
radio = pyrf24.RF24(22, 0) # CE = GPIO22, CSN = CE0 (SPI bus 0)
indirizzo = b"NODO1"
if not radio.begin():
print("Modulo nRF24 non rilevato!")
exit(1)
radio.setPALevel(pyrf24.RF24_PA_LOW)
radio.setDataRate(pyrf24.RF24_250KBPS)
radio.openReadingPipe(1, indirizzo)
radio.startListening()
print("Ricevitore nRF24 pronto...")
try:
while True:
if radio.available():
buffer = radio.read(4) # float = 4 byte
temperatura = float(buffer[0]) # Semplificato
# Oppure con struct:
# import struct
# temperatura = struct.unpack('f', buffer)[0]
print(f"Temperatura ricevuta: {temperatura:.2f} °C")
time.sleep(0.1)
except KeyboardInterrupt:
print("Chiusura...")
radio.stopListening()

Arduino (nodo sensore con comando LED):

#include <SPI.h>
#include <RF24.h>
RF24 radio(9, 10);
const byte indirizzo[6] = "NODO1";
const int PIN_LED = 5;
void setup() {
Serial.begin(9600);
pinMode(PIN_LED, OUTPUT);
if (!radio.begin()) {
Serial.println("nRF24 non rilevato!");
while (1);
}
radio.openReadingPipe(1, indirizzo);
radio.setPALevel(RF24_PA_LOW);
radio.setDataRate(RF24_250KBPS);
radio.startListening();
}
void loop() {
if (radio.available()) {
char comando[32] = "";
radio.read(&comando, sizeof(comando));
Serial.print("Comando ricevuto: ");
Serial.println(comando);
radio.stopListening();
if (strcmp(comando, "ACCENDI") == 0) {
digitalWrite(PIN_LED, HIGH);
char risposta[] = "LED acceso";
radio.write(&risposta, sizeof(risposta));
} else if (strcmp(comando, "SPEGNI") == 0) {
digitalWrite(PIN_LED, LOW);
char risposta[] = "LED spento";
radio.write(&risposta, sizeof(risposta));
} else {
char risposta[] = "Comando sconosciuto";
radio.write(&risposta, sizeof(risposta));
}
radio.startListening();
}
}

Raspberry (controllo remoto):

import pyrf24
import time
radio = pyrf24.RF24(22, 0)
indirizzo = b"NODO1"
radio.begin()
radio.setPALevel(pyrf24.RF24_PA_LOW)
radio.setDataRate(pyrf24.RF24_250KBPS)
radio.openWritingPipe(indirizzo)
while True:
comando = input("Comando (ACCENDI/SPEGNI): ").strip()
radio.stopListening()
radio.write(comando.encode())
time.sleep(0.1)
radio.startListening()
if radio.available():
buffer = radio.read(32)
risposta = buffer.decode().strip().rstrip('\x00')
print(f"Risposta: {risposta}")

9. Schema riepilogativo delle interfacce di Arduino

Section titled “9. Schema riepilogativo delle interfacce di Arduino”
┌─────────────────────────────────────────────────┐
│ ARDUINO UNO │
├─────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ PIN DIGITALI (D0-D13) │ │
│ │ D0/RX ── Comunicazione seriale (ricezione) │ │
│ │ D1/TX ── Comunicazione seriale (invio) │ │
│ │ D2-D13─ I/O digitale generico │ │
│ │ ~D3,~D5,~D6,~D9,~D10,~D11 ── PWM (0-255) │ │
│ │ D10/SS, D11/MOSI, D12/MISO, D13/SCK ── SPI │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ PIN ANALOGICI (A0-A5) │ │
│ │ A0-A5 ── Ingresso analogico 0-1023 (0-5V) │ │
│ │ A4/SDA, A5/SCL ── I²C/TWI │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ ALIMENTAZIONE │ │
│ │ Vin ── Alimentazione esterna (7-12V) │ │
│ │ 5V ── Uscita 5V (max ~500mA) │ │
│ │ 3.3V ── Uscita 3.3V (max ~150mA) │ │
│ │ GND ── Massa comune │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ COMUNICAZIONE │ │
│ │ USB ── Seriale con PC (alimenta + prog)│ │
│ │ UART ── TX/RX (D0-D1) seriale hardware │ │
│ │ SPI ── D10-D13 (per nRF24, SD, ecc.) │ │
│ │ I²C/TWI ── A4(SDA), A5(SCL) (per sensori) │ │
│ └─────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────┘

ComponenteAspettoCome si identifica
ResistenzaCilindro con bande colorateBande = valore (es. rosso-rosso-marrone = 220Ω)
LEDSfera trasparente/colorata con 2 gambeGamba lunga = anodo (+), gamba corta = catodo (-)
CondensatoreCilindro (elettrolitico) o disco (ceramico)Elettrolitico: striscia = negativo
DiodoCilindro con una strisciaStriscia = catodo
PulsantePiccolo blocco con 4 gambeGambe collegate a coppie
PotenziometroRotella con 3 gambeGambe laterali = 5V/GND, centrale = segnale
TransistorSemidisco con 3 gambeLettera sul corpo (es. 2N2222, BC547)
RegolatoreSembra un transistor, 3 gambe7805 = 5V output, 7812 = 12V output
IC (integrato)Rettangolo nero con gambe (DIP)Tacca = pin 1
ParametroValore
Tensione logica Arduino5V
Corrente max per pin I/O40 mA
Corrente totale Vcc/GND~200 mA
Tensione ingresso analogico0-5V
Resistenza pull-up interna~20 kΩ
Frequenza PWM~490 Hz (~980 Hz su D5/D6)

Progetto 1: Termostato con display seriale

Section titled “Progetto 1: Termostato con display seriale”

Materiali: Arduino Uno, TMP36, potenziometro, LED

Circuito:

TMP36 Potenziometro LED
───── ───────────── ───
VCC-5V 5V-GND-A2 D13-GND (con 220Ω)
A1

Codice:

const int PIN_TEMP = A1;
const int PIN_SOGLIA = A2;
const int PIN_LED = 13;
void setup() {
Serial.begin(9600);
pinMode(PIN_LED, OUTPUT);
}
void loop() {
int valTemp = analogRead(PIN_TEMP);
float temp = ((valTemp * 5.0 / 1023.0) - 0.5) * 100.0;
int valSoglia = analogRead(PIN_SOGLIA);
float soglia = ((valSoglia * 5.0 / 1023.0) - 0.5) * 100.0;
Serial.print("Temperatura: ");
Serial.print(temp);
Serial.print(" °C Soglia: ");
Serial.print(soglia);
Serial.println(" °C");
if (temp > soglia) {
digitalWrite(PIN_LED, HIGH);
Serial.println(">> ALLARME: temperatura superata!");
} else {
digitalWrite(PIN_LED, LOW);
}
delay(500);
}

Progetto 2: Stazione meteo wireless (Arduino + nRF24 → Raspberry)

Section titled “Progetto 2: Stazione meteo wireless (Arduino + nRF24 → Raspberry)”

Materiali:

  • Arduino Uno + nRF24L01 + DHT11 (temperatura/umidità)
  • Raspberry Pi + nRF24L01
  • Breadboard, cavi, alimentatore

Architettura:

┌─────────┐ nRF24 ┌──────────┐
│ Arduino │ ─── 2.4GHz ──→│ Raspberry │
│ DHT11 │ wireless │ Python │
│ nRF24 │ │ nRF24 │
└─────────┘ │ CSV/DB │
│ Web? │
└──────────┘

Codice Arduino (con DHT11):

#include <SPI.h>
#include <RF24.h>
#include <DHT.h>
RF24 radio(9, 10);
const byte indirizzo[6] = "METEO";
#define PIN_DHT 4
DHT dht(PIN_DHT, DHT11);
struct DatiMeteo {
float temperatura;
float umidita;
unsigned long timestamp;
};
void setup() {
Serial.begin(9600);
dht.begin();
if (!radio.begin()) {
Serial.println("nRF24 non rilevato!");
while (1);
}
radio.openWritingPipe(indirizzo);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_250KBPS);
radio.stopListening();
}
void loop() {
DatiMeteo dati;
dati.temperatura = dht.readTemperature();
dati.umidita = dht.readHumidity();
dati.timestamp = millis();
if (isnan(dati.temperatura) || isnan(dati.umidita)) {
Serial.println("Errore lettura DHT");
delay(2000);
return;
}
bool ok = radio.write(&dati, sizeof(dati));
if (ok) {
Serial.print("Inviato: ");
Serial.print(dati.temperatura);
Serial.print("°C, ");
Serial.print(dati.umidita);
Serial.println("%");
} else {
Serial.println("Invio fallito!");
}
delay(5000); // Invia ogni 5 secondi
}

Codice Raspberry (ricezione + logging CSV):

import pyrf24
import struct
import csv
import time
from datetime import datetime
radio = pyrf24.RF24(22, 0)
indirizzo = b"METEO"
radio.begin()
radio.setPALevel(pyrf24.RF24_PA_MAX)
radio.setDataRate(pyrf24.RF24_250KBPS)
radio.openReadingPipe(1, indirizzo)
radio.startListening()
print("Stazione meteo: in attesa di dati...")
with open('meteo_log.csv', 'a', newline='') as f:
writer = csv.writer(f)
try:
while True:
if radio.available():
buffer = radio.read(16) # 4+4+4+4 byte (float+float+uint32)
temperatura, umidita, timestamp = struct.unpack('ffI', buffer)
now = datetime.now().isoformat()
writer.writerow([now, f"{temperatura:.1f}", f"{umidita:.1f}"])
f.flush()
print(f"[{now}] Temp: {temperatura:.1f}°C Umid: {umidita:.1f}%")
time.sleep(0.1)
except KeyboardInterrupt:
print("Logging terminato.")

ProblemaCausa probabileSoluzione
LED non si accendeResistenza mancante o sbagliataUsa 220Ω in serie al LED
nRF24 non comunicaAlimentazione insufficienteAggiungi condensatore 10µF vicino al modulo
Valori analogici balleriniGND fluttuanteControlla che GND sia comune
Sketch non caricaPorta sbagliataVerifica Porta in Strumenti
Serial mostra caratteri straniBaud rate diversoStessi baud su TX e RX
Servo vibraPWM su pin sbagliatoUsa pin ~ (PWM)
Niente sul monitor serialeArduino in reset continuoControlla alimentazione
#define DEBUG
void setup() {
Serial.begin(9600);
}
void loop() {
int valore = analogRead(A0);
#ifdef DEBUG
Serial.print("DEBUG - A0: ");
Serial.println(valore);
#endif
// Resto del codice...
}

┌───────────────────────┐
│ COMPONENTI ARDUINO │
├───────────────────────┤
│ │
SENSORI ───────┤ ARDUINO UNO ├─────── ATTUATORI
(INPUT) │ (Microcontrollore) │ (OUTPUT)
│ ATmega328P │
┌─────────┐ │ 16 MHz, 32KB flash │ ┌──────────┐
│Potenziom.│ │ 2KB SRAM, 1KB EEPROM│ │ LED │
├─────────┤ │ │ ├──────────┤
│TMP36 │────┤ Alimentazione: ├────│Servo │
├─────────┤ │ • USB 5V │ ├──────────┤
│HC-SR04 │ │ • Vin 7-12V │ │Motor DC │
├─────────┤ │ • 5V / 3.3V output │ ├──────────┤
│Pulsante │ │ │ │Relay │
├─────────┤ │ Comunicazione: │ ├──────────┤
│LDR │ │ • Seriale (USB/UART) │ │Buzzer │
├─────────┤ │ • SPI (nRF24, SD) │ └──────────┘
│DHT11 │ │ • I²C (LCD, sensori) │
└─────────┘ │ │
│ nRF24L01 ←────→ Raspberry Pi │
│ Seriale ←────→ Raspberry Pi │
└───────────────────────┘