- Modbus 是由 Modicon(现为施耐德电气公司的一个品牌)在 1979 年发明的一种工业控制总线协议,是全球第一个真正用于工业现场的总线协议。Modbus 以其简单、健壮、开放而且不需要特许授权的特点,成为通用通信协议。为了适应以太网环境,Modbus 被封装在 TCP 包中,并且在默认情况下通过 TCP 协议的 502 端口进行传输。
- 基于 Modbus 协议的系统由带智能终端的可编程逻辑控制器和计算机通过公用线路或局部专用线路连接而成。其系统结构既包括硬件,又包括软件。可应用于各种数据采集和过程监控。
- Modbus 协议采用主 - 从结构,为客户机和服务器之间提供通信连接。
- Modbus 协议定义了一个与基础通信无关的协议数据单元(Protocol Description Unit,PDU),描述协议的基本功能。PDU 属于应用数据单元(Application Data Unit,ADU)的一部分,除此之外,ADU 还包括附加地址域和差错校验域及实际传输的数据,这个数据可能是业务数据,也可能是指令、响应信息或报警信息等。
- Modbus 协议包括 ASCII、RTU、TCP 三种报文类型,可以使用串口传输数据和指令。
一、功能码 03:读保持寄存器
可读多个或者单个寄存器内容主机请求
域名 | 所占字节数 | 可输入的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x03 |
寄存器起始地址 | 2个字节 | 根据所要读取的寄存器位置而定,范围是0x0000 至 0xFFFF |
寄存器数目 | 2个字节 | 1 至 125(0x7D) |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
从机响应 | ||
域名 | 所占字节数 | 返回的数据内容 |
:–: | :– | :–: |
从机地址 | 1个字节 | 从机地址 |
功能码 | 1个字节 | 0x03 |
字节数 | 1个字节 | 2×N |
寄存器的值 | N×2 个字节 | 根据所读取的保持寄存器内容而定 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
N = 寄存器的数量
- 1
从机返回错误帧
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
功能码 | 1个字节 | 0x83 |
异常码 | 1个字节 | 01 或 02 或 03 或 04 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
下面是来一个实例:
假如从机地址为1,保持寄存器1~3的内容分别是:0x042B、0x0341、0x0210。现在有一个主机想要从该从机内的保持寄存器地址1处开始读取3个保持寄存器的内容,则下面的报文将是主机所发送的数据帧和接收到的数据帧的内容
主机请求,发送的报文: 01 03 0001 0003 540B
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 03 |
寄存器地址 Hi | 00 |
寄存器地址 Lo | 01 |
寄存器数目 Hi | 00 |
寄存器数目 Lo | 03 |
CRC高字节 | 54 |
CRC低字节 | 0B |
从机响应,主机收到的报文:01 03 042B 0341 0210 C7B9 | |
域名 | 十六进制 |
:– | :–: |
从机地址 | 01 |
功能码 | 03 |
字节数 | 06 |
(01)寄存器的值 Hi | 04 |
(01)寄存器的值 Lo | 2B |
(02)寄存器的值 Hi | 03 |
(02)寄存器的值 Lo | 41 |
(03)寄存器的值 Hi | 02 |
(03)寄存器的值 Lo | 10 |
CRC高字节 | C7 |
CRC低字节 | b9 |
二、功能码 06:写单个保持寄存器
写单个保持寄存器的返回帧和写入帧是一模一样
主机------------请求
域名 | 所占字节数 | 可输入的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x06 |
寄存器地址 | 2个字节 | 根据所要写入的寄存器位置而定,范围是0x0000 至 0xFFFF |
寄存器值 | 2个字节 | 0x0000 至 0xFFFF |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
从机------------响应
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x06 |
寄存器地址 | 2个字节 | 根据从机被读取的地址而定,范围是0x0000 至 0xFFFF |
寄存器值 | 2个字节 | 根据从机所存放的数据而定,范围是0x0000 至 0xFFFF |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
错误
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
差错码 | 1个字节 | 0x86 |
异常码 | 1个字节 | 01 或 02 或 03 或 04 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
来一个实例:
假如从机地址为1,现在有一个主机想要从该从机内的保持寄存器地址1处写入0x0C02,则下面的报文将是主机所发送的数据帧和接收到的数据帧的内容
主机请求,发送的报文:01 06 0001 0C02 5CCB
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 06 |
寄存器地址高字节 | 00 |
寄存器地址低字节 | 01 |
(要写入的数据)的高字节 | 0C |
(要写入的数据)的低字节 | 02 |
CRC高字节 | 5C |
CRC低字节 | CB |
从机响应,主机收到的报文:01 06 0001 0C02 5CCB
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 06 |
寄存器地址高字节 | 00 |
寄存器地址低字节 | 01 |
寄存器的值 HI | 0C |
寄存器的值 Lo | 02 |
CRC高字节 | 5C |
CRC低字节 | CB |
写单个保持寄存器的成功的话,它的返回帧和写入帧是一模一样 |
三、功能码 10:写多个保持寄存器
主机------------请求
域名 | 所占字节数 | 可输入的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x10 |
寄存器起始地址 | 2个字节 | 根据所要写入的寄存器位置而定,范围是0x0000 至 0xFFFF |
寄存器数目 | 2个字节 | 根据所要写入的寄存器数目而定,范围是0x0001 至 0x0078 |
字节数 | 1个字节 | 2×N |
寄存器值 | N×2 个字节 | 要写入的数据值 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
N = 寄存器的数量
- 1
从机------------响应
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
功能码 | 1个字节 | 0x10 |
寄存器起始地址 | 2 个字节 | 根据被写入的寄存器地址而定,范围是0x0000 至 0xFFFF |
寄存器数目 | 2个字节 | 1 至 123(0x7B) |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
错误
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
差错码 | 1个字节 | 0x90 |
异常码 | 1个字节 | 01 或 02 或 03 或 04 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
来一个实例:
假如从机地址为1,现在有一个主机想要从该从机内的保持寄存器地址1~3写入0x0101 、0x0202、0303 ,则下面的报文将是主机所发送的数据帧和接收到的数据帧的内容
主机请求,发送的报文: 01 10 0001 0003 06 0101 0202 0303 6BDD
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 10 |
寄存器地址 Hi | 00 |
寄存器地址 Lo | 01 |
寄存器数量 Hi | 00 |
寄存器数量 Lo | 03 |
字节数 | 06 |
寄存器的值 Hi(01) | 01 |
寄存器的值 Lo(01) | 01 |
寄存器的值 Hi(02) | 02 |
寄存器的值 Lo(02) | 02 |
寄存器的值 Hi(03) | 03 |
寄存器的值 Lo(03) | 03 |
CRC高字节 | 2F |
CRC低字节 | 09 |
从机响应,主机收到的报文:01 10 0001 0003 D1C8
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 10 |
寄存器地址Hi | 00 |
寄存器地址Lo | 01 |
寄存器数量 Hi | 00 |
寄存器数量 Lo | 03 |
CRC高字节 | D1 |
CRC低字节 | C8 |
四、功能码 17:读/写多个保持寄存器
主机------------请求
域名 | 所占字节数 | 可输入的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x17 |
读起始地址 | 2个字节 | 根据所要读取的寄存器位置而定,范围是0x0000 至 0xFFFF |
要读的寄存器数目 | 2个字节 | 根据所要读取的寄存器数目而定,范围是0x0001 至近似 0x0076 |
写起始地址 | 2个字节 | 根据所要写入的寄存器位置而定,范围是0x0000 至 0xFFFF |
要写入的寄存器数目 | 2个字节 | 根据所要写入的寄存器数目而定,范围是0x0001 至近似 0x0076 |
字节数 | 1个字节 | 2×N |
要写入的寄存器的值 | N×2 个字节 | 要写入的数据值 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
N = 要写入的寄存器的数量
- 1
从机------------响应
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
功能码 | 1个字节 | 0x17 |
字节数 | 1个字节 | 2×N |
寄存器的值 | N×2 个字节 | 根据所读取的保持寄存器内容而定 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
*N = 要读取到的寄存器的数量
- 1
错误
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
差错码 | 1个字节 | 0x97 |
异常码 | 1个字节 | 01 或 02 或 03 或 04 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
来一个实例:
假如从机地址为1,保持寄存器1~3的内容分别是:0x042B、0x0341、0x0210。
现在有一个主机想要从该从机内的保持寄存器地址1处读取3个保持寄存器的数据,并向保持寄存器地址4~5写入0x0101 、0x0202,则下面的报文将是主机所发送的数据帧和接收到的数据帧的内容。
主机请求,发送的报文: 01 17 0001 0003 0004 0002 04 0101 0202 BA28
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 17 |
读寄存起始地址 Hi | 00 |
读寄存器起始地址 Lo | 01 |
读的寄存器数量 Hi | 00 |
读的寄存器数量 Lo | 03 |
写寄存起始地址 Hi | 00 |
写寄存器起始地址 Lo | 04 |
写的寄存器数量 Hi | 00 |
写的寄存器数量 Lo | 02 |
要写入的数据的字节数 | 04 |
(04)要写入的值 Hi | 01 |
(04)要写入的值 Lo | 01 |
(05)要写入的值 Hi | 02 |
(05)要写入的值 Lo | 02 |
CRC高字节 | BA |
CRC低字节 | 28 |
**从机响应,主机收到的报文:01 17 06 042B 0341 0210 54F4 **
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 17 |
读取到的字节数 | 06 |
(01)读取到的寄存器的值 Hi | 04 |
(01)读取到的寄存器的值 Lo | 2B |
(02)读取到的寄存器的值 Hi | 03 |
(02)读取到的寄存器的值 Lo | 41 |
(03)读取到的寄存器的值 Hi | 02 |
(03)读取到的寄存器的值Lo | 10 |
CRC高字节 | 54 |
CRC低字节 | F4 |
五、功能码 14:读文件记录
主机------------请求
域名 | 所占字节数 | 可输入的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x14 |
字节数 | 1字节 | 根据此数据帧后面还需要发送的数据的字节数,不包含CRC,范围是0x07 至 0xF5 字节 |
子请求 x,参考类型 | 1个字节 | 06 |
子请求 x,文件号 | 2 个字节 | 根据所需要读取的文件号而定,范围是0x0000 至 0xFFFF |
子请求 x,记录号 | 2个字节 | 根据所需要读取的记录号而定,也可以说是寄存器起始地址,范围是0x0000 至 0x270F |
子请求 x,记录长度 | 2个字节 | 根据所需要读取的寄存器数目N而定,范围是0x0000 至 0x270F |
子请求 x+1,… | ||
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
从机------------响应
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
功能码 | 1个字节 | 0x14 |
响应数据长度 | 1个字节 | 根据此数据帧后面还需要发送的数据的字节数,不包含CRC,范围是0x07 至 0xF5 |
子请求 x,文件响应长度 | 1个字节 | 根据当前文件号下的数据长度而定,范围是0x07 至 0xF5 |
子请求 x,参考类型 | 1字节 | 0x06 |
子请求 x,记录数据 | N×2 个字节 | 根据所读取到寄存器数据而定 |
子请求 x+1,… | ||
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
N 该文件下所需要读取的记录长度,也就是寄存器数目
- 1
错误
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
差错码 | 1个字节 | 0x94 |
异常码 | 1个字节 | 01 或 02 或 03 或 04 或08 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
来一个实例:
假如从机地址为1,它有2个文件:文件号分别是3、4。其中文件3以寄存器地址9开始,有2个寄存器:0x1101、0x2202;文件4以寄存器地址1开始,有4个寄存器:0x3303、0x4404、0x5505、0x6606。
现在主机需要去读取这2个文件的内容。
**主机请求,发送的报文: 01 14 0E 06 0003 0009 0002 06 0004 0001 0003 751E **
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 14 |
字节数 | 0E |
子请求 1,参考类型 | 06 |
子请求 1,文件号 Hi | 00 |
子请求 1,文件号 Lo | 03 |
子请求 1,记录号 Hi | 00 |
子请求 1,纪录号 Lo | 09 |
子请求 1,记录长度 Hi | 00 |
子请求 1,纪录长度 Lo | 02 |
子请求 2,参考类型 | 06 |
子请求 2,文件号 Hi | 00 |
子请求 2,文件号 Lo | 04 |
子请求 2,记录号 Hi | 00 |
子请求 2,纪录号 Lo | 01 |
子请求 2,记录长度 Hi | 00 |
子请求 2,纪录长度 Lo | 04 |
CRC高字节 | 75 |
CRC低字节 | 1E |
从机响应,主机收到的报文:01 17 10 05 06 1101 2202 09 06 3303 4404 5505 6606 5BC9
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 14 |
响应数据长度 | 10 |
子请求 1,文件响应长度 | 05 |
子请求 1,参考类型 | 06 |
子请求 1,记录数据Hi | 11 |
子请求 1,记录数据Lo | 01 |
子请求 1,记录数据Hi | 22 |
子请求 1,记录数据Lo | 02 |
子请求 2,文件响应长度 | 09 |
子请求 2,参考类型 | 06 |
子请求 2,记录数据Hi | 33 |
子请求 2,记录数据Lo | 03 |
子请求 2,记录数据Hi | 44 |
子请求 2,记录数据Lo | 04 |
子请求 2,记录数据Hi | 55 |
子请求 2,记录数据Lo | 05 |
子请求 2,记录数据Hi | 66 |
子请求 2,记录数据Lo | 06 |
CRC高字节 | 5B |
CRC低字节 | C9 |
六、功能码 15:写文件记录
写文件记录的发送帧和反馈帧一模一样
- 1
主机------------请求
域名 | 所占字节数 | 可输入的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x15 |
字节数 | 1字节 | 根据此数据帧后面还需要发送的数据的字节数,不包含CRC,范围是0x07 至 0xF5 字节 |
子请求 x,参考类型 | 1个字节 | 06 |
子请求 x,文件号 | 2 个字节 | 根据所需要写入的文件号而定,范围是0x0000 至 0xFFFF |
子请求 x,记录号 | 2个字节 | 根据所需要写入的记录号而定,也可以说是寄存器起始地址,范围是0x0000 至 0x270F |
子请求 x,记录长度 | 2个字节 | 根据所需要写入的寄存器数目N而定,范围是0x0000 至 0x270F |
子请求 x,记录数据 | N×2 个字节 | 要写入的数据值 |
子请求 x+1,… | ||
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
从机------------响应
域名 | 所占字节数 | 可输入的数据内容 |
---|---|---|
从机地址 | 1个字节 | 根据从机地址而定 |
功能码 | 1个字节 | 0x15 |
字节数 | 1字节 | 根据此数据帧后面还需要发送的数据的字节数,不包含CRC,范围是0x07 至 0xF5 字节 |
子请求 x,参考类型 | 1个字节 | 06 |
子请求 x,文件号 | 2 个字节 | 根据所需要写入的文件号而定,范围是0x0000 至 0xFFFF |
子请求 x,记录号 | 2个字节 | 根据写入的记录号而定,也可以说是寄存器起始地址,范围是0x0000 至 0x270F |
子请求 x,记录长度 | 2个字节 | 根据写入的寄存器数目N而定,范围是0x0000 至 0x270F |
子请求 x,记录数据 | N×2 个字节 | 被写入的数据值 |
子请求 x+1,… | ||
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
错误
域名 | 所占字节数 | 返回的数据内容 |
---|---|---|
从机地址 | 1个字节 | 从机地址 |
差错码 | 1个字节 | 0x95 |
异常码 | 1个字节 | 01 或 02 或 03 或 04 或08 |
CRC校验码 | 2个字节 | 根据前面的数据计算出来 |
来一个实例:
假如从机地址为1,它有一个文件4,文件4以寄存器7为起始地址,有3个寄存器。现在主机需要往里面写数据:0x0101、0x0202、0x0303。
**主机请求,发送的报文: 01 15 0D 06 0004 0007 0003 0101 0202 0303 73FC **
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 15 |
字节数 | 0D |
子请求 1,参考类型 | 06 |
子请求 1,文件号 Hi | 00 |
子请求 1,文件号 Lo | 04 |
子请求 1,记录号 Hi | 00 |
子请求 1,纪录号 Lo | 07 |
子请求 1,记录长度 Hi | 00 |
子请求 1,纪录长度 Lo | 03 |
子请求 1,记录数据Hi | 01 |
子请求 1,记录数据Lo | 01 |
子请求 1,记录数据Hi | 02 |
子请求 1,记录数据Lo | 02 |
子请求 1,记录数据Hi | 03 |
子请求 1,记录数据Lo | 03 |
CRC高字节 | 73 |
CRC低字节 | FC |
从机响应,主机收到的报文:01 15 0D 06 0004 0007 0003 0101 0202 0303 73FC
域名 | 十六进制 |
---|---|
从机地址 | 01 |
功能码 | 15 |
字节数 | 0D |
子请求 1,参考类型 | 06 |
子请求 1,文件号 Hi | 00 |
子请求 1,文件号 Lo | 04 |
子请求 1,记录号 Hi | 00 |
子请求 1,纪录号 Lo | 07 |
子请求 1,记录长度 Hi | 00 |
子请求 1,纪录长度 Lo | 03 |
子请求 1,记录数据Hi | 01 |
子请求 1,记录数据Lo | 01 |
子请求 1,记录数据Hi | 02 |
子请求 1,记录数据Lo | 02 |
子请求 1,记录数据Hi | 03 |
子请求 1,记录数据Lo | 03 |
CRC高字节 | 73 |
CRC低字节 | FC |
版权声明:欢迎分享本文,转载请保留出处!