Sistemi e reti · Telecomunicazioni · classe 5ª

Bus e protocolli seriali con Arduino

Una scheda da tenere aperta in laboratorio. Parti dalla mappa, poi per ogni protocollo trovi: la carta d'identità, come viaggiano i bit sul filo, come si collega ad Arduino UNO, un programma di esempio, gli errori tipici e gli esercizi da fare sulla scheda.

UART / TTL RS232 · RS485 SPI I²C 1-Wire CAN
Il quadro generale

Mappa concettuale

La prima domanda da farsi su un protocollo è: chi dice al ricevitore quando leggere il bit? La risposta divide tutto in tre famiglie. Tocca un protocollo per andare alla sua scheda.

Mappa concettuale dei protocolli seriali: asincroni (UART, RS232, RS485, CAN), sincroni (SPI, I2C), a slot temporali (1-Wire) COMUNICAZIONE SERIALE un bit alla volta · pochi fili · regole comuni = protocollo ASINCRONA nessun filo di clock TX e RX concordano la velocità (baud) SINCRONA il master genera il clock si legge il bit sul fronte A SLOT TEMPORALI un solo filo dati il master apre ogni "finestra" UART TX · RX 0/5 V (TTL) pin 0·1 RS232 come UART ±12 V invertiti MAX3232 RS485 A · B differenziale MAX485 CAN CAN_H · CAN_L bus multimaster MCP2515 SPI 4 fili full duplex pin 10–13 I²C SDA · SCL indirizzi 7 bit A4 · A5 1-Wire DQ + GND ID 64 bit un pin qualsiasi Dove li trovi: GPS, HC-05, Monitor seriale PC, strumenti, vecchi PLC Modbus RTU, industria, 1200 m auto, macchine agricole, robot SD, display TFT, 74HC595, ADC LCD, RTC, OLED, BMP280, MPU6050 DS18B20, chiavi iButton Nota: il modulo CAN (MCP2515) parla con Arduino via SPI; la seriale RS232/RS485 usa la UART di Arduino con un chip "traduttore" di livelli.
Il vocabolario

Otto concetti che tornano sempre

Ogni protocollo della scheda si descrive con queste parole. Se le sai, sai già leggere un datasheet.

Seriale e parallelo

Seriale: un bit dopo l'altro sullo stesso filo. Parallelo: più bit insieme su più fili. Oggi vince la seriale: meno fili, meno disturbi, distanze maggiori.

Sincrona e asincrona

Sincrona: un filo di clock dice "leggi adesso". Asincrona: niente clock, trasmettitore e ricevitore usano lo stesso baud rate e si riallineano con il bit di start.

Simplex, half, full duplex

Simplex: una sola direzione (radio FM). Half duplex: entrambe le direzioni a turno (walkie-talkie). Full duplex: entrambe insieme (telefono).

Punto-punto e bus

Punto-punto: due soli dispositivi. Bus: tanti dispositivi sugli stessi fili, quindi serve un modo per scegliere a chi si parla: un indirizzo o un filo di selezione.

Master e slave controller / target

Il master avvia la comunicazione e, nei bus sincroni, genera il clock. Lo slave risponde solo quando è interpellato. Nei documenti recenti trovi controller/target o controller/peripheral.

Single-ended e differenziale

Single-ended: il livello si misura tra il filo e GND (UART, I²C). Differenziale: conta la differenza tra due fili A e B (RS485, CAN). Il disturbo colpisce entrambi i fili allo stesso modo e si annulla.

Baud rate e tempo di bit

Il baud rate è il numero di simboli al secondo. In seriale un simbolo è un bit, quindi il tempo di un bit è l'inverso del baud rate.

t_bit = 1 / baud  →  9600 → 104 µs

Livelli logici

Arduino UNO lavora a 5 V, molti sensori moderni a 3,3 V. Collegare un'uscita a 5 V a un ingresso a 3,3 V può danneggiarlo: si usa un level shifter o un modulo che lo integra.

asincrona · punto-punto

UART · la seriale TTL

Due fili incrociati (TX→RX), nessun clock: ogni byte viaggia dentro una "busta" fatta di un bit di start e un bit di stop.

Fili
TX, RX e GND in comune. Si incrociano: il TX di uno va nell'RX dell'altro.
Tipo
Asincrona, full duplex, punto-punto
Livelli
TTL: 1 = 5 V (o 3,3 V), 0 = 0 V. A riposo la linea è a 1.
Trama
Formato 8N1: 1 start (0) + 8 bit dati, dal meno significativo (LSB) + nessuna parità + 1 stop (1) = 10 bit per byte
Velocità
9600, 19200, 38400, 57600, 115200 baud
Distanza
Pochi metri al massimo
Libreria
Serial (pin 0 e 1), SoftwareSerial (altri pin)

Da ricordare

