Comunicazione bidirezionale con libreria ModbusRtu.h

Buongiorno, per un progetto devo far comunicare 2 d1 mini con 2 convertitori ttl to rs485 per la lettura di temperatura per poi abilitazione comandi , uso la libreria Modbusrtu.h di smarmengo , il problema e che il master comunica allo slave , ma per la risposta non capisco che fare , ho pensato di copiare il codice master e inserirlo su slave , ma oltre questo quando preparo il msg non riesco a decifrare id crc etc....
Qualcuno ha già affrontato questo discorso

Ti segnalo che, nella sezione in lingua Inglese, si può scrivere SOLO in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana ... la prossima volta potrebbe venire direttamente eliminato. Grazie.

ciao...hai dato una occhiata agli esempi allegati alla libreria?

PS: che modulo usi per la conversione ttl RS485?

Hello, yes I'm using the library you smarmengo, Modbusrtu.h, the communication between master and slave is ok, in the sense that I receive the data from the master correctly, vice versa I didn't understand how the slave can send, e.g. reading a sensor to the master

For the converter I am using the TTL to RS485 RS485 to TTL Serial Converter Module, UART Port Bidirectional Module, 3.3/5V Power Signal

ok...il mio italiano non è il massimo ma rispondere in inglese mi sembra esagerato :grin:
per cortesia indichi un link al convertitore?

@minixium: Sei nella sezione ITALIANA del forum dove è d'obbligo l'uso della lingua Itaiana, quindi, cortesemente, edita (e NON riscrivi) i tuoi due post e traducili in Italiano. Grazie.

Guglielmo.

P.S.: ... e, come sempre mi raccomando, NON usate la traduzione automatica fatta dal browser perché poi non capite più in che sezione vi trovate!

Ciao scusami , mi sono confuso, comunque io uso questo convertitore ttl to rs485, lo trovi su aliexpress, questo non ha controlli da gestire.
Questo è il link:
https://it.aliexpress.com/item/1005004410877216.html?src=google&src=google&albch=shopping&acnt=548-301-0399&slnk=&plac=&mtctp=&albbt=Google_7_shopping&gclsrc=aw.ds&albagn=888888&ds_e_adid=&ds_e_matchtype=&ds_e_device=m&ds_e_network=x&ds_e_product_group_id=&ds_e_product_id=it1005004410877216&ds_e_product_merchant_id=107896619&ds_e_product_country=IT&ds_e_product_language=it&ds_e_product_channel=online&ds_e_product_store_id=&ds_url_v=2&albcp=15709057082&albag=&isSmbAutoCall=false&needSmbHouyi=false&gclid=EAIaIQobChMIz5Kmjcj9gQMVBoVoCR1Oag9hEAQYBSABEgKWhfD_BwE&aff_fcid=32cff44627874145be46a87aea4c4ced-1697562239901-00234-UneMJZVf&aff_fsk=UneMJZVf&aff_platform=aaf&sk=UneMJZVf&aff_trace_key=32cff44627874145be46a87aea4c4ced-1697562239901-00234-UneMJZVf&terminal_id=a7dcd5fe45164a23b0cd68bb11557a3d&afSmartRedirect=y

Si per la fretta non ho prestato attenzione , comunque colgo l'occasione per chiedere se mi sa dare un'indicazione sul mio problema sopra citato
Grazie

ciao...il modulo sembra uno di quelli che autoseleziona se in trasmissione o in ricezione a seconda del flusso dati...ne uso anch'io di questo tipo...posta i codici che hai scritto lato master e slave...perchè se usi bene la libreria fa tutto lei...nel senso che a "richiesta" del mastero lo slave risponde

Ciao , ti condivido il codice lato master

//master
#include <SoftwareSerial.h>
#include <ModbusRtu.h>

SoftwareSerial mySerial (4, 5); //RX-TX
/**
    Modbus object declaration
    u8id : node id = 0 for master, = 1..247 for slave
    u8serno : serial port (use 0 for Serial)
    u8txenpin : 0 for RS-232 and USB-FTDI
                 or any pin number > 1 for RS-485
*/
Modbus master(0, mySerial);//4, 13); // this is master and softwareSerial

/**
   This is an structe which contains a query to an slave device
*/
uint8_t u8state;
modbus_t telegram;
unsigned long u32wait;
uint8_t state =0;

// data array for modbus network sharing
//uint16_t au16data[16];
uint16_t au16datainvio[16] = {1,111 , 112, 113, 114, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 355};



