====== 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|한단계 뒤로]]