"1 + 8 + 1 = 10": un byte costa 10 bit.

  • A riposo la linea è alta; lo start la porta a 0.
  • TX con RX, RX con TX, e GND sempre in comune.
  • Stessa velocità e stesso formato sui due lati, altrimenti arrivano caratteri strani.
  • Byte al secondo ≈ baud / 10.
Il carattere 'A' = 0x41 = 0100 0001₂ in formato 8N1. I bit escono dal meno significativo: b0 = 1, poi cinque zeri, b6 = 1, b7 = 0. A 9600 baud ogni colonna dura 104 µs.

Collegamenti su Arduino UNO

PinFunzioneNota
D0 (RX)RiceveCondiviso con il convertitore USB: scollega i moduli su 0/1 durante il caricamento dello sketch.
D1 (TX)TrasmetteStessa linea che arriva al Monitor seriale del PC.
qualsiasiSoftwareSerialSeriale "via software" su altri pin. Sull'UNO è affidabile fino a circa 38400 baud.
UNO R4Serial1Sulla UNO R4 Serial è la USB e Serial1 è separata sui pin 0/1.
A_trasmettitore.ino
// Arduino A: legge un potenziometro e lo invia
#include <SoftwareSerial.h>
SoftwareSerial link(10, 11);   // RX, TX

void setup() {
  link.begin(9600);
}

void loop() {
  int v = analogRead(A0);      // 0..1023
  link.println(v);             // testo + "\r\n"
  delay(200);
}
B_ricevitore.ino
// Arduino B: riceve e mostra sul Monitor seriale
#include <SoftwareSerial.h>
SoftwareSerial link(10, 11);   // RX, TX

void setup() {
  Serial.begin(9600);          // verso il PC
  link.begin(9600);            // verso Arduino A
}

void loop() {
  if (link.available()) {
    String riga = link.readStringUntil('\n');
    Serial.print("Ricevuto: ");
    Serial.println(riga);
  }
}

Cablaggio: pin 11 di A → pin 10 di B, pin 11 di B → pin 10 di A, GND di A → GND di B.

Errori tipici

  • Caratteri incomprensibili sul Monitor seriale: il baud rate impostato in basso a destra non è lo stesso di Serial.begin().
  • Nessun dato: TX collegato a TX. Vanno incrociati.
  • Dati casuali: manca il GND in comune tra le due schede.
  • Upload fallito: c'è un modulo collegato ai pin 0/1.

Esercizi UART

Es. 1Base

LED comandato da tastiera

Materiale: UNO, LED integrato (pin 13) · Tool: Monitor seriale

  1. Se ricevi a accendi il LED, se ricevi s spegnilo.
  2. Rispondi con "LED ON" o "LED OFF".
  3. Aggiungi ? che restituisce lo stato attuale.
Suggerimento

Usa if (Serial.available()) { char c = Serial.read(); ... }. Imposta il Monitor seriale su "Nessun fine riga", altrimenti ricevi anche \n.

Es. 2Base

Grafico in tempo reale

Materiale: UNO, potenziometro, fotoresistenza · Tool: Plotter seriale (IDE 2)

  1. Invia due valori per riga nel formato pot:512,luce:300.
  2. Apri Strumenti → Plotter seriale e osserva le due curve.
  3. Prova a 9600 e a 115200 baud con delay(5): cosa cambia nella fluidità?
Es. 3Medio

Due Arduino che parlano

Materiale: 2 UNO, potenziometro, LED + 220 Ω · Tool: IDE, oppure Wokwi con due schede

  1. Parti dagli sketch di esempio sopra.
  2. Su B, converti il valore ricevuto con toInt() e usa map() per pilotare il LED in PWM sul pin 9.
  3. Fai in modo che B risponda "OK" ad A per ogni valore ricevuto.
Es. 4Avanzato

Vedi i bit con l'analizzatore logico

Tool: Wokwi (parte "Logic Analyzer") oppure analizzatore USB a 8 canali + PulseView

  1. Invia Serial.write('A') ogni secondo e collega un canale al pin 1 (TX).
  2. Apri la cattura in PulseView e aggiungi il decoder UART a 9600 baud.
  3. Misura con i cursori la durata di un bit e confrontala con 104 µs.
  4. Disegna sul quaderno la trama di 'Z' e verificala.
Es. 5Avanzato

Registratore dati su PC

Tool: Python 3 + libreria pyserial

  1. Arduino invia una lettura al secondo nel formato millis;valore.
  2. Scrivi uno script Python che apre la porta (COM3 o /dev/ttyACM0), legge le righe e le salva in dati.csv.
  3. Apri il CSV con un foglio di calcolo e crea il grafico.
Scheletro Python
logger.py
import serial
porta = serial.Serial("COM3", 9600, timeout=2)
with open("dati.csv", "w") as f:
    for _ in range(60):
        riga = porta.readline().decode().strip()
        print(riga)
        f.write(riga + "\n")
asincrona · punto-punto · livelli ±12 V

RS232 · la seriale "storica" del PC

