基于Python的Modbus RTU应用示例

[复制链接]
查看59399 | 回复0 | 2024-10-19 10:45:40 | 显示全部楼层 |阅读模式
简介

这篇文章写如何使用Python语言 与PLC 进行Modbus RTU通信。

相比ModBus TCP,Modbus RTU要慢很多,而且设备之间的通信连接也比较麻烦,还需要掌握一定的串行相关的硬件以及协议等知识。现实应用中有大量的设备只支持串行通信,所以Modbus RTU还是非常有必要学习和掌握的。

硬件清单

    笔记本电脑一部台达DVP系列PLC一台USB转RS232电缆一根Moxa RS232转RS485 转换器一个

补充说明:
    台达PLC作为从站设备  型号为DVP60ES2,其拥有3个com口,com1为RS232接口,com2,com3 为RS485接口



Delta-DVP-PLC

    由于笔记本没有串口,使用USB转RS232电缆实现串口功能




    本例程中会使用RS485接口和PLC通信,那么就需要使转换器将RS232 信号转换为 RS485。为何不直接用RS232进行modbus通信呢,因为RS232只支持两个设备之间一对一的通信,只有将RS232转换成RS485 才能具备多个设备站点组网的能力,才可以实现远程多机通信。




通信线接线

1.使用一根带有屏蔽的双绞线,棕色线接PLC的COM2 D+端子,蓝色线接PLC的COM2 D-端子,按照标准要在最后一个从站的D+与D-端子之间接一个120欧姆的终端电阻来消除线路阻抗带来的反射波。(本例程只有一个从站,未接电阻)



2.双绞线的另一端接在信号转换器上,其中棕色线接R+/D+端子,蓝色线接R-/D-端子。



3.将USB转RS232电缆和信号转换器插在一起,将电缆的USB端插在电脑U口上。


PLC上电,并将拨码开关打到run挡位。



串行通信参数基本概念

Modbus RTU是基于串行通信技术之上的一种应用层协议,而串行通信的基本参数有:

波特率:数据传输速率(表示每秒传输的位bit的个数)

数据位:通信中传输一组数据包含的位数。

停止位:通信数据包或者数据帧的最后一位。

奇偶校验位:奇偶校验位是串行通信中的一种数据检错方式。

串行通信常用的通信格式为( 9600,8,N,1)表示波特率为9600b/s,8位数据位,无奇偶校验,1位停止位。

从机设备串行端口参数设置

在多机串行网络中,包括主站在内的每一台设备的串行参数必须一致,否则无法通信。

Modbus串行网络中每一个从站都必须有一个唯一性的ID来标记自己在网络中的身份,这就是站号的意义。

Modbus TCP 是基于以太网协议,网络中每一个设备都有唯一的IP地址,所以ModBus TCP从站不需要站号。

台达PLC的com2参数需要编程来设置成我们想要的,PLC作为从站,同时要给PLC分配一个站号,并规定通信模式为RTU模式。



台达PLC-com2通信参数设置
说明:

    PLC上电之后的第一 个扫描周期(M1002)为TRUE,用于触发初始化程序。16#81 = 2# 1000 0001 =(9600,8,N,1),将参数16#81mov至D1120(com2参数寄存器),详情可查阅PLC手册将M1143设为TRUE表示 设置com2为RTU模式将M1120设为TRUE表示 设置com2通信保持将十进制 2 mov至D1121 表示设PLC的站号为 2将十进制 500 mov至D1129 通信超时时间为 500ms

PLC通信初始化程序写好之后下载至PLC中。

当程序运行之后PLC的COM2端口参数就被设置成9600/8-N-1;RTU模式;2号站。

Python主站程序

首先要在自己的电脑中部署python环境,请参阅历史文章《基于python的MQTT客户端》一文。

python代码中会用到modbus_tk库,如何安装modbus_tk请翻看《使用Python操作Ge Fanuc PLC》内容。

同时代码中需要使用到serial模块,是一个Python操作串行端口的库,一般安装python时会默认安装。

Modbus TRU的python程序示例:
import serial
import modbus_tk
import modbus_tk.defines as CST
from modbus_tk import modbus_rtu

   
def mod(PORT="com4"):#在 PORT 参数位置写自己串行端口的端口号 如 com1 com2 或者 com3
    response = []         #名为response的列表用来存储反馈数据。
    alarm = ""       #用来存放异常信息
    try:
      
        # 设定串口参数———— 此处的设置必须和从机设备的端口参数一致
        # 示例中参数为 9600 8 N 1
        master = modbus_rtu.RtuMaster(serial.Serial(
                                                        port=PORT,
                                                        baudrate=9600,
                                                        bytesize=8,
                                                        parity='N',
                                                        stopbits=1
                                                    ))

        master.set_timeout(3.0) #timeout
        master.set_verbose(True)
  
        # 读保持寄存器
        response = master.execute(
                                2,                          # 从站的站号 --->取决于从站的站号设置
                                CST.READ_HOLDING_REGISTERS, # modbus功能码 --->可以直接用功能码替代
                                0x1000,                     # 从站Modbus寄存器起始地址  --->数据格式 可以是 DEC 可以是 HEX
                                4                           # 被操作的寄存器的数量 --->包含起始地址的连续n个寄存器
                            )
        print(response)

        alarm = "ok" #正常返回提示
        return list(response),alarm

    except Exception as exc:
        print(str(exc))
        alarm = (str(exc))

    return response, alarm  #异常返回故障信息

