====== NModbus4 사용법 ======
산업현장에서 많이 사용하고 있는 MODBUS 프로토콜을 ComfilePi에서 동작시키는 방법을 알아보겠습니다. Nmodbus4 라이브러리를 이용하면 쉽고 간단하게 MODBUS프로토콜을 구현할 수 있습니다.
\\
\\
=====ComfilePi와 PLC 결선 =====
ComfilePi의 RS232 COM0와 PLC의 RS232 포트에 **TX-RX, RX-TX, GND-GND**로 연결합니다. ComfilePi와 PLC의 RS232 결선은 아래와 같습니다.
^ {{ :comfilepi:nmodbus4_k:comfilepi_connection.png }} ^ {{ :comfilepi:nmodbus4_k:msb_connection.png }} ^
※//PLC는 컴파일테크놀로지의 [[http://www.comfile.co.kr/shop/goods/goods_view.php?goodsno=60&category=005001|MSB612RA-DC]] 제품입니다. //
=====NModbus4 라이브러리 추가 =====
NModbus4 라이브러리를 Visual Studio 2017에 추가하는 방법에 대해 알아보겠습니다.
* 1. 프로젝트를 만든 후 우측의 **"솔루션 탐색기"**의 **"프로젝트(ModbusExample)"**에 우클릭으로 **"NuGet 패키지 관리(N).."**를 선택 합니다.
{{ :comfilepi:nmodbus4_k:nmodbus_1_a.png |}}
* 2. **"찾아보기"** 선택 -> 검색창에 **"NModbus"** 검색 -> **"NModbus4"** 선택 -> **"설치"** 클릭
{{ :comfilepi:nmodbus4_k:nmodbus_2_a.png |}}
* 3. 출력창에서 NModbus4 라이브러리 설치 상태를 확인 할 수 있습니다.
{{ :comfilepi:nmodbus4_k:nmodbus_3_a.png |}}
===== Modbus 프로그래밍 =====
NModbus4의 Function(함수)와 Serial Port설정에 대해 알아 보겠습니다.
* 1. Serial Port설정 : 데스크탑 PC의 Serial Port와 ComfilePi의 Serial Port는 다릅니다. 프로젝트 코드에 아래와 같이 SerialPort를 설정 해야합니다.
* ※ ComfilePi의 **COM0**는 **"/dev/serial0"**, **COM1**은 **"/dev/serial1"**로 설정합니다.
string portName = Environment.OSVersion.Platform == PlatformID.Win32NT ? "COM0" : "/dev/serial0";
SerialPort port = new SerialPort(portName, 115200);
port.ReadTimeout = 100;
port.WriteTimeout = 100;
port.Open();
* 2. ComfilePi를 Master로 사용시 PLC의 상태를 읽어오고 제어할 수 있는 함수입니다.
* ※ ModbusRTU Master는 **ModbusSerialMaster** 클래스를 사용합니다.
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);
* 3. NModbus4 라이브러를 이용해 만든 실행파일(.exe)을 ComfilePi에서 사용하려면 **실행파일(.exe)**과 **NModbus4.dll**를 ComfilePi의 '/home/pi' 위치에 복사해 사용합니다.
\\
===== 프로그램 =====
ModbusRTU 프로토콜로, NModbus4를 이용한 예제 프로그램 입니다. ComfilePi를 Master로 PLC(MSB612RA-DC)를 Slave로 작성 되었습니다.
====- Example 1====
소스코드 다운로드 ☞ {{ :comfilepi:nmodbus4_k:simple_modbus_example.zip |}}
{{ :comfilepi:nmodbus4_k:simple_modbus_example1.mp4?700x450 |}}
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 ? "COM0" : "/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();
}
}
}
\\
====- Example 2====
소스코드 다운로드 ☞ {{ :comfilepi:nmodbus4_k:modbus_example.zip |}}
{{ :comfilepi:nmodbus4_k:nmodbus_example2.mp4?700x450 |}}
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 ? "COM0" : "/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();
}
}
}
[[comfilepi:index#.NET_(닷넷)_개발환경|이전 페이지로 이동]]