Trasferimento di valori via seriale tra Arduino UNO e Arduino MEGA

Salve a tutti, come da titolo volevo trasferire i valori di un potenziometro connesso all'Arduino UNO all'Arduino MEGA, utilizzando i pin TX ed RX.

Nella parte Hardware connetto il pin TX di UNO al pin RX di MEGA e il pin RX di UNO al pin TX di MEGA. Connetto poi MEGA via USB per visualizzare i valori che Arduino UNO mi invia.

Il codice che uso su Arduino UNO (Il mittente) è questo:

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

void loop() 
{ 
  Serial.print(analogRead(A0));
  Serial.write(",");
}

Il codice che uso su Arduino MEGA (Il destinatario) è questo:

int val=0;

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

void loop() 
{

 if (Serial.available()) {
   val = Serial.read();
    
   if(val==44){
      Serial.println();
    }
    else{
      
      Serial.write(val);
    }
  }
}

P.S. Quando apro la schermata della seriale sul PC non vedo i valori. :confused:

Sulla Mega NON puoi usare la Serial ... che è già in uso dalla connessione USB con il PC ... hai altre tre porte seriali .. usa una di quelle ;)

Guglielmo

Ma potrebbe anche essere lo stesso problema sulla uno, con i pin 0 e 1?

speedyant: Ma potrebbe anche essere lo stesso problema sulla uno, con i pin 0 e 1?

NO perché non mi sembra la usi per connettersi con la USB a qualche cosa ...

Guglielmo

P.S. : Comunque io consiglio sempre, in questi casi, sulla UNO di usare la SoftwareSerial e lasciare libera la vera seriale che può sempre servire a fare debug ;)

Ok, quindi sull'UNO dovrei usare la SoftwareSerial (Come libreria è già inserita sull'IDE?) e come dovrei fare funzionare le altre porte seriali sul MEGA?

Si, la SoftwareSerial è già nell'IDE, basta che la includi, sulla Mega, basta che ti leggi il reference ...

Serial: 0 (RX) and 1 (TX); Serial 1: 19 (RX) and 18 (TX); Serial 2: 17 (RX) and 16 (TX); Serial 3: 15 (RX) and 14 (TX). Used to receive (RX) and transmit (TX) TTL serial data. Pins 0 and 1 are also connected to the corresponding pins of the ATmega16U2 USB-to-TTL Serial chip.

... quindi scegli ... Serial1, Serial2 o Serial3 :)

Guglielmo

Eccomi di nuovo, in questi giorni non ho avuto la possibilità di scrivere e controllare il codice.

Ho sistemato un po’ il codice e FUNZIONA! Almeno sembra :smiling_imp: (Grazie mille per i consigli!)

Il codice di UNO:

#include <SoftwareSerial.h>

SoftwareSerial Seriale(7,8); //RX,TX

void setup() 
{
  Serial.begin(9600);
  Seriale.begin(9600);
}

void loop() 
{
  Seriale.print(analogRead(A0));
  Seriale.print(",");
  Serial.println(analogRead(A0));
}

Il codice di MEGA:

int input;
void setup() 
{
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() 
{
  if(Serial1.available())
  {
    input=Serial1.read();
    if(input==44)
      Serial.println();
    else
      Serial.write(input);
  }
}

Adesso avrei un’altra domanda: Come potrei fare per inviare più dati ricavati da diversi potenziometri utilizzando sempre la stessa porta seriale?

1)Io pensavo ad una lettera che precedeva i vari valori dei potenziometri per fare in modo che MEGA riesca a riconoscere da dove vengono i dati.

2)Ci sarebbe anche una soluzione più semplice che sarebbe quella di far inviare da UNO tutti i valori dei potenziometri uno dopo l’altro e MEGA li riceve e in base all’ordine li riesce a distinguere, ma non mi attira tanto perché se volessi far filtrare i valori dei singoli potenziometri che nel tempo si mantengono uguali da UNO verrebbe un casino… Non so se mi sono spiegato bene…

Esempio:

Valori che MEGA riceve da UNO con il primo metodo:
a:152,b:789,c:1023,d:748,a:148,b:954,c:1000,d:0

