Modbus 데이터 네 종류와 주소 표기
설명서의 40001은 테이블 종류와 번호를 결합한 표기이고, 요청에 포함되는 주소는 번호에서 1을 뺀 값이다.
데이터 종류
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까지 독립적으로 센다. 주소만으로는 데이터가 특정되지 않으며 기능 코드가 함께 있어야 한다.
4xxxx 표기
장비 설명서에는 40001, 30005 같은 번호가 사용된다. 맨 앞 숫자가 테이블 종류이고 나머지가 해당 테이블 내부의 번호이다. 이 표기는 사양 문서에 있는 것이 아니라 설명서에서 정착된 관례이다.
0xxxx: coil1xxxx: discrete input3xxxx: input register4xxxx: holding register
번호와 주소의 차이
사양은 테이블 내부의 데이터에 1부터 번호를 부여하고, 요청에 포함되는 주소는 0부터 센다. 번호가 X인 데이터의 주소는 X-1이다. 앞자리 4는 요청에 포함되지 않는다.
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만큼 이동하여 다시 읽는다.