:: 진공에 대해 알려주마.

MODBUS 2 본문

진공/노하우

MODBUS 2

하이백 2023. 10. 14. 13:04

MODBUS-TCP를 사용한다.

C++인 경우에는 "libModBus"를 사용해 보시고 여기서는 C#으로 ...

 

ICP DAS ET-7242 MODULE

 

EtherNet을 사용하여 통신하는 IO Module을 사용하게 되었다. 통신 프로토콜은 Modbus TCP를 사용한다. 메뉴얼을 보고 통신 패킷을 구성하여 값을 읽고 쓰기 검토하였다. 소켓 구성하고 패킷 작성하고 리턴 밸류 파싱하고 귀찮다. 그냥 다운로드하여 쓰자.

간단한 것으로 검토하여 C#용 SharpModBus를 사용하기로 하였다. 보기에는 간단해 보였다. NuGet 패키지 관리로 다운받아 설치하고 아래와 같이 선언하고 포트를 열어 바로 사용하면 가능하다. Digital(Coil)은 bool로 처리하며 Analog(Register)는 unsigned short으로 읽고 쓰면 된다. 

거의 모든 모드버스용 라이브러리가 비슷하게 구성되어있다. 편의 기능이 더 있거나 상태를 더 잘 표시 하거나 한다. 자신이 필요로 하는 것을 골라 사용하면 된다.

// 선언
using SharpModbus;

// 전역변수
ModbusMaster mbMaster;
// 
const int IP_PORT = 502;	// 기본값
const int SLAVE_ID = 1;   	// 이값은 장치에 설정할수 있으며 초기값은 1이고 간혹 다른값 있음.

// 초기화
string IP_ADDRESS = "192.168.255.1";
mbMaster = ModbusMaster.TCP( IP_ADDR, IP_PORT );

// 장치에서 읽어오기
bool[] DIN_VALUE = mbMaster.ReadCoils( SLAVE_ID, 0, 16 );

// 읽어온 값 사용하기
bool DIN_CH0 = DIN_VALUE[0];
bool DIN_CH1 = DIN_VALUE[1];
...
bool DIN_CH15 = DIN_VALUE[15];

 


 

당연히 초기 설정을 하여야 한다. 각각의 모듈에 IP Address를 설정하고 거기에 모듈 내에 초기치 및 설정값(Voltage, 통신타입, 결과표시방법... )을 설정하여야 한다. 경험상 가능하면 공장 초기값에서 많이 변경하지 않는 것이 차후 서비스를 위하여 유리하다.

 

TCP 모델을 사용하여 이더넷으로 묶어서 제어

 

첫 번째 모듈의 값을 읽기 위해서는 아래와 같이 사용하면 된다. 

주의할 점이 몇 가지 있다. 네트워크 허브를 사용하여 모듈별 IP를 다르게 선언하여 각각의 모듈에 0번지를 읽고 쓰면 된다. Digital IO의 경우 Coil을 read/write 하면 되고 Analog IO는 register 관련 함수를 사용하여 read/write 하면 된다.

Digital IO는 읽기는 ReadInput, 복수개의 IO를 읽는 경우 ReadInputs를 사용한다. 

// Digital Input Module의 3번지 값 읽어오기 (0번지부터시작)
bool[] DIN_DEVICE = mbMaster.ReadInput( SLAVE_ID, 3 );

// Digital Input Module의 0번지에서 16개를 읽어오기
bool[] DIN_DEVICE = mbMaster.ReadInputs( SLAVE_ID, 0, 16 );

 

Digital IO는 쓰기는 WriteCoil, 복수개의 쓰기는 WriteCoils를 사용한다. 

// Digital Output Module 단일출력
mbMaster.WriteCoil( SLAVE_ID, 0, true );

// Digital Output Module 묶음출력 (0번지부터 3개의 신호를 연속 지정)
bool[] DOUT_DEVICE = {true, false, false};
mbMaster.WriteCoils( SLAVE_ID, 0, DOUT_DEVICE);

 

Analog module의 값 읽어오기

// Analog(Register) 읽기
ushort[] ainVal = mbMaster.ReadInputRegisters(SLAVE_ID, 0, 4);

 

Analog module의 값 쓰기

// Analog(Register) 쓰기
mbMaster.WriteRegister(SLAVE_ID, nAdd, nVal);

// Analog module의 출력값을 읽어오기(Readback 주소는 장치에서 지정)
ushort rbAnalog1 = mbMaster.ReadHoldingRegister(SLAVE_ID, 232);    // Channel 1번 출력값 읽어오기
ushort rbAnalog2 = mbMaster.ReadHoldingRegister(SLAVE_ID, 233);    // Channel 2번 출력값 읽어오기

Analog Output module의 output 신호를 다시 읽는 readback channel은 지정된 곳을 읽으면 된다. (여기서는 232번지)

 


 

바다야크님의 모두버스에 관한 아주 상세한 설명
https://badayak.com/entry/MODBUS-RTU-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%EC%89%BD%EA%B2%8C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

모든 통신 방식에 적용되는 무엇을 먼저 보낼 것인가? 관련 이론 "빅엔디안 vs 리틀엔디안"
https://www.tcpschool.com/c/c_refer_endian

 

Analog IO Module에서 register(analog value) 값을 읽으면 2의 보수 형식으로 답하게 된다. 이러한 경우 아래와 같이 변환하여 사용하면 된다. (ICP DAS는 두 가지의 형태로 값을 회신한다. 거기에 맞게 변화하여 사용해야 한다.)

장치가 -10 ~ +10 Volt로 설정된 경우 회신되는 값은 0 ~ 65,535로 변환되어 전달된다. 
리턴값이  32,767보다 크면 음수가 된다. 즉 첫 비트가 1이면 음수이고 0이면 양수이다.

아래를 위의 내용을 코드화한 것이다. 참고로 여기서는 0 값이 두 개가 존재한다. 하나는 0 다른 하나는 -0이다.

    private double Calc_WORD2AIO (double dVal)
    {
        int WORD_HALF = 32768;
        int WORD_FULL = 65535;
        double ANALOG_FULL = 10.0;           

        double dResult = 0;

        if(dVal < WORD_HALF)
        {
            dResult = ( dVal * ANALOG_FULL ) / WORD_HALF;
        }
        else
        {
            dVal = dVal - WORD_HALF;
            dResult = ( dVal * ANALOG_FULL ) / WORD_HALF;
            dResult = -dResult;
        }

        return dResult;
    }

 

아날로그의 경우 2바이트 값을 가지며 2바이트 최대값이 아날로그 모듈에 설정된 최대값이 된다. 아날로그 출력이 -10 ~ 10 volt 인 경우 아래와 같이 변환된다. 

0을 기준으로 아래의 표를 함수화 한 것이다. 장치에 따라 읽어오는 값이 다를 수 있으니 매뉴얼을 참조하거나 아니면 장치에서 원하는 스타일의 형태를 설정하면 된다.

 

'진공 > 노하우' 카테고리의 다른 글

가속, 주행, 감속 그리고 TACT  (0) 2023.11.01
리부트  (0) 2023.09.23
TOOLS (Type casting and ...)  (0) 2023.08.26
"A\0B\0C\0\0\0\0\0\0\0\0\0"  (0) 2023.04.08
VIEW MON of RS-485  (0) 2022.11.20
Comments