Difference between revisions of "Modbus Communication API"
(BackToTop button) |
|||
(24 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | + | <div class="noprint" id="BackToTop" style="background-color:; position:fixed; bottom:32px; left:95%; z-index:9999; padding:0; margin:0;"> | |
− | <div | + | |
− | <span style="color:blue; font-size:8pt; font-face:verdana,sans-serif; border:0.2em outset:#ceebf7; padding:0.1em; font-weight:bolder; -moz-border-radius:8px; "> | + | <span style="color:blue; font-size:8pt; font-face:verdana,sans-serif; border:0.2em outset:#ceebf7; padding:0.1em; font-weight:bolder; -moz-border-radius:8px;">[[File:TOP2.png|50px|TOP2.png|link=#top]]</span></div> |
− | [[ | + | A complete presentation can be found here: '''[http://softmc.servotronix.com/wiki/Modbus_Presentation Modbus_Presentation]''' |
+ | |||
== Overview == | == Overview == | ||
+ | |||
=== Basic Overview === | === Basic Overview === | ||
− | * This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication. | + | |
− | * It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page. | + | *This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication. |
− | * It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming. | + | *It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page. |
+ | *It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming. | ||
=== Modbus Communication Background === | === Modbus Communication Background === | ||
− | * A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time. | + | |
− | * Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side). | + | *A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time. |
− | * Each component has its own parameters that defines it. | + | *Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side). |
− | * When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections. | + | *Each component has its own parameters that defines it. |
− | * Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247. | + | *When the MC acts as a server, all server components share the '''same''' memory address space, thus acting as one server with multiple connections. |
+ | *Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247. | ||
=== The Modbus server registers === | === The Modbus server registers === | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | *There are 4 types of registers in the Modbus Server address space: | |
− | In order to get started | + | *#Bits (1-bit registers) |
− | # Download the required files: [[: | + | *#Input Bits (1-bit READ-ONLY registers) |
− | # Using the ControlStudio File Manager, Upload the following files to your MC: | + | *#Holding Registers (16-bit registers) |
− | #* mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3)'' | + | *#Input Registers (16-bit READ-ONLY registers) |
− | #* Modbus.lib | + | *Servers can read and write their own address space. |
− | + | *Clients can read and write a remote server’s address space. | |
− | + | ||
− | + | | |
− | + | ||
− | + | = Getting Started = | |
− | + | ||
− | + | In order to get started with Modbus features the following steps are required: | |
− | + | ||
+ | #Download the required files: [[Media:ModBus_Required_files_new.zip|Media:ModBus Required files new.zip]] | ||
+ | #Using the ControlStudio File Manager, Upload the following files to your MC as follows: | ||
+ | ##Kill all tasks. | ||
+ | ##In terminal, reset all tasks. | ||
+ | ##Add files. | ||
+ | ##upload the appropriate files as follows: | ||
+ | #*mb_x86.O ''(for softMC7 )'' / mb_armA9.O ''(for softMC3) / ''MB_LEX.O ''(for softMC703)'' | ||
+ | #*Modbus.lib | ||
+ | |||
+ | 5. Upload files to MC. | ||
+ | |||
+ | [[File:ModBussetup.jpg|1200x650px|RTENOTITLE]] | ||
− | That's it! You're now ready to configure the Modbus system. | + | 1. Load the correct Object file (based on the controller type) and the Modbus library manually, by typing the following in the terminal: |
+ | <pre>Oload mb_x86.O/ Oload mb_armA9.O /Oload MB_LEX.O | ||
+ | </pre> | ||
+ | |||
+ | | ||
+ | <pre>Loadglobal Modbus.LIB</pre> | ||
+ | |||
+ | That's it! You're now ready to configure the Modbus system. | ||
== Initializing the Modbus Environment == | == Initializing the Modbus Environment == | ||
+ | |||
To initialize the Modbus environment, including the server address space, call: | To initialize the Modbus environment, including the server address space, call: | ||
<pre>?init_multi_server([bits],[input_bits],[holding registers],[input_registers])</pre> | <pre>?init_multi_server([bits],[input_bits],[holding registers],[input_registers])</pre> | ||
− | * The function prints "success" and returns 0 on success, or return an error code on failure. | + | |
− | * <u>'''Notice:'''</u> You MUST call this method even if you only need Client components. In that case, just pass 0 as the required registers' size. | + | *The function prints "success" and returns 0 on success, or return an error code on failure. |
− | * <u>'''Notice:'''</u> You can call this method only if there are no active server components. | + | *<u>'''Notice:'''</u> You MUST call this method even if you only need Client components. In that case, just pass 0 as the required registers' size. |
+ | *<u>'''Notice:'''</u> You can call this method only if there are no active server components. | ||
+ | |||
<u>'''Error codes:'''</u> | <u>'''Error codes:'''</u> | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Error | ! Error | ||
Line 65: | Line 85: | ||
== Server Components == | == Server Components == | ||
+ | |||
=== '''Adding server components''' === | === '''Adding server components''' === | ||
− | * Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use). | + | |
− | * It is best to keep this handles in variables inside your program. | + | *Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use). |
+ | *It is best to keep this handles in variables inside your program. | ||
+ | |||
==== Creating a TCP server component ==== | ==== Creating a TCP server component ==== | ||
<pre>handle = mb_tcp_server_create([port],[deviceID])</pre> | <pre>handle = mb_tcp_server_create([port],[deviceID])</pre> | ||
− | * This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately. | + | |
− | * Returns a handle on success, or an error code on failure. | + | *This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately. |
+ | *Returns a handle on success, or an error code on failure. | ||
+ | |||
<u>'''Error codes:'''</u> | <u>'''Error codes:'''</u> | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Error | ! Error | ||
Line 90: | Line 116: | ||
| Failed to create server thread. | | Failed to create server thread. | ||
|} | |} | ||
+ | |||
==== Creating an RTU server component ==== | ==== Creating an RTU server component ==== | ||
<pre>handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])</pre> | <pre>handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])</pre> | ||
− | * This opens an RTU connection with the given parameters, and starts the created server immediately. | + | |
− | * Returns a handle on success, or an error code on failure. | + | *This opens an RTU connection with the given parameters, and starts the created server immediately. |
+ | *Returns a handle on success, or an error code on failure. | ||
+ | |||
<u>'''Error codes:'''</u> | <u>'''Error codes:'''</u> | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Error | ! Error | ||
Line 127: | Line 157: | ||
| The device is already in use by another system component. | | The device is already in use by another system component. | ||
|} | |} | ||
+ | |||
=== '''Stopping Server Components''' === | === '''Stopping Server Components''' === | ||
+ | |||
==== Stopping a specific server component ==== | ==== Stopping a specific server component ==== | ||
+ | |||
You can stop a specific server component by passing its handle to: | You can stop a specific server component by passing its handle to: | ||
<pre>result = mb_server_stop([handle])</pre> | <pre>result = mb_server_stop([handle])</pre> | ||
− | * Given a handle, this will stop and free the memory of the appropriate server component. | + | |
− | * Returns 0 on success, -1 on failure. | + | *Given a handle, this will stop and free the memory of the appropriate server component. |
+ | *Returns 0 on success, -1 on failure. | ||
+ | |||
==== Stopping all server components ==== | ==== Stopping all server components ==== | ||
+ | |||
You can stop all server components with a single call to: | You can stop all server components with a single call to: | ||
<pre>result = mb_server_stop_all</pre> | <pre>result = mb_server_stop_all</pre> | ||
+ | |||
This function will: | This function will: | ||
− | * Stop and free all server components. | + | |
− | * Free the shared address space. | + | *Stop and free all server components. |
− | * Return 0 on success, -1 on failure. | + | *Free the shared address space. |
+ | *Return 0 on success, -1 on failure. | ||
+ | |||
== Client Components == | == Client Components == | ||
+ | |||
=== '''Adding client components''' === | === '''Adding client components''' === | ||
− | * Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use). | + | |
− | * It is best to keep this handles in variables inside your program. | + | *Each time you'll add a component, you will receive a '''handle''', which is the component's identifier (for later use). |
+ | *It is best to keep this handles in variables inside your program. | ||
+ | |||
==== Adding a TCP Client component ==== | ==== Adding a TCP Client component ==== | ||
<pre>handle = mb_tcp_client_create([ip],[port])</pre> | <pre>handle = mb_tcp_client_create([ip],[port])</pre> | ||
− | * This will opens a TCP connection to the client on the given ip and port, and start the client immediately. | + | |
− | * Returns a handle on success, -1 on failure. | + | *This will opens a TCP connection to the client on the given ip and port, and start the client immediately. |
+ | *Returns a handle on success, -1 on failure. | ||
+ | |||
==== Adding an RTU Client component ==== | ==== Adding an RTU Client component ==== | ||
<pre>handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])</pre> | <pre>handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])</pre> | ||
− | * This will open an RTU connection to the client with the given parameters, and start the client immediately. | + | |
− | * Returns a handle on success, -1 on failure. | + | *This will open an RTU connection to the client with the given parameters, and start the client immediately. |
+ | *Returns a handle on success, -1 on failure. | ||
+ | |||
=== Stopping client components === | === Stopping client components === | ||
+ | |||
A specific client can be stopped by calling: | A specific client can be stopped by calling: | ||
<pre>result = mb_client_stop([handle])</pre> | <pre>result = mb_client_stop([handle])</pre> | ||
− | * Given a handle, this will stop and free the memory of the appropriate client component. | + | |
− | * Returns 0 on success, -1 on failure. | + | *Given a handle, this will stop and free the memory of the appropriate client component. |
+ | *Returns 0 on success, -1 on failure. | ||
+ | |||
== Reset the Modbus System == | == Reset the Modbus System == | ||
+ | |||
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call: | Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call: | ||
<pre>result = mb_reset</pre> | <pre>result = mb_reset</pre> | ||
+ | |||
This function: | This function: | ||
− | * Stops all running servers and clients. | + | |
− | * Frees their memory. | + | *Stops all running servers and clients. |
− | * Frees the shared address space. | + | *Frees their memory. |
− | * Reset the handle counter. | + | *Frees the shared address space. |
− | * Returns 0 on success, -1 on failure. | + | *Reset the handle counter. |
+ | *Returns 0 on success, -1 on failure. | ||
'''<u>Notice:</u>''' This function is called <u>automatically</u> when calling ''reset all''. | '''<u>Notice:</u>''' This function is called <u>automatically</u> when calling ''reset all''. | ||
== Reading and Writing == | == Reading and Writing == | ||
− | * Servers can read and write their own address space. | + | |
− | * Clients can read and write a remote server’s address space. | + | *Servers can read and write their own address space. |
− | * Therefore, Servers and clients use different functions to read/write data from the address space. | + | *Clients can read and write a remote server’s address space. |
+ | *Therefore, Servers and clients use different functions to read/write data from the address space. | ||
+ | |||
=== '''Server Components''' === | === '''Server Components''' === | ||
− | + | ||
+ | ---- | ||
+ | |||
==== Reading ==== | ==== Reading ==== | ||
− | * The following functions read variables from the different types of registers and return them. | + | |
− | * When a read error occurs, the functions will write [function name] + "ERROR" + [error code] in the Message Log. | + | *The following functions read variables from the different types of registers and return them. |
+ | *When a read error occurs, the functions will write [function name] + "ERROR" + [error code] in the Message Log. | ||
+ | |||
===== Reading from Holding registers ===== | ===== Reading from Holding registers ===== | ||
− | <pre> | + | <pre>Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap]) |
− | Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap]) | ||
Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap]) | Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap]) | ||
Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap]) | Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap]) | ||
Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap]) | Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap]) | ||
</pre> | </pre> | ||
+ | |||
===== Reading from Bits registers ===== | ===== Reading from Bits registers ===== | ||
<pre>val = MB_SERVER_READ_BIT([index])</pre> | <pre>val = MB_SERVER_READ_BIT([index])</pre> | ||
+ | |||
===== Reading from Input registers ===== | ===== Reading from Input registers ===== | ||
− | <pre> | + | <pre>Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap]) |
− | Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap]) | ||
Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap]) | Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap]) | ||
Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap]) | Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap]) | ||
Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap]) | Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap]) | ||
</pre> | </pre> | ||
+ | |||
===== Reading from Input Bits registers ===== | ===== Reading from Input Bits registers ===== | ||
<pre> val = MB_SERVER_READ_INBIT([index])</pre> | <pre> val = MB_SERVER_READ_INBIT([index])</pre> | ||
+ | |||
===== Valid Parameters ===== | ===== Valid Parameters ===== | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Parameter | ! Parameter | ||
Line 214: | Line 275: | ||
| 1 or 0 (True/False) | | 1 or 0 (True/False) | ||
|} | |} | ||
+ | |||
==== Writing ==== | ==== Writing ==== | ||
− | * The following functions write data into the different types of registers. | + | |
− | * When a write error occurs, the functions will write [function name] + "ERROR" + [error code] in the Message Log. | + | *The following functions write data into the different types of registers. |
+ | *When a write error occurs, the functions will write [function name] + "ERROR" + [error code] in the Message Log. | ||
+ | |||
===== Writing to holding registers ===== | ===== Writing to holding registers ===== | ||
− | <pre> | + | <pre>Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap]) |
− | Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap]) | ||
Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap]) | Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap]) | ||
Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap]) | Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap]) | ||
Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap]) | Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap]) | ||
</pre> | </pre> | ||
+ | |||
===== Writing to Bits registers ===== | ===== Writing to Bits registers ===== | ||
<pre>val = MB_SERVER_WRITE_BIT([index],[new value])</pre> | <pre>val = MB_SERVER_WRITE_BIT([index],[new value])</pre> | ||
+ | |||
===== Writing to Input registers ===== | ===== Writing to Input registers ===== | ||
− | <pre> | + | <pre>Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap]) |
− | Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap]) | ||
Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap]) | Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap]) | ||
Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap]) | Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap]) | ||
Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap]) | Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap]) | ||
</pre> | </pre> | ||
+ | |||
===== Writing to Input Bits registers ===== | ===== Writing to Input Bits registers ===== | ||
<pre>val = MB_SERVER_WRITE_INBIT([index],[value])</pre> | <pre>val = MB_SERVER_WRITE_INBIT([index],[value])</pre> | ||
+ | |||
===== Valid Parameters ===== | ===== Valid Parameters ===== | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Parameter | ! Parameter | ||
Line 256: | Line 323: | ||
| 1 or 0 (True/False) | | 1 or 0 (True/False) | ||
|} | |} | ||
+ | |||
==== Error codes ==== | ==== Error codes ==== | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Error | ! Error | ||
Line 276: | Line 345: | ||
=== '''Client Components''' === | === '''Client Components''' === | ||
− | + | ||
+ | ---- | ||
+ | |||
==== Reading ==== | ==== Reading ==== | ||
− | * The following functions read variables from the different types of registers in a REMOTE modbus server. | + | |
− | * The read value is inserted into an existing variable from the appropriate type (long/double). | + | *The following functions read variables from the different types of registers in a REMOTE modbus server. |
− | * The functions return 0 on success or an error code (not 0) on failure. | + | *The read value is inserted into an existing variable from the appropriate type (long/double). |
+ | *The functions return 0 on success or an error code (not 0) on failure. | ||
+ | |||
===== Reading from Holding registers ===== | ===== Reading from Holding registers ===== | ||
− | <pre> | + | <pre>Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr]) |
− | Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr]) | ||
Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr]) | Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr]) | ||
Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr]) | Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr]) | ||
Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr]) | Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr]) | ||
</pre> | </pre> | ||
+ | |||
===== Reading from Bits registers ===== | ===== Reading from Bits registers ===== | ||
<pre>val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])</pre> | <pre>val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])</pre> | ||
+ | |||
===== Reading from Input registers ===== | ===== Reading from Input registers ===== | ||
− | <pre> | + | <pre>Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) |
− | Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) | ||
Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr]) | Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr]) | ||
Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr]) | Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr]) | ||
Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr]) | Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr]) | ||
</pre> | </pre> | ||
+ | |||
===== Reading from Input Bits registers ===== | ===== Reading from Input Bits registers ===== | ||
<pre>val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])</pre> | <pre>val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])</pre> | ||
+ | |||
===== Valid Parameters ===== | ===== Valid Parameters ===== | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Parameter | ! Parameter | ||
Line 320: | Line 396: | ||
| The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (>= Num of bits). | | The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (>= Num of bits). | ||
|} | |} | ||
+ | |||
==== Writing ==== | ==== Writing ==== | ||
− | * The following functions write data from existing variables to the different types of registers in a REMOTE modbus server. | + | |
− | * The functions return 0 on success or an error code (not 0) on failure. | + | *The following functions write data from existing variables to the different types of registers in a REMOTE modbus server. |
+ | *The functions return 0 on success or an error code (not 0) on failure. | ||
+ | |||
===== Writing to Holding registers ===== | ===== Writing to Holding registers ===== | ||
− | <pre> | + | <pre>Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr]) |
− | Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr]) | ||
Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr]) | Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr]) | ||
Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr]) | Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr]) | ||
Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr]) | Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr]) | ||
</pre> | </pre> | ||
+ | |||
===== Writing to Bits registers ===== | ===== Writing to Bits registers ===== | ||
<pre>val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])</pre> | <pre>val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])</pre> | ||
+ | |||
===== Valid Parameters ===== | ===== Valid Parameters ===== | ||
− | {| | + | |
+ | {| border="1" class="wikitable" | ||
|- | |- | ||
! Parameter | ! Parameter | ||
Line 352: | Line 433: | ||
=== '''Reading and Writing Summary''' === | === '''Reading and Writing Summary''' === | ||
− | |||
+ | [[File:modbus;newAPI-readwriteSummary.jpg|850px|modbus;newAPI-readwriteSummary.jpg]] | ||
+ | |||
+ | = Modbus Configurator = | ||
− | |||
== Background == | == Background == | ||
+ | |||
=== General === | === General === | ||
+ | |||
The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags. | The Modbus Communication Scripts Generator ('''Modbus Configurator''') is a tool that allows you to map your softMC application variables to Modbus tags. | ||
− | '''Note''': Tag access is defined from the HMI perspective. In other words: | + | '''Note''': Tag access is defined from the HMI perspective. In other words: |
− | * '''Read Access''' variables are written by the softMC to the Modbus address space. | + | |
− | * '''Write Access''' variables are read by the softMC from the Modbus address space. | + | *'''Read Access''' variables are written by the softMC to the Modbus address space. |
+ | *'''Write Access''' variables are read by the softMC from the Modbus address space. | ||
+ | |||
+ | You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below). | ||
+ | |||
+ | The MC MBConfigurator creates three files: | ||
+ | |||
+ | *'''HMIMBMAP.LIB''' and '''HMIMBMAP.PRG''' files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type. | ||
+ | *A '''.CSV''' format file that can be used by an HMI development environment, such as '''JMobile Studio,''' '''Indusoft and HMIStudio''', to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file. | ||
+ | |||
+ | == MBConfigurator setup == | ||
+ | |||
+ | '''Note''': Variables destined to be mapped to Modbus tags must be defined as '''global''' variables by the "Common Shared" declaration. | ||
+ | |||
+ | 1. In order to map the variables, the program must be loaded in the softMC. | ||
+ | |||
+ | 2. Start the Modbus Configuration. From the ControlStudio toolbar, select '''Tools > Modbus Configurator'''. | ||
+ | |||
+ | The Modbus Configurator windows opens. | ||
+ | |||
+ | 3. Select '''Connection > Connect'''. | ||
+ | |||
+ | The settings dialog box opens. Makes sure the correct MC IP and port are inserted: | ||
− | + | [[File:MBconnection.jpg|RTENOTITLE]] | |
− | + | 4. In the Modbus Configurator window select '''Modbus Comm. Settings. '''Choose "'''Generate a csv file to use with softMI'''". Make sure Refresh rate is 10ms or higher. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | [[File:MBconnection2.jpg|RTENOTITLE]] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | [[File: | + | |
− | + | ||
− | + | 5. In the '''Registers''' tab, enter the amount of registers needed per type. | |
+ | |||
+ | #Notice: The maximum register number is 65536. | ||
+ | |||
+ | | ||
+ | |||
+ | 6. Select '''Connections''', click Add and select TCP communication type with port number 502. | ||
+ | |||
+ | [[File:MBconnection3.jpg|RTENOTITLE]] | ||
+ | |||
+ | 6. | ||
+ | |||
+ | 1. Once the Modbus Configurator is connected to softMC, a complete list of all the global variables will appear on the right side. '''Double-clicking''' on the variables will automatically map them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table. | ||
+ | |||
+ | 2. '''Veriable type''' can be changed by clicking on the register type. Bits are 1 bit registers. It can be used for triggering (Write) functions, such as enable/disable or reading various statuses (Read). Hregs are 16 bit registers which can be used for number input (Write), such as set velocity/position or reading values (Read), such as position feedback. | ||
+ | |||
+ | If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space. | ||
+ | |||
+ | A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC. | ||
+ | |||
+ | | ||
+ | |||
+ | [[File:MB3onnection4.jpg|1000x600px|MB3onnection4.jpg]] | ||
+ | |||
+ | | ||
+ | |||
+ | == Generating and Using Scripts == | ||
− | |||
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts. | After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts. | ||
1. Click '''Files''', and then '''Save As'''. | 1. Click '''Files''', and then '''Save As'''. | ||
− | :The mapping is saved in an '''.mbas''' file. | + | :The mapping is saved in an '''.mbas''' file. |
− | :If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up. | + | :If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up. |
2. To generate the product files, click '''Generate'''. | 2. To generate the product files, click '''Generate'''. | ||
− | + | The Log windows will display Success messages. | |
− | : | + | 3 files will be generated: '''HMIMBMAP.LIB''', '''HMIMBMAP.PRG''', which will be used by the MC and '''STX_HMI.CSV''', which will be used by the HMI program. |
− | + | 3. The defult location of the files generation is located in ControlStudio installation folder: C:\Program Files (x86)\Servotronix\MBConfigurator | |
− | [[File: | + | [[File:MBvonnection5.jpg|1000x600px|MBvonnection5.jpg]] |
+ | | ||
− | ==Using the Modbus-Handling Scripts== | + | == Using the Modbus-Handling Scripts == |
− | |||
− | + | 1. Using the ControlStudio, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC as shown in [[Media:ModBussetup.jpg|Media:ModBussetup.jpg]] | |
− | + | '''Note''': Before these files can be loaded and used, your application(s), which include all the global veriables must be loaded (all mapped variables must exist in the softMC memory).<br/> <br/> 2. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB: | |
− | <br/> | ||
− | <br/> | ||
− | |||
<pre>Load HMIMBMAP.LIB</pre> | <pre>Load HMIMBMAP.LIB</pre> | ||
− | :Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient. | + | :Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient. |
− | |||
− | |||
+ | 3. Verify that the library was loaded successfully: | ||
<pre>?tasklist</pre> | <pre>?tasklist</pre> | ||
− | + | 4. Start the Modbus communication task by loading the program: | |
− | |||
<pre>Load HMIMBMAP.PRG</pre> | <pre>Load HMIMBMAP.PRG</pre> | ||
HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command. | HMIMBMAP.PRG is defined as '''Program Continue''', therefore it starts automatically after it is loaded and it does not require an explicit StartTask command. | ||
− | Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient: | + | Of course, HMIMBMAP.PRG can be loaded and executed only '''after''' HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient: |
<pre>Load HMIMBMAP.LIB | <pre>Load HMIMBMAP.LIB | ||
− | Load HMIMBMAP.PRG | + | Load HMIMBMAP.PRG</pre> |
− | </pre> | + | |
+ | | ||
+ | |||
+ | == HMIMBMAP.PRG Explained == | ||
− | + | HMIMBMAP.PRG code: | |
− | |||
<pre>import HMIMBMAP.LIB | <pre>import HMIMBMAP.LIB | ||
Program Continue | Program Continue | ||
Line 461: | Line 569: | ||
The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite. | The functions '''Read_Modbus_Registers''' and '''Write_Modbus_Registers''' are invoked cyclically and indefinitely. '''Read_Modbus_Registers''' reads all the tags that are written by the HMI/PLC and updates the '''Write Access''' variables with new values, while '''Write_Modbus_Registers''' does the opposite. | ||
− | =HMI IDEs and .CSV Files= | + | = HMI IDEs and .CSV Files = |
+ | |||
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type. | Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type. | ||
− | + | ||
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality. | This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality. | ||
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE. | Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE. | ||
− | == | + | = HMI Programs = |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | '''Note''': HMI Studio is the most commonly used program. | |
− | + | *[[softMI_HMI_Getting_started|HMI Studio]] | |
+ | *[[JMobile_studio|JMobile studio]] | ||
+ | *[[AdvancedHMI|AdvancedHMI]] | ||
− | + | [[Category:Modbus Communication]] |
Latest revision as of 16:13, 16 February 2020
A complete presentation can be found here: Modbus_Presentation
Contents
- 1 Overview
- 2 Getting Started
- 2.1 Initializing the Modbus Environment
- 2.2 Server Components
- 2.3 Client Components
- 2.4 Reset the Modbus System
- 2.5 Reading and Writing
- 3 Modbus Configurator
- 4 HMI IDEs and .CSV Files
- 5 HMI Programs
Overview
Basic Overview
- This describes how to set up Modbus communication for the softMC, and how to generate softMC scripts to handle Modbus communication.
- It is assumed you are familiar with the principles of Modbus communication, although some of them will be described in this page.
- It is also assumed your are familiar with the softMC, ControlStudio and MC-Basic programming.
Modbus Communication Background
- A Motion Controller (MC) can act as a server (slave), a client (master) or both at the same time.
- Each MC connection (TCP/RTU) can be used either as a server component (if the connection is used by the MC’s server-side) or as a client component (if the connection is used by the MC’s client-side).
- Each component has its own parameters that defines it.
- When the MC acts as a server, all server components share the same memory address space, thus acting as one server with multiple connections.
- Each server (slave) on a Modbus network has its own deviceID, which is a number between 1 and 247.
The Modbus server registers
- There are 4 types of registers in the Modbus Server address space:
- Bits (1-bit registers)
- Input Bits (1-bit READ-ONLY registers)
- Holding Registers (16-bit registers)
- Input Registers (16-bit READ-ONLY registers)
- Servers can read and write their own address space.
- Clients can read and write a remote server’s address space.
Getting Started
In order to get started with Modbus features the following steps are required:
- Download the required files: Media:ModBus Required files new.zip
- Using the ControlStudio File Manager, Upload the following files to your MC as follows:
- Kill all tasks.
- In terminal, reset all tasks.
- Add files.
- upload the appropriate files as follows:
- mb_x86.O (for softMC7 ) / mb_armA9.O (for softMC3) / MB_LEX.O (for softMC703)
- Modbus.lib
5. Upload files to MC.
1. Load the correct Object file (based on the controller type) and the Modbus library manually, by typing the following in the terminal:
Oload mb_x86.O/ Oload mb_armA9.O /Oload MB_LEX.O
Loadglobal Modbus.LIB
That's it! You're now ready to configure the Modbus system.
Initializing the Modbus Environment
To initialize the Modbus environment, including the server address space, call:
?init_multi_server([bits],[input_bits],[holding registers],[input_registers])
- The function prints "success" and returns 0 on success, or return an error code on failure.
- Notice: You MUST call this method even if you only need Client components. In that case, just pass 0 as the required registers' size.
- Notice: You can call this method only if there are no active server components.
Error codes:
Error | Meaning |
---|---|
-1 | Memory allocation failure. |
-2 | Some servers are still running and using an already mapped address space. |
-3 | Failed to create a modbus mapping. |
Server Components
Adding server components
- Each time you'll add a component, you will receive a handle, which is the component's identifier (for later use).
- It is best to keep this handles in variables inside your program.
Creating a TCP server component
handle = mb_tcp_server_create([port],[deviceID])
- This opens a TCP connection to the server on port [port] with deviceID [deviceID], and starts the created server immediately.
- Returns a handle on success, or an error code on failure.
Error codes:
Error | Meaning |
---|---|
-1 | Server address spaces isn't initialized yet, please call "init_multi_server(...) and try again. |
-2 | Failed to create main socket. |
-3 | Failed to connect. |
-4 | Failed to create server thread. |
Creating an RTU server component
handle = mb_rtu_server_create([type],[port],[baudrate],[data bits],[stop bits],[parity],[deviceID])
- This opens an RTU connection with the given parameters, and starts the created server immediately.
- Returns a handle on success, or an error code on failure.
Error codes:
Error | Meaning |
---|---|
-1 | Server address spaces isn't initialized yet, please call "init_multi_server(...) and try again. |
-2 | Invalid device string. |
-3 | Invalid parity. |
-4 | Failed opening RTU. |
-5 | Failed allocating query buffer memory. |
-6 | Failed to set RTU mode. |
-7 | Unable to connect. |
-8 | Failed to create server thread. |
-9 | The device is already in use by another system component. |
Stopping Server Components
Stopping a specific server component
You can stop a specific server component by passing its handle to:
result = mb_server_stop([handle])
- Given a handle, this will stop and free the memory of the appropriate server component.
- Returns 0 on success, -1 on failure.
Stopping all server components
You can stop all server components with a single call to:
result = mb_server_stop_all
This function will:
- Stop and free all server components.
- Free the shared address space.
- Return 0 on success, -1 on failure.
Client Components
Adding client components
- Each time you'll add a component, you will receive a handle, which is the component's identifier (for later use).
- It is best to keep this handles in variables inside your program.
Adding a TCP Client component
handle = mb_tcp_client_create([ip],[port])
- This will opens a TCP connection to the client on the given ip and port, and start the client immediately.
- Returns a handle on success, -1 on failure.
Adding an RTU Client component
handle = mb_rtu_client_create([type],[port],[baudrate],[data bits],[stop bits],[parity])
- This will open an RTU connection to the client with the given parameters, and start the client immediately.
- Returns a handle on success, -1 on failure.
Stopping client components
A specific client can be stopped by calling:
result = mb_client_stop([handle])
- Given a handle, this will stop and free the memory of the appropriate client component.
- Returns 0 on success, -1 on failure.
Reset the Modbus System
Sometimes, a user may wish to stop all server and client components at once, and reset the Modbus system (for example, when a user want to initialize a different Modbus system). To do that, call:
result = mb_reset
This function:
- Stops all running servers and clients.
- Frees their memory.
- Frees the shared address space.
- Reset the handle counter.
- Returns 0 on success, -1 on failure.
Notice: This function is called automatically when calling reset all.
Reading and Writing
- Servers can read and write their own address space.
- Clients can read and write a remote server’s address space.
- Therefore, Servers and clients use different functions to read/write data from the address space.
Server Components
Reading
- The following functions read variables from the different types of registers and return them.
- When a read error occurs, the functions will write [function name] + "ERROR" + [error code] in the Message Log.
Reading from Holding registers
Val = MB_SERVER_READ_REG_LONG([index], [byte_swap], [word_swap]) Val = MB_SERVER_READ_REG_SHORT([index], [byte_swap]) Val = MB_SERVER_READ_REG_FLOAT([index], [byte_swap], [word_swap]) Val = MB_SERVER_READ_REG_DOUBLE([index], [byte_swap], [word_swap], [long swap])
Reading from Bits registers
val = MB_SERVER_READ_BIT([index])
Reading from Input registers
Val = MB_SERVER_READ_INREG_LONG([index], [byte_swap], [word_swap]) Val = MB_SERVER_READ_INREG_SHORT([index], [byte_swap]) Val = MB_SERVER_READ_INREG_FLOAT([index], [byte_swap], [word_swap]) Val = MB_SERVER_READ_INREG_DOUBLE([index], [byte_swap], [word_swap], [long swap])
Reading from Input Bits registers
val = MB_SERVER_READ_INBIT([index])
Valid Parameters
Parameter | Valid Input |
---|---|
Index | From 0 to the number of registers available. |
Byte_swap | 1 or 0 (True/False) |
Word_swap | 1 or 0 (True/False) |
Long_swap | 1 or 0 (True/False) |
Writing
- The following functions write data into the different types of registers.
- When a write error occurs, the functions will write [function name] + "ERROR" + [error code] in the Message Log.
Writing to holding registers
Val = MB_SERVER_WRITE_REG_LONG([index],[new value],[byte swap], [word swap]) Val = MB_SERVER_WRITE_REG_SHORT([index],[new value],[byte swap]) Val = MB_SERVER_WRITE_REG_FLOAT([index],[new value],[byte swap], [word swap]) Val = MB_SERVER_WRITE_REG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])
Writing to Bits registers
val = MB_SERVER_WRITE_BIT([index],[new value])
Writing to Input registers
Val = MB_SERVER_WRITE_INREG_LONG([index],[new value],[byte swap], [word swap]) Val = MB_SERVER_WRITE_INREG_SHORT([index],[new value],[byte swap]) Val = MB_SERVER_WRITE_INREG_FLOAT([index],[new value],[byte swap], [word swap]) Val = MB_SERVER_WRITE_INREG_DOUBLE([index],[new value],[byte swap], [word swap], [long swap])
Writing to Input Bits registers
val = MB_SERVER_WRITE_INBIT([index],[value])
Valid Parameters
Parameter | Valid Input |
---|---|
Index | From 0 to the number of registers available. |
New value | The value to write, must be from the appropriate type. |
Byte_swap | 1 or 0 (True/False) |
Word_swap | 1 or 0 (True/False) |
Long_swap | 1 or 0 (True/False) |
Error codes
Error | Meaning |
---|---|
-1 | Invalid index. |
-2 | Local server's address space isn't mapped yet. |
-3 | Failed to catch the register mutex. |
-4 | Failed to release the register mutex. |
Client Components
Reading
- The following functions read variables from the different types of registers in a REMOTE modbus server.
- The read value is inserted into an existing variable from the appropriate type (long/double).
- The functions return 0 on success or an error code (not 0) on failure.
Reading from Holding registers
Val = MB_CLIENT_READ_REG_LONG([handle],[deviceID],[addr],[dest ptr]) Val = MB_CLIENT_READ_REG_SHORT([handle],[deviceID],[addr],[dest ptr]) Val = MB_CLIENT_READ_REG_FLOAT([handle],[deviceID],[addr],[dest ptr]) Val = MB_CLIENT_READ_REG_DOUBLE([handle],[deviceID],[addr],[dest ptr])
Reading from Bits registers
val = MB_CLIENT_READ_BITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])
Reading from Input registers
Val = MB_CLIENT_READ_INREG_LONG ([handle],[deviceID],[addr],[dest ptr]) Val = MB_CLIENT_READ_INREG_SHORT([handle],[deviceID],[addr],[dest ptr]) Val = MB_CLIENT_READ_INREG_FLOAT([handle],[deviceID],[addr],[dest ptr]) Val = MB_CLIENT_READ_INREG_DOUBLE([handle],[deviceID],[addr],[dest ptr])
Reading from Input Bits registers
val = MB_CLIENT_READ_INBITS ([handle],[deviceID],[addr],[num of bits],[dest arr ptr])
Valid Parameters
Parameter | Valid Input |
---|---|
Handle | The client's unique identifier (received on client creation). |
DeviceID | The remote server(slave)'s device ID. |
Addr | The index of the register to read from. |
Num of bits (Reading bits) | The number of bits to read. |
dest ptr / dest arr ptr | The variable to store the read data. When reading bits, this must be an array of longs in the appropriate size (>= Num of bits). |
Writing
- The following functions write data from existing variables to the different types of registers in a REMOTE modbus server.
- The functions return 0 on success or an error code (not 0) on failure.
Writing to Holding registers
Val = MB_CLIENT_WRITE_REG_LONG([handle],[deviceID],[addr],[src ptr]) Val = MB_CLIENT_WRITE_REG_SHORT([handle],[deviceID],[addr],[src ptr]) Val = MB_CLIENT_WRITE_REG_FLOAT([handle],[deviceID],[addr],[src ptr]) Val = MB_CLIENT_WRITE_REG_DOUBLE([handle],[deviceID],[addr],[src ptr])
Writing to Bits registers
val = MB_CLIENT_WRITE_BIT([handle],[deviceID],[addr],[src ptr])
Valid Parameters
Parameter | Valid Input |
---|---|
Handle | The client's unique identifier (received on client creation). |
DeviceID | The remote server(slave)'s device ID. |
Addr | The index of the register to start writing to. |
src ptr | The variable that stores the data to be written. This must be a variable from the appropriate type. |
Reading and Writing Summary
Modbus Configurator
Background
General
The Modbus Communication Scripts Generator (Modbus Configurator) is a tool that allows you to map your softMC application variables to Modbus tags.
Note: Tag access is defined from the HMI perspective. In other words:
- Read Access variables are written by the softMC to the Modbus address space.
- Write Access variables are read by the softMC from the Modbus address space.
You can define whether a variable has Read Access (meaning it is read by the HMI/PLC), or Write Access (meaning it is written by the HMI/PLC). Currently, it is not possible to define a variable as having both Read Access and Write Access. However, all Write Access variables can be written once by the softMC upon system startup by a special routine that is generated in HMIMBMAP.LIB (see section below).
The MC MBConfigurator creates three files:
- HMIMBMAP.LIB and HMIMBMAP.PRG files are MC-Basic scripts that are used to start a softMC task. These are default file names, which you can change, but must retain the 8.3 format. This task cyclically and indefinitely reads/writes Modbus tags according to access type.
- A .CSV format file that can be used by an HMI development environment, such as JMobile Studio, Indusoft and HMIStudio, to automatically import Modbus tags. You define the HMI development environment by selecting various Python scripts that will generate the .csv file.
MBConfigurator setup
Note: Variables destined to be mapped to Modbus tags must be defined as global variables by the "Common Shared" declaration.
1. In order to map the variables, the program must be loaded in the softMC.
2. Start the Modbus Configuration. From the ControlStudio toolbar, select Tools > Modbus Configurator.
The Modbus Configurator windows opens.
3. Select Connection > Connect.
The settings dialog box opens. Makes sure the correct MC IP and port are inserted:
4. In the Modbus Configurator window select Modbus Comm. Settings. Choose "Generate a csv file to use with softMI". Make sure Refresh rate is 10ms or higher.
5. In the Registers tab, enter the amount of registers needed per type.
- Notice: The maximum register number is 65536.
6. Select Connections, click Add and select TCP communication type with port number 502.
6.
1. Once the Modbus Configurator is connected to softMC, a complete list of all the global variables will appear on the right side. Double-clicking on the variables will automatically map them to Modbus tags in consecutive order. The automatic Modbus address and data type are displayed in the table.
2. Veriable type can be changed by clicking on the register type. Bits are 1 bit registers. It can be used for triggering (Write) functions, such as enable/disable or reading various statuses (Read). Hregs are 16 bit registers which can be used for number input (Write), such as set velocity/position or reading values (Read), such as position feedback.
If a mapped variable is defined as CONST, its access type is automatically set to Read. In such instances the access type cannot be changed. Read Access variables are read only by the HMI; therefore the softMC only writes them to the Modbus address space.
A variable that is not defined as CONST automatically appears as Write Access. Double-click on the access type to toggle the variable between Read Access and Write Access, and thus determine whether the variable will be read or written by softMC.
Generating and Using Scripts
After you are done mapping variables and defining the access types, a snapshot of the current configuration must be saved in order to generate the Modbus-handling scripts.
1. Click Files, and then Save As.
- The mapping is saved in an .mbas file.
- If you makes changes after saving the .mbas file, the MBAS file indicator in the status bar will light up.
2. To generate the product files, click Generate.
The Log windows will display Success messages.
3 files will be generated: HMIMBMAP.LIB, HMIMBMAP.PRG, which will be used by the MC and STX_HMI.CSV, which will be used by the HMI program.
3. The defult location of the files generation is located in ControlStudio installation folder: C:\Program Files (x86)\Servotronix\MBConfigurator
Using the Modbus-Handling Scripts
1. Using the ControlStudio, copy HMIMBMAP.LIB and HMIMBMAP.PRG to the softMC as shown in Media:ModBussetup.jpg
Note: Before these files can be loaded and used, your application(s), which include all the global veriables must be loaded (all mapped variables must exist in the softMC memory).
2. Using the ControlStudio Terminal, load the library HMIMBMAP.LIB:
Load HMIMBMAP.LIB
- Since HMIMBMAP.PRG imports this library it must not be loaded globally. This code can be executed wherever is convenient.
3. Verify that the library was loaded successfully:
?tasklist
4. Start the Modbus communication task by loading the program:
Load HMIMBMAP.PRG
HMIMBMAP.PRG is defined as Program Continue, therefore it starts automatically after it is loaded and it does not require an explicit StartTask command.
Of course, HMIMBMAP.PRG can be loaded and executed only after HMIMBMAP.LIB is loaded. Therefore, you should add the following code to AUTOEXEC.PRG or wherever is convenient:
Load HMIMBMAP.LIB Load HMIMBMAP.PRG
HMIMBMAP.PRG Explained
HMIMBMAP.PRG code:
import HMIMBMAP.LIB Program Continue dim retVal as long = 0 retVal = Init_Modbus while 1 retVal = Read_Modbus_Registers retVal = Write_Modbus_Registers sleep 1 end while End Program
The functions Init_Modbus, Read_Modbus_Registers and Write_Modbus_Registers are implemented in HMIMBMAP.LIB, which is automatically generated by a Python script.
The function Init_Modbus starts the Modbus server and then writes to the Modbus address space all the Write Access Variables (i.e., all the variables read by the softMC from the Modbus address space). This feature allows you to setup the system to start with an initialized Modbus address space before the HMI/PLC connects to it. The HMI/PLC can read the address space and initialize itself accordingly.
The functions Read_Modbus_Registers and Write_Modbus_Registers are invoked cyclically and indefinitely. Read_Modbus_Registers reads all the tags that are written by the HMI/PLC and updates the Write Access variables with new values, while Write_Modbus_Registers does the opposite.
HMI IDEs and .CSV Files
Each line in the .csv file generated by the MCMBConfigurator file holds data about a single variable, such as Modbus address or data type.
This data can be used by an HMI IDE to import Modbus tags and associate them with HMI functionality.
Different manufacturer IDEs use different .csv formatting; therefore, various Python scripts are used to create the specific .csv files suitable for a particular manufacturer IDE.
HMI Programs
Note: HMI Studio is the most commonly used program.