aiuto per invio dati via seriale con 2 arduini

salve

avrei la necessita di inviare da un arduino una variabile di tipo float a un secondo arduino collegato via seriale ho gia fatto tutti i collegamenti e comunicano perfettamente e ho fatto un po di prove a inviare e ricevere le variabili int e byte e non ho nessun problema ma non riesco a capire come inviare numeri complessi tipo float

grazie

birrohgt:
salve

avrei la necessita di inviare da un arduino una variabile di tipo float a un secondo arduino collegato via seriale ho gia fatto tutti i collegamenti e comunicano perfettamente e ho fatto un po di prove a inviare e ricevere le variabili int e byte e non ho nessun problema ma non riesco a capire come inviare numeri complessi tipo float

grazie

Con la Serial.print() scrivi il valore float da una parte e con la Serial.parseFloat() lo leggi dall'altra.
serial/print
serial/parsefloat

krypton18:
Con la Serial.print() scrivi il valore float da una parte e con la Serial.parseFloat() lo leggi dall'altra.
serial/print
serial/parsefloat

grazie mille gentilissimo

ti chiedo un altro suggerimento sempre con i due arduini collegati con la seriale devo inviare e ricevere variabili diverse per esempio:

arduino (1) invia a arduino (2) che il LED1 si deve accendere, arduino(2) legge tramite seriale e mette a livello alto un uscita digitale e fin qui non ho problema.
devo aggiungere allo stesso modo la variabile LED2 ad arduino (1) che lo invia a arduino(2) e quest ultimo deve portare a livello altro una uscita digitale diversa

grazie

birrohgt:
grazie mille gentilissimo

ti chiedo un altro suggerimento sempre con i due arduini collegati con la seriale devo inviare e ricevere variabili diverse per esempio:

arduino (1) invia a arduino (2) che il LED1 si deve accendere, arduino(2) legge tramite seriale e mette a livello alto un uscita digitale e fin qui non ho problema.
devo aggiungere allo stesso modo la variabile LED2 ad arduino (1) che lo invia a arduino(2) e quest ultimo deve portare a livello altro una uscita digitale diversa

grazie

Qual è il problema nello specifico? Cioè quanti dati, e di che tipo (bool, int, float), devi inviare all'altro Arduino? Per favore, posta il programma che hai scritto finora.

Se devi inviare solo dei bit, li si può "impaccare" in un byte e fare una scrittura unica dall'Arduino (1) verso l'Arduino (2). Nell'Arduino (2) farai poi la lettura dei singoli bit contenuti nel byte ricevuto con funzioni tipo la bitRead().
Se invece vuoi fare anche la lettura di diversi tipi di dato con un'unica porta seriale, la faccenda si complica. Ho scoperto che la funzione che ti ho suggerito per leggere i float è bloccante, si comporta analogamente alla delay, cioè ferma il programma fintantoché non riceve i dati. Si può impostare un timeout superato il quale, se non viene letto nulla, il programma prosegue l'esecuzione. Comunque è una soluzione che non mi sconfinfera tanto. Sarebbe meglio inviare il valore float in modo grezzo e reinterpretarlo dalla parte ricevente, questo al fine di non bloccare il programma. Ma è più facile a dirsi che a farsi, nel senso che non ho trovato una soluzione standard per riuscire a ricomporre il dato. Un'altra soluzione, che però in termini di prestazioni e di eleganza del codice fa schifo, è di convertire il numero da float a caratteri ASCII e inviarlo quindi sotto forma di stringa per poi riconvertirlo in float (in realtà in double) con la funzione atof dalla parte ricevente. C'è da cercare dei tutorial su Internet e studiarli per intraprendere la prima via, non ho approfondito abbastanza, a fronte però di ottenere risultati prestazionali soddisfacenti e piena comprensione di quello che si sta facendo.