Stessa trama della UART, ma con tensioni più alte e invertite. Arriva più lontano e sopporta meglio i disturbi.

Fili minimi
TXD, RXD, GND (più eventuali segnali di handshake RTS/CTS, DTR/DSR)
Livelli
1 logico (mark) = da −3 a −15 V · 0 logico (space) = da +3 a +15 V
Connettore
DB9 lato PC: pin 2 = RXD, pin 3 = TXD, pin 5 = GND
Distanza
Circa 15 m (più corta ad alte velocità)
Adattatore
MAX232 (5 V) o MAX3232 (3,3–5 V): traduce TTL ↔ RS232
Oggi
Strumenti di misura, bilance, PLC, apparati di rete (porta console)

Da ricordare

"RS232 = UART a testa in giù e più forte".

  • Stesso formato 8N1, stesso codice Arduino.
  • Mai collegare RS232 direttamente ai pin di Arduino: −12 V lo danneggiano.
  • Tra due PC serve un cavo null-modem (2 e 3 incrociati).
Lo stesso carattere 'A' prima e dopo il MAX3232: i livelli sono invertiti e più ampi. A riposo la linea RS232 è negativa.

Catena di collegamento in laboratorio

Arduino TX (pin 1 o SoftwareSerial) → TXD-in del modulo MAX3232 → DB9 → adattatore USB-RS232 → PC con PuTTY o CoolTerm alla stessa velocità. Il codice è identico all'esempio UART.

Esercizi RS232

Es. 6Medio

Chat con il terminale del PC

Materiale: UNO, modulo MAX3232 con DB9, adattatore USB-RS232 · Tool: PuTTY o CoolTerm

  1. Arduino invia ogni 2 s "Temperatura: …" (valore anche simulato).
  2. Dal terminale invia R per azzerare un contatore su Arduino.
  3. Con il multimetro misura la tensione sul pin 3 del DB9 a riposo: è positiva o negativa? Perché?
Es. 7Base

Dal TTL al RS232 sulla carta

Tool: quaderno, righello

  1. Disegna la trama TTL di '5' (0x35) in 8N1.
  2. Sotto, disegna lo stesso segnale in RS232 con ±12 V.
  3. Indica sul disegno start, dati, stop e il livello di riposo.
Soluzione

0x35 = 0011 0101₂. Dal LSB: 1,0,1,0,1,1,0,0. Trama TTL: riposo 1 · start 0 · 1 0 1 0 1 1 0 0 · stop 1. In RS232 ogni 1 diventa −12 V e ogni 0 diventa +12 V.

asincrona · bus · differenziale

RS485 · la seriale per le lunghe distanze

Un doppino intrecciato (A e B) collega fino a 32 dispositivi anche a 1200 m. Si usa nell'industria, spesso con il protocollo Modbus RTU.

Fili
A e B (doppino intrecciato) + GND di riferimento consigliato
Segnale
Differenziale: conta la tensione tra A e B, non verso GND
Tipo
Half duplex con 2 fili: si parla a turno
Nodi
32 carichi standard sullo stesso bus
Distanza
Fino a 1200 m (a bassa velocità)
Terminazione
Resistenza da 120 Ω ai due estremi del bus
Modulo
MAX485: pin RO (→RX), DI (←TX), DE e RE (direzione)

Da ricordare

"Due fili, lontano, a turno".

  • Prima di trasmettere metti DE = 1, dopo Serial.flush() torna a 0.
  • RS485 definisce solo i segnali elettrici: il "chi parla con chi" lo decide il protocollo sopra (es. Modbus).
  • 120 Ω solo ai due capi, non su ogni nodo.
rs485_master.ino
#include <SoftwareSerial.h>
const int DIR = 2;               // DE e RE collegati insieme
SoftwareSerial rs(10, 11);       // RX ← RO, TX → DI

void setup() {
  pinMode(DIR, OUTPUT);
  digitalWrite(DIR, LOW);        // in ascolto
  rs.begin(9600);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(DIR, HIGH);       // ora parlo io
  rs.println("#2?");             // domanda al nodo 2
  rs.flush();                    // aspetta la fine dell'invio
  digitalWrite(DIR, LOW);        // torno in ascolto

  unsigned long t0 = millis();
  while (millis() - t0 < 500) {
    if (rs.available()) Serial.write(rs.read());
  }
  delay(1000);
}

Esercizi RS485

Es. 8Avanzato

Rete di sensori con indirizzi

Materiale: 2 o 3 UNO, un MAX485 per scheda, 10 m di doppino (anche cavo di rete), 2 resistenze da 120 Ω

  1. Il master interroga a turno i nodi con #1?, #2?.
  2. Ogni slave risponde solo se l'indirizzo è il suo, con una lettura analogica.
  3. Cosa succede se due slave rispondono insieme? Provalo e spiega.
Es. 9Medio

Misura la terminazione

