Realizzare una connessione Modbus TCP/IP
Home › Forum › Programmazione IEC 61131 (LogicLab) › Realizzare una connessione Modbus TCP/IP
Taggato: ModbusTCP/IP
- Questo topic ha 8 risposte, 1 partecipante ed è stato aggiornato l'ultima volta 4 anni, 2 mesi fa da
Sergio Bertana.
-
AutorePost
-
Gennaio 13, 2021 alle 11:33 am #58760
tommas.cavallini
PartecipanteSalve a tutti, premetto che ho appena iniziato ad affacciarmi a queste tematiche quindi sono un po’ inesperto.
Ad ogni modo, possiedo un PLC SlimLine LogicLab Compact Ethernet e devo instaurare una comunicazione con un datataker esterno in Modbus TCP/IP. Quali FB posso utilizzare? Ne ho trovati alcuni sul manuale ma non so quale dei tanti sia il più idoneo. Devo semplicemente leggere due dati dal datataker e visualizzarli in LogicLab.
Grazie a chiunque mi risponda.
Gennaio 13, 2021 alle 11:58 am #58769Sergio Bertana
Amministratore del forumNon conosco il prodotto in questione ma immagino che il prodotto sia un server Modbus e tu debba connetterti come client. Quindi puoi utilizzare il FB TCPClient per aprire la connessione TCP verso il dispositivo, poi passerai il File in uscita come parametro al FB ModbusMaster che potrai parametrizzarlo in base al codice funzione ed indirizzo Modbus necessario.
In fondo alla pagina di manuale del FB ModbusMaster c’è il programma ST_ModbusMaster_v1 che puoi copiare ed importare in un tuo progetto LogicLab che è già pronto con tutto quello che serve, in realtà c’è anche la gestione da porta seriale che puoi cancellare.
Se le variabili Modbus da leggere/scrivere su dispositivo sono molte e distanti tra di loro e quindi richiedono l’utilizzo di più pacchetti Modbus ti consiglio di abbinare il FB ACModbus che ti semplifica il lavoro.
Gennaio 29, 2021 alle 3:11 pm #58905tommas.cavallini
PartecipanteHo realizzato una comunicazione Modbus TCP/IP con un datataker utilizzando i FB SysTCPClient e ModbusMaster, al termine del quale, una volta ricevuto il dato in IEE754, ho effettuato una conversione con il FB BEArrayToVar.
A questo punto, il problema è che devo leggere 40 valori dallo stesso dispositivo e salvare ciascuno di essi in una variabile a sé stante: come potrei fare?
Ho visto anche il FB consigliato da lei, il ACModbus, ma il problema è che una volta lette queste variabili devo necessariamente effettuare la conversione con BEArrayToVar per ciascuno di essi singolarmente e instanziare una variabile per ciascuno dei dati, quindi temo che non posso utilizzarlo.
Cosa mi consiglia di fare per risolvere il problema?
Gennaio 29, 2021 alle 3:19 pm #58908Sergio Bertana
Amministratore del forumNon mi dici se i valori sono in registri consecutivi oppure no. Se sono in registri consecutivi puoi eseguire un unico comando di lettura di tutti i valori (40 valori float corrispondono a 80 registri modbus, 160 bytes). Il comando Modbus può acquisire fino a 250 bytes.
Se invece sono allocati ad indirizzi molto distanti tra di loro occorre per forza eseguire più comandi di lettura.
Ora assumendo che per sistemare l’endiannes dei dati occorra eseguire la funzione VarSwap su ogni valore letto, ti consiglio di appoggiare i valori letti in variabili di memoria di appoggio e poi eseguire lo swap su un’altra variabile che sarà quella che effettivamente utilizzerai.
Se utilizzi il FB ACModbus e vuoi ottimizzare il programma puoi appoggiare il valore letto da ogni comando sempre nella stessa variabile, poi con l’uscita COk, attivo per un loop se comando Modbus eseguito correttamente, sincronizzandosi con AIDx puoi eseguire lo swap del valore letto nella tua variabile.
Gennaio 30, 2021 alle 11:42 am #58909tommas.cavallini
PartecipanteLe dico subito che purtroppo la lettura dei valori dal datataker non va a buon fine se uso VarSwap (avevo pensato di usare proprio questo all’inizio, ma viene fuori un numero altissimo) mentre se uso il FB BEArrayToVar funziona e mi restituisce il valore letto in modo corretto.
Per il resto, 36 dei 40 sono in registri consecutivi, quindi per questi posso eseguire un unico comando di lettura (specificando alla voce Address il primo indirizzo da cui partire e alla voce Points del ModbusMaster quanti dati voglio leggere, nel mio caso 36*2, 72). Nel buffer del ModbusMaster quindi metterò un array che sia in grado di contenere 36 dati (chiamato per intenderci ArrayA), questo array poi sarà collegato a BEArrayToVar alla voce Source e in Destination metterò un altro array (ArrayB) che conterrà tutti i valori letti in modo corretto, giusto?
La mia domanda è: automaticamente, dopo ogni lettura, il dato letto va in ArrayA, viene eseguito BEArrayToVar e viene memorizzato in ArrayB. Al ciclo di lettura successivo, il secondo dato letto va in ArrayA subito dopo il precendente in automatico, per poi andare in ArrayB memorizzato sempre di fila, giusto?
Gennaio 30, 2021 alle 11:57 am #58914Sergio Bertana
Amministratore del forumDa quello che dici c’è un problema di endianness sui dati acquisiti via Modbus, è strano che tu debba usare la funzione BEArrayToVar, perchè questo vuol dire che è scambiato l’endianness anche nei singoli registri oltre che tra i registri. Mentre il protocollo Modbus indica chiaramente l’endianness dei registri (Dai una occhiata a questo post).
Bene leggere i 36*2 registri consecutivi (Se gli altri 4 non sono molto distanti come indirizzi puoi anche leggerne di piu eliminando i registri vuoti nel mezzo). Poi come dici tu tutti i registri letti saranno appoggiati in ArrayA, di tipo BYTE lungo 144 bytes. E dovrai creare l’ArrayB da 36 REAL per contenere il valore convertito.
Dovrai poi eseguire 36 volte la funzione BEArrayToVar, indicando come Type un REAL e passando come Source l’indirizzo di ArrayA e come Destination l’indirizzo di ArrayB opportunamente offsettati.
Gennaio 30, 2021 alle 4:27 pm #58917Sergio Bertana
Amministratore del forumHo provato a scrivere un esempio del programma…
VAR i : UDINT; (* Auxiliary variable *) IDx : USINT; (* Index *) ArrayA : ARRAY[0..143] OF BYTE; (* Array appoggio lettura Modbus *) ArrayB : ARRAY[0..36] OF REAL; (* Array appoggio valori acquisiti *) END_VAR // Simulo i valori acquisiti dallo strumento. i:=Sysmemmove(ADR(ArrayA[0]), ADR(16#42C81234), 4); //Carico 100.036 i:=Sysmemmove(ADR(ArrayA[4]), ADR(16#44022BC7), 4); //Carico 520,684 i:=Sysmemmove(ADR(ArrayA[140]), ADR(16#4733B0D8), 4); //Carico 46000,844 // Eseguo la conversione in REAL. FOR IDx:=0 TO 35 DO i:=BEArrayToVar(REAL_TYPE, ADR(ArrayB[IDx]), ADR(ArrayA[IDx*4])); END_FOR;
Per il calcolo dei valori in esadecimale ho utilizzato un convertitore IEE754 on line.
Febbraio 4, 2021 alle 5:03 pm #58949tommas.cavallini
PartecipantePerfetto, ho provato tutto per come mi ha spiegato Lei e funziona, quindi La ringrazio davvero.
Adesso però ho un altro problema: mi è stato chiesto di ritardare la lettura in Modbus in modo da eseguire una lettura al minuto. Per fare ciò ho pensato di agire sulla voce Delay: è corretto mettere un delay di 60 per il mio fine o sarebbe meglio mettere un eTON prima di Enable in modo da ritardare con il timer?
Nel caso in cui vada a modificare il Delay (mettendo 60), avendo due modbusMaster in cascata, alla voce Delay del secondo FB dovrei mettere 61 (60 del precedente + 1 di ritardo tra le due letture) o mi basta solo inserire il ritardo tra le due letture (1 sec) e nel primo lasciare 60?
Febbraio 4, 2021 alle 5:08 pm #58957Sergio Bertana
Amministratore del forumL’ingresso Delay del FB ModbusMaster serve proprio a questo, in pratica terminato il comando modbus si attiverà per un loop di programma l’uscita Ok, che potrai usarla per la conversione dei dati, ma l’uscita Done si attiverà solo dopo il tempo definito in Delay.
Quindi se colleghi pù FB Modbus in cascata la seconda partirà dopo il tempo di delay della prima, la terza dopo il tempo di delay della seconda e così via. Fino all’ultima della cascata che dopo il tempo di delay definito farà ripartire la prima.
-
AutorePost
- Devi essere connesso per rispondere a questo topic.