MODBUS

완전한 Modbus 가이드

기하 2021. 9. 6. 02:59

모드버스 개요

모드버스란?

나온지가 오래되었지만
Modbus는 여전히 현장 통신에 가장 일반적으로 사용되는 프로토콜 중 하나입니다. 
상대적으로 단순하고 견고하며 개방적이어서 많은 자동화 하드웨어 및 소프트웨어 공급업체에서
프로토콜을 선택했습니다. 
이 때문에 Modbus는 항상 지원하는 장치가 있으므로 안심할 수 있는 선택입니다.

 

Modbus의 또 다른 주요 이점은 특정 물리 계층을 규정하지 않는다는 것입니다. 
대신 Modbus는 RS-232, RS-485 또는 이더넷을 통한 TCP/IP 위에서 작동할 수 있습니다. 
그것들은 모두 저렴하고 이미 기업에서 일반적으로 사용됩니다. 
즉, 값비싼 프로토콜별 네트워크 인프라에 투자할 필요가 없습니다.

 

데이터 인코딩 형식, 전송 계층 및 기타 고려 사항에 따라
다양한 유형의 Modbus 구현이 있습니다. 가장 널리 사용되는 프로토콜 유형은 다음과 같습니다.

  • Modbus RTU(직렬 링크를 통한 바이너리)
  • Modbus ASCII(직렬 링크를 통한 텍스트 기반)
  • Modbus TCP(TCP/IP 전송을 통한 바이너리)
  •  

Modbus RTU 프로토콜 개요

Modbus RTU는 마스터-슬레이브 프로토콜입니다. 
이는 마스터라는 하나의 장치만 통신을 시작할 수 있음을 의미합니다 . 
네트워크의 다른 장치를 슬레이브라고 하며 요청에만 응답할 수 있습니다. 

 

Modbus RTU는 동일한 물리적 네트워크에서 최대 247개의 장치를 지원할 수 있습니다. 
더 많은 슬레이브를 지원하도록 프로토콜을 수정하는 것이 가능하지만
대부분의 응용 프로그램에서는 충분하다면 표준 슬레이브 제한이 있습니다.

 

Modbus RTU는 데이터를 바이너리로 인코딩하고
16비트 값에 대해 빅 엔디안 인코딩을 사용합니다. 

즉, 16비트 워드의 최상위 바이트가 먼저 전송됩니다.

 

다음은 각 항목에 대한 설명과 함께 Modbus RTU 요청 및 응답 메시지의 예입니다. 

먼저 마스터는 slave1에게 주소 2에서 시작하는 한 레지스터의 값을 반환하도록 request를 보냅니다.

 

Request에는

메시지가 슬레이브로 가는 도중에 손상되지 않았는지 확인하는 데 사용되는 체크섬도 포함됩니다. 

슬레이브1을 제외한 모든 슬레이브는 메시지를 무시해야 합니다. 
슬레이브 1는 다음과 유사한 응답 메시지를 보낼 것으로 예상됩니다.

모드버스 ASCII

Modbus ASCII는 Modbus RTU와 유사하게 작동하지만
데이터의 인코딩을  텍스트 기반으로 합니다. 

이렇게 하면 요청과 응답을 사람이 읽을 수 있게 하며, 이는 RTU에 비해 ​​주요 이점입니다. 
반면에 메시지가 두 배 길어지기 때문에 훨씬 덜 효율적입니다. 

이 때문에 Modbus ASCII는 테스트용으로만 사용되며 현장에서 실제로는거의 사용되지 않습니다.

Modbus RTU 및 ASCII의 제한 사항

프로토콜의 낮은 요구 사항과 단순성에는 다음과 같은 단점이 있습니다.

  • 동일한 네트워크에 여러 마스터가 있거나 양방향 통신을 달성하는 좋은 방법은 없습니다. 
    이는 미디어 액세스를 제어하여 충돌을 방지하는 메커니즘이 없기 때문입니다.
  • RS-485와 같은 직렬 링크로 많은 슬레이브를 지원하는 것은 어렵습니다. 
    사실, 수십 개 이상의 장치를 사용하는 것은
    마스터와 슬레이브의 복잡한 중첩 계층을 구축해야만 가능합니다.
  • 직렬 링크의 대역폭은 115200 보드로 제한됩니다. 
    이것은 현대 표준에 비해 상당히 낮지만 여전히 많은 응용 프로그램에서 작동합니다.

