====== CUWIN에서 MODBUS 사용하는 방법 ======
모드버스 프로토콜을 이용해서 CUWIN과 CUBLOC을 서로 연결하는 방법에 대해서 알아보겠습니다. 아래 그림처럼 CUWIN은 모드버스의 마스터가 되고, CUBLOC은 모드버스 SLAVE가 됩니다.
{{ :cuwin:cuwin_modbus:cubloccuwin.png?nolink&300 |}}
===== 큐블록 준비 =====
일체형 모듈인 MSB612RA-DC을 사용하였습니다.
{{ :cuwin:cuwin_modbus:msb612ra-dc.png?nolink&200 |}}
MSB LOGIC 프로그램을 이용해서 다음과 같이 셋팅후 다운로드하시면, CUBLOC쪽은 MODBUS SLAVE로 실행할 수 있는 모든 준비를 마치게 됩니다.
{{ :cuwin:cuwin_modbus:msbsetup.png?nolink |}}
레더로직은 아무것도 없이 그냥 END명령 하나만 넣으시면 됩니다.
{{ :cuwin:cuwin_modbus:msbsetup2.png?nolink |}}
===== 통신선 연결 ======
CUWIN과 CUBLOC을 연결하는 방법입니다. CUWIN은 CWV-070BR을 사용했습니다.
{{ :cuwin:cuwin_modbus:cwv070br.png?nolink |}}
CUWIN의 RS2323C COM1과 MSB의 RS232C 채널1을 다음과 같이 서로 연결합니다.
{{ :cuwin:cuwin_modbus:11.png?nolink |}}
{{ :cuwin:cuwin_modbus:dsc00014.jpg?nolink |}}
===== CUWIN 프로그래밍 =====
MODBUS 프로토콜을 C#으로 일일이 구현하기에는 매우 번거로우므로, 공개된 라이브러리를 활용해서 MODBUS를 구현하도록 하겠습니다.
google에서 NMODBUS를 검색하거나, https://code.google.com/p/nmodbus/ 로 이동하십시오.
{{ :cuwin:cuwin_modbus:nmodbussite.png?nolink |}}
보시는 것처럼 MODBUS 프로토콜을 다양한 언어환경에서 구현할 수 있도록 라이브러리를 공개하고 있는 사이트입니다.
{{ :cuwin:cuwin_modbus:nmodbussite2.png?nolink |}}
다운로드탭을 누른뒤, 가장 최근버젼의 바이너리 파일을 다운로드 받으세요. 받은 파일의 압축을 풀고난뒤, netcf 폴더까지 이동을 하시면 아래처럼 4개의 파일이 보입니다. (netcf 는 .Net Compact Framework 라는 뜻입니다.)
{{ :cuwin:cuwin_modbus:nmodbussite3.png?nolink |}}
이 4개 파일을 비주얼스튜디오의 솔루션탐색기에서 아래 화면처럼 "추가"하십시오.
{{ :cuwin:cuwin_modbus:참조추가1.png?nolink |}}
{{ :cuwin:cuwin_modbus:참조추가2.png?nolink |}}
{{ :cuwin:cuwin_modbus:참조추가3.png?nolink |}}
참조에 해당 파일이 추가된 것을 확인할 수 있습니다.
===== C# 프로그래밍 =====
이제 C#프로그램 쪽을 보도록 하겠습니다.
using Modbus.Device;
using 선언부에 위와 같은 문장을 삽입하세요.
사용할 RS232C포트를 오픈합니다.
_serialPort = new SerialPort("COM1", 115200);
_serialPort.Open();
그 다음 ModbusSerialMaster를 초기화 해주는 명령을 써줍니다.
_modbusMaster = ModbusSerialMaster.CreateRtu(_serialPort);
_modbusMaster.Transport.ReadTimeout = 500;
_modbusMaster.Transport.WriteTimeout = 500;
_modbusMaster.Transport.Retries = 0;
이것으로 MODBUS를 사용할 준비는 끝난 것입니다. 이제 아래 메소드중 원하는 메소드를 불러서 사용하시면 됩니다.
NMODBUS 에 대해서 구체적인 부분이 알고싶으시면 [[http://ftp.icpdas.com/pub/cd/8000cd/napdos/modbus/nmodbus/nmodbus_api_manual_v1.2_en.pdf|NMODBUS API 메뉴얼]]을 참조하세요.
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);
===== 데모 프로그램 =====
아래 데모 프로그램은 큐블록 MSB612RA-DC의 포트 하나를 ON 또는 OFF 하거나,A/D값을 읽어오는 예제입니다.
{{ :cuwin:cuwin_modbus:dsc00015.jpg?nolink |}}
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;
}
}
}
[[http://www.comfile.co.kr/download/touchcontrol/CUWIN_CWV_MODBUS.zip|소스 다운받기]]
다음은 동작 동영상입니다. 프로토콜 아날라이저를 사용해서, CUWIN 과 CUBLOC간의 데이터 통신 상황을 모니터링 하고 있습니다.
===== MODBUS 어드레스 =====
한가지 부연설명을 더 하자면, MODBUS 어드레스에 관한 것입니다.
ushort[] result = _modbusMaster.ReadInputRegisters(SLAVE_ADDRESS, 276, 1);
이 메소드는 276번지에서 1 워드를 읽어오는 메소드입니다. MSB의 A/D 채널0의 결과를 저장하는 MODBUS 상의 어드레스가 276번지입니다.
MSB상의 모드버스 어드레스는 다음 표를 참고하세요. MSB LOGIC 사용설명서상에서 발췌한 내용입니다.
{{ :cuwin:cuwin_modbus:address.png?nolink |}}
* 8-o 저희 회사에서는 프로그램 개발과정에 관련된 어떠한 기술지원도 제공해드릴 수 없음을 양해바랍니다. 저희 회사에서는 하드웨어와 관련된 부분에 대해서만 기술 지원이 가능합니다. Visaul Studio 에서 코딩하다 발생된 문의는 Microsoft사로 직접 해주시기 바랍니다.
[[cuwin:index|한단계 뒤로]]