문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 | ||
comfilepi:nmodbus4_k:index [2017/11/25 02:03] Comfile Technology [- Example 2] |
comfilepi:nmodbus4_k:index [2020/02/26 01:38] (현재) Comfile Technology |
||
---|---|---|---|
줄 1: | 줄 1: | ||
+ | ====== 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"**로 설정합니다. | ||
+ | <code xbasic> | ||
+ | string portName = Environment.OSVersion.Platform == PlatformID.Win32NT ? "COM0" : "/dev/serial0"; | ||
+ | SerialPort port = new SerialPort(portName, 115200); | ||
+ | port.ReadTimeout = 100; | ||
+ | port.WriteTimeout = 100; | ||
+ | port.Open(); | ||
+ | </code> | ||
+ | * 2. ComfilePi를 Master로 사용시 PLC의 상태를 읽어오고 제어할 수 있는 함수입니다. | ||
+ | * ※ ModbusRTU Master는 **ModbusSerialMaster** 클래스를 사용합니다. | ||
+ | <code xbasic> | ||
+ | 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); | ||
+ | |||
+ | </code> | ||
+ | * 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 |}} | ||
+ | <code xbasic> | ||
+ | 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(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ====- Example 2==== | ||
+ | 소스코드 다운로드 ☞ {{ :comfilepi:nmodbus4_k:modbus_example.zip |}} | ||
+ | |||
+ | {{ :comfilepi:nmodbus4_k:nmodbus_example2.mp4?700x450 |}} | ||
+ | <code xbasic> | ||
+ | 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(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | [[comfilepi:index#.NET_(닷넷)_개발환경|이전 페이지로 이동]] | ||