Modbus学习

一、初识Modbus

Modbus 是应用层的协议,需要借助其他协议,如物理层协议UART、RS485等协议传输,或者传输层TCPIP协议传输。

协议分支有:

Modbus RTU (最根本的协议)Modbus ASCII 、Modbus TCP/IP 、Modbus over TCP/IP 、Modbus UDP

常用接口(物理层):

  • RS232通讯

    全双工,这个基本用在点对点通信场景下,不适合多点拓扑连接,共模电平编码,一般需要Rxd/Txd/Gnd三根线连接。
    三/四线
    
  • RS485通讯

    半双工,这是最为常用的modbus物理层,差分电平编码,一对双绞线,抗干扰性能也不错
    两线
    
  • RS422通讯

    全双工,这种物理层也有比较多的应用,差分电平编码,两对双绞线,抗干扰性能也不错。与RS-485相比,其优势在于可以实现全双工,通信的效率高些,所需要的代价就是现场布线需要两对双绞线,增加了一定的成本。
    四线
    
  • 以太网通讯(越来越多)

    通用、便携、兼容
    
  • 其他:串口、无线、蓝牙

二、初识寄存器

简单介绍:Modbus的寄存器存储区概念来自于PLC。线圈代表单片机的可位寻址操作,寄存器则不可位寻址。

四种寄存器:线圈状态寄存器(0 Coil Status)、离散线圈输入状态寄存器(1 Input Status)、保持寄存器(4 Holding Register)、输入寄存器(3 Input Register)。

其中数字(0、1、4、3)是代表存储区编号,注意没 2,与协议没关系,但是能由编号得出该寄存器的十进制基地址。操作不同的存储区需要用不同的功能码。

1、线圈状态寄存器

2、离散线圈输入状态寄存器

3、保持寄存器

4、输入寄存器

三、PLC的地址

寄存器访问长度R/W寄存器编号十进制地址范围协议地址范围可操作功能码说明
线圈状态寄存器(Coil Status)位bitRW000001-099990-FFFF01H、05H、0FH
离散线圈输入状态寄存器(Input Status)位bitR110001-199990-FFFF02H
保持寄存器(Holding Register)字word(2Byte)RW440001-499990-FFFF03H、06H、10H
输入寄存器(Input Register)字word(2Byte)R330001-399990-FFFF04H

四、Modbus协议

一个完整的数据帧包括:地址 + 功能码 + 数据 + CRC校验

一个数据包最大256个字节。读最多个操作和写最多个操作都可能满

读操作规律:

读操作都发送 2Byte 地址 + 2Byte 数量(数量代表:线圈个数或寄存器个数)。

