Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

comunicazione seriale arduino con rs485

Progetti, interfacciamento, discussioni varie su questa piattaforma.

Moderatori: Foto UtenteWALTERmwp, Foto Utentexyz

0
voti

[1] comunicazione seriale arduino con rs485

Messaggioda Foto Utentedanielealfa » 11 nov 2022, 19:56

salve a tutti, avevo bisogno di inviare e ricevere una serie di tati via seriale e in rete ho trovato qualcosa
ho copiato i vari codici e ho creato questo
il tutto funziona abbastanza ma ogni tanto mi perde qualche dato ...
il byte ricevuto mi restituisce molto spesso ok , ogni tanto RX_WAIT e quando resta bloccato RX_TIMEOUT:
lo so con sara' chissa cosa ma per averlo adattato ed poi ho un problema con la codifica crc
per il momento vi ringrazio
modulo 1
Codice: Seleziona tutto
#include <SoftwareSerial.h>
#include "supporto.h"


#define SSerialRX        10
#define SSerialTX        11
#define SSerialTxControl 3
#define RS485Transmit    HIGH
#define RS485Receive     LOW

SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
int buttonState = 0;
byte ricevuto ;
byte old_ricevuto ;

int cont = 0;
unsigned long previousMillis  = 0;
const long interval           =  250;

typedef struct {
  // id messaggio
  uint32_t idmsg;
  // id del destinatario
  uint32_t  destinatario;
  // valori da comunicare al destinatario
  uint32_t comando;
  uint32_t valore;
} t_dati;
#define DIMDATI (sizeof(t_dati))
typedef struct {
  t_dati dati;
  uint32_t crc;
} t_pack;
#define DIMPACK (sizeof(t_pack))

//struct di ritorno
typedef struct {
  uint32_t idmsg1;
  uint32_t  destinatario1;
  uint32_t comando1;
  uint32_t valore1;
} t_dati1;
#define DIMDATI1 (sizeof(t_dati1))
typedef struct {
  t_dati1 dati1;
  uint32_t crc;
} t_pack1;
#define DIMPACK1 (sizeof(t_pack1))

t_pack tx;
t_pack1 rx;
void setup() {
  pinMode(5, INPUT_PULLUP);
  pinMode(13, OUTPUT);
  RS485Serial.begin(19200);
  Serial.begin(9600);
  Serial.println("\nTEST invio struct");
  pinMode(SSerialTxControl, OUTPUT);
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver
}
void loop() {
buttonState = digitalRead(5);
  if (buttonState == HIGH) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);

if (ricevuto!=old_ricevuto ){
switch (ricevuto) {
case RX_OK:    // your hand is on the sensor
      //lcd.setCursor(0, 1);
         Serial.println("ok        ");
      break;
      case RX_WAIT:    // your hand is on the sensor
      //lcd.setCursor(0, 1);
        Serial.println("RX_WAIT      ");
      break;
  case RX_TIMEOUT:    // your hand is on the sensor
      //lcd.setCursor(0, 1);
         Serial.println("RX_TIMEOUT");
      break;
  case RX_HIGH:    // your hand is on the sensor
      //lcd.setCursor(0, 1);
         Serial.println("RX_HIGH      ");
      break;
        case RX_LOW:    // your hand is on the sensor
      //lcd.setCursor(0, 1);
          Serial.println("RX_LOW       ");
      break;
}
  }
  old_ricevuto=ricevuto;
 
  if (RS485Serial.available() > 0) {
    ricevuto = Ricevi(RS485Serial, (unsigned char *)&rx, DIMPACK);
    if (ricevuto == RX_OK) {
      // i dati sono arrivati
      // verifico il CRC
      // if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
      // i dati sono validi
      // verifico che la richiesta sia per questo slave
      if (rx.dati1.destinatario1 == 1) {
        // faccio quello che devo fare
        Serial.println(rx.dati1.valore1);
      }
    }
  }

  if (millis() - previousMillis >= interval) {
    previousMillis += interval;
    cont ++;
    tx.dati.idmsg = millis();
    tx.dati.destinatario = 1;
    tx.dati.comando = buttonState;
    tx.dati.valore = cont;
    //tx.crc = calc_crc32((unsigned char *)&tx, DIMDATI);
    digitalWrite(SSerialTxControl, RS485Transmit);
    Trasmetti(RS485Serial, (unsigned char *)&tx, DIMPACK);
    digitalWrite(SSerialTxControl, RS485Receive);
  }
}


