Modbus 异常响应码与故障排查完全手册:从 01 到 11 的完整분석

무료무료 기술 자료

이 글은 바로 읽을 수 있으며 기초 학습과 검색 유입에 적합합니다.

Modbus 异常响应码与故障排查完全手册:从 01 到 11 的完整분석

关键词:Modbus 异常码、Modbus 故障排查、Modbus 错误码、Modbus Exception Code、Modbus 통신故障

在산업 자동화现场,Modbus 통신故障是最让엔지니어링师头疼的문제之一。当마스터发出请求后,슬레이브返回的不是正常데이터,而是一个「异常响应」——这表明통신链路没有문제,但业务逻辑层出现了错误。理解每一个异常码的含义、触发条件和排查方法,是每一位自动化엔지니어링师的必修课。

本文将从 Modbus 프로토콜사양(V1.1b3)出发,结合真实工业现场案例,深入분석전체 11 个표준异常码的触发机制、排查流程和솔루션。无论您是初次接触 Modbus 的新手,还是希望系统化梳理知识的老兵,都能从本文中找到实用的参考。

一、Modbus 异常响应的基本机制

Modbus 异常响应码与故障排查完全手册:从 01 到 11 的完整解析插图
▲ 图1:正常请求帧与异常响应帧형식对比。异常时기능 코드最高位置1(+0x80),紧跟1바이트异常码。

1.1 正常响应 vs 异常响应

在 Modbus 프로토콜中,마스터(Master/Client)向슬레이브(Slave/Server)보내기请求프레임,슬레이브处理后返回响应프레임。当一切正常时,响应的기능 코드与请求的기능 코드完全一致:

请求: [슬레이브 주소] [기능 코드 0x03] [시작주소高바이트] [시작주소低바이트] [레지스터 수량高바이트] [레지스터 수량低바이트] [CRC低] [CRC高]
正常响应: [슬레이브 주소] [기능 코드 0x03] [바이트数] [데이터...] [CRC低] [CRC高]

当슬레이브无法正常处理请求时,它会将기능 코드的最高位(bit 7)置为 1,并在데이터区放入一个바이트的异常码。也就是说,异常기능 코드 = 请求기능 코드 + 0x80。例如,请求기능 코드 0x03 出现异常时,响应기능 코드变为 0x83。

异常响应프레임结构(RTU 모드):
[슬레이브 주소] [기능 코드+0x80] [异常码] [CRC低] [CRC高]

예제 - 请求不存在的레지스터주소:
请求: 01 03 27 10 00 01 [CRC]
异常响应: 01 83 02 [CRC]  
→ 기능 코드 0x83 = 0x03 + 0x80,异常码 0x02 = 非法데이터주소

1.2 异常响应的判断逻辑

Modbus 异常响应码与故障排查完全手册:从 01 到 11 的完整解析插图1
▲ 图2:통신故障排查决策树 — 从物理层到적용层的系统化诊断流程。

当您在디버깅 도구(如 Modbus Poll、ModScan)中看到슬레이브返回的데이터时,判断是否为异常响应非常简单:

  1. 보기响应기능 코드是否大于 0x80(即最高位为 1)
  2. 如果기능 코드 > 0x80,则第二个바이트即为异常码
  3. 根据异常码查表确定错误유형

在编程实现中,检测逻辑如下:

// C 언어异常响应检测예제
if (response_function_code & 0x80) {
    uint8_t exception_code = response_데이터[0];
    switch (exception_code) {
        case 0x01: // 非法기능 코드
        case 0x02: // 非法데이터주소
        case 0x03: // 非法데이터值
        // ... 其他异常码处理
    }
}

二、11 个표준异常码完全분석

Modbus 프로토콜사양定义了 11 个표준异常码(0x01 ~ 0x0B)。下面逐一深度분석每个异常码的含义、触发条件、典型시나리오和排查方法。

异常码 0x01 — 非法功能(Illegal 기능)

Modbus 异常响应码与故障排查完全手册:从 01 到 11 的完整解析插图2
▲ 图3:8种표준异常码速查表 — 一表掌握所有异常原因与솔루션。

