Modbus RTU协议简介及CRC算法实现

1 Modbus 介绍

  Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。
  Modbus协议目前存在用于串口、以太网以及其他支持互联网协议的网络的版本。大多数Modbus设备通信通过串口EIA-485物理层进行。
  对于串行连接,存在两个变种,它们在数值数据表示不同和协议细节上略有不同。Modbus RTU是一种紧凑的,采用二进制表示数据的方式,Modbus ASCII是一种人类可读的,冗长的表示方式。这两个变种都使用串行通信(serial communication)方式。RTU格式后续的命令/数据带有循环冗余校验的校验和,而ASCII格式采用纵向冗余校验的校验和。被配置为RTU变种的节点不会和设置为ASCII变种的节点通信,反之亦然。
  本文描述是正是Modbus RTU中使用的校验和算法。
  MODBUS 通讯方式采用主从方式的查询相应机制,只有主站发出查询时,从站才能给出响
应,从站不能主动发送数据。主站可以向某一个从站发出查询,也可以向所有从站广播信息。
从站只响应单独发给它的查询,而不响应广播消息。

2 Modbus RTU协议传输方式

  串口配置每个字节的数据位:1 个起始位、8 个数据位、1 个停止位(无奇偶校验位)。
MODBUS-RTU 数据帧的结构:
 数据帧的结构

说明:

  • 数据字段中多字节成员是按网络字节序即高位在前。
  • 校验字段两个字节是小端字节序即低位在前。
  • 校验码是对其前面地址码,功能码和数据码的校验值。

2.1 地址码

  由一个字节(8 位二进制码)组成,各从机设备的寻址范围 01~F7(转成十进制 1~247),
其它地址保留。

2.2 功能码

  功能码告诉了被寻址到的终端执行何种功能。

2.3 数据码

  数据码包含了 终端执行特定功能所需要的数据或者终端响应查询时采集到的数据。这些数据的内容可能是数值、参考地址或者设置值。例如:功能域码告诉终端 读取一个寄存器,数据域则需要反映明从哪个寄存器开始及读取多少个数据,而从机数据码回送内容则包含了数据长度和相应的数据。

2.4 校验码

  校验码错误校验(CRC)域占用两个字节,包含了一个 16 位的二进制值。CRC 值由传输设
备计算出来,然后附加到数据帧上,接收设备在接收数据时重新计算 CRC 值,然后与接收到的
CRC 域中的值进行比较。如果这两个值不相等,就发生了错误。
  生成一个 CRC 的流程为:

  1. 预置一个 16 位寄存器为 OFFFFH(16 进制,全 1),称之为 CRC 寄存器。
  2. 把数据帧中的第一个字节的 8 位与 CRC 寄存器中的低字节进行异或运算,结果存回 CRC
    寄存器。
  3. 将 CRC 寄存器向右移一位,最高位填以 0,最低位移出并检测。
  4. 上一步中被移出的那一位如果为 0:重复第三步(下一次移位);为 1:将 CRC 寄存器与
    一个预设的固定值(多项式 0A001H)进行异或运算。
  5. 重复第三点和第四步直到 8 次移位。这样处理完了一个完整的八位。
  6. 重复第 2 步到第 5 步来处理下一个八位,直到所有的字节处理结束。
  7. 最终 CRC 寄存器的值就是 CRC 的值。

3 CRC算法实现

2.1 代码

#include <cstdint>
#include <cstdio>

//MODBUS-RTU协议使用的CRC16算法
uint16_t modbus_crc16(uint8_t *data, uint16_t size)
{
    uint16_t crc = 0xFFFF;
    for(uint16_t i = 0; i < size; ++i)
    {
        crc ^= (*data++);
        for(uint8_t b = 0; b < 8; ++b)
        {
            if(!(crc & 0x1))
                crc >>= 1;
            else
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
        }
    }
    return crc;
}

int main()
{
    uint8_t data1[] = { 0x01, 0x06, 0x00, 0x10, 0x00, 0x03 };
    uint8_t data2[] = { 0x01, 0x06, 0x00, 0x10, 0x00, 0x01 };
    uint16_t crc1 = modbus_crc16(data1,sizeof(data1));
	uint16_t crc2 = modbus_crc16(data2,sizeof(data2));
    printf("crc1: %02X %02X\n", (crc1 & 0xFF), (crc1 >> 8));
	printf("crc2: %02X %02X\n", (crc2 & 0xFF), (crc2 >> 8));
    return 0;
}

3.2 运行结果

运行结果:

$ ./modbuscrc
crc1: C8 0E
crc2: 49 CF
  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

flysnow010

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

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

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

打赏作者

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

抵扣说明:

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

余额充值