用 ADAM-6052 学习 ModBus TCP 协议 (1) – 读写 DO (线圈)状态

目录 Content
[hide]

研华 ADAM-6052 模块支持 Modbus TCP 协议,正好可以拿来研究 Modbus TCP 的协议格式。

〇、硬件特性

1. ADAM-6052 Specifications

  • Communication: 10/100 Base-T Ethernet
  • Supports Protocol: Modbus/TCP, TCP/IP, UDP, HTTP, ICMP, DHCP and ARP
  • Supports Peer-to-Peer and GCL

2. Digital Input

  • Channels: 8
  • Dry Contact:
    Logic level 0: Open
    Logic level 1: Close to Ground
  • Wet Contact:
    Logic level 0: 0 ~ 3 VDC
    Logic level 1: 10 ~ 30 VDC
  • Supports 3 kHz counter input (32-bit with overflow flag)
  • Supports 3 kHz frequency input
  • Supports inverted DI status

3. Digital Output

  • Channels: 8
  • Source Type: 10 ~ 35 VDC, 1 A (per channel)
  • Supports 5 kHz pulse output
  • Supports high-to-low and low-to-high delay output

一、Modbus TCP 协议格式

先来看看文档里如何描述 Modbus TCP 协议:

  • 一个完整的 Modebus TCP 命令由两部分组成:命令头和命令体。
  • 命令头:由 6 个字节组成,用于响应Modbus协议格式
  • 命令体:用于定义“目标设备”和“请求功能”

ADAM-6052 的 Modbus 地址如下:

最直观的就是抓取通讯字节流,通过实例和文档对比,达到快速理解的目的。

二、读取 DO 状态

使用 Function 01 功能码,读取线圈状态也即输出的状态。

请求读取地址 17 开始 8 个线圈的状态,使用嗅探工具抓包。

1. 请求报文

00 80 00 00 00 06 01 01 00 10 00 08

开始6个字节为命令头:

  • byte 0 :  事务标识符,本例为 00
  • byte 1 :  事务标识符,本例为 80
  • byte 2 :  协议标识符,通常为 00
  • byte 3 :  协议标识符,通常为 00
  • byte 4 :  后面的字节数,高字节。通常为 00,因为所有报文都小于 256 个字节
  • byte 5 :  后面的字节数,低字节。本例为 06,即 01 01 00 10 00 08 共 6 个字节

第7个字节开始为命令体:

  • byte 6 :  从站标识符,本例为 01
  • byte 7 :  功能码,本例为 01,即 read coils
  • byte 8 :  读取地址,高字节。本例为 00
  • byte 9 :  读取地址,低字节。本例为 10,即地址16。(17-1,原因是是从0开始)
  • byte 10: 读取数量,高字节。本例为 00
  • byte 11: 读取数量,低字节。本例为 08,即8个线圈

2. 返回报文

00 80 00 00 00 04 01 01 01 00

开始6个字节为命令头:

  • byte 0 :  事务标识符,本例为 00
  • byte 1 :  事务标识符,本例为 80
  • byte 2 :  协议标识符,通常为 00
  • byte 3 :  协议标识符,通常为 00
  • byte 4 :  后面的字节数,高字节。通常为 00,因为所有报文都小于256个字节
  • byte 5 :  后面的字节数,低字节。本例为 04,即 01 01 01 00 共4个字节

第7个字节开始为命令体:

  • byte 6 :  从站标识符,本例为 01
  • byte 7 :  功能码,本例为 01,即 read coils
  • byte 8 :  数据数量,本例为 01
  • byte 9 :  读取数值,本例为 00

3. 手工验证

动手试一试,更能增加感性认识。使用TCP调试工具直接向模块发送十六进制字节流看看有什么效果?

 

 

  1. 发送请求:00 80 00 00 00 06 01 01 00 10 00 08
  2. 返回响应:00 80 00 00 00 04 01 01 01 D5
  3. 分析结果: D5 二进制为 11010101,分别对应 DO7 – DO0,符合。

三、写入单个 DO 状态

Modbus TCP 提供了写入单个和多个输出的功能:

以写入 DO0 为例,DO0 地址为 17,依次写入 ON 和 OFF:

1.  请求报文

1B 13 00 00 00 06 01 05 00 10 FF 00
或者
1B 14 00 00 00 06 01 05 00 10 00 00

开始6个字节为命令头:

  • byte 0 :  事务标识符,本例为 1B
  • byte 1 :  事务标识符,本例为 13
  • byte 2 :  协议标识符,通常为 00
  • byte 3 :  协议标识符,通常为 00
  • byte 4 :  后面的字节数,高字节。通常为 00,因为所有报文都小于256个字节
  • byte 5 :  后面的字节数,低字节。本例为 06,即 01 05  00 10 FF 00 / 00 00 共 6 个字节

第7个字节开始为命令体:

  • byte 6 :  从站标识符,本例为 01
  • byte 7 :  功能码,本例为 05,即 Force a single coil to either ON or OFF
  • byte 8 :  写入地址,高字节。本例为 00
  • byte 9 :  写入地址,低字节。本例为 10,即地址16(17-1)
  • byte 10 : 写入数据,高字节。本例为 FF  (和 00)
  • byte 11 : 写入数据,低字节。常为 00

所以特别的:

  • byte 11 byte 10 写入数据为 FF 00 ,则为 ON
  • byte 11 byte 10 写入数据为 00 00 ,则为 OFF

2.  返回报文

同请求报文。