Materiale: bus RS485 cablato, multimetro

  1. A schede spente misura la resistenza tra A e B con entrambe le terminazioni.
  2. Ripeti togliendone una.
  3. Spiega i due valori.
Soluzione

Due 120 Ω in parallelo danno 60 Ω; con una sola terminazione leggi circa 120 Ω. Se leggi valori molto più bassi hai troppe terminazioni sul bus.

sincrona · full duplex · master + slave

SPI · veloce e semplice

Il master genera il clock e manda e riceve un bit a ogni colpo di clock, su due fili separati. Per scegliere lo slave abbassa il suo filo CS.

Fili
SCK clock · MOSI dati master→slave · MISO dati slave→master · CS (o SS) selezione, attiva bassa. Nomi nuovi: COPI, CIPO.
Tipo
Sincrona, full duplex: mentre un byte esce, un altro entra
Più slave
SCK, MOSI, MISO in comune; un CS separato per ogni slave
Indirizzi
Nessuno: si sceglie lo slave con il CS
Velocità
Sull'UNO fino a 8 MHz; di solito 1–4 MHz
Distanza
Centimetri: è pensato per stare sulla stessa scheda
Libreria
SPI.h · SPI.transfer(byte)

Da ricordare

"4 fili, e un filo in più per ogni amico".

  • CS basso = "sto parlando con te".
  • Pin UNO: 13 SCK · 12 MISO · 11 MOSI · 10 CS.
  • Il pin 10 va sempre impostato come uscita, anche se usi un altro CS.
  • Master e slave devono avere lo stesso modo (0–3) e lo stesso ordine dei bit.
Modo 0: clock a riposo basso, il dato si legge sul fronte di salita. Il master invia 0xA5 = 1010 0101₂ (MSB prima) e nello stesso tempo riceve 0x3C = 0011 1100₂.

I quattro modi SPI

ModoCPOLCPHAClock a riposoIl dato si legge sul fronte
SPI_MODE000bassodi salita (il più diffuso)
SPI_MODE101bassodi discesa
SPI_MODE210altodi discesa
SPI_MODE311altodi salita
spi_74hc595.ino
// 8 LED su uno shift register 74HC595 via SPI
#include <SPI.h>
const int LATCH = 10;          // ST_CP (pin 12 del 595)

void setup() {
  pinMode(LATCH, OUTPUT);
  SPI.begin();
}

void scrivi(byte b) {
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  digitalWrite(LATCH, LOW);
  SPI.transfer(b);
  digitalWrite(LATCH, HIGH);   // le uscite si aggiornano qui
  SPI.endTransaction();
}

void loop() {
  for (int i = 0; i < 8; i++) {
    scrivi(1 << i);            // luce che scorre
    delay(150);
  }
}

Cablaggio 74HC595

UNO74HC595
D11 MOSIpin 14 DS (dati)
D13 SCKpin 11 SH_CP (clock)
D10pin 12 ST_CP (latch)
GNDpin 8 GND e pin 13 OE
5Vpin 16 VCC e pin 10 MR
—pin 15 e 1–7: Q0…Q7 → LED + 220 Ω

Il 595 non ha MISO: è un caso "solo scrittura". Funziona uguale anche su Wokwi.

Errori tipici

  • Modo SPI sbagliato: i dati arrivano spostati di un bit. Controlla CPOL e CPHA nel datasheet.
  • CS lasciato basso su due slave insieme: entrambi rispondono su MISO e i dati si mescolano.
  • Moduli a 3,3 V (molte schede SD, display) collegati a 5 V senza adattatore.

Esercizi SPI

Es. 10Base

Barra di LED

Materiale: 74HC595, 8 LED, 8 × 220 Ω · Tool: breadboard o Wokwi

  1. Carica l'esempio e verifica la luce che scorre.
  2. Leggi un potenziometro e accendi da 0 a 8 LED come un VU-meter.
Suggerimento

Con n LED accesi dal basso il byte vale (1 << n) - 1. Per n = 8 usa direttamente 0xFF.

Es. 11Medio

Cambia le regole

Materiale: circuito dell'es. 10

  1. Sostituisci MSBFIRST con LSBFIRST: cosa succede alla luce che scorre? Perché?
  2. Prova SPI_MODE3: il 595 funziona ancora? Consulta il datasheet per spiegarlo.
Soluzione

Con LSBFIRST l'ordine dei bit si inverte: la luce scorre nel verso opposto. Il 595 legge sul fronte di salita di SH_CP: il modo 3 legge anch'esso sulla salita, quindi di norma funziona; i modi 1 e 2 leggono sulla discesa e danno errori.

Es. 12Medio

Diario su scheda microSD

