Modbus 장비가 요청을 받았지만 처리할 수 없으면 «예외 응답» 을 보냅니다. 예외 응답이 왔다는 것은 배선·속도·국번은 맞고 요청 내용이 장비와 안 맞는다는 뜻이라, 타임아웃보다 원인을 찾기 쉽습니다. 아래는 MODBUS Application Protocol Specification V1.1b3 의 6장(함수별 상태도)과 7장(예외 응답)을 따릅니다.
예외 응답이 오는 경우와 안 오는 경우
| 장비가 받은 것 | 장비의 반응(규격 7장) |
|---|---|
| 통신 오류 없이 받았고 처리할 수 있음 | 정상 응답 |
| 통신 오류 때문에 받지 못함 | 응답 없음 → 마스터는 타임아웃 |
| 받았지만 패리티·CRC·LRC 오류 | 응답 없음 → 마스터는 타임아웃 |
| 오류 없이 받았지만 처리할 수 없음(없는 주소 등) | 예외 응답 |
그래서 CRC 가 틀린 요청에는 예외가 오지 않습니다. 타임아웃만 난다면 예외가 아니라 통신 쪽 문제이니 Modbus 응답 없음 점검 글을 보세요.
모양: 함수 코드 + 0x80, 예외 코드 1바이트
요청 01 03 00 60 00 05 85 D7 ← 국번 1, 보유 레지스터 96 번부터 5개 응답 01 83 02 C0 F1 ← 83 = 03 + 80, 예외 코드 02
정상 응답은 요청의 함수 코드를 그대로 돌려주고, 예외 응답은 함수 코드의 맨 위 비트를 1로 바꿔(0x80 을 더해) 돌려줍니다. 함수 코드는 모두 0x80 보다 작으므로 첫 바이트 다음이 0x80 이상이면 예외입니다. RTU 는 뒤에 CRC 2바이트가 붙고, TCP 는 MBAP 머리 7바이트 뒤에 «83 02» 두 바이트만 옵니다.
| 요청 함수 | 예외 응답 함수 |
|---|---|
| 01 코일 읽기 | 81 |
| 02 입력 접점 읽기 | 82 |
| 03 보유 레지스터 읽기 | 83 |
| 04 입력 레지스터 읽기 | 84 |
| 05 코일 하나 쓰기 | 85 |
| 06 레지스터 하나 쓰기 | 86 |
| 0F 여러 코일 쓰기 | 8F |
| 10 여러 레지스터 쓰기 | 90 |
| 17 읽기·쓰기 함께 | 97 |
예외 코드표 (규격 7장)
| 코드 | 이름 | 뜻 |
|---|---|---|
| 01 | ILLEGAL FUNCTION | 그 함수 코드를 장비가 받지 않음. 장비에 구현되지 않았거나, 지금 상태(예: 설정 전)에서 처리할 수 없음 |
| 02 | ILLEGAL DATA ADDRESS | 주소가 장비에 없음. 정확히는 «시작 주소 + 개수» 의 조합이 장비 범위를 벗어남 |
| 03 | ILLEGAL DATA VALUE | 요청 데이터 칸의 값이 허용되지 않음 — 개수·바이트 수처럼 요청 구조가 맞지 않을 때 |
| 04 | SERVER DEVICE FAILURE | 요청을 처리하다 장비에서 복구할 수 없는 오류 |
| 05 | ACKNOWLEDGE | 프로그래밍 명령용. 받았고 처리에 오래 걸림(마스터의 타임아웃을 막으려고 먼저 답함) |
| 06 | SERVER DEVICE BUSY | 오래 걸리는 명령을 처리 중. 나중에 다시 보내야 함 |
| 08 | MEMORY PARITY ERROR | 파일 레코드(함수 20·21) 읽기에서 메모리 패리티 오류 |
| 0A | GATEWAY PATH UNAVAILABLE | 게이트웨이가 입력 포트에서 출력 포트로 가는 경로를 잡지 못함 — 설정 오류·과부하 |
| 0B | GATEWAY TARGET DEVICE FAILED TO RESPOND | 게이트웨이 뒤의 대상 장비가 응답하지 않음 — 대개 그 장비가 네트워크에 없음 |
07·09 는 이 판(V1.1b3)에 정의가 없습니다. 이런 코드가 오면 장비 매뉴얼의 자체 오류 표를 봅니다.
장비가 검사하는 순서: 01 → 03 → 02 → 04
규격 6장의 함수별 상태도는 읽기·쓰기 함수(01~06·0F·10)마다 같은 순서로 요청을 검사합니다. 그래서 어떤 예외가 왔는지 보면 어디까지는 통과했는지도 알 수 있습니다.
| 순서 | 검사 | 실패하면 |
|---|---|---|
| 1 | 함수 코드를 지원하는가 | 01 |
| 2 | 개수가 범위 안인가 — 03·04 는 1~125(0x007D), 01·02 는 1~2000(0x07D0), 10 은 1~123(0x007B), 0F 는 1~1968(0x07B0). 05 는 값이 0000 또는 FF00 인가 | 03 |
| 3 | 시작 주소, 그리고 시작 주소 + 개수가 장비 범위 안인가 | 02 |
| 4 | 실제로 읽기·쓰기를 해냈는가 | 04 |
예를 들어 03 이 왔다면 함수는 지원되고 주소를 보기도 전에 개수(또는 값)에서 걸린 것입니다. 표의 개수는 규격의 최대값이고, 장비는 더 작은 한도를 둘 수 있습니다.
02: 주소 범위 — 규격의 예
규격 7장은 레지스터가 100개(0~99)인 장비를 예로 듭니다. 96 번부터 4개(96~99)는 성공하지만, 96 번부터 5개는 100 번 레지스터가 없으므로 전체가 예외 02 입니다. 위의 «01 03 00 60 00 05» 가 바로 그 요청(0x60 = 96)입니다. 하나라도 범위 밖이면 나머지도 읽히지 않으므로, 이어진 칸끼리만 묶어 읽습니다.
- 0 기준 주소와 1 기준(40001) 표기를 섞으면 한 칸 밀려 마지막 칸이 범위 밖이 되기 쉽습니다 — Modbus 주소 표기 글을 보세요.
- 매뉴얼의 레지스터 표 사이에 빈 주소가 있으면 그 칸을 걸쳐 읽을 때 02 를 돌려주는 장비가 많습니다.
- 03 으로 읽어 02 가 나면, 그 값이 입력 레지스터(04)에 있는 장비인지 매뉴얼의 함수 코드 칸을 봅니다.
03: 값 — 규격이 말하는 것과 말하지 않는 것
규격은 03 을 «요청 나머지 부분의 구조가 틀렸을 때(예: 암시된 길이가 틀림)» 라고 정의하고, «레지스터에 쓰려는 값이 응용 프로그램의 기대 범위를 벗어났다는 뜻이 아니다 — Modbus 는 레지스터 값의 의미를 모른다» 고 덧붙입니다. 범위 밖 쓰기 값을 장비가 03 으로 거절하는지, 받아서 무시하거나 잘라 쓰는지는 장비 매뉴얼에 있습니다.
04·06: 장비 상태
04 는 장비 안의 처리 오류이므로 장비 상태 표시와 매뉴얼의 오류 항목을 봅니다. 06(바쁨)은 같은 요청을 나중에 다시 보내면 되는 경우로, 요청을 너무 촘촘히 보낼 때 나기도 합니다 — 요청 간격을 늘립니다. 그 밖의 예외는 다시 보내도 같은 답이 오므로 재시도 대상이 아닙니다.
0A·0B: 게이트웨이 뒤 문제
Modbus TCP ↔ RTU 게이트웨이가 0A·0B 를 돌려주면 PC 와 게이트웨이 사이(TCP)는 정상입니다. 0B 는 게이트웨이 뒤 시리얼 장비가 답하지 않은 것이므로 Unit ID(= 시리얼 국번)·속도·패리티·RS-485 배선을 봅니다. 0A 는 게이트웨이의 포트·경로 설정을 봅니다.
매뉴얼에 나온 장비별 예
- 01: 루텍 Accura 3300E 는 함수 03·06·16 만 지원합니다 — 그 밖의 함수(예: 04)는 이 장비에게 «지원하지 않는 함수» 입니다.
- 03: 한 번에 읽는 개수 한도가 규격(125)보다 작은 장비 — LS ELECTRIC GIMAC1000 은 124개, 한영넉스 VX 는 FC03 으로 31개까지입니다.
- 쓰기만 예외: 한영넉스 LC 는 통신 쓰기 금지(CWP)가 출하 때 ON 이라 앞판에서 OFF 로 바꾸기 전까지 쓰기 요청을 예외로 거절합니다(매뉴얼 p.31·p.34).
PortDock 에서는
- 웹 도구 «Modbus 프레임 해석기»: 받은 바이트를 붙여 넣으면 예외 응답인지, 어떤 코드인지 풀어 줍니다(RTU·TCP).
- Modbus Master: 통신 기록에 예외 이름을 함께 적고, 표마다 예외 수를 셉니다. 예외 응답은 재시도하지 않습니다.
- Modbus Slave: «장애 주입» 으로 일부러 예외를 돌려줘 마스터·HMI 가 예외를 어떻게 처리하는지 미리 볼 수 있습니다.
작성 2026-10-23