Modbus 协议从站开发通信西门子 PLC

Posted niaonao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Modbus 协议从站开发通信西门子 PLC相关的知识,希望对你有一定的参考价值。

文章目录

1. Modbus 协议

    Modbus 串行链路协议是一个主从模式的半双工数据传输协议
    Modbus 是施耐德电气公司,于 1979 年发明的,是全球第一个真正用于工业现场的总线协议,广泛应用于工业控制领域,且免费、便于部署维护。
    主从模式是指总线上包含一个主站和多个从站,每个从站具有唯一的从站标识 ID,主站通过 ID 进行寻址,然后和从站进行数据传输通信。主站最多可和 1-247 个从站通信。

Poll 端作为主站,Slave 端作为从站
有且只有一个主站,工业中 PLC 通常作为主站
主站请求从站,不支持从站向主站发起请求
根据主站从站商定好的格式发出寻址数据帧,主站请求从站,从站响应主站
测试工具包 Modbus Poll、Modbus Slave 下载 网盘提取码: bbdb

1.1 传输模式:单工模式、全双工模式、半双工模式

    单工模式、全双工模式、半双工模式类似交通道路中的单向单行道、双向双行道,双向单行道

  • 单工模式
    允许数据在单个方向上传输,发送数据仅支持从站点 A 传输到 B,就不支持从站点 B 传输到 A;A→B
  • 全双工模式
    允许数据在两个方向上错时传输,即站点在发送数据的同时也允许接收数据;A⇆B
  • 半双工模式
    允许数据在两个方向上同时传输,即站点在发送数据时不能接收数据,在接收数据时不能发送数据;A→B 或 B→A

1.2 广播模式、单播模式

  • 广播模式
    主站可向多个从站进行发送,设备地址设置为 0 用于广播模式,从站收到请求后不对主站进行响应;
  • 单播模式
    主站根据从站 ID 进行寻址可向指定从站发送请求,从站接收应答把消息返回给主站

1.3 Modbus 通信模式:ASCII、RTU

    在主从设备的通信中,可以使用 ASCII 通信模式和 RTU 通信模式,在一个 Modbus 网络上所有设备要统一通信模式和其他串口参数。

  • ASCII 模式:美国标准信息交换代码
    以 ASCII 模式通信时,在消息中,每个 8bit 字节作为两个 ASCII 字符发送;
    优点:字符发送的时间间隔可达到 1 秒而不产生错误。
    报文格式: 英文冒号 + 地址 + 功能编码 + 数据梳理 + 数据1 + ... + 数据n + LRC 高字节 + LRC 低字节 + 回车 + 换行

  • RTU (Remote Terminal Unit):远程终端单元
    在消息中,每个 8bit字节包含两个 4bit 的十六进制字符;
    优点:是相同波特率下比 ASCII 方式传送更多的数据;
    报文格式:地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + CRC 低字节 + CRC 高字节

一个十六进制数据 0xAF,需要两个字节传输需要两个 ASCII 字符 ‘A’,‘F’ ;
数据 0xAF 在 RTU 模式下需要一个字节,在 ASCII 模式下需要占用两个字节;
由于 ASCII 通信方式有开始标志和结束标志,所以一个数据包之间的各字节间的传输间隔时间可以大于1秒;而 RTU 通信方式下,由于没有规定开始和结束标记,所以协议规定每两个字节之间发送或者接收的时间间隔不能超过3.5倍字符传输时间,超过则认为一帧数据已经完成接收,超过后的数据是新一帧的数据;

通信模式RTUASCII
优点同波特率下,比 ASCII 多传输一倍的数据字符发送时间间隔超出 1 秒不会产生错误,因为一帧数据包含开始标记结束标记
缺点同一帧数据的两个字节间的传输时间间隔不能超出 3.5 倍字符传输时间同波特率下,比 RTU 少传输一倍的数据
字符集8bit 二进制,十六进制数 0…9,A…F十六进制,ASCII 字符 0…9,A…F
开始标记:
结束标记CR,LF
校验方式CRC 循环冗长检测LRC 纵向冗长检测
传输效率
程序处理较复杂ASCII 字符直观易调试
起始位1bit1bit
数据位8bit7bit
奇偶校验位1bit,无校验则无1bit,无校验则无
停止位1bit,无校验时 2bit1bit,无校验时 2bit