모드버스 TCP

Modbus TCP는 최신 TCP/IP 네트워크 위에 사용되는 Modbus의 적응입니다. 
Modbus TCP 구현에는 두 가지 유형이 있습니다.

  • TCP를 RTU 메시지의 전송 계층으로 사용하는 Modbus RTU over TCP
  • 메시지 형식이 약간 변경된 일반 Modbus TCP.

Modbus TCP는 이더넷 네트워크를 사용하기 때문에
직렬 링크를 사용하는 RTU보다 데이터 전송 속도가 훨씬 빠릅니다. 
단점은 TCP/IP 스택이 Modbus RTU가 제대로 작동하는 일부 유형의 필드 장치에서
지원하기가 훨씬 더 어렵다는 것입니다.

 

Modbus RTU 데이터 프레임

Modbus 데이터 프레임은 Modbus 네트워크를 통해 전송되는 메시지입니다. 
요청Request 응답Response 프레임이 있습니다. 
요청Request은 마스터에서 슬레이브로 보내는 메시지입니다. 
응답Response은 슬레이브에서 마스터로 다시 보내는 메시지입니다.

 

데이터 프레임의 길이와 내용은 수행 중인 읽기/쓰기 작업 유형에 따라 다릅니다. 

우리는 나중에 그들 모두를 다룰 것입니다. 

그러나 먼저 요청 프레임의 기본 구조를 살펴보겠습니다.

Modbus RTU 네트워크를 통해 전송되는 8비트 16진수 문자입니다. 

우리의 경우 전체 메시지의 길이는 7바이트입니다. 프레임 내부에 무엇이 있는지 봅시다.

모든 Modbus 메시지의 첫 번째 바이트 slave id 입니다. 

마스터는 요청 메시지가 전달되는 슬레이브의 ID를 지정합니다. 

슬레이브는 모든 응답 메시지에 자신의 ID를 지정해야 합니다.

모든 Modbus 메시지의 두 번째 바이트 function code입니다.

이 코드는 슬레이브가 수행할 작업 유형을 결정합니다. 잠시 후에 함수 코드를 다룰 것입니다.

모든 Modbus 메시지의 마지막 2바이트 CRC 입니다. 
이들은 프레임의 이전 바이트를 기반으로 계산되며 마

스터와 슬레이브 모두 수신된 메시지의 무결성을 확인할 수 있습니다. 

CRC 계산에 사용되는 알고리즘은 나중에 다룰 것입니다.

다음은 이 기사의 나머지 부분에서 사용할 일반 형식의 Modbus 메시지입니다.

ID 는 slave id, FC는 function code 이며, 

data는  특정 가변 길이 문자열이며, CRC2 바이트의 체크섬이다.

 

Modbus 주소

Modbus 장치에는 4가지 유형의 주소가 있습니다.

  • 코일               Coil
  • 이산 입력        Discrete Input
  • 입력 레지스터  Input Register
  • 유지 레지스터  Holding Register

코일은 1비트(부울) 읽기/쓰기 장치입니다. 
각 코일은 on또는 off상태일 수 있습니다 . 

 

이산 입력은 코일과 유사하지만 읽기 전용입니다.
개별 입력의 값을 설정하는 것은 불가능합니다. 
코일은 PLC의 출력으로, 이산 입력은 PLC의 입력으로 생각할 수 있습니다.

 

홀딩 레지스터는 PLC 메모리와 같습니다. 
Modbus 프로토콜을 통해 읽고 쓸 수 있는 16비트 단어입니다. 

 

입력 레지스터도 16비트 워드이지만 센서 판독과 같이 읽기 전용입니다.

 

Modbus 주소는 읽거나 써야 하는 데이터를 나타내기 위해

모든 요청과 함께 전송되는 16비트 부호 없는 정수입니다. 

주소는 Modbus 메시지에서 두 문자를 차지하며 최상위 바이트가 먼저 전송됩니다(빅 엔디안).

 

기능 코드

이 섹션에서는 Modbus 기능 코드를 살펴보고 각각에 대한 데이터 프레임 구성의 세부 사항을 설명합니다.

Read Coils - 0x01

이 기능 코드를 통해 마스터는 슬레이브 코일의 상태를 요청할 수 있습니다.