读操作都返回 1Byte 字节计数 + 计数数量的N个字节(N字节代表:线圈返回字节数 = 读线圈数/8 向上取整寄存器返回字节数 = 读取寄存器数*2

写操作规律:

所有的写单个数据包,返回数据包与请求数据包相同。

写多个需要

1、地址

十进制范围十六进制范围作用
00广播地址,所有的从设备必须处理广播报文,但是不用回应
1-2470x01 - 0xF7从设备地址,主设备是没有地址的,这一点需要注意
248-2550xF8 - 0xFF预留地址

2、功能码

范围:0x00 - 0x7F (1-127)

地址范围作用
111-127公共功能码
100-110用户定义功能码
73-99公共功能码
64-72用户定义功能码
1-64公共功能码

请求数据包发送功能码,回应数据包发送响应码。正常回应的回应码等于功能码,异常回应的异常功能码为功能码+0x80

异常响应时,在功能码后加异常码。

常见功能码 Modbus功能码列表(全)

功能码解释作用
0x01Read Coils 读线圈状态读取远程设备中1到2000个连续的线圈的状态
0x02Read Discrete Inputs 读离散输入状态读取远程设备中1到2000个连续的离散输入的状态
0x03Read Holding Registers 读保持寄存器内容读取远程设备中1到125个连续的保持寄存器的内容
0x04Read Input Registers 读输入寄存器内容读取远程设备中1到125个连续的输入寄存器的内容
0x05Write Single Coil 写单个线圈在远程设备中把单个线圈状态改变为打开或关闭的状态
0x06Write Single Register 写单个保持寄存器在远程设备中写入单个保持寄存器
0x07Read Exception Status (Serial Line only) 读取异常状态(仅限串行线路)读取远程设备中八个异常状态输出的内容
0x08Diagnostics (Serial Line only) 通信系统诊断(仅限串行线路)
0x0BGet Comm Event Counter (Serial Line only) 获取通讯事件计数器(仅限串行线路)从远程设备的通信事件计数器获取状态字和事件计数
0x0CGet Comm Event Log (Serial Line only) 获取通讯事件日志(仅限串行线路)从远程设备获取状态字、事件计数、消息计数和事件字节字段
0x0FWrite Multiple Coils 写多个线圈强制远程设备中线圈序列中的每个线圈接通或断开 1-1968 个
0x10Write Multiple registers 写多个保持寄存器在远程设备中写入连续寄存器块 1-123个
0x11Report Slave ID (Serial Line only) 报导从机信息(仅限串行线路)读取远程设备特有的类型、当前状态和其他信息的说明。数据内容特定于每种类型的设备
0x14Read File Record 读取文件记录
0x15Write File Record 写文件记录
0x16Mask Write Register 带屏蔽字写入寄存器
0x17Read/Write Multiple registers 读、写多个寄存器执行一次连续写和连续读,写入操作在读取之前执行
0x18Read FIFO Queue 读取先进先出队列
0x2BEncapsulated Interface Transport 封装接口传输

异常功能码

异常功能码 = 普通功能码 + 0x80

如:读保持寄存器异常,从机返回主机数据帧 Rx: 01 83 01 80 F0

3、数据

数据可能的几种格式

1、线圈状态寄存器

2、离散线圈输入状态寄存器

3、保持寄存器

4、输入寄存器

异常码
代码 HEX名称含义
01非法功能对于服务器(或从站)来说,询问中接收到的功能码是不可允许的操作。这也许是因为功能码仅仅适用于新设备而在被选单元中是不可实现的。同时,还指出服务器(或从站)在错误状态中处理这种请求,例如:因为它是未配置的,并且要求返回寄存器值。
02非法数据地址对于服务器(或从站)来说,询问中接收到的数据地址是不可允许的地址。特别是,参考号和传输长度的组合是无效的。对于带有 100 个寄存器的控制器来说,带有偏移量 96 和长度 4 的请求会成功,带有偏移量 96 和长度 5 的请求将产生异常码 02。
03非法数据值对于服务器(或从站)来说,询问中包括的值是不可允许的值。这个值指示了组合请求剩余结构中的故障,例如:隐含长度是不正确的。并不意味着,因为MODBUS 协议不知道任何特殊寄存器的任何特殊值的重要意义,寄存器中被提交存储的数据项有一个应用程序期望之外的值。
04从站设备故障当服务器(或从站)正在设法执行请求的操作时,产生不可重新获得的差错。
05确认与编程命令一起使用。服务器(或从站)已经接受请求,并且正在处理这个请求,但是需要长的持续时间进行这些操作。返回这个响应防止在客户机(或主站)中发生超时错误。客户机(或主站)可以继续发送轮询程序完成报文来确定是否完成处理。
06从属设备忙与编程命令一起使用。服务器(或从站)正在处理长持续时间的程序命令。当服务器(或从站)空闲时,用户(或主站)应该稍后重新传输报文。
0A不可用网关路径与网关一起使用,指示网关不能为处理请求分配输入端口至输出端口的内部通信路径。通常意味着网关是错误配置的或过载的。
0B网关目标设备响应失败与网关一起使用,指示没有从目标设备中获得响应。通常意味着设备未在网络中。

4、CRC

CRC 计算是包括字节:1Byte 地址、有效载荷(1Byte 功能码+ NByte 数据)的所有字节,即CRC前的所有数据。

1、多项式 0X8005
2、初始异或值 0xFFFF
3、数据反转:输入反转 要,输出反转 要
4、Modbus 是低地址字节先发,比如单片机计算结果是uint_16 0xCDC5,打包发送时是C5 CD
例子:01 03 00 00 00 0A C5 CD

拓展:
按照以上的计算,网页输出是 CDC5,因为网页输出的是uint_16 是大端在前,小端在后。
若是YModem协议,数据包结尾就是直接 MSB的CRC16 格式,但是MODEMBUS 是 LSB 的格式,所以是C5CD,YModem 的CRC只包括有效数据段,不包括前面1B功能码2B数据包计数。

CRC 计算代码

//modbus 可直接使用的
uint16_t calculate_crc(uint8_t *data, uint16_t len)
{
    uint16_t crc = 0xFFFF; // CRC 初始值
    for (int i = 0; i < len; i++) {
        crc ^= (uint16_t)data[i]; // 与数据异或
        for (int j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001; // 生成多项式 0xA001
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

5、 数据包实例

最常用的8种,其中 4个读取四种寄存器 + 2个写单个寄存器 + 2个写多个寄存器。未添加异常数据包。

1、读线圈状态 01

1、主机发送 Tx: 01 01 00 00 00 06 BC 08

地址功能码线圈地址数量(线圈)CRC
数据包实例010100 0000 06BC 08
可选范围HEX01-F70-9999/655351 - 07D0(1-2000)
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01读取单个线圈从地址0x0000读取6个线圈

2、从机回应 Rx: 01 01 01 32 D0 5D

地址功能码字节数数据(字节中一位代表一个线圈)CRC
数据包实例01010132D0 5D
读取范围HEX1-FA(1-250)
所占字节1Byte1Byte1Byte1-2502Byte
解释从机地址01读取单个线圈数据字节数高地址-低地址:0011 0010

读取的六个地址是从低地址0x0000 开始读取的,读到0x0006。没读的高位补 0 凑一个字节返回。

2、读离散(输入)线圈输入状态 02

1、主机发送 Tx: 01 02 00 00 00 06 F8 08

地址功能码地址数量(线圈)CRC
数据包实例010200 0000 06F8 08
可选范围HEX同线圈状态
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01读取离散(输入)线圈从地址0x0000读取6个线圈

2、从机回应 Rx: 01 02 01 24 A1 93

地址功能码字节数数据(字节中一位代表一个线圈)CRC
数据包实例01020124A1 93
可选范围HEX1-FA(1-250)
所占字节1Byte1Byte1Byte1-250(读取线圈数/8向上取整)2Byte
解释从机地址01正常读取数据字节数高地址-低地址:0010 0100
3、读保持寄存器 03

1、主机发送 Tx: 01 03 00 00 00 06 C5 C8

地址功能码地址数量(取寄存器)CRC
数据包实例010300 0000 06C5 08
可选范围HEX1-007D(1-125)
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01读保持寄存器从地址0x0000读取6个寄存器

2、从机回应 Rx: 01 03 0C 00 46 00 50 00 5A 00 00 00 00 00 00 DE 3F

地址功能码数据字节计数数据CRC
数据包实例01030C00 46 00 50 00 5A 00 00 00 00 00 00BC 08
可选范围HEX1-FA(1-250)
所占字节1Byte1Byte1Byte1-250(?6*2 = 12Byte)2Byte
解释从机地址01正常读取后面有12个Byte的数据十进制:70 80 90 00 00 00
4、读输出寄存器 04

1、主机发送 Tx: 01 04 00 00 00 05 30 09

地址功能码地址读取数量CRC
数据包实例010400 0000 0530 09
可选范围HEX1-007D(1-125)
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01读取输出寄存器从地址0x0000读取5个寄存器

2、从机回应Rx: 01 04 0A AB CD 12 34 23 45 00 00 00 02 10 C4

地址功能码字节计数数据CRC
数据包实例01040AAB CD 12 34 23 45 00 00 00 0210 C4
可选范围HEX1-FA(1-250)
所占字节1Byte1Byte1Byte1-250 ?5*2 = 10Byte2Byte
解释从机地址01正常读取后面有10个Byte的数据0xABCD、0x1234、0x2345、
0x0000、0x0002
5、写单个线圈状态 05

1、主机发送 Tx: 01 05 00 00 FF 00 8C 3A

地址功能码地址CRC
数据包实例010500 00FF 008C 3A
可选范围HEX真FF00 假0000
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01写取单个线圈从地址0x0000对某一位置一

2、从机回应 Rx: 01 05 00 00 FF 00 8C 3A 同请求

地址功能码地址CRC
数据包实例010500 00FF 008C 3A
可选范围HEX真FF00 假0000
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01正常写入从地址0x0000置一成功
6、写单个保持寄存器 06

1、主机发送 Tx: 01 06 00 00 04 D2 0B 57

地址功能码地址CRC
数据包实例010600 0004 D20B 57
可选范围HEX
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01写单个保持寄存器从地址0x0000写1个线圈

2、从机回应 Rx: 01 06 00 00 04 D2 0B 57 同请求

地址功能码地址CRC
数据包实例010600 0004 D20B 57
可选范围HEX
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01正常写入从地址0x0000读得十进制1234
7、写多个线圈 15

1、主机发送 Tx: 01 0F 00 00 00 0A 02 07 00 E7 08

地址功能码线圈地址写数量(线圈)数据计数数据CRC
数据包实例010F00 0000 0A0207 00E7 08
可选范围HEX1-07B0(1-1968)1-F6
所占字节1Byte1Byte2Byte2Byte1Byte(1-246)2Byte
解释从机地址01写多个线圈从地址0x0000请求写10个线圈数据计数0000000111

2、从机回应 Rx: 01 0F 00 00 00 0A D5 CC

地址功能码线圈地址写数量(线圈)CRC
数据包实例010F00 0000 0AD5 CC
可选范围HEX1-07B0(1-1968)
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01正常写入从地址0x0000写10个线圈成功
8、写多个保持寄存器 16

1、主机发送 Tx: 01 10 00 00 00 0A 14 12 34 09 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1A 85 A3 7E

地址功能码线圈地址写数量(寄存器)数据计数数据CRC
数据包实例011000 0000 0A14A3 7E
可选范围HEX1-007B(1-123)1-F6
所占字节1Byte1Byte2Byte2Byte1Byte1-2462Byte
解释从机地址01写多个保持寄存器从地址0x0000

2、从机回应 Rx: 01 10 00 00 00 0A 40 0E

地址功能码线圈地址写数量(寄存器)CRC
数据包实例011000 0000 0A40 0E
可选范围HEX
所占字节1Byte1Byte2Byte2Byte2Byte
解释从机地址01正常写入从地址0x0000

REF:

Modbus通讯协议从一窍不通到原来如此_modbus从站主动上报-CSDN博客ModbusRTU的几种常用功能码介绍及使用_modbus功能码-CSDN博客

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
freemodbus 是一款开源的Modbus通信协议栈,用于实现Modbus通信协议的开发。通过学习freemodbus,我收获了许多知识和技能。 首先,在学习freemodbus时,我了解到了Modbus通信协议的基本原理和工作方式。Modbus是一种常用的串行通信协议,主要用于工业自动化领域中设备之间的通信。它使用简单的请求-响应机制进行数据传输,包括读取和写入寄存器等功能。通过freemodbus学习,我了解到了Modbus通信协议的组成结构、数据帧格式以及常用的功能码等。 其次,通过实践freemodbus的使用,我学会了如何在嵌入式系统中实现Modbus通信功能。freemodbus提供了一系列的接口函数,可以方便地实现Modbus主站和从站的功能,并支持多种串口通信方式,如RS485、TCP等。学习过程中,我熟悉了freemodbus的API函数的使用方法,掌握了创建、初始化和配置Modbus通信对象的技巧。 另外,通过使用freemodbus,我学到了一些调试和排错的技巧。在实际应用中,由于硬件、软件等多种因素的影响,可能会出现通信故障或数据错误的情况。通过freemodbus的调试工具和相关的日志输出,我学会了如何在开发过程中定位和解决各种问题,提高了软件开发的技能和经验。 总体来说,学习freemodbus是一次非常有益的经历。通过这个学习过程,我不仅掌握了Modbus通信协议的原理和应用,还提高了嵌入式软件开发的能力。我相信,在今后的工作中,我可以更好地应用freemodbus开发各种工业自动化设备和系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值