modulo 2
Codice: Seleziona tutto
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#include <SoftwareSerial.h>
#include "supporto.h"

#define SSerialRX        9
#define SSerialTX        8
#define SSerialTxControl 7
#define RS485Transmit    HIGH
#define RS485Receive     LOW

SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX

byte ricevuto ;
int cont = 0;
unsigned long previousMillis  = 0;
const long interval           = 250;


typedef struct {
  // id messaggio
  uint32_t idmsg;
  // id del destinatario
  uint32_t  destinatario;
  // valori da comunicare al destinatario
  uint32_t comando;
  uint32_t valore;
} t_dati;
#define DIMDATI (sizeof(t_dati))
typedef struct {
  t_dati dati;
  uint32_t crc;
} t_pack;
#define DIMPACK (sizeof(t_pack))

//struct di ritorno
typedef struct {
  uint32_t idmsg1;
  uint32_t  destinatario1;
  uint32_t comando1;
  uint32_t valore1;
} t_dati1;
#define DIMDATI1 (sizeof(t_dati1))
typedef struct {
  t_dati1 dati1;
  uint32_t crc;
} t_pack1;
#define DIMPACK1 (sizeof(t_pack1))



t_pack1 tx;
t_pack rx;
void setup() {

  lcd.begin();
  RS485Serial.begin(19200);
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Menu demo");
  Serial.begin(9600);
  Serial.println("\nTEST invio struct");
  delay(500); //wait 2 sec
  pinMode(SSerialTxControl, OUTPUT);
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver
  lcd.clear(); //clear the whole LCD
}

void loop() {
   switch (ricevuto) {
case RX_OK:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("ok        ");
      break;
      case RX_WAIT:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_WAIT      ");
      break;
  case RX_TIMEOUT:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_TIMEOUT");
      break;
  case RX_HIGH:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_HIGH      ");
      break;
        case RX_LOW:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_LOW       ");
      break;
}
 
 
  switch (ricevuto) {
case RX_OK:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("ok        ");
      break;
      case RX_WAIT:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_WAIT      ");
      break;
  case RX_TIMEOUT:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_TIMEOUT");
      break;
  case RX_HIGH:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_HIGH      ");
      break;
        case RX_LOW:    // your hand is on the sensor
      lcd.setCursor(0, 1);
         lcd.print("RX_LOW       ");
      break;
}
  if (RS485Serial.available() > 0) {
    // sono in attesa di comandi dal master
    ricevuto = Ricevi(RS485Serial, (unsigned char *)&rx, DIMPACK);
    if (ricevuto == RX_OK) {
      // i dati sono arrivati
      // verifico il CRC
      // if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
      // i dati sono validi
      // verifico che la richiesta sia per questo slave
      if (rx.dati.destinatario == 1) {
        // faccio quello che devo fare
      }
      lcd.setCursor(0, 0);
      lcd.print(rx.dati.valore);
    lcd.setCursor(0, 3);
     lcd.print(rx.dati.idmsg/100);
   lcd.setCursor(2, 2);
     lcd.print(rx.dati.comando);
    }
  }
  if (millis() - previousMillis >= interval) {
    previousMillis += interval;
    cont ++;
    tx.dati1.idmsg1 = millis();
    tx.dati1.destinatario1 = 1;
    tx.dati1.comando1 = 99;
    tx.dati1.valore1 = cont;
    //tx.crc = calc_crc32((unsigned char *)&tx, DIMDATI);
    digitalWrite(SSerialTxControl, RS485Transmit);
    Trasmetti(RS485Serial, (unsigned char *)&tx, DIMPACK);
    digitalWrite(SSerialTxControl, RS485Receive);
  }
}


file supporto.h
Codice: Seleziona tutto


//unsigned long calc_crc32(unsigned char* buf, unsigned int len)
//{
// unsigned long crc;
//  unsigned int i;
   
   
// crc = 0xffffffff;
   // for (i = 0; i < len; i++)
    //  #if defined(__SAM3X8E__)
    // crc = ((crc >> 8) & 0x00ffffff) ^ crctab32[(crc ^ *buf++) & 0xff];
  //   #else
        //crc = ((crc >> 8) & 0x00ffffff) ^ pgm_read_dword_near(&crctab32[(crc ^ *buf++) & 0xff]);
