值得收藏 Modbus RTU 协议详解

值得收藏!Modbus RTU 协议详解~


Modbus是什么?

         ~~~~~~~~         Modbus是一个总线协议,属于应用层的一层协议。应用层面的协议还有TCP、UDP。因modbus其协议流程简单明了,易于组网被广泛使用,目前应该是在工业上使用的最多的,像是与PLC通信。
         ~~~~~~~~         嵌入式领域最常见的用法就是硬件电路采用RS485,在此硬件基础上使用modbus。


Modbus分类

Modbus协议分为三种,包括:

  • Modbus-RTU
  • Modbus-ASCII
  • Modbus-TCP

最常见使用的就是RTU了,所以本篇的重点放在讲解RTU上。


Modbus通讯过程

         ~~~~~~~~         Modbus是主从方式通信,通信由主机发起,一问一答式,从机无法主动向主机发送数据。通信方式类似于IIC、SPI协议。

         ~~~~~~~~         modbus数据帧在传输过程中,两个字节之间的相邻时间不得大于3.5个字符的时间,否则视为一帧数据传输结束。

         ~~~~~~~~         以:波特率9600、1bit起始位、8bit数据位、1bit停止位,1bit校验位、无流控为例,那么1s内就可以传输(1+8+1+1)/9600*3.5*1000≈4ms,所以,如果从机在接收过程中,超过了4ms没有收到数据,则认为本帧数据接收结束;同样的,在发送完数据后也要延时等待4ms的延时时间。

《GB/T 19582.2》中规定:
         ~~~~~~~~         
         ~~~~~~~~         RTU模式中每个字节为11位,格式为:8bit数据位(先发低位)、1bit起始位、1bit奇偶校验、1bit停止位
         ~~~~~~~~         
         ~~~~~~~~         要求使用偶校验。也可以使用其他模式(奇校验、无校验)。为了保证与其他产品的最大兼容性,建议还支持无校验模式。默认校验模式必须是偶校验。
         ~~~~~~~~         
         ~~~~~~~~         注:使用无校验时要求2个停止位,以此来满足11bit的数据。
         ~~~~~~~~         
串行的传输字符的方法为:
发送每个字符或字节的顺序是从左到右,如下图:


Modbus-RTU协议数据帧结构

地址码功能码数据区CRC校验
1 Bytes1ByteN Bytes2Byte
  • 地址码:1个字节的从机地址码,=0:广播地址,=1-247:从机地址,=248-255:保留
  • 功能码:常用的就是01、02、03、04、05、06、15、16,具体描述见下图
  • 数据区:数据区包含这么几部分:起始地址、数量、数据,这三项是大端模式
  • CRC校验:两个字节,小端模式,校验的数据范围为:地址码+功能码+数据区

下面将实际将常用的6个功能码进行实际的演示示例。


功能码01:读线圈状态

示例1:读1个线圈状态,线圈地址为0:

主机发送:01 01 00 00 00 01 FD CA
从机返回:01 01 01 00 51 88

解析主机发送的数据:

010100 0000 01FD CA
从机地址功能码要读的线圈起始地址(大端模式)要读取的线圈数量(大端模式)CRC校验码(小端模式)

解析从机返回的数据,只说数据区:

  • 01:后跟的字节数
  • 00:线圈状态

示例2:读从线圈0开始的10个线圈状态:

主机发送:01 01 00 00 00 0A BC 0D
从机返回:01 01 02 00 00 b9 fc

解析从机返回的数据,只说数据区:

  • 02:后跟的字节数
  • 00 00:一个比特代表一个线圈的状态

功能码02:读离散量输入

协议格式同功能码01。


功能码03:读保持寄存器

示例1:读1个保持寄存器,保持寄存器地址为0:

主机发送:01 03 00 00 00 01 84 0A
从机接收:01 03 02 00 00 b8 44

解析主机发送的数据:

010300 0000 0184 0A
从机地址功能码要读取的保持寄存器起始地址(大端模式)要读取的保持寄存器数量(大端模式)CRC校验码(小端模式)

解析主机返回的数据,只说数据区:

  • 02:后跟的字节数
  • 00 00:读取到的保持寄存器的值,大端模式