Materiale: modulo microSD SPI con adattatore di livello, sensore a scelta · Libreria: SD (inclusa nell'IDE)

  1. Ogni 5 s scrivi una riga secondi;valore in LOG.CSV.
  2. Leggi la scheda sul PC e fai il grafico.
  3. Quali pin sono condivisi con l'es. 10? Potresti usare 595 e SD insieme?
Es. 13Avanzato

Decodifica SPI

Tool: analizzatore logico + PulseView, oppure Wokwi Logic Analyzer

  1. Cattura SCK, MOSI e CS mentre invii 0xA5.
  2. Aggiungi il decoder SPI (modo 0) e leggi il byte.
  3. Misura la frequenza di SCK e confrontala con quella impostata in SPISettings.
sincrona · half duplex · bus con indirizzi

I²C · due fili per tanti dispositivi

Solo SDA (dati) e SCL (clock), in comune fra tutti. Il master chiama lo slave per indirizzo, e chi riceve conferma ogni byte con un ACK.

Fili
SDA dati, SCL clock, + GND e alimentazione
Tipo
Sincrona, half duplex, bus (anche multimaster)
Elettrica
Uscite open-drain: i dispositivi possono solo tirare la linea a 0. Il livello alto lo danno le resistenze di pull-up (tipico 4,7 kΩ)
Indirizzo
7 bit (112 indirizzi utilizzabili) + 1 bit R/W
Velocità
100 kHz (standard), 400 kHz (fast)
Pin UNO
A4 = SDA, A5 = SCL (ripetuti vicino ad AREF)
Libreria
Wire.h

Da ricordare

"Due fili, tanti amici, ognuno col suo numero".

  • START: SDA scende mentre SCL è alto. STOP: SDA sale mentre SCL è alto.
  • Nono bit = ACK: chi riceve tira SDA a 0. Se resta a 1 è un NACK.
  • Primo passo sempre: lancia lo scanner per scoprire gli indirizzi.
  • Due dispositivi con lo stesso indirizzo non possono stare sullo stesso bus.
Il master chiama l'LCD all'indirizzo 0x27 = 010 0111₂ in scrittura (R/W = 0). Il nono bit è l'ACK, dato dallo slave. Il dato cambia solo con SCL basso: se cambia con SCL alto è un START o uno STOP.

Indirizzi dei moduli più comuni in laboratorio

IndirizzoModuloNota
0x27 / 0x3FLCD 16×2 con adattatore PCF8574Dipende dal chip e dai ponticelli A0–A2
0x3COLED SSD1306 128×64A volte 0x3D
0x68RTC DS3231, IMU MPU6050Stesso indirizzo: l'MPU6050 può passare a 0x69 con il pin AD0
0x76 / 0x77BMP280, BME280Scelto dal pin SDO
0x57EEPROM AT24C32 sui moduli DS3231Compare anche se non la usi
i2c_scanner.ino
#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("Scansione I2C...");
  for (byte ind = 1; ind < 127; ind++) {
    Wire.beginTransmission(ind);
    if (Wire.endTransmission() == 0) {   // 0 = ACK
      Serial.print("Trovato: 0x");
      if (ind < 16) Serial.print('0');
      Serial.println(ind, HEX);
    }
  }
  Serial.println("Fine.");
}

void loop() {}
i2c_lcd.ino
// Libreria: LiquidCrystal I2C (Gestore librerie)
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);  // indirizzo dallo scanner

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.print("Ciao 5a!");
}

void loop() {
  lcd.setCursor(0, 1);
  lcd.print("t = ");
  lcd.print(millis() / 1000);
  lcd.print(" s   ");
  delay(250);
}
i2c_master.ino
// Due Arduino: il master invia al nodo 8
#include <Wire.h>

void setup() { Wire.begin(); }       // senza indirizzo = master

void loop() {
  byte v = analogRead(A0) >> 2;      // 0..255
  Wire.beginTransmission(8);
  Wire.write(v);
  Wire.endTransmission();
  delay(100);
}
i2c_slave.ino
#include <Wire.h>
volatile byte valore = 0;

void ricevi(int n) {                 // chiamata a ogni messaggio
  while (Wire.available()) valore = Wire.read();
}

void setup() {
  Wire.begin(8);                     // io sono il nodo 8
  Wire.onReceive(ricevi);
  pinMode(9, OUTPUT);
}

void loop() { analogWrite(9, valore); }

Cablaggio tra due UNO: A4↔A4, A5↔A5, GND↔GND, con pull-up da 4,7 kΩ verso 5 V su SDA e SCL.

Errori tipici

  • Lo scanner non trova nulla: SDA e SCL invertiti, oppure mancano le pull-up. Quelle interne dell'UNO sono troppo deboli; molti moduli però le hanno già a bordo.
  • Lo scanner si blocca: una linea è in corto a GND o un modulo è alimentato male.
  • LCD acceso ma senza scritte: indirizzo sbagliato, oppure contrasto da regolare con il trimmer sul retro.
  • Tanti moduli con pull-up tutte collegate: la resistenza equivalente diventa troppo bassa.

Esercizi I²C

Es. 14Base

Censimento del laboratorio