Request   [ID] [FC] [ADDR] [NUM] [CRC]

  • ADDR - 첫 번째 코일의 주소(2바이트)
  • NUM - 읽을 코일 수(2바이트)

A read coils reques는  항상 8 바이트입니디. 

다음은 주소0xA 에서 시작하는 2개의  코일 읽기 요청의 예입니다.

Response

[ID][FC][BC][DATA(1+)][CRC]

  • BC- 수 이하의 바이트  DATA반응 (1 바이트)
  • DATA - 코일의 상태를 포함하는 바이트 시퀀스(8코일당 1바이트)

읽기 코일의 반응은 적어도 6 바이트 길이입니다. 
이 예에서는 DATA2개의 코일만 요청했기 때문에 의 1바이트 만 있으므로
모든 데이터는 단일 바이트에 맞습니다.

 

ID    FC  BC DATA CRC

[01] [01] [01] [03] [11 89]

개별 입력 읽기 - 0x02

이 기능 코드를 통해 마스터는 슬레이브의 개별 입력 상태를 쿼리할 수 있습니다.

요구

[ID][FC][ADDR][NUM][CRC]

  • ADDR - 첫 번째 이산 입력의 주소(2바이트)
  • NUM - 읽을 입력 수(2바이트)

A는 별도의 입력을 읽어 요청이 항상 8 바이트 길이. 다음은 2address에서 시작하는 개별 입력 을 읽기 위한 요청의 예입니다 0x00.

ID FC ADDR NUM CRC [01] [02] [00 00] [00 02] [F9 CB]

응답

[ID][FC][BC][DATA(1+)][CRC]

  • BC- 수 바이트  DATA반응 (1 바이트)
  • DATA - 개별 입력의 상태를 포함하는 바이트 시퀀스(입력 8개당 1바이트)

A는 개별 입력 판독 응답은 적어도 6 바이트 길이이다. 예시:

ID FC BC DATA CRC [01] [02] [01] [02] [20 49]

Read Holding Registers - 0x03

이 기능 코드를 사용하면 마스터가 슬레이브의 보유 레지스터 상태를 쿼리할 수 있습니다.

Request   [ID]  [FC]  [ADDR]  [NUM]  [CRC]

  • ADDR - 첫 번째 레지스터의 주소(2바이트)
  • NUM - 읽을 레지스터 수(2바이트)

read holding registers는 항상 8바이트 길이입니다. 

아래 요청에서 우리는 주소0x02에서 1 보유 레지스터를 읽습니다 .

ID   FC  ADDR   NUM    CRC

[01] [03] [00 02] [00 01] [25 CA]

Response  [ID] [FC] [BC] [DATA(2+)] [CRC]

  • BC- DATA응답 의 바이트 수 (1바이트)
  • DATA 보유 레지스터 값을 포함하는 바이트 시퀀스(레지스터당 2바이트)

read holding registers 응답은 적어도 7 바이트 길이입니다. 예시:

ID FC BC DATA CRC [01] [03] [02] [07 FF] [FA 34]

입력 레지스터 읽기 - 0x04

이 기능 코드를 사용하여 마스터는 슬레이브의 입력 레지스터 상태를 쿼리합니다.

요구

[ID][FC][ADDR][NUM][CRC]

  • ADDR - 첫 번째 레지스터의 주소(2바이트)
  • NUM - 읽을 레지스터 수(2바이트)

읽기 입력 레지스터의 요청은 8 바이트 길이 항상이다. 아래 요청에서 우리 1는 주소에서 보유 레지스터를 읽습니다 0x00.

ID FC ADDR NUM CRC [01] [04] [00 00] [00 01] [31 CA]

응답

[ID][FC][BC][DATA(2+)][CRC]

  • BC- DATA응답 의 바이트 수 (1바이트)
  • DATA 보유 레지스터 값을 포함하는 바이트 시퀀스(레지스터당 2바이트)

A는 레지스터 잡고 읽어 응답하는 것은 적어도 7 바이트 길이입니다. 예시:

ID FC BC DATA CRC [01] [04] [02] [03 FF] [F9 80]

단일 코일 쓰기 - 0x05

단일 슬레이브 코일의 값을 설정합니다.

요구

[ID][FC][ADDR][VAL][CRC]

  • ADDR - 쓸 코일의 주소(2바이트)
  • VAL- 쓸 코일의 값(2바이트), 0xFF00코일을 ON로 0x0000설정 , 코일을  설정OFF