示例2:读10个保持寄存器,保持寄存器起始地址为0:

主机发送:01 03 00 00 00 0A C5 CD
从机返回:01 03 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a3 67

解析主机返回的数据(只说数据区):

  • 14:后跟的字节数
  • 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00:读取到的保持寄存器的值,大端模式,一个寄存器值用2字节表示。

功能码04:读输入寄存器

协议格式同功能码03。


功能码05:写单个线圈

示例1:写线圈0为0:

主机发送:01 05 00 00 00 00 CD CA
从机返回:01 05 00 00 00 00 cd ca

解析主机发送的数据:

010500 0000 00CD CA
从机地址功能码要写的线圈地址(大端模式)要写的线圈状态(大端模式)CRC校验码(小端模式)

主机发送什么,从机原样返回。

示例2:写线圈0为1:

主机发送:01 05 00 00 FF 00 8C 3A
从机返回:01 05 00 00 ff 00 8c 3a

解析主机发送的数据,只说数据区:

  • 00 00:要写的线圈地址,大端模式
  • FF 00:要写的线圈状态,FF 00表示将线圈置1

功能码06:写单个寄存器

示例1:写寄存器0为0:

主机发送:01 06 00 00 00 00 89 CA
从机返回;01 06 00 00 00 00 89 CA

解析主机发送的数据:

010600 0000 0089 CA
从机地址功能码要写的寄存器地址(大端模式)要写的寄存器(大端模式)CRC校验码(小端模式)

主机发送什么,从机原样返回。

示例2:写寄存器0为1:

主机发送:01 06 00 00 00 01 48 0A
从机返回:01 06 00 00 00 01 48 0a


功能码15:写多个线圈

写从线圈编号0开始的10个线圈:0-3线圈写1,4-7线圈写0,8-9线圈写1(0F 03):
主机发送:01 0F 00 00 00 0A 02 0F 03 A0 C9
从机返回:01 0f 00 00 00 0a d5 cc

解析主机发送的数据:

010F00 0000 0A020F 03A0 C9
从机地址功能码要写的线圈起始地址(大端模式)要写的线圈数量(大端模式)后跟的字节数待写入的线圈状态,小端模式,换成比特由低位到高位就是:1111 0000 11XX XXXX,X表示未用到,一个比特代表一个线圈的状态CRC校验码(小端模式)

解析从机返回的数据,只说数据区:

  • 00 00:已写的线圈起始地址,大端模式
  • 00 0A:已写的线圈数量,大端模式

功能码16:写多个寄存器

写寄存器编号0开始的10个寄存器:0-3寄存器写1,4-7寄存器写0,8-9寄存器写1:
主机发送:01 10 00 00 00 0A 14 00 01 00 01 00 01 00 01 00 00 00 00 00 00 00 00 00 01 00 01 4F 13
从机返回:01 10 00 00 00 0a 40 0e

解析主机发送的数据:

011000 0000 0A1400 01 00 01 00 01 00 01 00 00 00 00 00 00 00 00 00 01 00 014F 13
从机地址功能码要写的寄存器起始地址(大端模式)要写的寄存器数量(大端模式)后跟的字节数待写入的寄存器值,大端模式,两个字节代表一个寄存器的值CRC校验码(小端模式)

解析从机返回的数据,只说数据区:

  • 00 00:已写的寄存器起始地址,大端模式
  • 00 0A:已写的寄存器数量,大端模式

附录:Modbus CRC校验函数C语言实现

USHORT usMBCRC16( UCHAR * pucFrame, USHORT usLen )
{
    static const UCHAR aucCRCHi[] =
    {
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40
    };

    static const UCHAR aucCRCLo[] =
    {
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
        0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
        0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
        0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
        0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
        0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
        0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
        0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
        0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
        0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
        0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
        0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
        0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
        0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
        0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
        0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
        0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
        0x41, 0x81, 0x80, 0x40
    };
    UCHAR           ucCRCHi = 0xFF;
    UCHAR           ucCRCLo = 0xFF;
    int             iIndex;

    while( usLen-- )
    {
        iIndex = ucCRCLo ^ *( pucFrame++ );
        ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] );
        ucCRCHi = aucCRCLo[iIndex];
    }
    return ( USHORT )( ucCRCHi << 8 | ucCRCLo );
}