Materiale: UNO + tutti i moduli I²C disponibili · Tool: scanner

  1. Collega un modulo alla volta e annota l'indirizzo.
  2. Collegali tutti insieme: lo scanner li trova tutti?
  3. Compila una tabella modulo / indirizzo / tensione di alimentazione.
Es. 15Medio

Orologio-termometro su un solo bus

Materiale: LCD I²C, RTC DS3231 · Librerie: LiquidCrystal I2C, RTClib

  1. Collega LCD e RTC agli stessi A4/A5.
  2. Mostra ora e minuti sulla prima riga.
  3. Il DS3231 ha anche un sensore di temperatura interno: mostralo sulla seconda riga.
Es. 16Medio

Master e slave

Materiale: 2 UNO, potenziometro, LED · Tool: IDE o Wokwi

  1. Usa gli sketch master/slave sopra.
  2. Aggiungi un secondo slave all'indirizzo 9 che accende un LED solo se il valore supera 128.
  3. Fai rispondere lo slave con Wire.onRequest() e leggi la risposta con Wire.requestFrom().
Es. 17Avanzato

Trova l'ACK sulla cattura

Tool: analizzatore logico + PulseView (decoder I²C)

  1. Cattura SDA e SCL mentre l'LCD si aggiorna.
  2. Individua START, indirizzo, R/W, ACK e STOP.
  3. Nello sketch cambia l'indirizzo in uno inesistente: come appare il NACK?
  4. Passa a Wire.setClock(400000) e misura la nuova frequenza di SCL.
a slot temporali · bus · un solo filo dati

1-Wire · un filo, tanti sensori

Un solo filo dati (DQ) più la massa. Ogni dispositivo ha un numero di serie di 64 bit scritto in fabbrica, quindi se ne possono appendere molti sullo stesso filo.

Fili
DQ + GND (+ VDD, oppure alimentazione "parassita" presa da DQ)
Pull-up
4,7 kΩ tra DQ e VDD, obbligatoria
Tipo
Half duplex, master unico; ogni bit è una finestra di tempo aperta dal master
Indirizzo
ROM a 64 bit: famiglia (8 bit) + numero di serie (48 bit) + CRC (8 bit)
Velocità
Circa 16 kbit/s (standard)
Distanza
Decine di metri con cavo e pull-up adeguati
Librerie
OneWire + DallasTemperature

Da ricordare

"Un filo, un nome di 64 bit".

  • Ogni dialogo inizia con reset (master a 0 per almeno 480 µs) e presenza (lo slave risponde abbassando la linea).
  • DS18B20 visto di fronte, lato piatto: GND · DQ · VDD.
  • Da −55 a +125 °C, risoluzione fino a 0,0625 °C (12 bit), conversione 750 ms.
Scala non proporzionale. In azzurro le parti comandate dal master, in rosa la risposta del sensore. Un "1" è un impulso basso brevissimo, uno "0" un impulso basso lungo tutta la finestra.
ds18b20.ino
#include <OneWire.h>
#include <DallasTemperature.h>

OneWire bus(2);                      // DQ sul pin 2
DallasTemperature sensori(&bus);

void setup() {
  Serial.begin(9600);
  sensori.begin();
  Serial.print("Sensori trovati: ");
  Serial.println(sensori.getDeviceCount());
}

void loop() {
  sensori.requestTemperatures();     // avvia la conversione
  float t = sensori.getTempCByIndex(0);
  Serial.println(t);                 // -127 = sensore non trovato
  delay(1000);
}
stampa_indirizzi.ino (dentro setup)
DeviceAddress ind;
for (int i = 0; i < sensori.getDeviceCount(); i++) {
  sensori.getAddress(ind, i);
  Serial.print("Sensore ");
  Serial.print(i);
  Serial.print(": ");
  for (int j = 0; j < 8; j++) {
    if (ind[j] < 16) Serial.print('0');
    Serial.print(ind[j], HEX);
  }
  Serial.println();                  // il primo byte è 28 = DS18B20
}

Errori tipici

  • Si legge −127 °C: sensore non trovato. Controlla la pull-up e il verso del sensore.
  • Si legge 85 °C: è il valore di accensione, la conversione non è finita o l'alimentazione è insufficiente.
  • Sensore che scalda molto: è montato al contrario. Staccalo subito.

Esercizi 1-Wire

Es. 18Base

Temperatura sul Plotter

Materiale: DS18B20, 4,7 kΩ · Tool: Plotter seriale o Wokwi

  1. Carica l'esempio e apri il Plotter seriale.
  2. Stringi il sensore tra le dita e osserva la curva.
  3. Stima dal grafico la costante di tempo del sensore.
Es. 19Medio

Tre sensori, un filo

Materiale: 3 × DS18B20 in parallelo, una sola pull-up

  1. Stampa i tre indirizzi ROM e scrivili su un'etichetta vicino a ogni sensore.
  2. Leggi le temperature per indirizzo con getTempC(ind) invece che per indice.
  3. Perché leggere per indirizzo è più sicuro che per indice?
