【嵌入式】Modbus协议异常码函数 - 原理及C语言实现

LuckiBit

在 Modbus 协议中,异常码是用来表示错误状态的。每当接收到一个无效请求或在处理请求时发生错误,主机或从机需要返回一个异常响应。

1. Modbus 异常响应报文

在 Modbus 协议中,异常响应报文与正常响应报文在以下两个域中有所不同:

1.1 功能码域

  • 正常响应:
    在正常响应中,服务器利用功能码域来应答最初请求的功能码。

    • 所有功能码的**最高有效位(MSB)**都为 0(即它们的值小于十六进制 0x80)。
  • 异常响应:
    在异常响应中,服务器会将功能码的MSB 设置为 1

    • 这使得异常响应中的功能码值比正常响应中的功能码值高出十六进制 0x80

设置 MSB 的目的:
通过设置功能码的 MSB,客户端应用程序可以:

  • 识别该响应是异常响应。
  • 检测数据域中返回的异常码。
场景功能码(十六进制)MSB
正常响应0x03(例如:读取保持寄存器)0
异常响应0x831

1.2 数据域

  • 正常响应:
    在正常响应中,服务器可以在数据域中返回数据或统计表(即客户端请求的内容)。

  • 异常响应:
    在异常响应中,服务器会在数据域中放置一个异常码

    • 该异常码定义了导致异常的服务器状态。

示例:异常响应结构

字段长度(字节)描述
从机地址1响应的服务器(从机)的地址。
功能码1原始功能码 + 0x80(MSB 设置为 1)。
异常码1表示具体错误的异常码。
CRC 校验码2用于校验数据正确性的 CRC 校验。

示例:异常响应功能码和异常码说明

  1. 异常功能码:
    • 假设原始请求功能码为 0x06(写单个寄存器),如果发生异常,则响应的功能码为 0x86

2. Modbus 异常码处理说明

  1. 异常响应格式

    • 异常响应的功能码为请求功能码的高位加上 0x80
    • 数据域只包含一个字节,表示异常码。
  2. 常见 Modbus 异常码

    异常码名称含义
    0x01非法功能功能码不被支持
    0x02非法数据地址地址超出范围
    0x03非法数据值数据值无效
    0x04从机设备故障从机设备发生不可恢复的错误
    0x05确认请求正在处理
    0x06从机忙从机忙于处理长操作,无法接受新请求
    0x08内存奇偶校验错误存储设备存在错误
    0x0A网关路径不可用网关无法路由请求
    0x0B网关目标设备响应失败网关未接收到目标设备的响应
  3. 实现 Modbus 异常码返回函数

    • 该函数根据请求的功能码和异常码生成完整的异常帧。

3. 异常码函数实现

/**
 * @brief 生成 Modbus 异常响应帧
 * @param buffer 存储异常响应帧的缓冲区
 * @param function_code 请求的功能码
 * @param exception_code 异常码
 * @return 返回异常响应帧的长度
 */
unsigned char modbus_exception_response(unsigned char *buffer, unsigned char function_code, unsigned char exception_code)
{
    unsigned int crc;

    buffer[0] = modbus.slave_address;              // 从机地址
    buffer[1] = function_code | 0x80;             // 异常功能码
    buffer[2] = exception_code;                   // 异常码

    crc = crc16(buffer, 3);                       // 计算 CRC 校验
    buffer[3] = crc & 0xFF;                       // CRC 低字节
    buffer[4] = (crc >> 8) & 0xFF;                // CRC 高字节

    return 5;                                     // 返回帧长度
}

4. 异常码处理的调用示例

在解析接收到的数据帧时,根据功能码或数据有效性,调用异常码处理函数返回异常响应。

示例:功能码解析时返回异常

void modbus03_handler(const unsigned char *request, unsigned char length)
{
    unsigned char response[256];
    unsigned char response_length;

    if (length < 6)  // 请求长度不正确
    {
        response_length = modbus_exception_response(response, 0x03, 0x03);  // 非法数据值
        uart_send_frame(response, response_length);  // 发送异常响应
        return;
    }

    // 数据解析和处理逻辑...

    // 如果某些数据超出范围
    if (invalid_data)
    {
        response_length = modbus_exception_response(response, 0x03, 0x02);  // 非法数据地址
        uart_send_frame(response, response_length);
        return;
    }

    // 正常处理逻辑...
}

示例:未实现的功能码处理

void modbus_function_handler(unsigned char function_code, const unsigned char *request, unsigned char length)
{
    unsigned char response[256];
    unsigned char response_length;

    switch (function_code)
    {
        case 0x03:
            modbus03_handler(request, length);
            break;
        case 0x06:
            modbus06_handler(request, length);
            break;
        case 0x10:
            modbus10_handler(request, length);
            break;
        default:  // 非法功能码
            response_length = modbus_exception_response(response, function_code, 0x01);  // 非法功能
            uart_send_frame(response, response_length);
            break;
    }
}

5. 主程序调用结构

主循环中将接收的数据解析并按需返回异常:

void process_uart_data(void)
{
    if (rx_complete)
    {
        rx_complete = 0;  // 清除标志位

        if (rx_index < 2)  // 数据帧长度不足
        {
            unsigned char response[256];
            unsigned char response_length = modbus_exception_response(response, 0x00, 0x03);  // 非法数据值
            uart_send_frame(response, response_length);
            return;
        }

        unsigned char function_code = rx_buffer[1];
        modbus_function_handler(function_code, rx_buffer, rx_index);

        rx_index = 0;  // 清空缓冲区
    }
}

6. 总结

  • 扩展性:异常码函数可以直接调用,适用于所有功能码。
  • 模块化:每个功能码独立封装,方便维护和扩展。
  • 标准化:按照 Modbus 协议定义,异常响应帧格式清晰。
  • 稳定性:接收到错误请求时,从机能快速返回明确的异常信息,提高系统稳定性和容错性。

通过这种实现,Modbus 协议的功能和异常处理更清晰规范,满足嵌入式设备的实际需求。

7. 结束语

  1. 本节内容已经全部介绍完毕,希望通过这篇文章,大家对 Modbus 异常码处理有了更深入的理解和认识。
  2. 感谢各位的阅读和支持,如果觉得这篇文章对你有帮助,请不要吝惜你的点赞和评论,这对我们非常重要。再次感谢大家的关注和支持点我关注❤️

相关文章:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LuckiBit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值