Vai al contenuto

Realizzare una connessione Modbus TCP/IP

Home Forum Programmazione IEC 61131 (LogicLab) Realizzare una connessione Modbus TCP/IP

Taggato: 

Stai visualizzando 9 post - dal 1 a 9 (di 9 totali)
  • Autore
    Post
  • #58760
    tommas.cavallini
    Partecipante

    Salve 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.

    #58769
    Sergio Bertana
    Amministratore del forum

    Non 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.

    #58905
    tommas.cavallini
    Partecipante

    Ho 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?

    #58908
    Sergio Bertana
    Amministratore del forum

    Non 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.

    #58909
    tommas.cavallini
    Partecipante

    Le 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?

    #58914
    Sergio Bertana
    Amministratore del forum

    Da 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.

    #58917
    Sergio Bertana
    Amministratore del forum

    Ho 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.

    #58949
    tommas.cavallini
    Partecipante

    Perfetto, 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?

    #58957
    Sergio Bertana
    Amministratore del forum

    L’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.

Stai visualizzando 9 post - dal 1 a 9 (di 9 totali)
  • Devi essere connesso per rispondere a questo topic.