In this document we'll use the CUWIN as a Modbus master, and a CUBLOC-based MSB612RA-DC as a Modbus slave.
Configure the serial settings in MSB Logic.
Nothing else is needed in Ladder Logic except and END
ing rung.
For this exercise we will use the CUWIN CWV070 as the Modbus master.
Connect the CUWIN's RS-232 COM1 port to the MSB612RA-DC RS-232 Ch1 port.
NModbus is a free and open source implementation of the Modbus protocol for the .Net Framework and .Net Compact Framework. It is currently hosted at https://code.google.com/p/nmodbus/ but there are also other forks on GitHub.
Download the NModbus binaries.
After downloading and extracting the NModbus binaries from the repository, there will be two folders inside the “bin” folder: net and netcf. net is for the .Net Framework, and netcf is for the .Net Compact Framework. The CUWIN is a .Net Compact Framework device, so netcf is the appropriate folder.
Add a reference to the Modbus.dll file in netcf folder introduced above.
Add a using
declaration to the source file that will contain the Modbus Master code.
using Modbus.Device;
Create a new SerialPort on COM1 with the same serial settings as the Modbus slave.
_serialPort = new SerialPort("COM1", 115200); _serialPort.Open();
Initialize a new ModbusSerialMaster
with the _serialPort
as its transport.
_modbusMaster = ModbusSerialMaster.CreateRtu(_serialPort); _modbusMaster.Transport.ReadTimeout = 500; _modbusMaster.Transport.WriteTimeout = 500; _modbusMaster.Transport.Retries = 0;
Then call any of the given methods to query a Modbus slave:
bool[] ReadCoils(byte slaveAddress, ushort startAddress, ushort numberOfPoints); ushort[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints); ushort[] ReadInputRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints); bool[] ReadInputs(byte slaveAddress, ushort startAddress, ushort numberOfPoints); ushort[] ReadWriteMultipleRegisters(byte slaveAddress, ushort startReadAddress, ushort numberOfPointsToRead, ushort startWriteAddress, ushort[] writeData); void WriteMultipleCoils(byte slaveAddress, ushort startAddress, bool[] data); void WriteMultipleRegisters(byte slaveAddress, ushort startAddress, ushort[] data); void WriteSingleCoil(byte slaveAddress, ushort coilAddress, bool value); void WriteSingleRegister(byte slaveAddress, ushort registerAddress, ushort value);
The following sample project will toggle MSB624RA-DC's relay 32 (at address 32) and read from the MSB624RA-DC's analog input (at address 276). Refer to the following table for the MSB624RA-DCs Modbus memory map.
Word (Holding/Input Registers) Function Codes: 3, 4, 6, 16 |
|
---|---|
Address (base 10) | Data Region (base 10) |
0 ~ 255 | D Region (D0 ~ D255) |
256 ~ 355 | Y Region (Y0 ~ Y99) ADC Result Y20 ~ Y27 (276 ~ 283) |
1000 ~ 1255 | T Region (T0 ~ T255) |
2000 ~ 2255 | C Region (C0 ~ C255) |
3000 ~ 3255 | WM Region (WM0 ~ WM255) |
Bit (Coil, Input Status) Function Codes: 1, 2, 4, 15 |
|
---|---|
Address (base 10) | Data Region (base 10) |
0 ~ 127 | P Region (P0 ~ P127) |
4096 ~ 6143 | M Region (M0 ~ M2047) |
using System; using System.Linq; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using Modbus.Device; using System.IO.Ports; namespace NModbusTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } ModbusSerialMaster _modbusMaster; SerialPort _serialPort; const int SLAVE_ADDRESS = 1; private void Form1_Load(object sender, EventArgs e) { _serialPort = new SerialPort("COM1", 115200); _serialPort.Open(); _modbusMaster = ModbusSerialMaster.CreateRtu(_serialPort); _modbusMaster.Transport.ReadTimeout = 500; _modbusMaster.Transport.WriteTimeout = 500; _modbusMaster.Transport.Retries = 0; } void ReportError(string s) { MessageBox.Show(s); } private void ReadADC() { try { ushort[] result = _modbusMaster.ReadInputRegisters(SLAVE_ADDRESS, 276, 1); _adcLabel.Text = result[0].ToString(); } catch (Exception ex) { ReportError(ex.Message); } } private void ReadDigitalOutput() { try { bool[] result = _modbusMaster.ReadCoils(SLAVE_ADDRESS, 32, 1); if (result[0]) { _digitalOutLabel.Text = "ON"; } else { _digitalOutLabel.Text = "OFF"; } } catch (Exception ex) { ReportError(ex.Message); } } private void WriteDigitalOutput(bool on) { try { _modbusMaster.WriteSingleCoil(SLAVE_ADDRESS, 32, on); } catch (Exception ex) { ReportError(ex.Message); } } private void _digitalOutReadButton_Click(object sender, EventArgs e) { ReadDigitalOutput(); } private void _onButton_Click(object sender, EventArgs e) { WriteDigitalOutput(true); } private void _offButton_Click(object sender, EventArgs e) { WriteDigitalOutput(false); } private void _adcReadButton_Click(object sender, EventArgs e) { ReadADC(); } private void Form1_Closing(object sender, CancelEventArgs e) { _modbusMaster.Dispose(); _modbusMaster = null; _serialPort.Close(); _serialPort.Dispose(); _serialPort = null; } } }
Download the VB.Net Project Files
Imports System Imports System.Linq Imports System.Collections.Generic Imports System.ComponentModel Imports System.Data Imports System.Drawing Imports System.Text Imports System.Windows.Forms Imports System.Threading Imports Modbus.Device Imports System.IO.Ports Public Class Form1 Private _modbusMaster As ModbusSerialMaster Private _serialPort As SerialPort Const SLAVE_ADDRESS As Integer = 1 Private Sub ReportError(ByVal s As String) MessageBox.Show(s) End Sub Private Sub ReadADC() Try Dim result As UShort() = _modbusMaster.ReadInputRegisters(SLAVE_ADDRESS, 276, 1) _adcLabel.Text = result(0).ToString() Catch ex As Exception ReportError(ex.Message) End Try End Sub Private Sub ReadDigitalOutput() Try Dim result As Boolean() = _modbusMaster.ReadCoils(SLAVE_ADDRESS, 32, 1) If result(0) Then _digitalOutLabel.Text = "ON" Else _digitalOutLabel.Text = "OFF" End If Catch ex As Exception ReportError(ex.Message) End Try End Sub Private Sub WriteDigitalOutput(ByVal [on] As Boolean) Try _modbusMaster.WriteSingleCoil(SLAVE_ADDRESS, 32, [on]) Catch ex As Exception ReportError(ex.Message) End Try End Sub Private Sub _digitalOutReadButton_Click(ByVal sender As Object, ByVal e As EventArgs) ReadDigitalOutput() End Sub Private Sub _onButton_Click(ByVal sender As Object, ByVal e As EventArgs) WriteDigitalOutput(True) End Sub Private Sub _offButton_Click(ByVal sender As Object, ByVal e As EventArgs) WriteDigitalOutput(False) End Sub Private Sub _adcReadButton_Click(ByVal sender As Object, ByVal e As EventArgs) ReadADC() End Sub Private Sub Form1_Closing(ByVal sender As Object, ByVal e As CancelEventArgs) _modbusMaster.Dispose() _modbusMaster = Nothing _serialPort.Close() _serialPort.Dispose() _serialPort = Nothing End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load _serialPort = New SerialPort("COM1", 115200) _serialPort.Open() _modbusMaster = ModbusSerialMaster.CreateRtu(_serialPort) _modbusMaster.Transport.ReadTimeout = 500 _modbusMaster.Transport.WriteTimeout = 500 _modbusMaster.Transport.Retries = 0 End Sub End Class