含义:슬레이브不支持请求的기능 코드。这是最常见的异常码之一,通常发生在마스터使用了슬레이브未实现的기능 코드时。

典型触发시나리오:

  • 기능 코드超出范围:마스터보내기了기능 코드 0x14(读文件记录),但슬레이브只实现了 0x03、0x04、0x06、0x10
  • PLC 型号不支持:部分低端 PLC 只支持 0x03 和 0x06,尝试使用 0x10(写多个레지스터)会返回 0x01
  • 设备설정错误:某些设备的 Modbus 实现通过설정开关활성화/禁用기능 코드,如果对应功能被禁用,同样返回 0x01
  • 게이트웨이转换문제:Modbus TCP 到 RTU 的게이트웨이可能不支持某些기능 코드的透传

排查步骤:

  1. 查阅设备手册,确认슬레이브支持哪些기능 코드
  2. 使用 Modbus Poll 等도구逐一测试기능 코드,缩小문제范围
  3. 检查게이트웨이/컨버터的기능 코드过滤설정
  4. 如果使用自研程序,确认기능 코드常量定义是否正确

实际案例:某水处理项目中,上位机使用기능 코드 0x17(读/写多个레지스터)操作施耐德 PM800 电力仪表,始终返回异常码 0x01。经查手册发现 PM800 只支持 0x03 和 0x10。솔루션:拆分为先 0x03 읽기、再 0x10 쓰기两步操作。

异常码 0x02 — 非法데이터주소(Illegal 데이터 주소)

含义:请求的레지스터주소在슬레이브中不存在。这是엔지니어링师在디버깅阶段最容易遇到的异常码。

典型触发시나리오:

  • 주소偏移错误:PLC 的 Modbus 주소通常从 0 开始,但上位机설정时可能填了 1 시작的주소
  • 레지스터范围越界:请求的시작주소 + 数量超出了슬레이브的最大레지스터范围
  • 주소映射错误:有些设备使用不同的주소映射表(如有些设备 40001 对应内部주소 0,有些对应 1)
  • 데이터유형混淆:32 位浮点数占用 2 个레지스터,如果只请求 1 个레지스터,可能触发越界

排查步骤:

  1. 使用 0x03 기능 코드,从주소 0 开始逐一읽기,确定有效주소范围
  2. 确认设备手册中的주소是「프로토콜주소」还是「PLC 주소」——两者可能相差 1
  3. 对于 32 位데이터,确保请求的레지스터 수량为偶数
  4. 检查프레임中주소的大小端바이트序是否正确

异常码 0x03 — 非法데이터值(Illegal 데이터 Value)

含义:요청 내数值在슬레이브的允许范围之外。这不涉及주소문제,而是「值」的문제。

典型触发시나리오:

  • 쓰기值超出范围:온도设定值范围为 0~100°C,但마스터쓰기了 150
  • 레지스터 수량不合法:0x10 기능 코드的「레지스터 수량」필드为 0 或超过了슬레이브单次可处理的最大值(通常为 123)
  • 바이트数不일치:0x10 기능 코드的「바이트数」필드与「레지스터 수량 × 2」不一致
  • 프레임길이错误:整个프레임的实际길이与报头中声明的길이不符

排查步骤:

  1. 重点检查 0x10(写多个레지스터)的프레임结构——这是最容易出错的시나리오
  2. 验证「바이트数 = 레지스터 수량 × 2」是否成立
  3. 确认쓰기值是否在设备手册规定的范围内
  4. 对于 0x06(写单个레지스터),检查쓰기值的范围(0x0000 ~ 0xFFFF)

异常码 0x04 — 슬레이브设备故障(Slave Device Failure)

含义:슬레이브在处理请求时发生了不可恢复的内部错误。这是一个「万金油」异常码,表示슬레이브自身出现了严重문제。

典型触发시나리오:

  • EEPROM/Flash 쓰기失败:슬레이브将설정쓰기非易失性存储器时失败
  • 센서故障:슬레이브연결的센서损坏,无法提供有效读数
  • 内部통신故障:슬레이브内部的主控芯片与外设之间的통신异常
  • 文件系统错误:涉及文件操作的기능 코드(0x14、0x15)遇到文件系统异常

