Questo blocco funzione da eseguire in task Back utilizzabile con modello a cascata, esegue la gestione del protocollo modbus master, per la codifica/decodifica dei frame Modbus viene utilizzato il FB _MModbusFrame. Con Type è possibile selezionare il tipo di protocollo RTU, Ascii ed over IP. Con File è possibile definire il terminale di I/O su cui effettuare la comunicazione.
Attivando Enable sul terminale di I/O viene inviato un frame per eseguire la funzione modbus definita in FCode sul nodo definito in Node. Terminata l’esecuzione del comando viene attivata l’uscita Done. Se l’esecuzione comando ha esito positivo si attiva per un loop di programma l’uscita Ok. Disattivando Enable si azzera Done e l’eventuale Fault, per eseguire nuovamente il comando occorre riabilitare l’ingresso Enable. L’ingresso SpyOn se attivo permette di spiare il funzionamento della FB.
Se FCode è una funzione di lettura, il valore delle variabili a partire dall’indirizzo definito in Address per il numero di variabili definito da Points, viene letto dal sistema slave e trasferito nelle variabili indirizzate da Buffer. Se FCode è una funzione di scrittura, il valore delle variabili presenti nel buffer di memoria indirizzato da Buffer per il numero di variabili definito da Points, è inviato al dispositivo slave che lo trasferirà nelle sue variabili a partire dall’indirizzo definito in Address. Sono supportati i seguenti codici modbus.
Ad ogni esecuzione corretta del comando viene attivata per un loop di programma l’uscita Done ed incrementato il valore di Packets. In caso di errore esecuzione o tempo di esecuzione comando superiore al tempo definito in Timeout, viene attivata per un loop di programma l’uscita Fault ed incrementato il valore in Errors.
Utilizzandolo con i FB dedicati alla gestione dei dispositivi Modbus si semplifica notevolmente lo sviluppo delle applicazioni.
Approfondimenti
- Questo topic tratta l’utilizzo dell’utilty Modbus Master del programma Toolly per testare la connessione Modbus su di un dispositivo.
- In questo topic viene illustato come utilizzare più FB ModBusMaster in cascata per comunicare con più dispositivi.
- In questo topic un semplice programma di comunicazione Modbus.
- In questo topic suggerimenti su comunicazione con più dispositivi Modbus TCP.
Upgrade list
- Se l’oggetto aggiornato non è nell’ultima versione del package, vedi capitolo “Aggiornamento librerie” in questo articolo.
- Gli oggetti obsoleti sono inseriti nella libreria eLLabObsoleteLib fare riferimento al relativo manuale ed al manuale programmazione in formato pdf.
ModbusMaster_v1
Implementa una gestione ottimizzata della acquisizione dei frames modbus di risposta evitando la dichiarazione del parametro IFTime. Tutti gli altri parametri in ingresso rimangono invariati, i parametri Timeout e Delay ora sono definiti di tipo REAL ed occorre impostarne il valore in secondi.
ModbusMaster_v2
Aggiunta gestione ingresso Absolute, se attivo considera indirizzamento assoluto e non viene sottratto 1 all’indirizzo Modbus inviato nel frame di richiesta. Visto che è stato aggiunto il solo parametro di ingresso Absolute mantenendo identico il funzionamento può sostituire la ModbusMaster_v1 nei progetti esistenti.
ModbusMaster_v3
Ingresso Type di definizione tipo di protocollo ora è di tipo MODBUS_PROTOCOL. I parametri in I/O Timeout, Delay e CTime ora sono di tipo TIME.
Descrizione
Enable (BOOL) Comando abilitazione esecuzione comando modbus. Per rieseguire il comando disabilitare e poi riabilitare questo ingresso.
SpyOn (BOOL) Se attivo permette di spiare il funzionamento della FB (Vedi articolo).
Absolute (BOOL) Per compatibilità con la specifica Modbus il FB sottrae 1 all’indirizzo Modbus. Se bit attivo si considera indirizzamento assoluto e non si esegue la sottrazione.
File (eFILEP) Flusso dati stream da utilizzare per la comunicazione.
Type (MODBUS_PROTOCOL) Tipo di protocollo modbus (Definizione).
Node (USINT) Numero di nodo modbus su cui effettuare il comando (Range da 0 a 255).
FCode (USINT) Codice funzione modbus da eseguire nel comando (Vedi tabella sotto).
Address (UINT) Indirizzo di allocazione variabili su sistema slave. In accordo alle specifiche modbus l’indirizzo inviato nel frame dati è (Address-1) (Range da 16#0001 a 16#FFFF).
Points (USINT) Numero di variabili consecutive su cui opera il comando.
Buffer (PVOID) Indirizzo buffer dati letti o da scrivere.
Timeout (TIME) Tempo massimo esecuzione comando. Se il comando non termina nel tempo definito viene abortito ed attivata l’uscita Fault.
Delay (TIME) Tempo di pausa dopo l’esecuzione del comando modbus.
Done (BOOL) Si attiva al termine della esecuzione comando e rimane attiva fino alla disabilitazione di Enable.
Ok (BOOL) Attivo per un loop se esecuzione comando corretta.
Fault (BOOL) Attivo per un loop se errore esecuzione comando.
CTime (TIME) Tempo di esecuzione comando, invio comando e ricezione risposta.
Packets (UDINT) Numero di comandi modbus eseguiti, incrementato ad ogni comando, raggiunto massimo riparte da 0.
Errors (UDINT) Numero di errori, incrementato ad ogni errore, raggiunto massimo riparte da 0.

FCode, funzioni modbus supportate
16#01 Read coil status (Massimo 250 coils)
16#02 Read input status (Massimo 125 inputs)
16#03 Read holding registers (Massimo 125 registri)
16#04 Read input registers (Massimo 125 registri)
+----+-----------+---+---+---+---+ +----+-----------+-----+--...--+ Query |Node|01/02/03/04|Address|Points | Response |Node|01/02/03/04|Bytes| Data | +----+-----------+---+---+---+---+ +----+-----------+-----+--...--+
16#05 Force single coil
16#06 Preset single register
+----+-----+---+---+--+--+ +----+-----+---+---+--+--+ Query |Node|05/06|Address|Data | Response |Node|05/06|Address|Data | +----+-----+---+---+--+--+ +----+-----+---+---+--+--+
16#0F Force Multiple Coils (Massimo 250 coils)
16#10 Preset multiple registers (Massimo 125 registri)
+----+-----+---+---+---+---+-----+--...--+ +----+-----+---+---+---+---+ Query |Node|0F/10|Address|Points |Bytes| Data | Response |Node|0F/10|Address|Points | +----+-----+---+---+---+---+-----+--...--+ +----+-----+---+---+---+---+
16#41 Read memory bytes (Funzione custom, massimo 250 bytes)
+----+--+---+---+---+---+ +----+--+-------+--...--+ Query |Node|41|Address|Points | Response |Node|41|Points | Data | +----+--+---+---+---+---+ +----+--+-------+--...--+
16#42 Write memory bytes (Funzione custom, massimo 250 bytes)
+----+--+---+---+---+---+--...--+ +----+--+-------+ Query |Node|42|Address|Points | Data | Response |Node|42|Points | +----+--+---+---+---+---+--...--+ +----+--+-------+
I codici 16#41 e 16#42 sono stati implementati per compatibilità con i vecchi sistemi programmabili con Remoter.
Messaggi di errore (Eccezione)
Il dispositivo, se non è in grado di eseguire l’operazione richiesta dal comando ricevuto, risponde con un messaggio di errore che prevede il seguente formato:
+-------------+---------------+----------------+---+---+ | Modbus node | Function code | Exception code | CRC | +-------------+---------------+----------------+---+---+
- Modbus node: Indirizzo del dispositivo slave che risponde.
- Function code: Codice funzione con MSB=1 (per indicare l’eccezione); esempio 16#83 (per la lettura 16#03 ) o 16#86 (per la scrittura 16#06).
- Exception code: Codice eccezione.
Codici eccezione
Code | Name | Description |
---|---|---|
16#01 | Illegal function | E’ stato richiesto un codice funzione che il dispositivo non supporta. |
16#02 | Illegal data address | Viene generato in diverse situazioni:
|
16#03 | Illegal data value | Il dato definito nella richiesta non è accettato dal dispositivo. |
16#04 | Slave device failure | Si è verificato un errore irreversibile mentre lo slave stava tentando di eseguire l’azione richiesta. |
16#05 | Acknowledge | Lo slave ha accettato la richiesta e la sta elaborando, ma per farlo sarà necessario un lungo periodo di tempo. Questa risposta viene restituita per evitare che si verifichi un errore di timeout nel master. |
16#06 | Slave device busy | Lo slave è impegnato nell’elaborazione di un comando che richiede una lunga elaborazione. |
16#07 | Negative acknowledge | Lo slave non può eseguire la funzione di programma ricevuta nella query. |
16#08 | Memory parity error | Lo slave ha tentato di leggere la memoria ma ha rilevato un errore di parità. |
Trigger di spy
Se SpyOn attivo è possibile utilizzare la console di spionaggio per verificare il funzionamento della FB. Sono previsti vari livelli di triggers.
Livelli di trigger
Trigger | Descrizione |
---|---|
16#00000001 | Tx: Invio frame comando modbus. |
16#00000002 | Rx: Ricezione frame risposta modbus. |
16#40000000 | Er: Errore di esecuzione. |
Esempi
Come utilizzare gli esempi
ST_ModbusMaster: Vengono eseguiti comandi Modbus di lettura/scrittura sia di coils che di registri. E’ possibile utilizzare l’esempio su di un unico sistema SlimLine se usato in seriale collegando tra di loro le porte seriali COM0 e COM1 di un modulo CPU (Usare un cavo cross). Se usato in TCP definendo come indirizzo IP dello slave il localhost ADR(‘127.0.0.1′). E’ possibile utilizzare l’esempio insieme a quello del FB ModbusSlave.
LogicLab (Ptp205, ST_ModbusMaster)
PROGRAM ST_ModbusMaster
VAR
i : UDINT; (* Aux counter *)
SerialOrTCP : BOOL := FALSE; (* FALSE:Serial, TRUE:TCP communication *)
CaseNr : USINT; (* Program case *)
Sp : SysSerialPort; (* Serial port *)
TCPClient : SysTCPClient; (* TCP client management *)
MMdb : ModbusMaster_v3; (* Modbus master FB *)
RCoils : ARRAY[0..15] OF BOOL; (* Coil status (Read) *)
RHRegs : ARRAY[0..15] OF WORD; (* Holding registers (Read) *)
WCoils : ARRAY[0..15] OF BOOL; (* Coil status (Write) *)
WHRegs : ARRAY[0..15] OF WORD; (* Holding registers (Write) *)
END_VAR
// *****************************************************************************
// PROGRAM "ST_ModbusMaster"
// *****************************************************************************
// Are executed all possible Modbus commands with a connection over another
// SlimLine. It's possible to test all the three possible Modbus types (Serial
// RTU, serial ascii, TCP).
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
// INITIALIZATION
// -------------------------------------------------------------------------
// Program initializations.
IF (SysFirstLoop) THEN
// Serial port settings.
Sp.COM:=ADR('COM0'); //COM port definition
Sp.Baudrate:=115200; //Baudrate
Sp.Parity:='E'; //Parity
Sp.DataBits:=8; //Data bits
Sp.StopBits:=1; //Stop bits
Sp.DTRManagement:=DTR_AUTO_WO_TIMES; //DTR management
Sp.DTRComplement:=FALSE; //DTR complement
Sp.EchoFlush:=FALSE; //Received echo flush
Sp.DTROnTime:=0; //DTR On time delay (mS)
Sp.DTROffTime:=0; //DTR Off time delay (mS)
Sp.FlushTm:=0; //Flush time (mS)
Sp.RxSize:=0; //Rx buffer size
Sp.TxSize:=0; //Tx buffer size
// TCP client settings.
// Port 502 to connect to embed Modbus slave.
// Port 3000 to connect to ModbusSlave FB example.
TCPClient.PeerAdd:=ADR('127.0.0.1'); //Peer address
TCPClient.PeerPort:=3000; //Peer port
TCPClient.LocalAdd:=ADR('0.0.0.0'); //Local address
TCPClient.LocalPort:=0; //Local port
TCPClient.FlushTm:=50; //Flush time (mS)
TCPClient.LifeTm:=20; //Life time (S)
TCPClient.RxSize:=128; //Rx buffer size
TCPClient.TxSize:=128; //Tx buffer size
// Modbus master settings.
MMdb.Absolute:=FALSE; //Absolute addressing
MMdb.Node:=1; //Node number
MMdb.Timeout:=T#1s; //Timeout time
MMdb.Delay:=T#100ms; //Delay time
END_IF;
// -------------------------------------------------------------------------
// MODBUS MANAGEMENT
// -------------------------------------------------------------------------
// Eseguo selezione canale comunicazione.
IF NOT(SerialOrTCP) THEN
// Serial port management.
Sp(Open:=TRUE); //Serial port management
MMdb.File:=Sp.File; //File pointer
MMdb.Type:=MODBUS_PROTOCOL#MDB_RTU; //Modbus protocol type
// MMdb.Type:=MODBUS_PROTOCOL#MDB_ASCII; //Modbus protocol type
ELSE
// TCP client management.
TCPClient(Connect:=TRUE); //TCPClient management
MMdb.File:=TCPClient.File; //File pointer
MMdb.Type:=MODBUS_PROTOCOL#MDB_TCP; //Modbus protocol type
END_IF;
// Manage the modbus master communication.
MMdb(); //Modbus master
IF NOT(SysFIsOpen(MMdb.File)) THEN MMdb.Enable:=FALSE; CaseNr:=0; RETURN; END_IF;
// -------------------------------------------------------------------------
// PROGRAM CASES
// -------------------------------------------------------------------------
// Manage the program cases.
CASE (CaseNr) OF
// ---------------------------------------------------------------------
// Execute a Force multiple coils.
0:
MMdb.Enable:=TRUE; //Modbus enable
MMdb.FCode:=16#0F; //Modbus function code
MMdb.Address:=40000; //Modbus register address
MMdb.Points:=SIZEOF(WCoils); //Modbus register points
MMdb.Buffer:=ADR(WCoils); //Memory buffer address
IF NOT(MMdb.Done) THEN RETURN; END_IF;
MMdb.Enable:=FALSE; //Modbus enable
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Execute a Force single coil.
1:
MMdb.Enable:=TRUE; //Modbus enable
MMdb.FCode:=16#05; //Modbus function code
MMdb.Address:=40000+0; //Modbus register address
MMdb.Points:=0; //Modbus register points
MMdb.Buffer:=ADR(WCoils); //Memory buffer address
IF NOT(MMdb.Done) THEN RETURN; END_IF;
MMdb.Enable:=FALSE; //Modbus enable
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Execute a Read coil status.
2:
MMdb.Enable:=TRUE; //Modbus enable
MMdb.FCode:=16#01; //Modbus function code
MMdb.Address:=40000+0; //Modbus register address
MMdb.Points:=SIZEOF(RCoils); //Modbus register points
MMdb.Buffer:=ADR(RCoils); //Memory buffer address
IF NOT(MMdb.Done) THEN RETURN; END_IF;
MMdb.Enable:=FALSE; //Modbus enable
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Execute a Preset multiple registers.
3:
MMdb.Enable:=TRUE; //Modbus enable
MMdb.FCode:=16#10; //Modbus function code
MMdb.Address:=40000+(16/2); //Modbus register address
MMdb.Points:=SIZEOF(WHRegs)/2; //Modbus register points
MMdb.Buffer:=ADR(WHRegs); //Memory buffer address
IF NOT(MMdb.Done) THEN RETURN; END_IF;
MMdb.Enable:=FALSE; //Modbus enable
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Execute a Preset single register.
4:
MMdb.Enable:=TRUE; //Modbus enable
MMdb.FCode:=16#06; //Modbus function code
MMdb.Address:=40000+(16/2); //Modbus register address
MMdb.Points:=0; //Modbus register points
MMdb.Buffer:=ADR(WHRegs[0]); //Memory buffer address
IF NOT(MMdb.Done) THEN RETURN; END_IF;
MMdb.Enable:=FALSE; //Modbus enable
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Execute a Read holding registers.
5:
MMdb.Enable:=TRUE; //Modbus enable
MMdb.FCode:=16#03; //Modbus function code
MMdb.Address:=40000+(16/2); //Modbus register address
MMdb.Points:=SIZEOF(RHRegs)/2; //Modbus register points
MMdb.Buffer:=ADR(RHRegs); //Memory buffer address
IF NOT(MMdb.Done) THEN RETURN; END_IF;
MMdb.Enable:=FALSE; //Modbus enable
CaseNr:=0; //Program case
END_CASE;
// [End of file]