1.4 基本数据类型

  • 位 bit
    BOOL 布尔型,值为 0 或 1;如 I0.0、Q0.1
  • 字节 byte
    1 byte = 8 bit
    短整形类型;如 IB0 包括 I0.1~I0.7
  • 字 word
    1 word = 2 byte = 16 bit
    相邻的两个字节组成一个字,来表示一个无符号数
  • 双字 double word
    1 double word = 2 word = 4 byte = 32 bit
    相邻的两个字组成一个双字

2. 功能编码 function


    功能编码在报文中占用一个字节,编号范围限制 1 ~ 255。
    功能代码编号为 1 ~ 127,其中 65 ~ 72,100 ~ 110 是用户自定义编码,其他为通用功能编码。
    128 ~ 255 为保留值用于异常信息应答报文。

传输模式RTUASCIIPLC 单片机地址范围
0x01读线圈位bit00001-09999
0x02读离散量输入位bit10001-19999
0x03读保持寄存器字word40001-49999
0x04读输入寄存器位bit30001-39999
0x05写单个线圈位bit
0x06写单个寄存器字word
0x07读取异常状态诊断
0x08诊断诊断
0x0F写多个线圈位bit
0x10写多个寄存器字word

3. 报文格式说明

3.1 报文格式

传输模式报文格式
ASCII英文冒号 + 地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + LRC 高字节 + LRC 低字节 + 回车 + 换行
RTU地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + CRC 低字节 + CRC 高字节


    主站 Poll 端发送请求报文,从站 Slave 端响应报文;主从统一 Modbus 协议,功能编码,从站地址,传输方式,端口等信息;使用 Modbus 协议;
    Slave Id 从站唯一标识为 255,十六进制 0xFF;
    Function 功能编码统一读保持寄存器 03,十六进制 0x03;
    Address 规定从下标 0 开始读取,十六进制 0x0000;
    Quantity 规定读取数量为 2,十六进制 0x0002;

通过 Modbus Poll 工具可以看到:
RTU 传输模式下请求报文 FF 03 00 00 00 02 D1 D5
ASCII 传输模式下请求报文 3A 46 46 30 33 30 30 30 30 30 30 30 32 46 43 0D 0A ;

3.2 Modbus RTU 报文说明

Tx:000309-FF 03 00 00 00 02 D1 D5
Rx:000310-FF 03 04 00 0C 00 0A A5 F8

请求报文,主站寻址 Slave Id 为 255 的从站,从读保持寄存器起始位置 0 开始读取两个数据;
响应报文,Slave ID 为 255 的从站响应请求,从读保持寄存器返回两个数据 12、10;
rx 是接收,tx是发送。
请求报文 + 报文编号 + 地址 + 功能编码 + 起始地址 + 读取数量 + CRC 低字节 + CRC 高字节
请求报文 + 报文编号 + 地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + CRC 低字节 + CRC 高字节

  • Modbus RTU 请求报文
请求报文说明
Slave ID 从站地址0xFF
Function 功能编码0x03
Address 起始位置0x0000
Quantity 读取数量0x0002
CRC 低校验位0xD1
CRC 高校验位0xD5
  • Modbus RTU 响应报文
响应报文说明
Slave ID 从站地址0xFF
Function 功能编码0x03
Quantity 数据数量0x04
数据10x000C
数据20x000A
CRC 低校验位0xA5
CRC 高校验位0xF8

3.4 Modbus TCP 报文说明

Tx:000000-00 03 00 00 00 06 FF 03 00 00 00 0A
Rx:000001-00 03 00 00 00 17 FF 03 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

