글 / Modbus·OPC UA

Modbus 데이터 네 종류와 주소 표기

설명서의 40001은 테이블 종류와 번호를 결합한 표기이고, 요청에 포함되는 주소는 번호에서 1을 뺀 값이다.

작성일 · 읽는 시간 2분 · Modbus Application Protocol V1.1b3 기준

데이터 종류

Modbus 장비의 데이터는 네 개의 테이블로 구분된다. 구분 기준은 크기가 1비트인지 16비트인지, 읽기만 가능한지 쓰기도 가능한지이다.

종류 크기 접근 읽기 쓰기
discrete input 1비트 읽기 전용 02 없음
coil 1비트 읽기·쓰기 01 05, 15
input register 16비트 읽기 전용 04 없음
holding register 16비트 읽기·쓰기 03 06, 16

읽기·쓰기 열의 숫자는 기능 코드(function code)로, 요청의 맨 앞에서 대상 테이블과 동작을 지정하는 1바이트 값이다. 주소는 테이블마다 0부터 65535까지 독립적으로 센다. 주소만으로는 데이터가 특정되지 않으며 기능 코드가 함께 있어야 한다.

크기와 접근으로 구분한 Modbus 데이터 네 종류와 기능 코드

4xxxx 표기

장비 설명서에는 40001, 30005 같은 번호가 사용된다. 맨 앞 숫자가 테이블 종류이고 나머지가 해당 테이블 내부의 번호이다. 이 표기는 사양 문서에 있는 것이 아니라 설명서에서 정착된 관례이다.

  • 0xxxx: coil
  • 1xxxx: discrete input
  • 3xxxx: input register
  • 4xxxx: holding register

번호와 주소의 차이

사양은 테이블 내부의 데이터에 1부터 번호를 부여하고, 요청에 포함되는 주소는 0부터 센다. 번호가 X인 데이터의 주소는 X-1이다. 앞자리 4는 요청에 포함되지 않는다.

설명서의 표기 40108이 테이블 종류와 주소 107로 변환되는 과정

pythonaddress.py
TABLES = {0: "coil", 1: "discrete input", 3: "input register", 4: "holding register"}


def to_address(ref: int) -> tuple[str, int]:
    # 맨 앞 자리는 테이블 종류, 나머지는 1부터 세는 번호다
    kind, number = divmod(ref, 10000)
    return TABLES[kind], number - 1


print(to_address(40001))  # ('holding register', 0)
print(to_address(40108))  # ('holding register', 107)

설명서에 기재된 숫자가 번호인지 주소인지는 문서마다 다르다. 읽은 값이 인접한 위치의 값으로 보이면 주소를 1만큼 이동하여 다시 읽는다.