User Tools

Site Tools

한국어

comfilepi:modbus_with_nmodbus4:index

Modbus with NModbus4

This demonstration illustrates how to use the ComfilePi as a Modbus RTU master, using NModbus4, to monitor and control a PLC.

NOTE: Unfotuantely, The Mono Framework has not yet implemented the SerialPort's DataReceived event (See Mono Bug 2075). However, this is easily resolved using a background thread that polls the receive buffer. A similar example, using a background thread to read the from the serial port, is illustrated in the 2nd example on this page.

Connecting the ComfilePi to a PLC

In this demonstration, we connect the ComfilePi to one of Comfile Technology's MSB612RA-DC PLC. The PLC's RS232 Channel 1 is connected to COM0 (i.e. /dev/serial0) on the ComfilePi.

Procedure

  1. From your WinForms project, right-click on the project's node in Solution Explorer and select Manage NuGet Packages….

  2. Enter NModbus in the search field, select the NModbus4 package, and then press the Install button.


  3. In your project's code, open a serial port with the appropriate communication settings for the PLC. Note that the serial port names on the development PC differ from those on the ComfilePi. They can be distinguished at runtime using the Environment.OsVersion.Platform enumeration.
    string portName = Environment.OSVersion.Platform == PlatformID.Win32NT ? "COM1" : "/dev/serial0";
    SerialPort port = new SerialPort(portName, 115200);
    port.ReadTimeout = 100;
    port.WriteTimeout = 100;
    port.Open();
  4. Instantiate a ModbusSerialMaster utilizing the SerialPort used in the previous step.
    ModbusSerialMaster master = ModbusSerialMaster.CreateRtu(port);
  5. Call any of the many methods in the ModbusSerialMaster type to read from or write to the PLC.
    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);

Example 1

The following example illustrates the general usage of NModbus4 in a sample WinForms application.

using Modbus.Device;
using System;
using System.IO.Ports;
using System.Windows.Forms;
 
namespace SimpleModbusExample
{
    public partial class Form1 : Form
    {
        const int SLAVE_ADDRESS = 1;
        const int COIL_ADDRESS = 32;
 
        public Form1()
        {
            InitializeComponent();
        }
 
        SerialPort _port;
        ModbusSerialMaster _master;
 
        private void Form1_Load(object sender, EventArgs e)
        {
            // Intialize serial port
            string portName = Environment.OSVersion.Platform == PlatformID.Win32NT ? "COM1" : "/dev/serial0";
            _port = new SerialPort(portName, 115200);
            _port.ReadTimeout = 100;
            _port.WriteTimeout = 100;
            _port.Open();
 
            // Initialize Modbus master
            _master = ModbusSerialMaster.CreateRtu(_port);
 
            // Read the current state of the output
            ReadState();
        }
 
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            // Destroy Modbus master
            _master.Dispose();
            _master = null;
 
            // Destroy serial port
            _port.Close();
            _port.Dispose();
            _port = null;
        }
 
        private void OnButton_Click(object sender, EventArgs e)
        {
            // Turn output ON
            _master.WriteSingleCoil(SLAVE_ADDRESS, COIL_ADDRESS, true);
 
        }
 
        private void OffButton_Click(object sender, EventArgs e)
        {
            // Turn output OFF
            _master.WriteSingleCoil(SLAVE_ADDRESS, COIL_ADDRESS, false);
        }
 
        void ReadState()
        {
            // Read the current state of the output
            var state = _master.ReadCoils(SLAVE_ADDRESS, COIL_ADDRESS, 1);
 
            // Update the UI
            if (state[0])
            {
                StateLabel.Text = "On";
            }
            else
            {
                StateLabel.Text = "Off";
            }
        }
 
        private void ReadStateButton_Click(object sender, EventArgs e)
        {
            // Read the current state of the output
            ReadState();
        }
    }
}

Download Source Code

Example 2

The following example is a more real-world demonstration with the Modbus master running in a background thread repeatedly monitoring the state of the PLC in real-time.

using System;
using System.Windows.Forms;
using System.IO.Ports;
using Modbus.Device;
using System.Threading;
 
namespace ModbusExample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private volatile bool _stopModbus;
        private Thread _modbusThread;
 
        private void RunModbus()
        {
            string portName = Environment.OSVersion.Platform == PlatformID.Win32NT ? "COM1" : "/dev/serial0";
            SerialPort port = new SerialPort(portName, 115200);
            port.ReadTimeout = 100;
            port.WriteTimeout = 100;
            port.Open();
 
            _stopModbus = false;
 
            ModbusSerialMaster master = ModbusSerialMaster.CreateRtu(port);
            IAsyncResult result = null;
 
            while(!_stopModbus)
            {
                // Read UI's button states and assign to device's outputs
                bool[] outputs = new bool[4];
                result = BeginInvoke(new Action(() =>
                {
                    outputs[0] = button1.IsOn;
                    outputs[1] = button2.IsOn;
                    outputs[2] = button3.IsOn;
                    outputs[3] = button4.IsOn;
                }));
 
                while (!_stopModbus && !result.IsCompleted)
                {
                    Thread.Yield();
                }
 
                if (!_stopModbus)
                {
                    try
                    {
                        master.WriteMultipleCoils(1, 32, outputs);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
 
                // Read inputs and assign to UI's Lamps
                if (!_stopModbus)
                {
                    try
                    {
                        var inputs = master.ReadCoils(1, 8, 4);
 
                        result = BeginInvoke(new Action(() =>
                        {
                            lamp8.IsOn = inputs[3];
                            lamp9.IsOn = inputs[2];
                            lamp10.IsOn = inputs[1];
                            lamp11.IsOn = inputs[0];
                        }));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }                    
                }
 
                while (!_stopModbus && !result.IsCompleted)
                {
                    Thread.Yield();
                }
            }
 
            master.Dispose();
 
            port.Close();
            port.Dispose();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            _modbusThread = new Thread(RunModbus);
            _modbusThread.IsBackground = true;
            _modbusThread.Start();
        }
 
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            _stopModbus = true;
            _modbusThread.Join();
        }
    }
}

Download Source Code

comfilepi/modbus_with_nmodbus4/index.txt · Last modified: 2017/06/19 15:54 by COMFILE Technology