//    #endif
  //  return (crc ^ 0xffffffff);
//}




#ifndef CHR_START
  #define CHR_START '['
#endif
#ifndef CHR_STOP
  #define CHR_STOP  ']'
#endif
#ifndef CHR_SEP
  #define CHR_SEP   ','
#endif
#ifndef TIMEOUT
  #define TIMEOUT   500
#endif

// - 0 = ricezione non completata
// - 1 = dati ricevuti correttamente
// - 2 = errore timeout
// - 3 = errore dati in arrivo oltre la dimensione massima
// - 4 = errore dati incompleti
#define RX_WAIT    0
#define RX_OK      1
#define RX_TIMEOUT 2
#define RX_HIGH    3
#define RX_LOW     4

// funzione che trasmette
// i dati vengono trasmessi un byte alla volta
// parametri:
// - seriale = canale su cui trasmettere (serial / HC12)
// - pacchetto = dati da trasmettere. serve un puntatore per scorrere la struttura dati un byte alla volta
// - dimensione = numero di byte da trasmettere



void Trasmetti(Stream &seriale, unsigned char * pacchetto, size_t dimensione) {
  // invio il carattere di start
  seriale.print(CHR_START);
  // invio i dati
  for (byte i = 0; i < dimensione; i++) {
    seriale.print(*(pacchetto + i), HEX);
    seriale.print(CHR_SEP);
  }
  // invio il carattere di stop
  seriale.print(CHR_STOP);

  return;
}

// funzion che riceve
// i dati arrivano sotto forma di caratteri che presi a 2 a 2 formano
// un byte rappresentato in HEX
// parametri:
// - seriale = canale da cui ricevere (serial / HC12)
// - pacchetto = contenitore dei dati da ricevere. serve un puntatore per scorrere la struttura dati un byte alla volta
// - dimensione = numero di byte massimo da ricevere
// ritorna:
// - 0 = ricezione non completata
// - 1 = dati ricevuti correttamente
// - 2 = errore timeout
// - 3 = errore dati in arrivo oltre la dimensione massima
// - 4 = errore dati incompleti
byte Ricevi(Stream &seriale, unsigned char * pacchetto, size_t dimensione) {
  // dimensione array di appoggio
  #define MAX 2
  //indice del byte ricevuto all'interno della struttura di destinazione
  //inizializzo con un valore fuori range massimo
  static uint32_t i = dimensione;
  // indice del carattere arrivato dentro l'array di appoggio
  static uint8_t j = 0;
  // array di appoggio per decodificare la stringa HEX in numero
  static char stringa[MAX + 1] = "";
  // valore millis per controllo timeout
  static uint32_t inizio = millis();
  // valore appena ricevuto
  byte valore;

  while (seriale.available()) {
    valore = seriale.read();
    // controllo che carattere è
    switch (valore) {
      case CHR_START:
        // è il carattere di inizio trasmissione
        // azzero gli indici
        i = 0;
        j = 0;
        // azzero l'array di appoggio;
        stringa[0] = '\0';
        stringa[1] = '\0';
        stringa[2] = '\0';
        // faccio partire il tempo per il timeout
        inizio = millis();
        break;
      case CHR_STOP:
        // è il carattere di fine trasmissione
        if (i == dimensione) {
          return RX_OK;
        } else {
          //il terminatore è arrivato troppo presto
          return RX_LOW;
        }
        break;
      case CHR_SEP:
        // è il carattere separatore
        // salvo il byte
        if (i < dimensione) {
          *(pacchetto+i) = strtol(stringa, NULL, 16);
        } else {
          // ho superato la dimensione della struttura
          return RX_HIGH;
        }
        // devo passare al byte successivo
        i++;
        j = 0;
        // azzero l'array di appoggio;
        stringa[0] = '\0';
        stringa[1] = '\0';
        stringa[2] = '\0';
        break;
      default:
        // è un carattere da convertire
        if (j < MAX) {
          stringa[j] = valore;
          j++;
        }
        break;
    }
    // controllo il timeout
    if ((millis() - inizio) > TIMEOUT) {
      // azzero tutto prima di restituire errore
      i = 0;
      j = 0;
      // azzero l'array di appoggio;
      stringa[0] = '\0';
      stringa[1] = '\0';
      stringa[2] = '\0';
      return RX_TIMEOUT;
    }
  }

  return RX_WAIT;
}
Avatar utente
Foto Utentedanielealfa
243 2 4 7
Expert
Expert
 
