데이터 모델과 주소
Modbus 서버는 값을 네 가지 테이블(table)에 나눠 보관합니다. 클라이언트는 테이블마다 정해진 기능 코드로 값을 읽고 씁니다. 이 페이지는 MODBUS Application Protocol Specification V1.1b3의 §4.2 데이터 인코딩, §4.3 데이터 모델, §4.4 주소 모델을 근거로 합니다.
네 가지 테이블
섹션 제목: “네 가지 테이블”| 테이블 | 단위 | 접근 | 읽기 기능 코드 | 쓰기 기능 코드 | 주로 담는 값 |
|---|---|---|---|---|---|
| 코일(coils) | 1비트 | 읽기·쓰기 | 01 | 05, 15 | 출력 접점, 운전 지령 |
| 이산 입력(discrete inputs) | 1비트 | 읽기 전용 | 02 | 없음 | 입력 접점, 센서 상태 |
| 입력 레지스터(input registers) | 16비트 | 읽기 전용 | 04 | 없음 | 측정값 |
| 보유 레지스터(holding registers) | 16비트 | 읽기·쓰기 | 03 | 06, 16, 22, 23 | 설정값, 지령값 |
- 테이블은 서로 독립입니다. 보유 레지스터 0과 입력 레지스터 0은 다른 값입니다.
- 명세는 테이블이 장비 메모리에서 겹쳐도 된다고 허용합니다. 어떤 장비는 같은 메모리를 코일과 레지스터로 함께 보여 줍니다. 실제 배치는 장비 매뉴얼을 확인합니다.
- 클라이언트는 입력 테이블(이산 입력, 입력 레지스터)에 쓸 수 없습니다. 이 값은 장비가 스스로 바꿉니다.
1 기반 번호와 0 기반 주소
섹션 제목: “1 기반 번호와 0 기반 주소”명세 §4.4는 데이터 모델의 요소를 1부터 n까지 번호로 부르고, PDU에서는 0부터 65535까지의 주소(address)로 가리킨다고 정합니다. 즉 “1번 보유 레지스터”는 PDU 주소 0입니다.
장비 매뉴얼은 여기에 테이블 접두 숫자를 붙인 관례 표기를 자주 씁니다. 이 표기는 매뉴얼의 약속일 뿐이며, 접두 숫자는 PDU에 실리지 않습니다.
| 매뉴얼 표기 | 테이블 | 기능 코드 | PDU 주소 |
|---|---|---|---|
| 00001 | 코일 | 01 | 0 |
| 00010 | 코일 | 01 | 9 |
| 10001 | 이산 입력 | 02 | 0 |
| 30001 | 입력 레지스터 | 04 | 0 |
| 40001 | 보유 레지스터 | 03 | 0 |
| 40108 | 보유 레지스터 | 03 | 107 (0x006B) |
| 400001 (6자리) | 보유 레지스터 | 03 | 0 |
변환 규칙은 다음과 같습니다.
- 접두 숫자로 테이블과 기능 코드를 고릅니다.
- 남은 번호에서 1을 뺍니다.
- 결과를 16비트 주소로 PDU에 넣습니다.
일부 장비 매뉴얼은 처음부터 0 기반 주소를 적습니다. 매뉴얼에 “address 0 = 40001”처럼 기준이 적혀 있는지 먼저 확인합니다. 주소를 한 칸 잘못 잡으면 오류 없이 옆 레지스터 값이 돌아오므로 알아차리기 어렵습니다. 문제 해결도 참고합니다.
값의 인코딩
섹션 제목: “값의 인코딩”명세 §4.2에 따라 주소, 수량, 레지스터 값은 모두 빅 엔디언(big-endian)으로 보냅니다. 상위 바이트가 먼저 나갑니다. 레지스터 값 0x1234는 12 34 순서로 전송됩니다.
비트 테이블은 8비트씩 묶어 한 바이트에 담습니다. 첫 주소의 비트가 첫 바이트의 최하위 비트(LSB)입니다. 다음 예는 코일 0~7에 0xA5를 쓰고 다시 읽습니다.
쓰기 요청 PDU 0F 0000 0008 01 A5 | | | | +-- 값 0xA5 = 1010 0101b | | | +----- 바이트 수 1 | | +---------- 수량 8 | +--------------- 시작 주소 0 +------------------ 기능 코드 15 (Write Multiple Coils)
코일 주소 7 6 5 4 3 2 1 0비트 값 1 0 1 0 0 1 0 1 → 코일 0, 2, 5, 7이 1수량이 8의 배수가 아니면 마지막 바이트의 남는 상위 비트는 0으로 채웁니다.
16비트를 넘는 값
섹션 제목: “16비트를 넘는 값”Modbus 레지스터는 16비트 하나뿐입니다. 부호, 단위, 배율과 32비트 값의 배치는 명세가 정하지 않으며 장비마다 다릅니다.
- 부호 있는 16비트 값: -5는
0xFFFB(65531)로 전송됩니다. 2의 보수로 해석할지는 장비 매뉴얼을 따릅니다. - 배율: 23.1 °C를
231처럼 10배 정수로 보내는 장비가 많습니다. - 32비트 정수와 부동소수점: 두 레지스터를 씁니다. 순서는 장비마다 다릅니다. IEEE 754 단정밀도 10.0(
0x41200000)의 예는 다음과 같습니다.
| 배치 | 레지스터 n | 레지스터 n+1 | 설명 |
|---|---|---|---|
| ABCD (빅 엔디언) | 0x4120 |
0x0000 |
상위 워드가 먼저입니다. |
| CDAB (워드 교환) | 0x0000 |
0x4120 |
하위 워드가 먼저입니다. |
PDComm은 레지스터를 16비트 정수로만 다룹니다. 32비트 값의 조립과 분해는 애플리케이션이 장비 매뉴얼에 맞게 합니다.
PDComm의 데이터 모델
섹션 제목: “PDComm의 데이터 모델”PDComm 엔드포인트(endpoint)는 서버로 동작할 때 자신의 데이터 모델을 가집니다.
- 새 엔드포인트는 네 테이블에 각각 주소 0부터 1024개 항목을 0으로 준비합니다.
data_set명령은 한 테이블의 일부를 바꿉니다. 입력 테이블도 바꿀 수 있습니다. 이는 장비 쪽 입력이 변한 상황을 흉내 내는 것이며, Modbus 쓰기 기능이 생기는 것은 아닙니다.model_set명령은 네 테이블의 시작 주소와 크기, 파일 레코드, FIFO 큐, 장치 식별 객체를 한 번에 바꿉니다. 모델 밖의 주소를 요청하면 서버가 예외 02(Illegal Data Address)로 응답합니다.data_get명령은 현재 모델 전체를 JSON으로 돌려줍니다.
명령 형식은 JSON 명령 레퍼런스에 있습니다. 직접 다뤄 보려면 튜토리얼: 주소와 프레임 관찰을 따라 합니다.