Valori che MEGA riceve da UNO con il primo metodo se vengono filtrati:
a:152,b:789,c:1023,d:748,a:1001,c:11 -->Si capisce sempre di che potenziometro sono.

Valori che MEGA riceve da UNO con il secondo metodo:
152-789-1023-748,148-954-1000-0,

Valori che MEGA riceve da UNO con il secondo metodo se vengono filtrati:
152-789-1023-748,11-52,78,1000-150-623-888 -->Non si capisce di che potenziometro sono

Io creerei una struttura fissa di dati e trasmetterei sempre il pacchetto completo ...

... esempio : STX AAAABBBBCCCC....ZZZZ ETX CRC dove lo STX (0x02) ti serve a riconoscere l'inizio trasmissione, poi invii comunque i dati, in formato fisso 4 char, di TUTTI i potenziometri (se non c'è lettura, per distinguere dal valore 0000, metti 9999 che non potrai mai avere visto che sull'analogico hai un valore da 0 a 1023) poi il carattere ETX (0x03) per indicare la fine della trasmissione ed un carattere di CRC per verificare di aver ricevuto correttamente i dati :)

Guglielmo

Il carattere CRC come dovrebbe funzionare?

xEDOx: Il carattere CRC come dovrebbe funzionare?

Intanto leggi QUI ... ... probabilmente a te basterebbe un CRC8 (che trovi da QUESTO post in poi) che trasmetti in un singolo carattere ;)

Guglielmo

Ooook… Non è che abbia capito molto… :frowning: Comunque ho provato a scrivere un programma basilare e chiaramente non funziona… :sweat_smile:

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

SoftwareSerial Seriale(7, 8); //RX,TX

void setup()
{
  Serial.begin(9600);
  Seriale.begin(9600);

}


void loop() 
{
  
  byte mycrc;
  mycrc = CRC8.calculate(analogRead(A0), 1);

  Serial.write(0x02);
  Serial.print(analogRead(A0));
  Serial.write(0x03);
  Serial.print(mycrc);
}

crc8.cpp (463 Bytes)

crc8.h (837 Bytes)

... il CRC, o "cyclic redundancy check" è un calcolo che viene fatto su un blocco di dati per verificare che in ricezione non ci siano errori.

Se tu devi trasmettere una sequenza di caratteri, come fai a sapere se quando li ricevi c'è stato un errore (es. un bit che leggi 0 ma invece era 1) ? Il modo più semplice è usare un CRC (... esistono modi ben più complessi). In pratica, tu prendi il tuo blocco di caratteri che dovrai trasmettere, lo dai in pasto alla funzione CRC e quella ti ritorna un numero (... il CRC) che tu trasmetti assieme ai tuo dati (tipicamente alla fine).

Chi riceve, prende il blocco di dati (escluso il CRC) ricalcola con lo stesso algoritmo il CRC e confronta il valore da lui calcolato con quello che tu gli hai mandato. Se sono uguali la trasmissione è corretta, se sono diversi ... c'è chiaramente stato un errore di trasmissione.

Quindi ... per calcolare un CRC devi passare alla funzione [u]l'indirizzo di dove comincia il BLOCCO[/u] di dati (e non un valore come stai facendo tu) e l*[u]a lunghezza del blocco di dati[/u]*.

Per questo ti avevo scritto di creare una struttura che contiene un carattere di inizio trasmissione (es. STX), tutti i caratteri dei vari valori in un formato fisso (così li separi facilmente) e un carattere di fine trasmissione (es. ETX).

Tutto questo è un bel blocco di caratteri ... dai alla funzione CRC l'indirizzo del primo carattere (lo STX), ed il numero di caratteri (.... tipicamente si esclude dal conteggio e dal calcolo l'ETX finale). Quella ti ritorna IL CRC che tu trasmetti dopo l'ETX ... chi riceve fa lo stesso calcolo e verifica che il tuo CRC sia uguale al suo. :)

Guglielmo

Penso di aver capito la teoria ora… Comunque la funzione CRC legge valori char giusto? per passargli i valori dai pin analogici come dovrei fare?

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

SoftwareSerial Seriale(7, 8); //RX,TX