void setup() {
  
  Serial.begin(9600);
  master.begin(&mySerial, 19200 ); // baud-rate at 19200
  master.setTimeOut( 5000 ); // if there is no answer in 2000 ms, roll over
  master.start();

  u32wait = millis() + 1000;
  u8state = 0;

}

void loop() {

switch ( u8state ) {
   
  
   case 0:
     
      if (millis() > u32wait) u8state++; // wait state

     break;
   
    case 1:
      
      
      telegram.u8id = 1; // slave address
      telegram.u8fct = 16; // function code (write single register)
      telegram.u16RegAdd = 0; // start address in slave
      telegram.u16CoilsNo = 16; // number of elements (coils or registers) to read
      telegram.au16reg = au16datainvio; // pointer to a memory array in the Arduino

      master.query( telegram ); // send query (only once)

 u8state++;
    
  break;
    
case 2:
     
      master.poll();

\\questa è una mia prova nel vedere se nell'array cambia qualcosa
   master.poll( au16datainvio, 16 );
  Serial.println(au16datainvio[0]);
   Serial.println(au16datainvio[1]);
   Serial.println(au16datainvio[2]);
   Serial.println(au16datainvio[3]);
   Serial.println(au16datainvio[4]);
   Serial.println(au16datainvio[5]);
   Serial.println(au16datainvio[6]);
   Serial.println(au16datainvio[7]);
   Serial.println(au16datainvio[8]);
   Serial.println(au16datainvio[9]);
   Serial.println(au16datainvio[10]);
   Serial.println(au16datainvio[11]);
   Serial.println(au16datainvio[12]);
   Serial.println(au16datainvio[13]);
   Serial.println(au16datainvio[14]);
   Serial.println(au16datainvio[15]);
     Serial.println(au16datainvio[16]);
   Serial.println(au16datainvio[17]);
  Serial.println(au16datainvio[18]);   
  Serial.println(au16datainvio[19]);
  Serial.println(au16datainvio[20]); 

u32wait = millis() + 2000;
   
   if (master.getState() == COM_IDLE) {
           
            u8state = 0;
   }
 
  Serial.println("Case2");

u32wait = millis() + 1000;
 
 break;


}

Lato Slave

#include <SoftwareSerial.h>
#include <ModbusRtu.h>
#include <DHT.h>


//###############################################
#define DHTPIN 2       // pin d4 Digital d1mini
#define DHTTYPE DHT22  // DHT 22 (AM2302)
//#define DHTTYPE    DHT21     // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);
 //##########################################################

SoftwareSerial mySerial(4, 5);  //d1mini d1=5 d2=4
Modbus slave(1, mySerial);  // this is slave @1 and softwareSerial
uint16_t a = 0;
modbus_t telegram;
unsigned long tempus;
boolean trasmesso = false;
uint8_t state = 0;
uint8_t u8state = 0 ;
// data array for modbus network sharing
uint16_t au16dataricevi[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };


void setup() {

  dht.begin();
  Serial.println("setup");
  slave.begin(&mySerial, 19200);  // baud-rate at 19200
  Serial.begin(9600);
}

void loop() {

//############### Hier alles was Zeitverzoegert erfolgen soll##################
  //DHT22 Begin ##############################################
  //##########################################################
  float luftfeuchtigkeit_dht22 = dht.readHumidity();
  float temperatur_dht22 = dht.readTemperature();
/*
  Serial.print("Temperature_DHT22 = ");
  Serial.print(temperatur_dht22 * 100);
  Serial.println(" *C");

  Serial.print("Luftfeuchtigkeit = ");
  Serial.print(luftfeuchtigkeit_dht22 * 100);
  Serial.println(" %");
  //DHT22 Ende ##############################################
  //##########################################################
  uint16_t c, b;
  //uint16_t= b ;
  c = luftfeuchtigkeit_dht22;
  b = temperatur_dht22;
*/

 
 if (millis() > tempus) u8state++;{
 
 state = slave.poll(au16dataricevi, 16);

  if (state > 4) {

    Serial.println("ricevi");

    Serial.println(au16dataricevi[0]);
    Serial.println(au16dataricevi[1]);
    Serial.println(au16dataricevi[2]);
    Serial.println(au16dataricevi[3]);
    Serial.println(au16dataricevi[4]);
    Serial.println(au16dataricevi[5]);
    Serial.println(au16dataricevi[6]);
    Serial.println(au16dataricevi[7]);
    Serial.println(au16dataricevi[8]);
    Serial.println(au16dataricevi[9]);
    Serial.println(au16dataricevi[10]);
    Serial.println(au16dataricevi[11]);
    Serial.println(au16dataricevi[12]);
    Serial.println(au16dataricevi[13]);
    Serial.println(au16dataricevi[14]);
    Serial.println(au16dataricevi[15]);
    Serial.println(au16dataricevi[16]);
    
    

 tempus = millis() + 5000;
  
    au16dataricevi[2] = 444; //se volessi inviare questi valori al master ?
  au16dataricevi[3] = 111;   //""""""""""""
  
  }

tempus = millis() + 1000;

}
}

Come ti accennavo il master invia allo slave , ma la risposta da quest'ultimo non capisco come gestirla

la libreria fa tutto...il master chiede di leggere/modificare il valore di "n" registri ed invia la richiesta allo slave...questi registri nello slave sono le posizioni dell'array:

uint16_t au16dataricevi[16]

che poi in polling metti a disposizione del master con:

 state = slave.poll(au16dataricevi, 16);

questa funzione verifica che tipo di richiesta ha fatto il master e se di lettura invia il valore della/delle posizioni richieste (registri) altrimenti scrive il valore nella posizione (registro) indicato; altresì la funzione ritorna lo stato del suo processo...con, per semplificare, NO REQUEST, OK, NOT OK.
quindi tu devi solo mettere nel posto giusto il valore che ti interessa o verificare cos'è stato modificato dei precedenti valori...

Ciao Andreaber , quindi correggimi se sbaglio nel telegram di invio nel mio caso uso la funzione 16 per scrivere quindi lo slave non rispondera' , devo allora creare un'altro telegram per leggere?
Se così fosse nel poll , come spacchetto l'array che mi invia lo slave , gli devo aggiungere l'argomento (variabile, dimensione)
Grazie

ciao minixium,

scusa la domanda...hai idea di come funziona il protocollo Modbus RTU?
sapere com'è strutturato è indispensabile per capire com'è stata sviluppata la libreria e poterla usare correttamente.
ti allego un pdf con descrizione, breve, del protocollo e delle funzioni più comuni.
una volta capito il protocollo controlli cosa fa la funzione poll della libreria e vedrai che quello che ho scritto nel mio messaggio precedente ti sarà più chiaro.
Modbus RTU.pdf (229,8 KB)

Ciao Andreaber , grazie per il file , comunque ho già letto altre guide , la struttura del msg mi sembra abbastanza chiara , almeno credo , tranne se non mi sfugge qualcosa :

id slave-- function lettura o scrittura--- inizio per numero di byte --- e la variabile da inviare , che poi è quello che ho inserito nel codice master , che riceve lo slave in modo corretto , a livello logico non capisco come risponde

l'esempio "simple slave" della libreria è:

#include <ModbusRtu.h>

// data array for modbus network sharing
uint16_t au16data[16] = {
  3, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };

Modbus slave(1,Serial,0); // this is slave @1 and RS-232 or USB-FTDI

void setup() {
  Serial.begin( 19200 ); // baud-rate at 19200
  slave.start();
}

void loop() {
  slave.poll( au16data, 16 );
}

se allo slave, dov'è caicato questo programma, il master chiede: "dammi il valore dal registro 3 al registro 5" cosa risponderà?

Già a questo punto ho qualche difficoltà , se ti devo devo indicare dalla posizione array , le posizioni sono 4-2-7182 ,

però riguardo il msg modbus ho dei dubbi :
address può essere indirizzo 3 slave
ma fuction non può essere 1415
start address 9265
data bit 4 per una lunghezza di 2

l'array :

uint16_t au16data[16]

definisce solo il numero di registri...e ne contiene i valori.
tutto il resto ID, funzione, numero bytes, quanti registri, crc etc vengoni gestiti fuori da questa array. l'ID lo definisci all'inizio quando istanzi l'oggetto:

Modbus slave(1,Serial,0);

poi definisci appunto l'array (lista dei registri) con:

uint16_t au16data[16]

tutto il resto lo fa la funzione pool...verifica cosa chiede il master, fa riferimento all'array...e o scrive nuovi valori nelle varie posizioni o verifica il valore nelle specifiche posizioni e poi crea la relativa risposta che spedisce in autonomia.