if __name__ == "__main__":

     mod() # 如果需要连续执行  将mod()函数包含在循环语句的循环体中即可

这是一个示例程序,如果需要进行其他操作只需要修改第27行response = master.execute( )语句括号中的内容即可。

注意:PORT参数取决自己电脑的端口号,如:com1,com2。


功能码说明:
# supported modbus functions 功能代码
# 读线圈
READ_COILS = 1
# 离散读输入
READ_DISCRETE_INPUTS = 2
# 读保持寄存器
READ_HOLDING_REGISTERS = 3
# 读输入寄存器
READ_INPUT_REGISTERS = 4
# 写单一线圈
WRITE_SINGLE_COIL = 5
# 写单一寄存器
WRITE_SINGLE_REGISTER = 6
# *读例外状态
READ_EXCEPTION_STATUS = 7
DIAGNOSTIC = 8
# *报告slave的id
REPORT_SLAVE_ID = 17
# 写多个线圈
WRITE_MULTIPLE_COILS = 15
# 写多寄存器
WRITE_MULTIPLE_REGISTERS = 16
# *读写多个寄存器
READ_WRITE_MULTIPLE_REGISTERS = 23
# *设备信息
DEVICE_INFO = 43

# supported block types 支持的块类型
# 线圈
COILS = 1
# 离散输入
DISCRETE_INPUTS = 2
# 保持寄存器
HOLDING_REGISTERS = 3
# 模拟量输入
ANALOG_INPUTS = 4



异常代码说明:
#modbus exception codes  异常代码
# 代码功能不合法
ILLEGAL_FUNCTION = 1
# 数据地址不合法
ILLEGAL_DATA_ADDRESS = 2
# 数据值不合法
ILLEGAL_DATA_VALUE = 3
# slave设备失败
SLAVE_DEVICE_FAILURE = 4
# 命令已收到
COMMAND_ACKNOWLEDGE = 5
# slave设备忙
SLAVE_DEVICE_BUSY = 6
# 内存奇偶校验差
MEMORY_PARITY_ERROR = 8


操作示例1:
# 操作2号从站;功能码 10#15 = hex0f;起始地址Y0 = 10#1280; 连续操作数12个 ;输出值放在一个列表[]中。
response = master.execute(2, CST.WRITE_MULTIPLE_COILS, 1280,12, output_value = [1,1,1,0,1,0,1,0,1,1,1,1])

执行后效果如图:



写Y输出
操作示例2:
# 目标设备:2号从站,从T0 开始 连续写 2 个定时器寄存器  T0 地址1536  功能码 16 = hex10
response = master.execute(2, CST.WRITE_MULTIPLE_REGISTERS, 1536,2, output_value = [1234,9876])
print(response)



video: https://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&action=mpvideo&auto=0&vid=wxv_1990240136034385921

操作示例3:
#  目标设备:2号从站,从D0 开始连续写6个寄存器  D0 地址  = 4096   功能码 16 = hex10
response = master.execute(2, CST.WRITE_MULTIPLE_REGISTERS, 4096,4, output_value = [9999,8888,7777,6666,5555,4444])
print(response)



video: https://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&action=mpvideo&auto=0&vid=wxv_1990235072234389507

操作示例4:
#  目标设备:2号从站,从D0 开始连续读取6个寄存器  D0 地址  = 4096   功能码 3= hex03
response = master.execute(2, CST.READ_HOLDING_REGISTERS, 4096,6)
print(response)



video: https://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&action=mpvideo&auto=0&vid=wxv_1990237245638836228

使用Python操作GE Fanuc Rx3i PLC

基于Python的MQTT客户端

PowerFlex 变频器参数备份&恢复

TDengine部署与基本运维

Redis学习笔记

MariaDB数据库 部署与配置指南 - CentOS 8

物联网-MQTT服务器搭建-阿里云篇

ModBus仿真环境的搭建

ModBus通信协议之功能码&寄存器

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册哦

x
您需要登录后才可以回帖 登录 | 注册哦

本版积分规则