byte N=4;

void setup()
{
  Serial.begin(9600);
  Seriale.begin(9600);

}


void loop() 
{

  char potval[N];

  for(int i=0; i<N; i++)
  {
    potval[i]=analogRead(i);
  }
  
  byte CRC;
  CRC = CRC8.calculate(potval,N);

  Serial.print(0x02);
  for(int i=0; i<N; i++)
    Serial.print(potval[i]);
  Serial.print(0x03);
  Serial.print(CRC);

Seriale.print(0x02);
  for (int i = 0; i < N; i++)
    Seriale.print(potval[i]);
  Seriale.print(0x03);
  Seriale.print(CRC);

}

Semplicemente NON devi passargli i valori dei pin analogici :D

Tu prima devi creare l'intera struttura ... (... consci la "struct" del C ? Potresti usare quella) e poi calcolare il CRC della struttura, non dei singoli valori !

Se non vuoi usare una struct ... dovrai costruirti un array e dovrai strutturartelo per contenere tutte le informazioni.

La CRC lavora con un insieme di bytes ... e se ne frega di cosa c'è dentro (... char, byte, int, float, ...). Quello che gli interessa è da dove deve iniziare e per quanti bytes. :)

Guglielmo

P.S. : Se poi è troppo complicato ... inizia senza il controllo CRC e magari .. lo aggiungerai in seguito, quando ti sarà più chiaro ;)

Si so che cosa è una struct, ma non ne capisco l’utilità in questa situazione… Non è mica sufficiente un’array che contenga i valori dei potenziometri? Poi calcolo il CRC dell’array…

... era per fare una struttura un po' più elegante, con un char per STX, una array di N char[4] per le misure, un char per l'ETX ... ma, come ti ho scritto, puoi benissimo fare tutto con un array ;)

Guglielmo

Aaaaaaaaan... Tutto ha senso ora... Allora concordo pienamente... Quindi come passo i dati al CRC? Nel senso cosa devo mettere quando scrivo funzionecrc(dati,numerodidati) al posto di dati?

Non gli devi passare i dati ma il "pointer" a dove cominciano, quindi, se usi una struct dovrai passare il pointer alla struct mentre se usi un array semplicemente l'array (... che equivale a passare il pointer al primo elemento).

Guglielmo

Ho cambiato strada e ecco come viene: :sweat_smile: :sweat_smile: :sweat_smile:

#include <SoftwareSerial.h>

SoftwareSerial Seriale(7, 8); //RX,TX

byte N = 1; //NUMERO DI POTENZIOMETRI

int tot_pacchetti = 0;


byte CRC;

byte CRC8(const byte *data, byte len) {
  byte crc = 0x00;
  while (len--) {
    byte extract = *data++;
    for (byte tempI = 8; tempI; tempI--) {
      byte sum = (crc ^ extract) & 0x01;
      crc >>= 1;
      if (sum) {
        crc ^= 0x8C;
      }
      extract >>= 1;
    }
  }
  return crc;
}

void setup()
{
  Serial.begin(9600);
  Seriale.begin(9600);

}


void loop()
{

  byte potval[N];
  int PotVal[N];
  
  for (int i = 0; i < N; i++)
  {
    potval[i] = analogRead(i);
    PotVal[i] = analogRead(i);
  }

  CRC = CRC8(potval, N);

  //Per debug
  Serial.write(0x02);
  for (int i = 0; i < N; i++)
  {
    Serial.print(PotVal[i]);
    if (i < N - 1)
      Serial.print(",");
  }
  Serial.write(0x03);
  Serial.print(CRC);
  Serial.println();


  //Trasmissione dati vera
  Seriale.write(0x02);
  for (int i = 0; i < N; i++)
  {
    Seriale.print(PotVal[i]);
    if (i < N - 1)
      Seriale.print(",");
  }
  Seriale.write(0x03);
  Seriale.print(CRC);
  Seriale.println();

  tot_pacchetti++;

}

Occhio che l'analogRead() ti ritorna un int (10 bit significativi, da 0 a 1023) NON un byte come hai dichiarato potval ... ::)

Guglielmo