Messaggi: 1313
Iscritto il: 27 mag 2009, 22:51

0
voti

[2] Re: comunicazione seriale arduino con rs485

Messaggioda Foto UtenteWALTERmwp » 11 nov 2022, 20:52

Ciao @danielealfa.
Il discorso, che vale un po' per tutti quelli con un approccio un po' approssimativo, è sempre lo stesso: se desiserate un parere, un aiuto, dovete fornire più informazioni possibili ed esporle in modo chiaro e ordinato.
Spiegate, illustrate quello che state facendo definendo lo stato del setup hardware(cosa avete cablato e come) e, in tal caso, a livello software quali informazioni vengono trasmesse e quali ci si attende, così da evitare a chi legge più passaggi interpretativi.
Se si chiede una mano e l'attenzione degli altri bisogna impegnarsi in una coerente esposizione.
Grazie.

Saluti
W - U.H.F.
Avatar utente
Foto UtenteWALTERmwp
30,2k 4 8 13
G.Master EY
G.Master EY
 
Messaggi: 8986
Iscritto il: 17 lug 2010, 18:42
Località: le 4 del mattino

0
voti

[3] Re: comunicazione seriale arduino con rs485

Messaggioda Foto Utentedanielealfa » 11 nov 2022, 21:19

ciao, grazie della rua risposta, allora a livello sw e' come ho scritto sopra ogni arduino ha il codice che ho postato sopra
ho usato i moduli classici rs485 per arduino, i pin sono saldati per quindi non ho falsi contatti ,
il problema che ho e' che non ha un comunicazione fluida. i valori a volte vengono scritti male sul lcd


e seconda cosa quando vado a deccomentare nel file supporto.h le prime righe ho questo errori

Codice: Seleziona tutto
exit status 1
'crctab32' was not declared in this scope


Codice: Seleziona tutto
In file included from C:\Users\danie\Documents\Arduino\lato_b\lato_b.ino:4:0:
C:\Users\danie\AppData\Local\Temp\arduino_build_850713\sketch\supporto.h: In function 'long unsigned int calc_crc32(unsigned char*, unsigned int)':
C:\Users\danie\AppData\Local\Temp\arduino_build_850713\sketch\supporto.h:3:41: warning: unused parameter 'buf' [-Wunused-parameter]
unsigned long calc_crc32(unsigned char* buf, unsigned int len)
                                         ^~~
C:\Users\danie\AppData\Local\Temp\arduino_build_850713\sketch\supporto.h:17:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
Avatar utente
Foto Utentedanielealfa
243 2 4 7
Expert
Expert
 
Messaggi: 1313
Iscritto il: 27 mag 2009, 22:51

0
voti

[4] Re: comunicazione seriale arduino con rs485

Messaggioda Foto Utentedjnz » 12 nov 2022, 12:36

Una software serial non è adatta a velocità superiori ai 9600 b/s. Per usare diverse comunicazioni seriali a piena velocità meglio usare una board Mega che ha quattro seriali hardware.
Una domanda ben posta è già mezza risposta.
Avatar utente
Foto Utentedjnz
1.590 1 4 7
Master
Master
 
Messaggi: 708
Iscritto il: 26 lug 2020, 14:52

0
voti

[5] Re: comunicazione seriale arduino con rs485

Messaggioda Foto Utentedanielealfa » 12 nov 2022, 14:56

grazie anche a te della tua informazione.
allora la velocita' non e' vincolante, ora l ho messa a 4800 , intanto non ho bisogno di una velocita assurda
ora l ho modificata e vedo che funziona un po meglio
Avatar utente
Foto Utentedanielealfa
243 2 4 7
Expert
Expert
 
Messaggi: 1313
Iscritto il: 27 mag 2009, 22:51


Torna a Arduino

Chi c’è in linea

Visitano il forum: Nessuno e 14 ospiti