请求报文,使用 Modbus 协议,主站寻址 Slave Id 为 255 的从站,从读保持寄存器起始位置 0 开始读取 10 个数据;
响应报文,Slave ID 为 255 的从站响应请求,从读保持寄存器返回 10 个数据 0、0…、0;
标识发送请求 + 报文编号 + 通信标识符 + 协议标识符 + 数据长度 + 地址 + 功能编码 + 起始地址 + 读取数量
标识响应请求 + 报文编号 + 通信标识符 + 协议标识符 + 数据长度 + 地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n

  • Modbus TCP 请求报文
请求报文说明
Tx:000000标识发送请求
00 03通信事务处理标识符,应答报文要求与请求报文保持一致
00 00协议标识符,应答报文要求与请求报文一致,00 00 标识 modbus 协议
00 06数据长度,十六进制 0x0006,十进制数据长度为 6
FF从站 ID 唯一标识,十六进制 0xFF,十进制从站 ID 为 255
03功能编码,0x03 读保持寄存器
00 00读取寄存器起始位置,十六进制 0x00,十进制从下标 0 位置开始读取
00 0A读取寄存器长度,十六进制 0x000A,十进制读取寄存器长度 10
  • Modbus TCP 响应报文
响应报文说明
Rx:000001标识响应请求
00 03通信事务处理标识符,应答报文要求与请求报文保持一致
00 00协议标识符,应答报文要求与请求报文一致,00 00 标识 modbus 协议
00 17数据长度,十六进制 0x0017,十进制数据长度为 23
FF从站 ID 唯一标识,十六进制 0xFF,十进制从站 ID 为 255
03功能编码,0x03 读保持寄存器
00 00读取寄存器起始位置,十六进制 0x00,十进制从下标 0 位置开始读取
00 0A读取寄存器长度,十六进制 0x000A,十进制读取寄存器长度 10

4. Modbus 主站 Poll 端

    工业中通常 PLC 作为主站,比如西门子 PLC 产品。以西门子 S7-200 产品为例

4.1 编写 Modbus 主站初始化程序

    初始化 Modbus 通信始终接通

    MBUS_CTRL 指令用于初始化、监视或禁用 Modbus 通信。
    ON 设置为始终接通
    Mode 指通信模式,输入的数值选择通信协议;1 标识启用 Modbus 协议,0 标识启用 PPI 系统协议;
    Baud 指波特率,此处设置为 9600;
    Parity 指奇偶校验位;0 不校验,1 奇校验,2 偶校验;
    Timeout 指等待从站应答的毫秒时间数;超时数值可设置为 1~32767,常设置为 1000;

4.2 编写实现 Modbus 主站读写 Slave 从站的通信程序

    从地址为 3 的 Slave 从站读取 DI 通道从 I0.0 开始的 16 位的值,存放到 VB0 开始的存储区中。

地址 00001 是 Q0.0,地址 10001 是 I0.0,地址 30001 是 AIWO,地址 40001 是 V 存储器;
V 寄存器支持位、字节、字、双字访问,
VB 表示存储区的一个字节 Byte,存放短整形数据
VW 表示存储区的一个字 Word,存放整形
VD 表示存储器的两个字 Double Word,存放双整形、浮点型数据

    MBUS_MSG 指令用于启动对 Slave 从站的请求并处理应答;
    EN 和 First 输入打开时, MBUS_MSG 指令启动对 Slave 从站的请求;
    Slave 从站地址
    RW 指定读取或写入动作;读为 0 写为 1
    Addr 指起始的 Modbus 地址;
    Count 指在该请求中读取或写入的数据元素的数目;对于读写线圈是读取或写入的位数;对于读写寄存器是字数;
    DataPtr 指 S7-200 CPU 的 V 存储器中与读取或写入请求相关的数据的间接地址指针;对于读取请求应该指向用于存储从 Slave 从站读取的数据的第一个 CPU 存储器位置;对于写入请求,指向要发送到 Slave 从站的数据的第一个 CPU 存储器位置;

    向地址为 3 的 Slave 从站写入 5 个保持寄存器数据,从 CPU 的 VB10-VB19 获取 5 个写数据后,写入 Slave 从站中的地址 40001-40005。

    程序运行后,就一直在寻址 SlaveID 为 3 的从站服务,对从站进行请求,相应的从站接收到请求后进行响应。