modbus相关文章推荐:


ends…完!

  • 137
    点赞
  • 1041
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
### 回答1: Modbus RTU是一种串行通信协议,用于在工业自动化、过程控制和建筑自动化等领域中的设备之间传输数据。Modbus RTU协议Modbus协议的一种实现方式,它将数据封装在串行通讯帧中,并采用CRC校验的方式进行校验,以确保数据传输的可靠性。 Modbus RTU协议主要由应用层、传输层和物理层组成。应用层定义了Modbus RTU消息的格式、功能码和数据格式,传输层将应用层消息组成数据帧用于传输,并提供错误检测和纠错功能,物理层则定义了Modbus RTU消息的电气和物理特征,例如传输速率和电压电平等。 Modbus RTU协议具有简单、开放、实用等特点,可以在各种设备之间传输数据。它被广泛应用于工业自动化、过程控制和建筑自动化等领域。Modbus RTU协议还支持多主从节点之间的通信,使得多个设备可以同时进行数据通信。 总之,Modbus RTU协议是一种用于串行通信的协议,具有可靠、简单、开放、实用等特点,被广泛应用于工业自动化、过程控制和建筑自动化等领域。 ### 回答2: Modbus RTU协议是一种串行通信协议,用于在工业自动化系统中控制和监测设备之间进行通信。它使用RS-485物理层,是Modbus协议的一种常用形式,也是现在广泛应用的最常见的工业通信协议之一。 Modbus RTU协议基于传统的Modbus协议,但它的数据位数可以由原来的8位扩展到16位,这意味着它可以传输更多的数据。此外,它还使用了CRC校验来确保数据传输的正确性和完整性。 Modbus RTU采用了主从架构模式,即主设备向从设备发送指令请求,而从设备则执行这些指令并将结果返回给主设备。此外,该协议还支持多个从设备和一个主设备进行通信。 Modbus RTU协议应用广泛,被用于许多工业自动化应用,如工厂自动化、过程控制、楼宇自动化、能源管理等领域,它可以大大提高工业系统中数据的可靠性和效率。 总的来说,Modbus RTU协议是一种通用的工业通信协议,它能够提供安全稳定的通信连接,能够实现工业自动化系统之间设备间的可靠数据传输和共享。 ### 回答3: Modbus是一种常用的工业通信协议,它能够使用各种串行或现场总线网络来传输控制器和设备之间的信息。Modbus RTUModbus协议最常用的变种之一,该协议适用于串行通信,并在现场总线网络中也得到广泛使用。 Modbus RTU协议特点: 1. 数据传输快速且可靠:Modbus RTU协议在数据传输中被高度优化,能够以高达115200bps的速率传输数据。 2. 通信设备数量多:Modbus RTU协议使用简单的串行通信方式,可以将多个设备连接在同一条通信线上。 3. 常用于工业控制领域:Modbus RTU协议广泛应用于工业控制系统领域,包括制造业、能源行业、化工行业等。 Modbus RTU的核心内容包括使用CRC校验值的帧结构、寄存器和离散寄存器的操作方式、功能码和地址等,下面简述其主要操作方式: 1. 保持寄存器和输入寄存器:Modbus RTU协议中保持寄存器和输入寄存器是常用的交换数据的方式。保持寄存器在设备中存储了当前状态的值,输入寄存器则是设备提供给主机持续更新的值。 2. 离散寄存器和线圈:Modbus RTU协议中离散寄存器主要用于存储离散状态,例如开关、按钮的状态等。线圈则主要用于输出控制。主机可以通过读取它们的状态来获取设备的状态并控制其行为。 3. 功能码和地址:使用Modbus RTU协议时,主机可以通过发送具体功能码和地址操作设备寄存器。目前常用的功能码包括读取保持寄存器和线圈、写保持寄存器和线圈、读取输入寄存器和离散寄存器等。 总之,Modbus RTU协议是工业通信中常用且可靠的协议。掌握其协议格式、寄存器操作等内容能够帮助工程师更好的实现工业控制系统的数据采集、监控和控制等功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

觉皇嵌入式

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

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

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

打赏作者

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

抵扣说明:

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

余额充值