Oltre a queste considerazioni tieni presente che, a meno che tu non usi due porte seriali diverse per distribuire il lavoro di invio/ricezione di dati dissimili, devi pensare anche alla sincronizzazione fra i due sistemi. I due dispositivi si devono "mettere d'accordo" per determinare quando il dato è da inviare, dargli il tempo di giungere a destinazione, ed eseguire l'invio del successivo. Se non si fa così l'Arduino (2) riceverebbe i dati in ordine sparso e assolutamente non coerente. Esempio di una specie di semplice protocollo sincrono fra i due Arduino:

  1. Arduino (1) <--- RICHIESTA DATO_1 <--- Arduino (2)
  2. Arduino (1) ---> INVIO DATO_1 ---> Arduino (2)
  3. Arduino (1) <--- DATO_1 RICEVUTO <--- Arduino (2)
  4. Arduino (1) <--- RICHIESTA DATO_2 <--- Arduino (2)
  5. Arduino (1) ---> INVIO DATO_2 ---> Arduino (2)
  6. Arduino (1) <--- DATO_2 RICEVUTO <--- Arduino (2)

Quello schemino sta ad indicare che se invii un dato da Arduino (1), Arduino (2) deve inviare la conferma di dato ricevuto affinché Arduino (1) possa procedere a inviare il dato successivo. In pratica si tratta di fare una macchina a stati che gestisca le varie situazioni e Arduino (2) diventa parte attiva dello scambio dati inviando abilitazioni (richieste) all'invio di ulteriori dati da parte di Arduino (1).
Volendo i passi 3 e 4 si possono sintetizzare in un unico comando.

edit: si può evitare uno scambio dati con sincronia come quello che ti ho spiegato e usare un altro approccio "asincrono", ossia lo scenario dove Arduino (2) riceve dati e basta, aggiungendo un carattere terminatore in testa o in coda al dato da inviare. Cioè si va a demarcare l'inizio/fine di un dato con un carattere di terminazione, di solito si usa il carriage return, che quando viene rilevato dalla parte ricevente consente di discriminare la fine di DATO_1 e l'inizio di DATO_2 e così via. Chiaramente in quest'ultimo caso il programma della parte ricevente deve essere ottimizzato e senza blocchi per non perdere dati "per strada".

Se scegli l'approccio sincrono, non ti devi preoccupare troppo delle performance del programma ricevente visto che tramite le sue richieste detta i modi e i tempi della comunicazione.
L'approccio asincrono è vantaggioso per le performance, siccome i dati vengono inviati e ricevuti "in tempo reale" e il trasmettitore è completamente indipendente da cosa fa il ricevitore.

grazie per la spiegazione ma sono un po alle prime armi a sto cercando di imparare

allora ti spigo quello che vorrei fare da arduino (1) devo inviare al arduino(2) 2 tipi di informazioni.

