comunicazione seriale arduino con rs485
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
modulo 2
file supporto.h
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;
}