Con riferimento ad Arduino Uno, Mega2560, Leonardo e schede simili:
- Come funzionano le comunicazioni seriali?
- Quanto è veloce la seriale?
- Come si collega un mittente e un destinatario?
Nota: questa è una domanda di riferimento.
Con riferimento ad Arduino Uno, Mega2560, Leonardo e schede simili:
Nota: questa è una domanda di riferimento.
Risposte:
Le comunicazioni seriali asincrone (generalmente definite seriali) vengono utilizzate per inviare byte da un dispositivo a un altro. Un dispositivo potrebbe essere uno o più dei seguenti:
A differenza delle comunicazioni seriali SPI / USB / I2C non ha un segnale di clock. L'orologio di campionamento è una frequenza di campionamento concordata (nota come baud rate). Sia il mittente che il destinatario devono essere configurati per utilizzare la stessa velocità o il destinatario riceverà dati privi di significato (a causa dei bit che non vengono campionati alla stessa velocità con cui sono stati inviati).
La trasmissione è asincrona, il che significa sostanzialmente che i byte possono essere inviati in qualsiasi momento, con divari variabili tra loro. Questo grafico illustra un singolo byte inviato:
Il grafico sopra mostra la lettera 'F' che viene trasmessa. In ASCII questo è 0x46 (in esadecimale) o 0b01000110 (in binario). Il minimo significativa (ordine inferiore) bit è trasmesso per primo, quindi nel grafico di cui sopra si vede i bit arrivano nell'ordine: 01100010
.
Il tempo "inattivo" tra i byte viene trasmesso come bit "1" continui (in effetti, la linea di trasmissione viene mantenuta alta in modo continuo).
Per indicare l'inizio di un byte, il Bit di avvio viene sempre indicato tirando la linea in basso come mostrato nel grafico. Una volta che il ricevitore vede il bit di avvio, attende 1,5 volte il tempo di campionamento, quindi campiona i bit di dati. Aspetta 1,5 volte in modo che:
Se la velocità di trasmissione è di 9600 baud, ad esempio, la frequenza di campionamento sarà di 1/9600 = 0.00010416
secondi (104,16 µs).
Pertanto, a 9600 baud, dopo aver ricevuto un bit di avvio, il ricevitore attende 156,25 µs, quindi campiona ogni 104,16 µs.
Lo scopo del bit di stop è garantire che ci sia sicuramente un 1 bit tra ogni byte. Senza il bit di stop, se un byte termina in uno zero, sarebbe impossibile per l'hardware distinguere tra quello e il bit iniziale del byte successivo.
Per produrre l'output sopra riportato su Uno è possibile scrivere questo codice:
void setup()
{
Serial.begin(9600);
Serial.print("F");
}
void loop ()
{
}
Per risparmiare tempo di trasmissione (ai vecchi tempi, eh) ti è stato permesso di specificare diversi numeri di bit di dati. L'hardware AtMega supporta la numerazione dei bit di dati da 5 a 9. Chiaramente meno bit di dati meno informazioni è possibile inviare, ma più veloce sarà.
Opzionalmente puoi avere un bit di parità. Questo viene calcolato, se richiesto, contando il numero di 1 nel carattere e quindi assicurandosi che questo numero sia dispari o anche impostando il bit di parità su 0 o 1 come richiesto.
Ad esempio, per la lettera "F" (o 0x46 o 0b01000110) puoi vedere che ce ne sono 3 lì (in 01000110). Quindi abbiamo già dispari parità. Quindi, il bit di parità sarebbe il seguente:
Il bit di parità, se presente, appare dopo l'ultimo bit di dati ma prima del bit di stop.
Se il destinatario non ottiene il bit di parità corretto, viene chiamato "errore di parità". Indica che c'è qualche problema. Probabilmente il mittente e il destinatario sono configurati per utilizzare velocità di trasmissione diverse (bit), o c'era del rumore sulla linea che trasformava uno zero in uno o viceversa.
Alcuni sistemi precedenti utilizzavano anche la parità "mark" (in cui il bit di parità era sempre 1 indipendentemente dai dati) o la parità "space" (in cui il bit di parità era sempre 0 indipendentemente dai dati).
Alcune apparecchiature di comunicazione utilizzano dati a 9 bit, quindi in questi casi il bit di parità viene trasformato nel 9 ° bit. Esistono tecniche speciali per l'invio di questo 9 ° bit (i registri sono registri a 8 bit, quindi il 9 ° bit deve essere inserito altrove).
Le prime apparecchiature tendevano a essere un po 'più lente elettronicamente, quindi per dare al ricevitore il tempo di elaborare il byte in entrata, a volte veniva specificato che il mittente avrebbe inviato due bit di stop. Questo in pratica aggiunge più tempo in cui la linea di dati viene mantenuta alta (un altro bit) prima che possa apparire il prossimo bit di inizio. Questo tempo di bit in più dà al ricevitore il tempo di elaborare l'ultimo byte in entrata.
Se il ricevitore non ottiene un 1 logico quando si suppone che sia il bit di stop, questo viene chiamato "errore di framing". Indica che c'è qualche problema. Molto probabilmente il mittente e il destinatario sono configurati per utilizzare diverse velocità di trasmissione (bit).
Comunemente, la comunicazione seriale viene indicata indicando la velocità, il numero di bit di dati, il tipo di parità e il numero di bit di stop, in questo modo:
9600/8-N-1
Questo ci sta dicendo:
È importante che il mittente e il destinatario concordino quanto sopra, altrimenti è improbabile che la comunicazione abbia successo.
Arduino Uno ha pin digitali 0 e 1 disponibili per hardware seriale:
Per connettere due Arduinos devi scambiare Tx e Rx in questo modo:
È supportata un'ampia gamma di velocità (vedere la figura seguente). Le velocità "standard" sono generalmente un multiplo di 300 baud (es. 300/600/1200/2400 ecc.).
Altre velocità "non standard" possono essere gestite impostando i registri appropriati. La classe HardwareSerial fa questo per te. per esempio.
Serial.begin (115200); // set speed to 115200 baud
Come regola empirica, supponendo che si stiano utilizzando dati a 8 bit, è possibile stimare il numero di byte che è possibile trasmettere al secondo dividendo il baud rate per 10 (a causa del bit di avvio e di arresto).
Pertanto, a 9600 baud è possibile trasmettere 960 byte ( 9600 / 10 = 960
) al secondo.
La velocità di trasmissione su Atmega viene generata dividendo l'orologio di sistema e quindi contando fino a un numero predefinito. Questa tabella dal foglio dati mostra i valori di registro e le percentuali di errore per un clock a 16 MHz (come quello sull'Arduino Uno).
Il bit U2Xn influenza il divisore della frequenza di clock (0 = divide per 16, 1 = divide per 8). Il registro UBRRn contiene il numero fino al conteggio del processore.
Quindi dalla tabella sopra, vediamo che otteniamo 9600 baud da un clock a 16 MHz come segue:
16000000 / 16 / 104 = 9615
Dividiamo per 104 e non 103 perché il contatore è zero-relativo. Quindi l'errore qui è 15 / 9600 = 0.0016
che è vicino a quello che dice la tabella sopra (0,02%).
Noterai che alcuni baud rate hanno un errore maggiore rispetto ad altri.
Secondo il foglio dati, la percentuale massima di errore per 8 bit di dati è compresa tra 1,5% e 2,0% (vedere il foglio dati per maggiori dettagli).
Arduino Leonardo e Micro hanno un approccio diverso alle comunicazioni seriali, poiché si collegano direttamente tramite USB al computer host, non tramite la porta seriale.
Per questo motivo, devi attendere che Serial diventi "pronto" (poiché il software stabilisce una connessione USB), con un paio di linee extra, come questo:
void setup()
{
Serial.begin(115200);
while (!Serial)
{} // wait for Serial comms to become ready
Serial.print("Fab");
}
void loop ()
{
}
Tuttavia, se si desidera comunicare effettivamente tramite i pin D0 e D1 (anziché tramite il cavo USB), è necessario utilizzare Serial1 anziché Serial. Fai così:
void setup()
{
Serial1.begin(115200);
Serial1.print("Fab");
}
void loop ()
{
}
Si noti che Arduino utilizza i livelli TTL per le comunicazioni seriali. Ciò significa che si aspetta:
Le apparecchiature seriali precedenti progettate per essere collegate alla porta seriale di un PC utilizzano probabilmente livelli di tensione RS232, vale a dire:
Non solo questo è "invertito" rispetto ai livelli TTL (un "uno" è più negativo di uno "zero"), l'Arduino non può gestire tensioni negative sui suoi pin di ingresso (né quelli positivi superiori a 5 V).
Pertanto è necessario un circuito di interfaccia per comunicare con tali dispositivi. Solo per l'ingresso (nell'Arduino), un semplice transistor, un diodo e un paio di resistori lo faranno:
Per la comunicazione bidirezionale è necessario essere in grado di generare tensioni negative, quindi è necessario un circuito più complesso. Ad esempio, il chip MAX232 lo farà, in combinazione con quattro condensatori da 1 µF, fungendo da circuiti della pompa di carica.
Esiste una libreria chiamata SoftwareSerial che consente di effettuare comunicazioni seriali (fino a un certo punto) nel software anziché nell'hardware. Ciò ha il vantaggio di poter utilizzare diverse configurazioni dei pin per le comunicazioni seriali. Lo svantaggio è che fare seriale nel software richiede più processore e tende a errori. Vedere Seriale software per maggiori dettagli.
Arduino "Mega" ha 3 porte seriali hardware aggiuntive. Sono contrassegnati sulla scheda come Tx1 / Rx1, Tx2 / Rx2, Tx3 / Rx3. Dovrebbero essere usati preferibilmente al SoftwareSerial, se possibile. Per aprire quelle altre porte usate i nomi Serial1, Serial2, Serial3, in questo modo:
Serial1.begin (115200); // start hardware serial port Tx1/Rx1
Serial2.begin (115200); // start hardware serial port Tx2/Rx2
Serial3.begin (115200); // start hardware serial port Tx3/Rx3
Sia l'invio che la ricezione, utilizzando la libreria HardwareSerial, utilizzano gli interrupt.
Quando si esegue un Serial.print
, i dati che si sta tentando di stampare vengono collocati in un buffer "di trasmissione" interno. Se si dispone di 1024 byte o più di RAM (come su Uno) si ottiene un buffer a 64 byte, altrimenti si ottiene un buffer a 16 byte. Se il buffer ha spazio, quindi Serial.print
restituisce immediatamente, quindi non ritardando il codice. Se non c'è spazio, si "blocca" in attesa che il buffer si svuoti abbastanza da consentire lo spazio.
Quindi, quando ogni byte viene trasmesso dall'hardware, viene chiamato un interrupt ("USART, Data Register Empty") e la routine di interruzione invia il byte successivo dal buffer dalla porta seriale.
Quando vengono ricevuti i dati in entrata, viene chiamata una routine di interrupt (l'interruzione "USART Rx Complete") e il byte in entrata viene inserito in un buffer "di ricezione" (delle stesse dimensioni del buffer di trasmissione menzionato sopra).
Quando chiami Serial.available
, scopri quanti byte sono disponibili in quel buffer di "ricezione". Quando si chiama Serial.read
un byte viene rimosso dal buffer di ricezione e restituito al codice.
Su Arduinos con 1000 byte o più di RAM, non c'è fretta di rimuovere i dati dal buffer di ricezione, a condizione che non si riempia. Se si riempie, tutti gli altri dati in arrivo vengono eliminati.
Si noti che a causa delle dimensioni di questo buffer non ha senso attendere l'arrivo di un numero molto elevato di byte, ad esempio:
while (Serial.available () < 200)
{ } // wait for 200 bytes to arrive
Questo non funzionerà mai perché il buffer non può contenere così tanto.
Prima di leggere, assicurarsi sempre che i dati siano disponibili. Ad esempio, questo è sbagliato:
if (Serial.available ())
{
char a = Serial.read ();
char b = Serial.read (); // may not be available
}
Il Serial.available
test garantisce solo la disponibilità di un byte, tuttavia il codice tenta di leggerne due. Può funzionare, se ci sono due byte nel buffer, in caso contrario verrà restituito -1 che apparirà come 'ÿ' se stampato.
Essere consapevoli di quanto tempo ci vuole per inviare i dati. Come accennato in precedenza, a 9600 baud si trasmettono solo 960 byte al secondo, quindi provare a inviare 1000 letture da una porta analogica, a 9600 baud, non avrà molto successo.