排查步骤:

  1. 检查슬레이브设备的电源是否稳定
  2. 보기슬레이브的 LED 指示灯状态(通常有故障灯)
  3. 尝试对슬레이브进行断电重启
  4. 문의设备厂商获取诊断도구或固件업그레이드

异常码 0x05 — 确认(Acknowledge)

含义:슬레이브已经接受请求,但需要较长时间来处理。这不是一个错误,而是一个「请稍候」的信号。슬레이브正在执行操作,处理完成后会返回正常响应。

典型触发시나리오:

  • EEPROM 쓰기耗时较长:某些设备的非易失性存储器쓰기可能需要数百毫秒
  • 固件업그레이드操作:쓰기程序存储器需要较长时间
  • 모터执行动作:슬레이브正在执行物理动作(如阀门开关)

编程建议:마스터收到异常码 0x05 后,不应바로重试或报错,而应대기适当时间后重新轮询。建议使用状态机处理:

// 异步处理确认响应的状态机
enum { IDLE, WAITING, POLLING } state = IDLE;

void modbus_handler(uint8_t func, uint8_t* 데이터) {
    if (func & 0x80) {
        if (데이터[0] == 0x05) {
            state = POLLING;
            시작_poll_timer(500); // 500ms 后重新查询
        }
    }
}

异常码 0x06 — 슬레이브设备忙(Slave Device Busy)

含义:슬레이브正在处理一个耗时较长的命令,暂时无法响应新的请求。与 0x05 的区别在于:0x05 是「我在处理你刚发的请求」,0x06 是「我现在没空处理任何请求」。

典型触发시나리오:

  • 슬레이브在执行耗时操作:如固件업그레이드、大量데이터拷贝
  • 슬레이브 CPU 负载过高:硬件性能有限,无法及时处理 Modbus 请求
  • 슬레이브正在进行自诊断:部分设备在启动时会执行自检,期间不响应통신

排查步骤:

  1. 适当추가마스터的轮询间隔(如从 100ms 추가到 500ms)
  2. 减少同时통신的슬레이브数量
  3. 检查슬레이브的固件버전,确认是否有已知的性能문제

异常码 0x07 — 否定确认(Negative Acknowledge)

含义:슬레이브无法执行요청 내编程功能。这是专门为 0x0D(编程功能)设计的异常码,表示编程请求被拒绝。

典型触发시나리오:

  • 编程请求유형不支持:슬레이브的编程功能有限,不支持特定的编程操作
  • 编程매개변수无效:请求中包含了不支持的编程매개변수

注意事项:异常码 0x07 在 Modbus 프로토콜사양 V1.1b3 中定义,但实际上绝大多数 Modbus 设备并不实现기능 코드 0x0D(编程),因此这个异常码在现实中极少遇到。

异常码 0x08 — 存储器奇짝수 패리티错误(Memory Parity 오답)

含义:슬레이브在읽기文件记录时,检测到存储器奇짝수 패리티错误。仅与文件操作기능 코드(0x14、0x15)相关。

典型触发시나리오:

  • 文件记录损坏:文件存储区域因电源故障或其他原因데이터损坏
  • Flash 存储器老化:频繁쓰기导致 Flash 存储单元的可靠性下降

异常码 0x0A — 게이트웨이路径不可用(Gateway Path Unavailable)

含义:게이트웨이无法建立到目标设备的内部통신路径。这通常发生在게이트웨이연결了多个下游设备时。

典型触发시나리오:

  • 下游设备离线:게이트웨이后的 Modbus RTU 设备断电或断开연결
  • 下游设备주소错误:게이트웨이被설정为转发到不存在的슬레이브 주소
  • 게이트웨이内部路由表错误:게이트웨이的路由설정不正确

排查步骤:

  1. 检查게이트웨이下游设备的통신状态指示灯
  2. 使用 Modbus Poll 直接연결下游设备,排除设备本身故障
  3. 检查게이트웨이的路由表설정
  4. 确认下游设备的 Modbus 주소和통신 속도设置

异常码 0x0B — 게이트웨이目标设备响应失败(Gateway Target Device Failed to Respond)