la prima è di tipo float (un numero con virgola tipo 7.15 (quello che mi hai gia spiegato)
la seconda deve essere una variabile giusta qualsiasi di tipo int o char ecc non ha importanza (bisogna segliere la migliore per il mio scopo) cioe ad esempio attivare o disattivare un pin digitale sul arduino(2) esempio se mi arriva il numero 1 o la scritta "accendi" mi deve accendere un led

non ho ancora un progetto da postare perche sto solo facendo delle prove di invio dati tra i due arduini per arrivare al mio scopo
non devo fare una cosa molto complessa slo inviare e interpretare questi due tipo di comadi

grazie per aiuto se mi potresti consigliare che strada prendere per fare ciò

per il numero con la virgola puoi anche pensare di moltiplicarlo per 100 e poi trasmetterlo come intero, una volta ricevuto lo dividi per la stessa quantità :wink:
per accendere o spegnere più di un led puoi combinare un numero e on o off
così il led 1 sarà 1ON o 1OFF
il led2 sarà 2ON o 2OFF
e così via
dall'altra parte con un controllo switch case farai la scelta adeguata

Patrick_M:
per il numero con la virgola puoi anche pensare di moltiplicarlo per 100 e poi trasmetterlo come intero, una volta ricevuto lo dividi per la stessa quantità :wink:
per accendere o spegnere più di un led puoi combinare un numero e on o off
così il led 1 sarà 1ON o 1OFF
il led2 sarà 2ON o 2OFF
e così via
dall'altra parte con un controllo switch case farai la scelta adeguata

scusa non ho capito come invio i dati dal arduino 1 con due serial print in char??????????

Serial.print('valore del float x 100')
Serial.print(1on)

poi in ricezione devo leggere i dati dalla seriale mettendoli in una stringa????

grzie

birrohgt:
grazie per la spiegazione ma sono un po alle prime armi a sto cercando di imparare

allora ti spigo quello che vorrei fare da arduino (1) devo inviare al arduino(2) 2 tipi di informazioni.

la prima è di tipo float (un numero con virgola tipo 7.15 (quello che mi hai gia spiegato)
la seconda deve essere una variabile giusta qualsiasi di tipo int o char ecc non ha importanza (bisogna segliere la migliore per il mio scopo) cioe ad esempio attivare o disattivare un pin digitale sul arduino(2) esempio se mi arriva il numero 1 o la scritta "accendi" mi deve accendere un led

non ho ancora un progetto da postare perche sto solo facendo delle prove di invio dati tra i due arduini per arrivare al mio scopo
non devo fare una cosa molto complessa slo inviare e interpretare questi due tipo di comadi

grazie per aiuto se mi potresti consigliare che strada prendere per fare ciò

Il modo più semplice per trasmettere dati diversi senza alcuna forma di sincronizzazione, se ti limiti a due dati, è usare due software serial e quindi due canali fisici distinti ciascuno dedicato a inviare un tipo di dato. Ogni canale deve avere un TX e un RX dedicati, da cui derivano 4 fili di connessione fra i due Arduino (TX_1, RX_1 - TX_2, RX_2).

Studiati bene questo tutorial e adatta il programma al tuo scopo:
TwoPortReceive

Nell'esempio la scrittura dei dati avviene sul monitor seriale dell'Arduino locale. A te invece interessa inviare dati all'altro Arduino, per cui nel programma dell'Arduino (1) dovrai sostituire le Serial.write() rispettivamente con:
portOne.write(cmd_bool);
portTwo.println(var_float, num_cifre_decimali);

Nota comune per i due programmi: le Serial.println(); usate come "blank line" omettile che non servono.

Nota bene: nel programma che invia le listen() e le available() non le devi usare.

Puoi fare anche il viceversa a seconda di come preferisci. Però stabilisci un ordine perché quello che fai da una parte deve essere speculare nell'altra.

Nell'Arduino (2) farai:

cmd_bool = portOne.read();
var_float = portTwo.parseFloat();

Nota bene: nella ricezione non puoi copiare e incollare direttamente le variabili nell'ordine in cui le ho scritte io. L'uso delle software serial presenta la limitazione di dover ricevere i dati in momenti separati, quindi si usano le listen().

Per non complicarti la vita ti conviene rendere cmd_bool e var_float delle variabili globali. Anche se personalmente non lo farei, ma per fare una prova veloce lo puoi fare.

Schema dei collegamenti se usi due Arduino UNO:

Nota bene: se usi Arduino MEGA i PIN 8,9 non li puoi usare per la software serial e devi sceglierne altri compatibili: limitazioni SoftwareSerial
Anche altri modelli di Arduino hanno limitazioni sui PIN utilizzabili.

Definizione dei PIN programma che invia:

#define TX_1 11
#define RX_1 10
#define TX_2 9
#define RX_2 8

SoftwareSerial portOne(RX_1, TX_1);
SoftwareSerial portTwo(RX_2, TX_2);

Definizione dei PIN programma che riceve:
SoftwareSerial portOne(11, 10);
SoftwareSerial portTwo(8, 9);

#define TX_1 10
#define RX_1 11
#define TX_2 8
#define RX_2 9

SoftwareSerial portOne(RX_1, TX_1);
SoftwareSerial portTwo(RX_2, TX_2);

Come vedi TX e RX si invertono fra i due Arduino se si mantiene lo stesso ordine di PIN.

per il numero con la virgola puoi anche pensare di moltiplicarlo per 100 e poi trasmetterlo come intero, una volta ricevuto lo dividi per la stessa quantità :wink:

Giustissimo Patrick, volevo citare anche questo metodo ma poi mi sono scordato di farlo :D.

krypton18:
Il modo più semplice per trasmettere dati diversi senza alcuna forma di sincronizzazione, se ti limiti a due dati, è usare due software serial e quindi due canali fisici distinti ciascuno dedicato a inviare un tipo di dato. Ogni canale deve avere un TX e un RX dedicati, da cui derivano 4 fili di connessione fra i due Arduino (TX_1, RX_1 - TX_2, RX_2).

Studiati bene questo tutorial e adatta il programma al tuo scopo:
TwoPortReceive

Nell'esempio la scrittura dei dati avviene sul monitor seriale dell'Arduino locale. A te invece interessa inviare dati all'altro Arduino, per cui nel programma dell'Arduino (1) dovrai sostituire le Serial.write() rispettivamente con:
portOne.write(cmd_bool);
portTwo.print(var_float, num_cifre_decimali);

Nota bene: nel programma che invia le listen () non le devi usare.

Puoi fare anche il viceversa a seconda di come preferisci. Però stabilisci un ordine perché quello che fai da una parte deve essere speculare nell'altra.

Nell'Arduino (2) farai:

cmd_bool = portOne.read();
var_float = portTwo.parseFloat();

Nota bene: nella ricezione non puoi copiare e incollare direttamente le variabili nell'ordine in cui le ho scritte io. L'uso delle software serial presenta la limitazione di dover ricevere i dati in momenti separati, quindi si usano le listen().

Per non complicarti la vita ti conviene rendere cmd_bool e var_float delle variabili globali. Anche se personalmente non lo farei, ma per fare una prova veloce lo puoi fare.

Schema dei collegamenti se usi due Arduino UNO:

Nota bene: se usi Arduino MEGA i PIN 8,9 non li puoi usare per la software serial e devi sceglierne altri compatibili: limitazioni SoftwareSerial

Definizione dei PIN programma che invia:

#define TX_1 11

#define RX_1 10
#define TX_2 9
#define RX_2 8

SoftwareSerial portOne(RX_1, TX_1);
SoftwareSerial portTwo(RX_2, TX_2);




Definizione dei PIN programma che riceve:
SoftwareSerial portOne(11, 10);
SoftwareSerial portTwo(8, 9);


#define TX_1 10
#define RX_1 11
#define TX_2 8
#define RX_2 9

SoftwareSerial portOne(RX_1, TX_1);
SoftwareSerial portTwo(RX_2, TX_2);




Come vedi TX e RX si invertono fra i due Arduino se si mantiene lo stesso ordine di PIN.

grazie per il tuo lavoro
ma io devo lavorare con un arduino uno e un arduino due (con traslazione di livello da 3.3 a 5v)
quindi la softserial non funziona su arduino due

sto provando ad usare le stringhe e sembra funzionare non so se sia il metodo migliore

questo sto usando su arduino ricevente

String stringa;
String stringa0;
String stringa1;

void setup() 
{
  Serial.begin(9600);
  Serial1.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);

}

void loop() 
{

 
    if(Serial1.available())
     {    
       stringa = Serial1.readString();   
       
     }

      
   stringa0 = stringa.substring(0, 4);
   stringa1 = stringa.substring(4, 11);
      
 if (stringa1 == "accendi")
  {
     digitalWrite(LED_BUILTIN, HIGH);
  }
else
  {
    digitalWrite(LED_BUILTIN, LOW);
  }
 
 static unsigned long t = millis();
  if (millis() - t > 1000) {
     Serial.println(stringa0);
     Serial.println(stringa1);
   
    t = millis();
    
 }
 
}

nel arduino che invia questo

 float ph = 7.30;
 String val = "accendi"; 
 

void setup() 
{
 Serial.begin(9600);
 Serial1.begin(115200);

 delay (3000);
}

void loop() 

{

   
 Serial1.print(ph);
 Serial1.print(val);

 delay(2000);

}

se hai suggerimenti grazie

Attento: Arduino UNO ha una sola porta seriale fisica, la Serial. La Serial1, per quanto ne so, non esiste proprio su Arduino UNO quindi non so come ti faccia a funzionare. Io ti consiglio di tener libera la Serial e usare due software serial che arrivano a due porte fisiche di Arduino DUE con traslazione di livello. Su Arduino DUE potresti usare Serial1 e Serial2. Tendenzialmente la Serial è sempre meglio lasciarla libera, visto che è la stessa porta usata per caricare gli sketch nella flash di Arduino.

sto provando ad usare le stringhe e sembra funzionare non so se sia il metodo migliore

Si può fare anche così, non è sbagliato. Ma è più dispensioso a livello di RAM e devi usare delle funzioni in più.

edit: Ah giusto in effetti con due stringhe concatenate che poi vai a spezzettare si può usare anche una seriale sola, non ci avevo pensato. Comunque controlla bene la faccenda della Serial1 su Arduino UNO.

Nel programma di Arduino UNO puoi fare un invio solo:

String stringa = val + String(ph);

Serial.println(stringa)

Se non va prova questa modifica alla prima riga:

String stringa = String(val + String(ph));

Al posto di "acceso" / "spento" puoi inviare 1 o 0 per dimimuire il numero di byte inviati.

krypton18:
Attento: Arduino UNO ha una sola porta seriale fisica, la Serial. La Serial1, per quanto ne so, non esiste proprio su Arduino UNO quindi non so come ti faccia a funzionare. Io ti consiglio di tener libera la Serial e usare due software serial che arrivano a due porte fisiche di Arduino DUE con traslazione di livello. Su Arduino DUE potresti usare Serial1 e Serial2. Tendenzialmente la Serial è sempre meglio lasciarla libera, visto che è la stessa porta usata per caricare gli sketch nella flash di Arduino.
Si può fare anche così, non è sbagliato. Ma è più dispensioso a livello di RAM e devi usare delle funzioni in più.

edit: Ah giusto in effetti con due stringhe concatenate che poi vai a spezzettare si può usare anche una seriale sola, non ci avevo pensato. Comunque controlla bene la faccenda della Serial1 su Arduino UNO.

Nel programma di Arduino UNO puoi fare un invio solo:

String stringa = val + String(ph);

Serial.println(stringa)



Se non va prova questa modifica alla prima riga:

String stringa = String(val + String(ph));

Al posto di "acceso" / "spento" puoi inviare 1 o 0 per dimimuire il numero di byte inviati.

ok provo grazie

scusa ho sbagliato a scrivere ho un arduino mega e un arduino due uso le seriale hardware 1 su tutti e due

edit ho fatto le prove e funziona ma ho un problema la funzione Serial1.readString mi da dei blocchi al resto del codice
ce un modo per leggere i dati in seriale ma non fermare anche se di poco il resto del codice?

Prova questo spezzone di codice nel ricevitore:

if (Serial1.available()) {   
	stringa += Serial1.read();   
}

if (stringa.endsWith("\n")) {
	stringa0 = stringa.substring(0, 4);
	stringa1 = stringa.substring(4, 11);
        stringa = "";
}

La read() è una funzione che in una singola chiamata ritorna il byte corrente ricevuto dalla seriale.
Nell'ipotesi che il sistema interpreti che un byte equivale ad un char ASCII, in stringa si accumula ciascun carattere ricevuto fino a formare la stringa completa.
Cosa determina se la stringa è stata ricevuta interamente? Il carattere terminatore new line (\n) stampato dalla println().
Quindi con la endsWith() si va a testare se esso è presente alla fine della stringa, se l'esito è positivo si vanno a scrivere stringa0 e stringa1 e si azzera stringa per predisporla a una successiva ricezione.

ok grazie provo

Occhio che ho modificato il post per correggere degli errori di sintassi nel codice, non so se hai fatto in tempo e copiare il listato aggiornato con le correzioni.

ho collegato al posto di arduino mega un arduino nano usando la software serial sui pin 10,11

il problema che quando invio un carattere da arduino due ad esempio:

Serial1.print ('a');

su arduino nano con la software serial ricevo il valore decimale corrispondente al carattere a cioe 97

if (mySerial.available()) {
    byte k = (mySerial.read());
    Serial.println(k);

perche questo non mi succede con arduino mega? usando le porte seriali hardware?

come posso risolvere?

grazie

Non usare variabili di tipo byte per leggere dalla seriale. La .print riconosce tutte le variabili non char come il numero corrispondente, quindi O la sostituisci con una.write, che invia semplicemente il byte su seriale, O sostituisci 'byte k' con 'char k'

grazie si avevo fatto un errore

poi mi sono accorto che il problema non era solo quello ma che la software serial non comunica simultaneamente e nel mio progetto mi serve quindi ho usato la AltSoftSerial e ho risolto