"Costruzione" protocollo seriale 232

Buonasera!
come potrete facilmente intuire dal mio numero di post, non sono particolarmente ferrato nel mondo di Arduino, a dire il vero non lo sono nel mondo dei micro controllori in generale... però nutro una grande passione in merito! Dopo aver giocato per mesi con Arduino, scrivendo sketch molto semplici ed altri leggermente più complessi ma sempre e solo finalizzati alla didattica, ho deciso di provare a cimentarmi nella risoluzione di un problema reale.
Vorrei riuscire a far comunicare un mega con una scheda di un produttore terzo che implementa un protocollo seriale "proprietario" e che è brevemente descritto nelle due immagini allegate a questo post.
Ora, al di là della mera parte circuitale, dove ovviamente andrò ad adattare i livelli logici con un max232, io non ho la più pallida idea da dove partire ad implementare uno sketch che mi permetta di inviare pacchetti di 3 byte ed attenderne l'eco come richiesto dal protocollo della scheda.
Ovviamente se dovessi riuscire ad instaurare una comunicazione efficace tra arduino e la scheda, poi dovrei gestire la visualizzazione dei dati ricevuti da quest'ultima e l'invio dei dati modificati in base ad input a pulsanti, però al momento mi accontenterei di capire la teoria dietro all'invio di pacchetti di dati via seriale ed eventualmente riuscire a scrivere uno sketch che simuli il tipo di protocollo richiesto dalla scheda, magari anche tra due seriali dello stesso mega.
Potreste gentilmente darmi qualche spunto sull'argomento? magari qualche stralcio di sketch o qualche link da leggere utile alla comprensione dell'argomento?
Grazie anticipatamente a chi vorrà aiutarmi!
Francesco

IMG_0215.jpg

Ciao! Dalle informazioni contenute nelle immagini, la comunicazione si basa su l'invio di tre byte e la ricezione di tre byte.

1 byte dato, 2 byte istruzione, 3 byte somma byte dato+ byte istruzione.

Cosa dovrai fare su arduino? Se ci sono dati sulla seriale, faccio tre Serial.read() e salvo i tre byte in tre variabili.

byte dato;
byte istruzione;
byte somma;


void loop(){

     if (Serial.available() > 0){

          dato=Serial.read();
          istruzione=Serial.read();
          somma=Serial.read();

     }


}

Per comunicare con la scheda da parte di arduino farai tre Serial.write()

E' indicata la velocità della comunicazione seriale, tu dovrai usare la stessa velocità per arduino

Non ci sono informazioni sufficienti per sapere cosa deve contenere byte dato e byte istruzione

Ossia non ho una tabella che mi indica byte valore corrisponde a questa azione, esempio se io invio il byte istruzione di valore 65, poi non so cosa succede, perché non ho un elenco delle istruzioni che può ricevere.

Buongiorno!
Grazie per la risposta. In realtà se osservi il secondo allegato (0215) vedrai che c'è un esempio di invio dati.
Percui, in base all'allegato 215 e alla tua spiegazione, se io banalmente volessi inviare dato=200 istruzione=3 somma=203 dovrei scrivere un codice così:

byte dato;
byte istruzione;
byte somma;


void loop(){

     Serial.write(200);
     delay(2);
     Serial.write(3);
     delay(2);
     Serial.write(203);
     delay(2);    
 }

banalmente? senza preoccuparmi di conversioni varie ed eventuali da byte a decimale?
per quanto riguarda la ricezione dei dati, invece, è chiaro. mi preoccupava anche li l'eventuale conversione che avrei dovuto svolgere.
confermi che quanto scritto sopra da me potrebbe funzionare in base alle direttive dei due allegati?
Grazie!

Con write e read scrivi e leggi direttamente dei byte di valore 0 .. 255.

Il problema nascerebbe con print, che invece trasmette una stringa di caratteri ascii (che sempre byte sono, ma rappresentano i caratteri corrispondenti).

AH! questa cosa mi sfuggiva! Grazie! :slight_smile:

Francesco_Fiorese:
Percui, in base all'allegato 215 e alla tua spiegazione, se io banalmente volessi inviare dato=200 istruzione=3 somma=203 dovrei scrivere un codice così:

Beh si, una cosa del genere, comunque considera che puoi anche evitare di fare un write() per ogni byte, la write() accetta anche un buffer di byte, che corrisponde al tuo pacchetto di dati.
Inoltre la gestione della comunicazione ti conviene gestirla con apposite funzioni per evitare di "affollare" il tuo codice base (tra l'altro il terzo byte è solo la somma dei primi due, quindi puoi calcolarla direttamente nella funzione che invia il pacchetto via seriale).

Per cui puoi fare ad esempio una cosa del genere:

void setup()
{
  inviaPacchetto(200, 3);
  delay(1000);
 }

void loop()
{

}

byte pacchetto[3];
#define DATO 0
#define CMD 1
#define SUM 2

void inviaPacchetto(byte dato, byte comando)
{
  pacchetto[DATO] = dato;
  pacchetto[CMD] = comando;
  pacchetto[SUM] = dato+comando;
  Serial.write(pacchetto, 3);
}

EDIT: vedo che nel protocollo per un determinato comando c'è una pausa di 2ms tra i byte, per cui la routine la dovresti cambiare così, aggiungendo un parametro per il ritardo tra i byte (che imposti a zero se per quel comando non dovesse risultare necessario il ritardo):

void setup()
{
  inviaPacchetto(200, 3, 2);
  delay(1000);
 }

void loop()
{

}

byte pacchetto[3];
#define DATO 0
#define CMD 1
#define SUM 2

void inviaPacchetto(byte dato, byte comando, int ritardo)
{
  pacchetto[DATO] = dato;
  pacchetto[CMD] = comando;
  pacchetto[SUM] = dato+comando;
  for (int i=DATO; i<=SUM; ++i)
  {
    Serial.write(pacchetto[i]);
    if ( ritardo > 0 )
      delay(ritardo);
  }
}

Se per il ritardo usi un unsigned non ti dovrebbe neanche servire la if (non soncosa succede ad assegnare ad un unsigned un valore negativo)

Silente:
Se per il ritardo usi un unsigned non ti dovrebbe neanche servire la if (non soncosa succede ad assegnare ad un unsigned un valore negativo)

Più che altro ho messo la if per scrupolo, non solo per i valori negativi (cosa che non dovrebbe capitare) ma soprattutto perché non so se "delay(0)" funziona.. :wink:

Grazie dell'aiuto ragazzi!
Adesso mi metto a scrivere, vi farò sapere l'esito delle prove nei prossimi giorni!

Buongiorno ragazzi!
Allora, ho fatto qualche prova. Presi due mega, alimentato uno via USB e l'altro prendendo alimentazione dal primo per evitare eventuali problemi di riferimenti a massa, sul mega1 collegato in i2c un display 2x16 e un pulsante, poi:

TX Seriale1 Mega1 su RX Seriale1 Mega2
TX Seriale2 Mega2 su RX Seriale3 Mega1

Non ho usato la stessa seriale per TX ed RX poiché mi dava problemi, ma non ho capito perché. Sospetto sia qualche problema legato al buffer di trasmissione ma non me la sono sentita(per il momento) di cimentarmi nella lettura del datasheet del micro.

lo sketch del Mega1 è il seguente:

#include <LiquidCrystal_I2C.h>

#include <Wire.h>

LiquidCrystal_I2C lcd(0x27,16,2);


void inviaPacchetto(byte datoinv, byte comandoinv, int ritardo)
{
 
    Serial1.write(datoinv);
    if ( ritardo > 0 )
      delay(ritardo);
    Serial1.write(comandoinv);
    if ( ritardo > 0 )
      delay(ritardo);
    Serial1.write(datoinv+comandoinv);
    if ( ritardo > 0 )
      delay(ritardo);

  

    
  lcd.setCursor(5,0);
  lcd.print( datoinv);            

  lcd.setCursor(8,0);
  lcd.print( comandoinv);

  lcd.setCursor(11,0);
  lcd.print( datoinv+comandoinv);
  
}

byte dato;
byte istruzione;
byte somma;
byte datoscrittura;
int ingresso = 7; 

void setup()
{
 Serial1.begin(57600);
 Serial3.begin(57600);
 lcd.init();
 lcd.backlight();

 pinMode(ingresso, INPUT_PULLUP);
 
 }

void loop()
{

  
if (digitalRead(ingresso) == LOW )   {
     
      datoscrittura ++ ;
      inviaPacchetto(datoscrittura, 3, 2);
      delay(200);
}

      if (datoscrittura >=20) {
        datoscrittura=0;
        lcd.clear()
   
      }
  
    
    if (Serial3.available() > 0){

          dato=Serial3.read();
          istruzione=Serial3.read();
          somma=Serial3.read();
  }

  lcd.setCursor(0,0);
  lcd.print( "inv");

  lcd.setCursor(0,1);
  lcd.print( "ric");

  lcd.setCursor(5,1);
  lcd.print( dato);

  lcd.setCursor(8,1);
  lcd.print( istruzione);

  lcd.setCursor(11,1);
  lcd.print( somma);

}

e come vedete praticamente ad ogni pressione del tasto sulla input7 aumenta datoscrittura fino a 20 e spedisce il pacchetto di 3 byte, rimanendo in attesa di risposta, risposta che viene inviata dal Mega2, con il seguente sketch:

byte dato;
byte istruzione;
byte somma;

void setup()
{
 Serial1.begin(57600);
 Serial2.begin(57600);

 }

void loop()
{

    if (Serial1.available() > 0){

          dato=Serial1.read();
          istruzione=Serial1.read();
          somma=Serial1.read();
          
          Serial2.write(dato);
          Serial2.write(istruzione);
          Serial2.write(somma);
           
}

}

il problema è che la lettura a display dei byte ricevuti non è corretta. Il primo byte lo legge correttamente ma non fa il reset a 20, gli altri due al primo invio si sentano a 255 e li rimangono :confused:
Ho provato a dare il comando di flush della seriale e clear del display ad ogni invio ma non cambia nulla.
Ho provato con la seriale USB a debuggare e praticamente i 3 byte partono corretti ma già il mega 2 li riceve confusi, il che mi fa pensare che sia un problema che nasce già al primo invio del pacchetto.

Vedete qualche errore grossolano negli sketch?
Attendo Vostre!
grazie, ciao!
Francesco

Ciao! Non riesco a vedere errori nei programmi, non è detto che non ci sono, solo che io non riesco ad individuarli :slight_smile:

Un problema che potresti riscontrare!

Mi viene in mente un problema che spesso si presenta con la comunicazione seriale.
Il problema è che Arduino esegue le istruzioni più velocemente della comunicazione seriale, se io metto tre serial read(), queste vengono eseguite molto velocemente, più velocemente della trasmissione seriale,e questo porta alla lettura di valori sbagliati. Come risolvere, mettere una pausa che attende che il carattere sulla seriale sia disponibile, prima di ogni serial.read();

Esempio. Si dovrà cambiare il nome della seriale che si usa nel programma.

if (Serial1.available() > 0){ // Ci sono dati sulla seriale

         
          while(!Serial1.available()); // Attende che il dato sia disponibile, notare il punto e virgola

          dato=Serial1.read();

          while(!Serial1.available()); // Attende che il dato sia disponibile, notare il punto e virgola

          istruzione=Serial1.read();

          while(!Serial1.available()); // Attende che il dato sia disponibile, notare il punto e virgola

          somma=Serial1.read();
          
          Serial2.write(dato);
          Serial2.write(istruzione);
          Serial2.write(somma);
           
}

Contaci, che il problema è quello.
Ma perché fare tutto questo casino ?
I normali esempi di lettura diretta ed eco, non andavano bene?

torn24:
Ciao! Non riesco a vedere errori nei programmi, non è detto che non ci sono, solo che io non riesco ad individuarli :slight_smile:

Un problema che potresti riscontrare!

Mi viene in mente un problema che spesso si presenta con la comunicazione seriale.
Il problema è che Arduino esegue le istruzioni più velocemente della comunicazione seriale, se io metto tre serial read(), queste vengono eseguite molto velocemente, più velocemente della trasmissione seriale,e questo porta alla lettura di valori sbagliati. Come risolvere, mettere una pausa che attende che il carattere sulla seriale sia disponibile, prima di ogni serial.read();

Esempio. Si dovrà cambiare il nome della seriale che si usa nel programma.

if (Serial1.available() > 0){ // Ci sono dati sulla seriale

while(!Serial1.available()); // Attende che il dato sia disponibile, notare il punto e virgola

dato=Serial1.read();

while(!Serial1.available()); // Attende che il dato sia disponibile, notare il punto e virgola

istruzione=Serial1.read();

while(!Serial1.available()); // Attende che il dato sia disponibile, notare il punto e virgola

somma=Serial1.read();
         
          Serial2.write(dato);
          Serial2.write(istruzione);
          Serial2.write(somma);
         
}

Grazie della dritta, questa sera dovrei riuscire a provare;)

Standardoil:
Contaci, che il problema è quello.
Ma perché fare tutto questo casino ?
I normali esempi di lettura diretta ed eco, non andavano bene?

ciao!
tipo a che esempi ti rifererisci? Ad ogni modo questa e un'applicazione nella quale devo rispettare un determinato protocollo, non si tratta di far "semplicemente" cominciare due Arduino...

Ciao Ragazzi!
Grazie alle ultime dritte la comunicazione funziona benone, sto ora testando le altre parti critiche del sw poi passerò alla progettazione del PCB.
intanto grazie a tutti!
ciao!