Comunicare con Arduino I 2 C TxRx Bluetooth
Comunicare con Arduino I 2 C Tx-Rx Bluetooth RS 485
Introduzione �La nascita dei microcontrollori è dovuta alla necessità di controllare diverse grandezze fisiche in tempo reale �La società attuale va così di corsa che l’uomo da solo non riesce a far fronte a tutte le esigenze dettate �Ciò non basta, c’è la necessità di accorciare le distanze; le diverse grandezze misurate devono essere elaborate e controllate in altri posti remoti dal trasduttore �Si è aggiunta allora la necessità di far comunicare più dispositivi tra loro �La scheda arduino può far fronte a queste esigenze con i metodi elencati nella slide successiva
Modi per comunicare �Modo seriale: basta mettere i pin di due schede in collegamento; tale comunicazione è per piccolissime distanze e può servire per ampliare le capacità della scheda. Tale metodo è detto I 2 C ed è il più semplice �TX-RX: comunicazione in radiofrequenza; non è simmetrica in quanto uno fa da trasmettitore e l’altro da ricevitore �Bluethoot: un dispositivo dotato di bluethoot può comunicare con la scheda arduino alla quale viene collegato comunque un modulo bluethoot �Ethernet: esiste una scheda di rete che si può collegare alla scheda arduino e quindi, ad una rete locale �Wifi: tramite una antenna, si può collegare arduino ad una rete locale �
I 2 C �Arduino dispone di due pin analogici per la comunicazione: il pin A 4 detto anche SDA, serial data e, A 5 SCL serial Clock �Se si vuol far comunicare due schede arduino, basta collegare il A 4 dell’uno con il A 4 dell’altro e A 5 dell’uno con A 5 dell’altro. �La comunicazione non è simmetrica in quanto uno farà da master e l’altro da slave.
Accensione di un led con I 2 C �Una scheda arduino invia un comando per far accendere un led situato su un’altra scheda arduino �Il programma master è il seguente: //master #include <Wire. h> void setup() { Wire. begin(); pin. Mode (2, OUTPUT); } void loop() { Wire. request. From(2, 1); // richiedi 1 byte al dispositivo presente all'indirizzo 2. String b = ""; char c = Wire. read(); b = b + c; delay (100); if (b == "a") { digital. Write(2, HIGH); } else { digital. Write(2, LOW); } delay(10); }
Programma slave #include <Wire. h> void setup() { pin. Mode(2, INPUT); pin. Mode(3, OUTPUT); Wire. begin(2); // I 2 C con indirizzo 2 Wire. on. Request(request. Event); } void loop() { delay(100); } void request. Event() { if (digital. Read(2) == HIGH){ Wire. write("a"); digital. Write(3, HIGH); } else { Wire. write("s"); digital. Write(3, LOW); } }
Tx-Rx
Funzioni di configurazione �vw_set_tx_pin(transmit_pin) Imposta il pin di trasmissione. Il pin di default impostato nella libreria è il 12. �vw_set_rx_pin(receive_pin) Imposta il pin per la ricezione. Il pin di default impostato nella libreria è il 11. �vw_setup(baudrate) Inizializza la libreria. Prima di mandare in esecuzione tale comando tutti i pin devono essere già stati impostati. L'argomento è la velocità di trasferimento (numero di bit al secondo).
Funzioni di trasmissione � vw_send(message, length) Trasmette il messaggio. "message" è un array di byte mentre length è il numero di byte da spedire. Questa funzione ritorna il controllo al programma chiamante immediatamente ed esegue l'invio mediante un processo in background basato su interrupt. Restituisce true se il messaggio è stato accettato per la trasmissione false se il messaggio è troppo lungo (maggiore di. VW_MAX_MESSAGE_LEN - 3). vw_tx_active() Ritorna true se il messaggio è in spedizione altrimenti false. E' utilizzato per testare se, dopo il comando di spedizione, il messaggio è stato completamente trasmesso. vw_wait_tx() Aspetta che il messaggio sia completamente spedito. Solitamente è utilizzato dopo il comando vw_send().
Funzioni di ricezione Funzioni di Ricezione � vw_rx_start() Attiva il processo di ricezione. E' necessario effettuare una chiamata a tale funzione prima di procedere con qualsiasi ricezione. Attiva un processo in background basato su interrupt che controlla se ci sono dati in arrivo. vw_have_message() Ritorna true se il messaggio è stato ricevuto. E' analogo ai comandi "available" presenti in molte librerie. vw_wait_rx() Attende l'arrivo di un messaggio. Tale funzione termina solo quando arriva il messaggio altrimenti resta in attesa per sempre. vw_wait_rx_max(timeout_ms) Aspetta l'arrivo di un messaggio per un tempo definito in "timeout_ms". Restituisce true se arriva un messaggio nell'intervallo stabilito, false altrimenti. vw_get_message(buf, &buflen)) Legge l'ultimo messaggio ricevuto. Tale funzione dovrebbe essere chiamata solo quando si è verificato l'arrivo di un messaggio mediante una delle 3 precedenti funzioni. "buf" è un array dove verrà depositato il messaggio in arrivo. "buflen" contiene inizialmente la dimensione dell'array e successivamente il numero di byte letti. La funzione restituisce true se il messaggio ricevuto è corretto altrimenti false se il messaggio appare corrotto (non ). vw_rx_stop() Disabilita il processo di ricezione
Circuito
Programma TX #include <Virtual. Wire. h> const int TX_DIO_Pin = 2; const int PIN_BUTTON 1 = A 0; const int PIN_BUTTON 2 = A 1; const int PIN_BUTTON 3 = A 2; const int PIN_BUTTON 4 = A 3; const int PIN_BUTTON 5 = A 4; const int PIN_BUTTON 6 = A 5; unsigned int Data; void setup() {Serial. begin(9600); pin. Mode(13, OUTPUT); vw_set_tx_pin(TX_DIO_Pin); vw_set_ptt_inverted(true); vw_setup(1000); } void loop() { if(has. Been. Pressed(PIN_BUTTON 1)){ Data = 1; send. Data(Data); Serial. println("HF- Delta. Loop"); // Visualizzo il messaggio sul display } if(has. Been. Pressed(PIN_BUTTON 2)){ Data = 2; send. Data(Data); Serial. println("HF- More. Gain"); } if(has. Been. Pressed(PIN_BUTTON 3)){ Data = 3; send. Data(Data); Serial. println("HF- 15 mt Dipole"); } if(has. Been. Pressed(PIN_BUTTON 4)){ Data = 4; send. Data(Data); Serial. println("V/UHF- Quadrifil"); // Visualizzo il messaggio sul display } if(has. Been. Pressed(PIN_BUTTON 5)){ Data = 5; send. Data(Data); Serial. println("V/UHF-Yagi V/UHF"); // Visualizzo il messaggio sul display } } boolean has. Been. Pressed(int pin){ if(analog. Read(pin)>1000){ return true; }else{ return false; } } void send. Data(int Data){ byte Tx. Buffer[2]; Tx. Buffer[0] = Data >> 8; Tx. Buffer[1] = Data; digital. Write(13, HIGH); vw_send((byte *)Tx. Buffer, 2); vw_wait_tx(); digital. Write(13, LOW); delay(1000); }
Programma RX #include <Virtual. Wire. h> const int RX_DIO_Pin = 2; const int PIN_RELAY 4 = 10; //antenne V/UHF Quadrifilare const int PIN_RELAY 5 = 11; //antenne V/UHF Yagi const int PIN_RELAY 1 = 3; //antenne HF Dipolo const int PIN_RELAY 2 = 4; //antenne HF More. Gain const int PIN_RELAY 3 = 5; //antenne HF Delta Loop const int PIN_RELAYvhf. OFF = 6; // resetta tutti i relè V/UHF const int PIN_RELAYhf. OFF = 7; // resetta tutti i relè HF boolean RELAY 1 = false; boolean RELAY 2 = false; boolean RELAY 3 = false; boolean RELAY 4 = false; boolean RELAY 5 = false; boolean RELAYvhf. OFF = false; boolean RELAYhf. OFF = false; void setup(){ pin. Mode(13, OUTPUT); Serial. begin(9600); pin. Mode(PIN_RELAY 1, OUTPUT); pin. Mode(PIN_RELAY 2, OUTPUT); pin. Mode(PIN_RELAY 3, OUTPUT); pin. Mode(PIN_RELAY 4, OUTPUT); pin. Mode(PIN_RELAY 5, OUTPUT); pin. Mode(PIN_RELAYvhf. OFF, OUTPUT); pin. Mode(PIN_RELAYhf. OFF, OUTPUT); vw_set_rx_pin(RX_DIO_Pin); vw_setup(1000); vw_rx_start(); }
Programma RX void loop(){ uint 8_t Buffer_Size = 2; unsigned int Data; uint 8_t Rx. Buffer[Buffer_Size]; if (vw_get_message(Rx. Buffer, &Buffer_Size)){ Data = Rx. Buffer[0] << 8 | Rx. Buffer[1]; } if(Data==1){ //antenne HF Serial. println(Data); digital. Write(PIN_RELAYhf. OFF, HIGH); // azzera tutti i relè delay(500); digital. Write(PIN_RELAYhf. OFF, LOW); // li lascia aperti digital. Write(PIN_RELAY 3, HIGH); //attiva il relè. delay(2000); // attendi due secondi. digital. Write(PIN_RELAY 3, LOW); //stacca corrente (il relè rimane nel suo stato). } if(Data==2){ Serial. println(Data); digital. Write(PIN_RELAYhf. OFF, HIGH); // azzera tutti i relè delay(500); digital. Write(PIN_RELAYhf. OFF, LOW); // li lascia aperti digital. Write(PIN_RELAY 2, HIGH); //attiva il relè 2. delay(2000); // attendi due secondi. digital. Write(PIN_RELAY 2, LOW); //stacca corrente (il relè rimane nel suo stato). } if(Data==3){ Serial. println(Data); digital. Write(PIN_RELAYhf. OFF, HIGH); // azzera tutti i relè delay(500); digital. Write(PIN_RELAYhf. OFF, LOW); // li lascia aperti digital. Write(PIN_RELAY 1, HIGH); //attiva il relè 2. delay(2000); . digital. Write(PIN_RELAY 1, LOW); } if(Data==4){ Serial. println(Data); digital. Write(PIN_RELAYvhf. OFF, HIGH); // azzera tutti i delay(500); digital. Write(PIN_RELAYvhf. OFF, LOW); // li lascia aperti digital. Write(PIN_RELAY 4, HIGH); //attiva il relè 2. delay(2000); // attendi due secondi. digital. Write(PIN_RELAY 4, LOW); . } if(Data==5){ Serial. println(Data); digital. Write(PIN_RELAYvhf. OFF, HIGH); // azzera tutti i relè delay(500); digital. Write(PIN_RELAYvhf. OFF, LOW); // li lascia aperti digital. Write(PIN_RELAY 5, HIGH); //attiva il relè 2. delay(2000); // attendi due secondi. digital. Write(PIN_RELAY 5, LOW); } delay(500); }
Introduzione al bluetooth �In telecomunicazione è uno standard tecnico industriale per le comunicazioni senza filo ad onde radio �La distanza coperta con questa tecnica è dell’ordine dei dieci metri �Questa tecnica mette in comunicazione dispositivi elettronici anche differenti come palmari, cellulari, pc, tv, stampanti, fotocamere. �La tecnica è stata messa in atto dalla Ericson �La frequenza di lavoro è di 2. 45 GHz e la velocità di trasferimento dati è 2 Mbps
HC-05 Modulo bluetooth
Schema elettrico Il modulo HC 05 è dotato di 4 pin: VCC GND TX che va su RX di Arduino RX che va su TX di Arduino
Bluetooth: codice //Il codice è molto semplice, è quello di una banale comunicazione seriale, tanto è vero che non richiede librerie aggiuntive int value; int led = 5; void setup() { pin. Mode(led, OUTPUT); Serial. begin(9600); } void loop() { if( Serial. available()>0 ) { value = Serial. read(); if( value == 'H' ) { digital. Write(led, HIGH); } else if( value == 'L' ) { digital. Write(led, LOW); } } delay(100); }
Bluetooth � La comunicazione bluetooth avviene tramite seriale di un qualsiasi pc; il programma è infatti, un semplice controllo di led o interruttori tramite la seriale del pc. � Nel caso del bluetooth, bisogna controllare la porta virtuale del pc dove viene installato il modulo HC-05. La porta seriale attraverso la quale il pc comunica con arduino è diversa da quella attraverso la quale il pc comunica con il modulo HC-05. � Per evitare eventuali conflitti, conviene prima passare il programma compilato al microcontrollore e poi, montare il modulo bluetooth. � I comandi al bluetooth possono essere passati anche tramite il monitor seriale di arduino cambiando la porta di accesso. Ciò però può portare dei conflitti e allora, conviene installare un programma che interfacci il bluetooh al pc. � Un programma molto utile è Pu. TTY, è un programma molto semplice da usare ed è free.
Dispositivi e stampanti
Codice
Pu. TTY Prima della connessione
Bluetooth e Pu. TTY Per connettere il Bloutooth bisogna avviare il programma Pu. TTY Appena avviato, compare la schermata a lato
Bluetooth e Pu. TTY Il primo passo da fare è quello di selezionare il monitor seriale
Bluetooth e Pu. TTY Il passo successivo è quello di inserire la porta seriale
Bluetooth e Pu. TTY �Se tutto va a buon fine, comparirà la seguente schermata
Connessione Anche HC-05 è connesso
Bluetooth e Pu. TTY Se la porta non è quella giusta o è occupata, la schermata è questa
Monitor seriale Si piò anche utilizzare il monitor seriale di Arduino, basta selezionare la porta in cui si trova il bluetooth, in questo caso la com 12
RS 485 �È una connessione fisica, cablata; il trasferimento dei dati avviene tramite seriale; non è un protocollo. �La velocità di trasmissione è di circa 100 Kb/s per 1200 m �La connessione può essere fatta tra due o più device dello stesso tipo; si possono collegare fino a 32 dispositivi; è un sistema a single master e multi slave nel senso che c’è un solo master e più slave. Gli slave non comunicano tra loro ma solo con il master. �In questa sede, viene trattata la comunicazione tra due schede Arduino 1 �La comunicazione avviene in maniera differenziale e in half duplex secondo le direttive EIA/TIA-485
rs 485 I pin sono DI = data in RO = ricevitore out DE= data enable RE= receive enable VCC=alimentazione + GND=massa A e B
Collegamenti
Comunicazione differenziale � La comunicazione RS 485 è di tipo speculare: ci sono due livelli logici, quello di trasmissione e il suo complementare, quello speculare che a livello logico alto fa corrispondere uno basso e viceversa . La comunicazione avviene quindi su due cavi. La comunicazione è differenziale. Su un cavo viaggia un segnale e sull’altro cavo viaggia il segnale speculare. In questo modo, il livello logico alto corrisponde non a 5 V di uscita ma a 10 V perché si misura la differenza tra i due livelli; il livello logico basso corrisponde quindi a 5 V Questa tecnica fa in modo che la comunicazione RS 485 è immune da disturbi
Comunicazione differenziale All'uscita del trasmettitore la differenza di potenziale tra le linee A e B deve essere di almeno 4 V e la tensione di modo comune deve essere minore di 7 V (normalmente una linea vale 0 V e l'altra circa 5 V). Il ricevitore deve essere in grado di interpretare correttamente lo stato della linea quando la differenza di potenziale è superiore in modulo a 200 m. V. In appendice ho riportato una tabella con tutti i valori elettrici definiti dallo standard
Comunicazione half duplex �Per comunicazione half duplex si intende la trasmissione dati che avviene nei due versi, su uno stesso cavo ma non contemporaneamente �Un solo cavo viene quindi utilizzato sia per la ricezione che per la trasmissione ma in tempi differenti, prima l’una e poi l’altra. �Differente è la full duplex, tecnica che permette la comunicazione in entrambe i versi, sullo stesso cavo e negli stessi istanti ma, non adottata in questo caso. �Conviene utilizzare un cavo twistato perché è immune da disturbi
RS 485
Adattatori di impedenza �Ciascun cavo è caratterizzato da resistenza, capacità ed induttanza. La capacità di un cavo di buona qualità varia tra i 50 p. F/m e i 100 p. F/m. La capacità varia anche con il baud rate secondo questa tabella
�Uno dei disturbi ai quali si può far fronte è quello della riflessione del segnale �Per evitare questo disturbo basta aggiungere una resistenza di terminazione detta adattatore di impedenza �Se la durata di un singolo bit trasmesso SBTx è maggiore di almeno 10 volte del tempo tp che il segnale impiega a percorrere tutta la linea allora la terminazione non serve.
Collegamento di più dispositivi
Esempio di adattamento di impedenza � La velocità del segnale all’interno del cavo è 2/3 della velocità della luce � Se il cavo è lungo 1, 2 Km, il tempo per attraversare il cavo sarà tp=1. 2/(0. 666*c)= 6 us � Se la velocità di trasmissione è 9600 baud (9600 bit per secondo) allora il tempo di bit è SBTx= 1/9600 = 104. 166 us � 104. 66>6*10 � Quindi non serve la terminazione � Se invece fosse necessario terminare la linea quello che si fa è mettere sul nodo più lontano dal master una resistenza a carbone collegata tra A e B il cui valore deve essere pari all'impedenza caratteristica della linea ZL. Il problema è determinare in modo corretto l'impedenza ZL che è legata all'impedenza del cavo Zo e all'impedenza dei chip 485. In generale l'impedenza ZL varia tra i 120 e 560 ohm ma con i moderni 485 si arriva anche a 10. . . 12 Kohm.
Diagramma a occhio Per poter visualizzare la correttezza dei collegamenti basta visualizzare il segnale con un oscilloscopio con ingresso differenziale
Collegamenti
Schema DI= Data Input può essere collegato su pin D 11 RO= Receive Output può essere collegato sul pin D 10 RE= Receive Enable può andare su D 3 DE= Data Enable può andare sullo stesso D 3 GND Vcc=5 v di arduino A e B sono le uscite che vanno su A e B del corrispondente RS 285
Codice Arduino master #include <Software. Serial. h> #define SSerial. RX 10 #define SSerial. TX 11 #define SSerial. Tx. Control 3 #define RS 485 Transmit HIGH #define RS 485 Receive LOW #define Pin 13 LED 13 Software. Serial RS 485 Serial(SSerial. RX, SSerial. TX); int byte. Received; int byte. Send; void setup() { Serial. begin(9600); Serial. println("Your. Duino. com Software. Serial remote loop example"); Serial. println("Use Serial Monitor"); pin. Mode(Pin 13 LED, OUTPUT); pin. Mode(SSerial. Tx. Control, OUTPUT); digital. Write(SSerial. Tx. Control, RS 485 Receive); RS 485 Serial. begin(4800); } void loop() { digital. Write(Pin 13 LED, HIGH); if (Serial. available()) { byte. Received = Serial. read(); digital. Write(SSerial. Tx. Control, RS 485 Transmit); RS 485 Serial. write(byte. Received); digital. Write(Pin 13 LED, LOW); delay(10); digital. Write(SSerial. Tx. Control, RS 485 Receive); } if (RS 485 Serial. available()) { digital. Write(Pin 13 LED, HIGH); byte. Received = RS 485 Serial. read(); Serial. write(byte. Received); delay(10); digital. Write(Pin 13 LED, LOW); } }
Codice di un device remoto #include <Software. Serial. h> #define SSerial. RX #define SSerial. TX 11 #define SSerial. Tx. Control 3 #define RS 485 Transmit HIGH #define RS 485 Receive LOW #define Pin 13 LED 13 Software. Serial RS 485 Serial(SSerial. RX, SSerial. TX); int byte. Received; int byte. Send; void setup() {Serial. begin(9600); Serial. println("Serial. Remote"); pin. Mode(Pin 13 LED, OUTPUT); pin. Mode(SSerial. Tx. Control, OUTPUT); digital. Write(SSerial. Tx. Control, RS 485 Receive); RS 485 Serial. begin(4800); } void loop() { if (RS 485 Serial. available()) { byte. Send = RS 485 Serial. read(); digital. Write(Pin 13 LED, HIGH); delay(10); digital. Write(Pin 13 LED, LOW); digital. Write(SSerial. Tx. Control, RS 485 Transmit); RS 485 Serial. write(byte. Send); delay(10); digital. Write(SSerial. Tx. Control, RS 485 Receive); delay(100); }
Commento ai codici �Il codice per la comunicazione RS 485 è molto semplice e non è altro che una comunicazione seriale �Sono state evidenziate le righe specifiche per questo modulo �Software. Serial RS 485 Serial(SSerial. RX, SSerial. TX); è la dichiarazione dell’oggetto in funzione rispettivamente del ricevitore e del trasmettitore �RS 485 Serial. begin(4800); inizializza la comunicazione seriale di RS 485 a 4800 baud �RS 485 Serial. available() chiede la disponibilità della RS 485 �RS 485 Serial. read(); legge I dati inviati tramite RS 485 �RS 485 Serial. write(byte. Send); invia dei dati
RS 485 send #include <RS 485. h> #include <SPI. h> RS 485 my. Device = RS 485(); void setup() { Serial. begin(115200); delay(100); if ( my. Device. begin() == 0) { Serial. println("RS-485 module started successfully"); } else { Serial. println("RS-485 did not initialize correctly"); } delay(100); // Configure the baud rate of the module my. Device. baud. Rate. Config(9600); // Configure the parity bit as disabled my. Device. parity. Bit(DISABLE); // Use one stop bit configuration my. Device. stop. Bit. Config(1); // Print hello message Serial. println("Hello this is RS-485 communication send data example. "); } void loop() { // Reading the analog input 1 int analog 1 = analog. Read(A 1); //Reading the analog input 2 int analog 2 = analog. Read(A 2); // Send data through RS-485 line my. Device. send("Data from analog 1 input : "); my. Device. send(analog 1); my. Device. send("n"); my. Device. send("Data from analog 2 input : "); my. Device. send(analog 2); my. Device. send("n"); delay(1000); }
RS 485 receive #include <RS 485. h> // Include the SPI library #include <SPI. h> // Create an instance RS 485 my. Device = RS 485(); void setup() { Serial. begin(115200); delay(100); if ( my. Device. begin() == 0) { Serial. println("RS-485 module started successfully"); } else { Serial. println("RS-485 did not initialize correctly"); } delay(100); my. Device. baud. Rate. Config(115200); // Configure the parity bit as disabled my. Device. parity. Bit(DISABLE); // Use one stop bit configuration my. Device. stop. Bit. Config(1); // Print hello message Serial. println("This is RS-485 communication receive data example. "); } void loop() { if (my. Device. available()) { while (my. Device. available()) { // Read one byte from the buffer char data = my. Device. read(); // Print data received in the serial monitor Serial. print(data); } } delay(10); }
Vantaggi e svantaggi � CAN-bus: � � � RS 485: � � � Vantaggi: � E' multi-master; � Si trovano già alcuni microcontrollori equipaggiati di unità CAN. Esistono in commercio chip che si possono interfacciare con arduino a basso costo; � E' uno standard de facto ed è open source, quindi c'è solo da studiare com'è strutturato il protocollo; � Immune ai disturbi ed elevata velocità di comunicazione; � Efficiente gestione delle collisioni; Svantaggi: � Trama trasmessa parecchio articolata; � L'implementazione su Arduino dipenderebbe dal tipo di chip CAN-controller utilizzato. Vantaggi: � E' multi-master; � E' sufficiente collegare un chip RS 485 -transceiver alla seriale di Arduino. Basso costo e semplicità; � Elevata velocità di comunicazione (fino a 100 Kbit/s a 1200 m); � Buona immunità ai disturbi; � Siccome il protocollo spetta a noi, possiamo decidere comporre il messaggio da trasmettere; Svantaggi: � RS 485 non è un procollo ma solo uno standard di livello fisico. A noi spetterebbe l'ideazione di un protocollo ad hoc (magari ispirandoci al DMX). Ethernet: � � Vantaggi: � E' una configurazione distribuita; � Esistenza di protocolli di comunicazione consolidati, affidabili e documentati; � Semplicita` di amministrazione remota; � Struttura versatile e diffusa del collegamento, anche su TV e altri elettrodomestici; � possibilita` di Po. E, con ulteriore semplificazione dei cablaggi; Svantaggi: � E' una configurazione distribuita; � Implica l'uso di tante schede arduino quanti i nodi del sistema. Il costo delle singole schede probabilmente supera quello delle altre soluzioni. � Il cablaggio in un impianto esistente puo` essere impegnativo
- Slides: 52