含义:게이트웨이能够建立통신路径,但目标设备未能提供有效响应。与 0x0A 的区别:0x0A 是게이트웨이内部路径不通,0x0B 是路径通了但目标设备无响应。

典型触发시나리오:

  • 目标设备繁忙:设备正在处理上一条指令
  • 目标设备响应超时:Modbus RTU 的 3.5 문자超时机制触发
  • 데이터형식不일치:下游设备的통신매개변수(통신 속도、체크섬 방식)与게이트웨이设置不一致

三、异常码速查表

异常码 名称(英文) 名称(중국어) 常见程度
0x01Illegal 기능非法功能★★★★★
0x02Illegal 데이터 주소非法데이터주소★★★★★
0x03Illegal 데이터 Value非法데이터值★★★★☆
0x04Slave Device Failure슬레이브设备故障★★★☆☆
0x05Acknowledge确认(대기中)★★★☆☆
0x06Slave Device Busy슬레이브设备忙★★★☆☆
0x07Negative Acknowledge否定确认★☆☆☆☆
0x08Memory Parity 오답存储器체크섬错误★☆☆☆☆
0x0AGateway Path Unavailable게이트웨이路径不可用★★☆☆☆
0x0BGateway Target Failed게이트웨이目标响应失败★★☆☆☆

四、深度故障排查方法论

4.1 分层排查法

工业통신故障排查应遵循「自底向上」的原则,从物理层逐步向上层排查:

  1. 物理层:检查线缆연결、终端电阻、设备전원 공급、接地情况
  2. 데이터链路层:使用示波器或逻辑分析仪检查 RS-485 信号质量
  3. 네트워크层:在 Modbus TCP 시나리오下,使用 Wireshark 抓包分析
  4. 적용层:使用 Modbus Poll 等도구보내기最小化请求来定位문제

4.2 对比排除法

当现场有多个同型号设备时,使用对比排除法是最高效的定位手段:

  1. 将疑似故障设备与正常工作的设备交换位置
  2. 使用同一台마스터도구分别测试两台设备
  3. 比较两台设备的响应프레임差异

4.3 最小化复现法

将复杂请求简化为最简单的合法请求,逐步추가复杂度:

步骤 1: 보내기最简请求 01 03 00 00 00 01 [CRC] —— 읽기주소 0 的 1 个레지스터
步骤 2: 如果成功,逐步추가레지스터 수량 00 02, 00 03 ...
步骤 3: 如果失败,缩小주소范围排查

五、RTU 与 TCP 모드下的异常差异

虽然异常码的定义在 RTU 和 TCP 모드下完全一致,但两种모드下的异常处理流程有所不同:

对比维度Modbus RTUModbus TCP
超时处理3.5 문자时间无响应判定超时TCP 연결超时由操作系统控制
异常检测CRC 검증错误直接丢弃프레임TCP 层保证데이터完整性
MBAP 报头无需要检查트랜잭션 식별자일치
게이트웨이시나리오较少涉及异常码 0x0A/0x0B 更常见

六、编程实现:异常处理的最佳实践

以下是使用 C 언어实现 Modbus 异常处理的完整예제,适用于嵌入式系统개발:

/**
 * Modbus 异常码处理函数
 * @param func      请求기능 코드
 * @param exception 异常码
 * @return 人类可读的错误설명문자串
 */
const char* modbus_exception_str(uint8_t func, uint8_t exception) {
    static char buf[128];
    const char* exc_name;
    
    switch (exception) {
        case 0x01: exc_name = "非法기능 코드"; break;
        case 0x02: exc_name = "非法데이터주소"; break;
        case 0x03: exc_name = "非法데이터值"; break;
        case 0x04: exc_name = "슬레이브设备故障"; break;
        case 0x05: exc_name = "确认(대기中)"; break;
        case 0x06: exc_name = "슬레이브设备忙"; break;
        case 0x07: exc_name = "否定确认"; break;
        case 0x08: exc_name = "存储器체크섬错误"; break;
        case 0x0A: exc_name = "게이트웨이路径不可用"; break;
        case 0x0B: exc_name = "게이트웨이目标响应失败"; break;
        default:   exc_name = "未知异常码"; break;
    }
    
    snprintf(buf, sizeof(buf), 
             "Modbus 异常: 기능 코드 0x%02X → 异常码 0x%02X (%s)",
             func, exception, exc_name);
    return buf;
}