Es. 20Avanzato

Termostato comandato da seriale

Materiale: DS18B20, LED o modulo relè · combina UART e 1-Wire

  1. Dal Monitor seriale invia S25.5 per impostare la soglia.
  2. Accendi l'uscita sotto soglia − 0,5 °C e spegnila sopra soglia + 0,5 °C (isteresi).
  3. Spiega perché senza isteresi il relè "batte".
asincrona · bus multimaster · differenziale

CAN · il bus delle automobili

Tutti i nodi possono trasmettere. Se due partono insieme vince il messaggio con l'identificativo più basso, senza perdere dati: è l'arbitraggio.

Fili
CAN_H e CAN_L (doppino) + GND
Stati
Dominante = 0 (CAN_H ≈ 3,5 V, CAN_L ≈ 1,5 V) · Recessivo = 1 (entrambi ≈ 2,5 V)
Indirizzi
Non si indirizza il nodo ma il messaggio: ID a 11 bit (o 29 bit esteso)
Dati
Da 0 a 8 byte per trama, con CRC e ACK
Velocità
Fino a 1 Mbit/s (circa 40 m); 125 kbit/s arriva a circa 500 m
Terminazione
120 Ω ai due estremi
Su Arduino
Modulo MCP2515 (controller) + TJA1050 (transceiver), collegato via SPI

Da ricordare

"Lo 0 vince sempre: ID più basso, priorità più alta".

  • Un nodo che trasmette 1 ma legge 0 sul bus capisce di aver perso e si ritira.
  • Stesse 120 Ω e 60 Ω misurati della RS485.
  • Il modulo CAN usa SPI: stessi pin 10–13.
Ogni bit 0 (dominante) apre le due linee; ogni bit 1 (recessivo) le lascia a 2,5 V. Il ricevitore guarda solo la differenza CAN_H − CAN_L.
can_tx.ino
// Libreria: "arduino-mcp2515" di autowp
#include <SPI.h>
#include <mcp2515.h>

MCP2515 can(10);                    // CS del modulo sul pin 10
struct can_frame msg;

void setup() {
  can.reset();
  can.setBitrate(CAN_125KBPS, MCP_8MHZ);  // quarzo del modulo: di solito 8 MHz
  can.setNormalMode();
  msg.can_id  = 0x100;
  msg.can_dlc = 2;                  // 2 byte di dati
}

void loop() {
  int v = analogRead(A0);
  msg.data[0] = v >> 8;             // byte alto
  msg.data[1] = v & 0xFF;           // byte basso
  can.sendMessage(&msg);
  delay(100);
}

Esercizi CAN

Es. 21Avanzato

Due nodi e l'arbitraggio

Materiale: 2 o 3 UNO, un modulo MCP2515 ciascuno, doppino

  1. Il nodo A invia ID 0x100, il nodo B ID 0x200, entrambi ogni 10 ms.
  2. Il nodo C riceve con readMessage() e conta i messaggi per ID.
  3. Riduci l'intervallo a 1 ms: quale ID arriva sempre? Spiega con l'arbitraggio.
Tutto in una tabella

Confronto rapido

ProtocolloFili (senza GND)ClockDuplexTopologiaCome sceglie il destinatarioVelocità tipicaDistanzaPin UNO
UART2: TX, RXnofullpunto-puntonon serve9600–115200 baudpochi m0, 1
RS2322: TXD, RXDnofullpunto-puntonon servefino a 115200 baud~15 m0, 1 + MAX3232
RS4852: A, Bnohalfbus, 32 nodiprotocollo sopra (Modbus)fino a Mbit/s su brevi tratte1200 mRX, TX + MAX485
SPI4: SCK, MOSI, MISO, CSsìfullmaster + slaveun filo CS per slave1–8 MHzcm10, 11, 12, 13
I²C2: SDA, SCLsìhalfbusindirizzo a 7 bit100 / 400 kHz< 1 mA4, A5
1-Wire1: DQslot temporalihalfbusROM a 64 bit~16 kbit/sdecine di muno qualsiasi
CAN2: CAN_H, CAN_Lnohalfbus multimasterID del messaggio125 kbit/s – 1 Mbit/s40–500 mSPI + MCP2515

Quale scelgo?

Devo parlare con il PC o con un modulo GPS/BluetoothUART
Ho tanti sensori lenti e pochi pin liberiI²C
Mi serve velocità: display grafico, scheda SDSPI
Tante temperature lungo un solo cavo1-Wire
Centinaia di metri in un ambiente disturbatoRS485
Più centraline che devono poter parlare tutte, con prioritàCAN
Tutti gratuiti

Strumenti per il laboratorio

L'unico acquisto consigliato è un analizzatore logico USB a 8 canali, 24 MHz (circa 10 €), compatibile con PulseView. Senza, Wokwi offre un analizzatore simulato.