1B 13 00 00 00 06 01 05 00 10 FF 00
或者

1B 14 00 00 00 06 01 05 00 10 00 00

不再详述。

四、写入多个 DO 状态

以写入状态 11010101 共 8 个 DO 为例:

1. 请求报文

2E 7A 00 00 00 08 01 0F 00 10 00 08 01 D5

开始 6 个字节为命令头:

  • byte 0 :  事务标识符,本例为 2E
  • byte 1 :  事务标识符,本例为 7A
  • byte 2 :  协议标识符,通常为 00
  • byte 3 :  协议标识符,通常为 00
  • byte 4 :  后面的字节数,高字节。通常为 00,因为所有报文都小于256个字节
  • byte 5 :  后面的字节数,低字节。本例为 08,即 01 0F 00 10 00 08 01 D5 共 8 个字节

第7个字节开始为命令体:

  • byte 6 :  从站标识符,本例为 01
  • byte 7 :  功能码,本例为 0F,即 Forces each coil in a sequence of coils to either ON or OFF
  • byte 8 :  开始地址,高字节。本例为 00
  • byte 9 :  开始地址,低字节。本例为 10,即地址16。(17-1)
  • byte 10 : 线圈数量,高字节。本例为 00
  • byte 11 : 线圈数量,低字节。本例为 08
  • byte 12 : 后面的字节数。本例为 01
  • byte 13 : 写入数据。本例为 D5,即 11010101

2. 返回报文

2E 7A 00 00 00 06 01 0F 00 10 00 08

开始 6 个字节为命令头:

  • byte 0 :  事务标识符,本例为 2E
  • byte 1 :  事务标识符,本例为 7A
  • byte 2 :  协议标识符,通常为 00
  • byte 3 :  协议标识符,通常为 00
  • byte 4 :  后面的字节数,高字节。通常为 00,因为所有报文都小于256个字节
  • byte 5 :  后面的字节数,低字节。本例为 06,即 01 0F 00 10 00 08 共 6 个字节

第7个字节开始为命令体:

  • byte 6 :  从站标识符,本例为 01
  • byte 7 :  功能码,本例为 0F,即 Forces each coil in a sequence of coils to either ON or OFF
  • byte 8 :  开始地址,高字节。本例为 00
  • byte 9 :  开始地址,低字节。本例为 10,即地址16。(17-1)
  • byte 10 : 线圈数量,高字节。本例为 00
  • byte 11 : 线圈数量,低字节。本例为 08

五、异常处理

1.  读取格式不标准

如果命令报文格式正确,一般都会正确地返回应答报文。

读取的正确命令是:00 80 00 00 00 06 01 01 00 10 00 FF
相应的返回报文是:00 80 00 00 00 04 01 01 01 00

但是如果命令报文格式不标准呢?

a. 如果地址不存在例如 00 FF

比如请求的报文是:00 80 00 00 00 06 01 01 00 FF 00 08
相应的返回报文是:00 80 00 00 00 03 01 81 02

这种情况,Slave 返回代码表示请求错误 81 02

b. 如果读取线圈数量为 00 FF

比如请求的报文是:00 80 00 00 00 06 01 01 00 10 00 FF
相应的返回报文是:00 80 00 00 00 23 01 01 20 00 00 11 11 11 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

这种情况貌似没有问题。

c. 如果读取线圈数量为 FF 00

比如请求的报文是:00 80 00 00 00 06 01 01 00 10 FF 00
相应的返回报文是:00 80 00 00 00 03 01 81 02

这种情况,Slave 返回代码表示请求错误 81 02

2. 单个写入格式不标准

如果单个写入命令报文格式正确,一般都会正确地返回原报文。

1B 13 00 00 00 06 01 05 00 10 FF 00
或者
1B 13 00 00 00 06 01 05 00 10 00 00

a.如果地址不存在例如 00 FF

比如请求的报文是:1B 13 00 00 00 06 01 05 00 FF FF 00
相应的返回报文是:1B 13 00 00 00 03 01 85 02

这种情况,Slave 返回代码表示请求错误 85 02

b.如果写入值不标准(非FF00/0000)

如果写入数值不是FF00或者0000

比如请求的报文是:1B 13 00 00 00 06 01 05 00 10 FF FF
相应的返回报文是:1B 13 00 00 00 03 01 85 03

这种情况,Slave 返回代码表示请求错误 85 03

3. 多个写入格式不标准

如果多个写入命令报文格式正确,一般都会正确地返回应答报文。

比如请求的报文是:2E 7A 00 00 00 08 01 0F 00 10 00 08 01 D5
相应的返回报文是:2E 7A 00 00 00 08 01 0F 00 10 00 08 01 D5

a.如果地址不存在例如 00 FF

比如请求的报文是:2E 7A 00 00 00 08 01 0F 00 FF 00 08 01 D5
相应的返回报文是:2E 7A 00 00 00 03 01 8F 02

这种情况,Slave 返回代码表示请求错误 8F 02

b. 如果写入线圈数量不正确例如 00 09

比如请求的报文是:2E 7A 00 00 00 08 01 0F 00 10 00 09 01 D5
相应的返回报文是:2E 7A 00 00 00 03 01 8F 03

这种情况,Slave 返回代码表示请求错误 8F 03

4. 第5&6、第14个字节数值不正确

另,第5&6个字节即 byte4、 byte5的字节数不符不影响结果。

扩展阅读

Leave a Reply

Your email address will not be published. Required fields are marked *