5. Modbus 从站 Slave 端

    此处通过 Java 实现 Modbus TCP 从站端服务。

5.1 编写 Slave 从站 Java 程序

    从站设置 TCP 连接,初始化一个从站 ModbusSlave,规定主站从站 host、port,规定功能编码为 0x03,初始化都保持寄存器,从偏移位 0 开始,存放 2 个数值型数据,启动 ModbusSlave 监听服务。

import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.net.InetAddress;

/**
 * @author niaonao
 * @version 1.0.0
 * @since 2022/5/11
 */
public class ModbusSlaveLocal 
    private static final Log LOG = LogFactory.getLog(ModbusSlaveLocal.class);
    /**
     * 从站地址
     */
    private static final int SLAVE_ADDRESS = 0xFF;
    private static final int ONE_SECOND = 1000;
    private static final int SIZE = 2;

    /**
     * 从站IP、端口
     */
    private static final String SLAVE_HOST = "127.0.0.1";
    private static final int SLAVE_PORT = 501;

    public static void main(String[] args) 
        try 
            // 设置控制台输出主站和从站命令交互日志
            Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

            // 创建读保持寄存器,从第 0 个位置开始写入 2 个数值数据;即写入数据到地址 40001-40002
            ModbusHoldingRegisters holding = new ModbusHoldingRegisters(SIZE);
            for (int i = 0; i < SIZE; i++) 
                holding.set(i, i);
            
            DataHolder dataHolder = new DataHolder();
            dataHolder.setHoldingRegisters(holding);

            // 创建从站
            TcpParameters tcpParameters = new TcpParameters();
            InetAddress address= InetAddress.getByName(SLAVE_HOST);
            tcpParameters.setKeepAlive(true);
            tcpParameters.setHost(address);
            tcpParameters.setPort(SLAVE_PORT);
            ModbusSlave slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
            slave.setServerAddress(SLAVE_ADDRESS);
            slave.setReadTimeout(ONE_SECOND);
            slave.setDataHolder(dataHolder);
            slave.listen();

            // 这部分代码主要是设置Java虚拟机关闭的时候需要做的事情,即本程序关闭的时候需要做的事情,直接使用即可
            if (slave.isListening()) 
                Runtime.getRuntime().addShutdownHook(new Thread() 
                    @Override
                    public void run() 
                        synchronized (slave) 
                            slave.notifyAll();
                        
                    
                );

                synchronized (slave) 
                    slave.wait();
                

                /*
                 * using master-branch it should be #slave.close();
                 */
                slave.shutdown();
            
         catch (Exception e) 
            LOG.warn("从站程序执行异常信息:" + e.getMessage(), e);
        
    

5.2 主站测试工具 Poll 通信从站 Java 程序

    测试工具 Modbus Poll 模拟请求 Slave ID 为 255 的从站服务。
    Poll 端使用测试工具测试,通过 SlaveId 地址寻址请求 Slave 从站,从地址 0 开始读取 2 个数据,即地址 40001、40002。
    响应报文可以看到,主站请求得到响应,响应报文包含了 Slave 端放入读保持寄存器的两个数据,数值 0 和数值 1。


    启动 Slave 端 Java 程序,Poll 配置后连接上 Slave 从站,请求正常响应,请求响应报文如下:

Tx:000453-05 AD 00 00 00 06 FF 03 00 00 00 02
Rx:000454-05 AD 00 00 00 07 FF 03 04 00 00 00 01

参考文章
ModBus协议报文格式解析说明
我是Modbus-RTU协议,我有两个兄弟
西门子 S7-200 Modbus RTU 主站编程

以上是关于Modbus 协议从站开发通信西门子 PLC的主要内容,如果未能解决你的问题,请参考以下文章

Modbus 协议从站开发通信西门子 PLC

西门子S7-200PLC网络通信协议都有哪些?各有啥特点?

请教高手如何实现西门子PLC与AB PLC之间的通讯

Modbus Slave是指啥意思

MPI转以太网Plus模块Modbus主站连接两台变频器通信案例

西门子PLC有几种通讯方式