Comunicazione Seriale : Ricevere dati correttamente.

Ciao a tutti.
Sto usando L’ide0022 di arduino e la libreria NewSoftSerial per la comunicazione seriale tra due arduino.
Stavo provando a scambioare dati tra i due, e ci riesco, ma ho un problema a mettere insieme i dati ricevuti.

Il codice che ho scritto è questo:
PER TX
Mi stampa continuamente interi da inviare all’altro arduino che ascolta in ricezione

#include <NewSoftSerial.h>

NewSoftSerial mySerial(2, 3);

void setup()  
{
  Serial.begin(115200);
  Serial.println("Inizio a trasmettere");
  mySerial.begin(115200);
}

void loop() {
          for (int i=0; i<100; i++) { 
          delay (1000);       
                Serial.println(i);
                mySerial.print(i);
        }
        {

 if (Serial.available()) {
     mySerial.print((char)Serial.read());
  }
}
        }

PER RX

#include <NewSoftSerial.h>

NewSoftSerial mySerial(2, 3);
byte rx;    // variabile per contenere il carattere ricevuto
void setup()  
{
  Serial.begin(115200);
  Serial.println("Ricevo");
  mySerial.begin(115200);
  mySerial.flush();

}

void loop()        
{

  if (mySerial.available() >0) // Controllo se il buffer di ricezione contiene qualcosa
		{
		rx = mySerial.read(); // leggo il carattere ricevuto e lo memorizzo in rx
                Serial.println(rx);
                  }
                    }

Quando conta da 0 a 9 non ci sono problemi, quando deve mettere insieme 2 cifre (10,11,12 … ecc) le separa trattandole un valore alla volta.
così:

Ricevo:
0
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3

Come posso fare a fare in modo che stampi qualsiasi valore come lo riceve, e non il byte separato?
Insomma come posso fare a sincronizzarlo in modo che capisca la parola che deve stampare?

Il motivo è legato al fatto che la seriale invia un byte per volta e riceve un byte per volta, il fatto che più byte composti a formare una stringa di senso compiuto per l'uomo è solo un caso per l'unità di calcolo, caso di cui non tiene conto. Da qui nascono i protocolli software, che permettono di ricomporre l'informazione comprensibile all'essere umano.

Come fare allora? Io non ho mai provato, ma dovrebbe essere possibile incapsulare tutti i dati da inviare in una struttura o classe e anziche inviare il contenuto della classe si invia byte per byte tutta la memoria occupata dalla classe/struttura. Dall'altro lato la struttura/Classe viene ricomposta in una porzione di memoria capiente quanto basta ottenuta previo allocazione dinamica della memoria.

La cosa è possibile e viene chiamata serializzazione ma io ho avuto esperienza solo con la serializzazione delle strutture dati (struct), con le classi la cosa potrebbe essere molto più complessa fino a richiedere un metodo di classe specifico per la serializzazione.

Ciao.

Da quel che ho capito dalle numerose risposte da parte degli utenti del forum(gentilissimi) al riguardo, devi mettere un carattere che la tua applicazione non usa tra i valori e utilizzarlo per capire quando un valore inizia o finisce. Per esempio, io scelgo la virgola come separatore in modo che se io invio i seguenti byte:

,
1
2
3
,

arduino li metterà in un array chiamato ad esempio serialin ottenendo [,][1][2][3][,] e poi usando una funzione come explode divida l'array in modo da prendere solo 123 che è il numero inviato dalla seriale. Tuttavia ti consiglio di aspettare qualcuno più esperto di me in quanto ogni volta che ho implementato questa funzione nei miei programmi essi sono diventati lunghi, incasinati e generalmente poco funzionanti. Alessandro

EDIT: Dimenticavo di consigliarti di utilizzare il protocollo I2C che a mio parere a livello software è molto più semplice. (Se vuoi ho una ottima videoguida da condividere ;))

EDIT: Dimenticavo di consigliarti di utilizzare il protocollo I2C che a mio parere a livello software è molto più semplice. (Se vuoi ho una ottima videoguida da condividere smiley-wink)

Tra seriale e I2c è più affidabile la seriale e poi è più veloce, quindi io del parere totalmente contrario, si usa ic2 solo nel casi in cui si deve comunicare con più dispositivi e con I2c si posso mettere teoricamente fino a 127 dispositivi I2c su un bus bifilare (two wire) e farli dialogare tra di loro.

Per il reso è ok, quel carattere può essere chiamato separatore. Mentre nel caso il carattere venga messo prima ad una sequenza di byte e ne qualifica il senso/tipo/ecc il carattere viene detto "sentinella". Es. @scacco#matto

@ nome utente

password

Ciao.

Perfetto.. mi serviranno sia la sentinella che il separatore per distinguere tipo e dati.... Domani cercheró di implementare qualcosa. Mi preoccupa solamente la mole di lavoro a cui saranno sottoposti i microprocessori... vedremo!

Per trasferire dati tra arduini puoi usare la libreria EasyTransfer --> https://github.com/madsci1016/Arduino-EasyTransfer che, come anticipato da MauroTec, incapsula tutti i dati in una classe e li trasferisce in blocco. (più o meno :roll_eyes:)

Ho risolto con un mio protocollino che sembra funzionare… A saperlo prima… Ora sono con il cell. Quando ho il PC a disposizione mostreró quello che ho fatto.

Ecco come promesso…
Ovviamente questo è solo un esempio e una parte di un codice molto più lungo e con altre funzioni… ma la base è questa.
TX

#include <SoftwareSerial.h>
#include "leOS.h"

SoftwareSerial mySerial(2, 3);
leOS temperature;

void setup()  
  {
  Serial.begin(1200);
  Serial.println("Inizializzo seriale");
  mySerial.begin(1200);
  temperature.begin(); /
  temperature.addTask(temp, 3000);
 
}

void loop() 
{

        }


 void temp() {
        val_t=val_t++;

         mySerial.print("t");   
         mySerial.print(val_t);
         mySerial.println(">"); 
}

RX

#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3);
char temp[10];
int cont_t;
boolean inizio_t = false;
boolean fine_t = false;


void setup()  
{
  Serial.begin(1200);
  Serial.println("Ricevo");
  mySerial.begin(1200);
  mySerial.flush();

}

void loop()
{
  
   while(mySerial.available() > 0)
   {
     //char rx = mySerial.read();
     //Serial.println(rx);
     ottieni_dati();
     
     }
}

// -------------------- METODI -------------------

void ottieni_dati()
{
 char rx = mySerial.read();
// --------------- TEMPERATURA -------------	 

          if(rx == 't')
	 {
	     inizio_t = true;
	     cont_t = 0;
	     temp[cont_t] = '\0';
	 }
	 else if(rx == '>')
	 {
	     fine_t = true;
	 }
	 else if(inizio_t == true)
	 {
	     temp[cont_t] = rx;
	     cont_t++;
	     temp[cont_t] = '\0';
   
	 }
   

   if(inizio_t && fine_t)
   {
	 // Converto la stringa in intero
	 int tempInt = atoi(temp);

	 // Uso il valore
        Serial.print("Temperatura: ");
        Serial.println(tempInt);
	  // Azzero tutto per la possima lettura
	 inizio_t = false;
	 fine_t = false;

	 cont_t = 0;
	 temp[cont_t] = '\0';
   }
   
}

ma non c'è qualche "barbatrucco" tipo mettere i pin ad alta impedenza quando hanno finito di trasmettere, o mettere 2 pin trasmittenti differenti sui trasmettitori e mettere 2 pin riceventi sul ricevitore (anche se funziona un pin per volta è ok)