scrivere e caricare codice

Arduino IDE 2

Include Monitor seriale, Plotter seriale e Gestore librerie (Wire, SPI, SoftwareSerial sono già presenti).

simulare senza scheda

Wokwi

Simulatore online: UNO, LCD I²C, OLED, 74HC595, DS18B20, schede SD e un analizzatore logico che esporta le catture per PulseView.

simulare, livello base

Tinkercad Circuits

Utile per i primi circuiti e la seriale. Ha un LCD I²C: controlla sempre l'indirizzo con lo scanner.

vedere i bit

PulseView (sigrok)

Software per analizzatori logici con decoder UART, SPI, I²C, 1-Wire, CAN. Apre anche i file .vcd di Wokwi.

terminale seriale

PuTTY · CoolTerm

Per parlare con Arduino o con apparati RS232 senza l'IDE. CoolTerm mostra anche i byte in esadecimale.

programmare il PC

Python + pyserial

Leggere, salvare e rielaborare i dati che arrivano dalla porta seriale.

schemi elettrici

KiCad

Per disegnare lo schema dei circuiti da consegnare con la relazione.

Mettiti alla prova

Calcoli e domande di verifica

Rispondi sul quaderno, poi apri la soluzione.

1. Quanto tempo serve per inviare "CIAO" seguito da \r\n a 9600 baud, 8N1?

6 caratteri × 10 bit = 60 bit. 60 / 9600 = 6,25 ms.

2. Quanto dura un bit a 115200 baud?

1 / 115200 ≈ 8,68 µs.

3. A 9600 baud, quanti byte al secondo passano al massimo?

9600 / 10 = 960 byte/s, perché ogni byte richiede start e stop.

4. Perché l'I²C ha bisogno delle resistenze di pull-up e l'SPI no?

Le uscite I²C sono open-drain: sanno solo tirare la linea a 0. Il livello 1 lo fornisce la pull-up. Questo permette a più dispositivi di condividere la linea senza cortocircuiti. Le uscite SPI invece sono push-pull e pilotano sia l'1 sia lo 0.

5. Quanti dispositivi con indirizzi diversi può avere al massimo un bus I²C a 7 bit?

2⁷ = 128 indirizzi, di cui 16 riservati: 112 utilizzabili.

6. Hai 4 slave SPI. Quanti fili servono in totale tra master e slave (GND escluso)?

SCK + MOSI + MISO in comune = 3, più 4 fili CS = 7 fili.

7. Una transazione I²C che scrive un byte all'LCD: quanti colpi di clock servono, circa? A 100 kHz quanto dura?

Indirizzo + R/W + ACK = 9 clock, dato + ACK = 9 clock: 18 clock più START e STOP. Circa 20 × 10 µs = ≈ 0,2 ms.

8. Un DS18B20 a 12 bit misura 0x0191. Che temperatura è?

0x0191 = 401. La risoluzione è 0,0625 °C, quindi 401 × 0,0625 = 25,0625 °C.

9. Su un bus CAN due nodi trasmettono insieme gli ID 0x123 e 0x121. Chi vince?

Vince 0x121: al primo bit diverso (il bit 1) il nodo con 0x121 trasmette 0 (dominante) e l'altro, che trasmette 1, legge 0 e si ritira.

10. Collego un GPS a 3,3 V all'UNO: TX del GPS → pin 10, pin 11 → RX del GPS. Dove serve attenzione?

Sul filo dal pin 11 (5 V) all'RX del GPS (3,3 V): serve un partitore o un level shifter. Il filo opposto di solito funziona, perché 3,3 V è già letto come 1 dall'UNO.

11. Perché RS485 e CAN arrivano molto più lontano di UART e I²C?

Usano segnali differenziali su doppino intrecciato: il disturbo si somma uguale ai due fili e si annulla nella differenza. Inoltre le linee sono terminate con 120 Ω, che evita le riflessioni.

12. Lo scanner I²C mostra 0x27 e 0x68. Collego un MPU6050: cosa succede e come risolvi?

L'MPU6050 ha indirizzo 0x68 come il DS3231: conflitto. Si porta a 1 il pin AD0 dell'MPU6050, che passa a 0x69.

Progetto finale

La stazione meteo del laboratorio

Mettete insieme quattro protocolli su una sola scheda UNO, in gruppi di tre.

  • 1-Wire: due DS18B20 (interno ed esterno) sul pin 2.
  • I²C: LCD 16×2 e RTC DS3231 su A4/A5, più un BMP280 per la pressione se disponibile.
  • SPI: modulo microSD che salva una riga al minuto in METEO.CSV.
  • UART: comandi dal PC, ad esempio ORA hh:mm per regolare l'orologio e DUMP per stampare il file.
  • Consegna: schema in KiCad, sketch commentato, una cattura PulseView per ogni protocollo con i campi evidenziati, grafico di 24 ore di dati.