쓰기 단일 코일 요청은 8 바이트 길이 항상이다. 예시:

ID FC ADDR NUM CRC [01] [05] [00 0A] [00 00] [ED C8]

응답

단일 코일 쓰기에 대한 성공적인 응답 은 요청을 정확히 반복합니다.

ID FC ADDR NUM CRC [01] [05] [00 0A] [00 00] [ED C8]

단일 레지스터 쓰기 - 0x06

단일 슬레이브의 홀딩 레지스터 값을 설정합니다.

요구

[ID][FC][ADDR][VAL][CRC]

  • ADDR - 쓸 레지스터의 주소(2바이트)
  • VAL - 쓸 레지스터의 값(2바이트)

쓰기 단일 등록 요청은 8 바이트 길이 항상이다. 예시:

ID FC ADDR VAL CRC [01] [06] [00 02] [0C 00] [2D 0A]

응답

단일 레지스터 쓰기에 대한 성공적인 응답 은 요청과 정확히 같습니다.

ID FC ADDR VAL CRC [01] [06] [00 02] [0C 00] [2D 0A]

다중 코일 쓰기 - 0x0F

슬레이브 코일의 연속 범위 값을 설정합니다.

요구

[ID][FC][ADDR][NUM][BC][DATA(1+)][CRC]

  • ADDR - 쓸 첫 번째 코일의 주소(2바이트)
  • NUM - 쓸 코일 수(2바이트)
  • BC - 요청의 데이터 바이트 수(1바이트)
  • DATA - 설정할 코일의 값(8코일당 1바이트)

이 예에서 우리는의 값을 설정 10( 0x0A)에서 시작 코일 0x01에 ON:

ID FC ADDR NUM BC DATA CRC [01] [0F] [00 01] [00 0A] [0F] [FF 03] [AB CD]

응답

ID FC ADDR NUM CRC [01] [0F] [00 01] [00 0A] [AB CD]

  • ADDR - 첫 번째 업데이트된 코일의 주소(2바이트)
  • NUM - 업데이트된 코일의 수(2바이트)

다중 레지스터 쓰기 - 0x10

슬레이브의 홀딩 레지스터의 연속 범위 값을 설정합니다.

요구

[ID][FC][ADDR][NUM][BC][DATA(2+)][CRC]

  • ADDR - 쓸 첫 번째 레지스터의 주소(2바이트)
  • NUM - 쓸 레지스터 수(2바이트)
  • BC - 요청의 데이터 바이트 수(1바이트)
  • DATA - 설정할 레지스터 값(레지스터당 2바이트)

이 예에서는 다음에서 시작하는 2개의 레지스터를 작성합니다 0x0A.

ID FC ADDR NUM BC DATA CRC [01] [10] [00 0A] [00 02] [04] [00 0A 01 02] [AB CD]

응답

ID FC ADDR NUM CRC [01] [10] [00 0A] [00 02] [AB CD]

  • ADDR - 첫 번째 업데이트된 레지스터의 주소(2바이트)
  • NUM - 업데이트된 레지스터의 수(2바이트)

예외 응답

경우에 따라 슬레이브가 마스터 요청을 처리하지 못할 수 있습니다. 
이러한 경우 Modbus는 예외 응답 프레임을 정의합니다 .

[ID][FC][EC][CRC]

  • FC- 최상위 비트가 1(1바이트)로 설정된 예외를 발생시킨 요청의 기능 코드
  • EC - 발생한 일을 설명하는 예외 코드(1바이트)

read coils요청 에 대한 예외 응답의 예 :

ID FC EC CRC [01] [81] [02] [C1 91]

의 기능 코드 read coils는 0x01이지만 예외 응답에서 최상위 비트가 로 설정 1되었으므로
코드는 0x81다음과 같습니다.

0000 0001 => 1000 0001 (0x01) (0x81)

표준 예외 코드

다음은 가장 일반적인 Modbus 예외 코드 목록입니다.

  • 01 -  Illegal Function - 지정된 기능 코드가 슬레이브에서 지원되지 않습니다.
  • 02 - Illegal Data Address - 지정된 데이터 주소가 슬레이브에 정의되어 있지 않습니다.
  • 03 -  Invalid Data Value - 지정된 데이터가 유효하지 않습니다.
  • 04 - Device Failure - 슬레이브가 응답 생성에 실패했습니다.
  • 05 - Acknowledge - 슬레이브가 명령을 수락하고 처리 중입니다.
  • 06 -  Busy - 슬레이브가 사용 중이며 메시지를 처리하지 않습니다.
  •  

