在 Modbus 协议中,异常响应报文与正常响应报文在以下两个域中有所不同:
0
(即它们的值小于十六进制 0x80
)。1
。
0x80
。设置 MSB 的目的: 通过设置功能码的 MSB,客户端应用程序可以:
场景 | 功能码(十六进制) | MSB |
---|---|---|
正常响应 | 0x03(例如:读取保持寄存器) | 0 |
异常响应 | 0x83 | 1 |
字段 | 长度(字节) | 描述 |
---|---|---|
从机地址 | 1 | 响应的服务器(从机)的地址。 |
功能码 | 1 | 原始功能码 + 0x80(MSB 设置为 1)。 |
异常码 | 1 | 表示具体错误的异常码。 |
CRC 校验码 | 2 | 用于校验数据正确性的 CRC 校验。 |
0x06
(写单个寄存器),如果发生异常,则响应的功能码为 0x86
。0x80
。/**
* @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; // 返回帧长度
}
在解析接收到的数据帧时,根据功能码或数据有效性,调用异常码处理函数返回异常响应。
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;
}
}
主循环中将接收的数据解析并按需返回异常:
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; // 清空缓冲区
}
}
通过这种实现,Modbus 协议的功能和异常处理更清晰规范,满足嵌入式设备的实际需求。
本节内容已经全部介绍完毕,希望通过这篇文章,大家对
Modbus
异常码处理有了更深入的理解和认识。