/**
 * 处理 Modbus 响应
 * 返回 0 表示正常响应,负值表示异常
 */
int modbus_handle_response(uint8_t* rsp, int rsp_len,
                           uint8_t expected_func) {
    if (rsp_len < 2) return -1; // 响应길이异常
    
    uint8_t func = rsp[1]; // RTU 모드下,第二个바이트是기능 코드
    
    if (func & 0x80) {
        // 异常响应
        uint8_t exception = rsp[2];
        log_error(modbus_exception_str(func & 0x7F, exception));
        
        // 根据异常码采取不同的重试策略
        switch (exception) {
            case 0x01: // 기능 코드不支持 - 不重试
            case 0x02: // 주소非法 - 不重试
                return -exception;
            case 0x05: // 确认 - 대기后重试
            case 0x06: // 设备忙 - 지연重试
                return -exception; // 调用者处理重试逻辑
            default:
                return -exception;
        }
    }
    
    // 正常响应处理...
    return 0;
}

七、常见문제 FAQ

Q1: Modbus 슬레이브返回了异常码 0x02,但주소看起来是正确的,为什么?

最常见的原因是「주소偏移 1」的문제。某些设备(特别是 PLC)的 Modbus 주소与프로토콜주소存在 1 的偏移。比如 PLC 端설정주소为 40001,但 Modbus 프로토콜中对应的内部주소是 0(而不是 1)。请查阅设备手册确认주소映射关系。

Q2: 为什么슬레이브有时返回正常데이터,有时返回异常码 0x06?

这通常意味着슬레이브的 CPU 处理能力不足。当轮询频率过高时,슬레이브来不及处理所有请求,就会返回 0x06。解决方法:降低轮询频率,或减少单次请求的레지스터 수량。

Q3: 异常码 0x05 和 0x06 有什么区别?

0x05(确认):슬레이브已经在处理你보내기的特定请求,需要대기完成。0x06(设备忙):슬레이브当前无法处理任何新请求,原因可能是任意操作。简单记忆:0x05 是「你的事我在办」,0x06 是「我现在很忙谁都别来」。

Q4: 슬레이브完全不响应(超时),而不是返回异常码,该怎么排查?

完全无响应通常意味着문제在物理层或데이터链路层:

  1. 检查슬레이브 주소是否正确(주소不일치是슬레이브静默的最常见原因)
  2. 检查 RS-485 的 A/B 线是否接反
  3. 检查통신 속도和체크섬 방식是否일치
  4. 检查终端电阻和偏置电阻
  5. 使用示波器确认总线上是否有信号

八、总结

Modbus 的异常响应机制是프로토콜设计中的一大亮点——它不是简单地让통신失败,而是通过异常码精确地告诉마스터「哪里出了문제」。掌握这些异常码的含义和排查方法,可以将故障定位时间从数小时缩短到数分钟。

建议将本文的异常码速查表打印出来贴在工位旁,或者在디버깅 도구中통합异常码自动분석功能。在工业现场,每一分钟的停机都意味着真金白银的损失——而快速定位 Modbus 异常码,往往是解决문제的第一步。

相关阅读:Modbus 기능 코드完全분석 | Modbus RTU 与 TCP 深度对比 | Modbus CRC 검증원리与编程实现

실제 프로젝트에 이 자료를 활용하시겠습니까?

도구 센터에서 프레임 분석, CRC 검증, 장비 디버깅을 진행하거나 요청을 제출하여 선정 및 연동 제안을 받아보세요.

엔지니어 회원

이 글을 실행 가능한 디버깅 자료로 활용하세요

가입하면 고급 프레임 분석, 자료 패키지 다운로드, 코드 예제, 엔지니어링 사례, 우선 기술 지원을 이용할 수 있어 실제 프로젝트 납품에 적합합니다.

고급 도구 무제한 이용
자료 패키지와 코드 패키지
완전한 엔지니어링 사례 라이브러리
우선 기술 지원 채널

답글 작성

이메일 주소는 공개되지 않습니다. 必填项已用 * 标注