Modbus RTU CRC 계산

모든 Modbus RTU 메시지(프레임) 는 끝에 2개의 CRC 바이트를 포함합니다.

이러한 바이트는 수신된 모든 메시지의 무결성을 확인하기 위해 
마스터  슬레이브 모두에서 사용됩니다 .

CRC 값은 나머지 메시지를 기반으로 계산됩니다. 

즉, 마지막 두 바이트를 제외한 모든 바이트가 사용됩니다.

Modbus 장치가 메시지를 수신하면 자체 CRC 값을 계산하고 수신된 CRC 값과 비교합니다.

 

CRC 알고리즘

CRC는 Cyclic Redundancy check의 약자입니다.
음은 C#에서 CRC를 계산하는 샘플 코드입니다.

public static void CRC(byte[] data, out byte msb, out byte lsb)
{
    ushort crcFull = 0xFFFF;
    for (var i = 0; i < data.length; i++)
    {
        crcFull = (ushort)(crcFull ^ data[i]);
        for (var j = 0; j < 8; j++)
        {
            var crclsb = (char)(crcFull & 0x0001);
            crcFull = (ushort)((crcFull >> 1) & 0x7FFF);
            if (crclsb == 1)
            {
                crcFull = (ushort)(crcFull ^ 0xA001);
            }
        }
    }

    lsb = (byte)((crcFull >> 8) & 0xFF);
    msb = (byte)(crcFull & 0xFF);
}

참고 모드버스ASCIILRC라는 다른 알고리즘을 사용하여 체크섬을 계산합니다..

 

모드버스 TCP

Modbus TCP는 일반적으로 이더넷 물리 계층을 통해
TCP/IP 스택을 사용하여 Modbus 프레임을 전송하도록 설계된 프로토콜입니다.

Modbus와 TCP가 함께 작동할 수 있는 두 가지 방법이 있습니다. 
하나는 실제 Modbus TCP 프로토콜이고
다른 하나는 Modbus RTU-over-TCP 입니다.

Modbus TCP와 TCP를 통한 RTU

두 경우 모두 TCP는 Modbus 메시지를 전달하는 전송 프로토콜입니다. 그러나 메시지는 다릅니다.

Rtu-over-TCP에서 TCP는 Modbus RTU(직렬)에서 사용되는 것과 똑같은 메시지를 전송하는 데 사용됩니다.

반면 Modbus TCP에서는 메시지(프레임) 자체의 구조가 다르기 때문에 두 형식이 호환되지 않습니다.

모드버스 TCP 프레임

Modbus TCP 프레임은 일반 Modbus RTU 프레임과 다릅니다.

RTU 프레임의 일반적인 구조는 다음과 같습니다.

[slave ID][data][CRC bytes]

이를 TCP 프레임으로 변환하려면 다음을 수행해야 합니다.

  • 제거하다 slave ID
  • 제거하다 CRC bytes
  • MBAP header메시지 앞에 추가

이와 같이:

[slave ID][data][CRC bytes] [MBAP][data]

MBAP는 Modbus 응용 프로그램 프로토콜을 나타냅니다 . MBAP 헤더 자체의 구조는 다음과 같습니다.

[transaction ID][protocol ID][ length ][unit id] 2 bytes 2 bytes 2 bytes 1 byte

Transaction ID각 새 요청에 대해 마스터가 설정하고 응답에서 슬레이브가 사용해야 하는 난수입니다. Protocol ID항상 0Modbus TCP에 있습니다. 및 나머지를 Length포함하여 뒤에 오는 바이트 수입니다 . 슬레이브 ID와 유사한 장치 주소입니다.unit iddataUnit ID

 

 

 

[참조번역인용] https://unserver.xyz/modbus-guide/

 

Complete Modbus Guide - Unserver

Complete Modbus Guide Modbus Overview What is Modbus? Despite it’s age, Modbus is still one of the most commonly used protocols for field communicaitons. It’s relative simplicity and robustness and openness made it a protocol of choice for many automat

unserver.xyz