前言:

自己学习python的过程中,偶然接触到 modbus_tk 这个库,以前学习过modbus,在新的python语言环境下学习,权当复习了,记录下过程,感谢各位道友的分享,让我也少走了很多弯路。

modbus_tk 搭建modbu_rtu 主站 :MODBUS学习笔记——modbus tk modbus TCP主机实现_物联网 IoT 经验分享-_modbus tk

pyhon3 支持的浮点数处理:modbus_tk 读取浮点数的处理_u010161190的博客_modbus浮点数怎么读取

python struct 学习:python之struct详解_编程之路_python struct

环境:

modbusSlave  (分配com7)

vspd    (虚拟com2 <==> com7 )

modbu_rtu.py ( 分配com2)

过程:

0> 配置modbus slave , 端口、通讯参数等

1> 打开modbus slave, 模拟出各个寄存器区,设置好寄存器的数据方式,signed? float ABCD?float DCBA?

python实现modbus tcp控制 python modbus slave_寄存器

2> 参照网友xukai871105例子,操作各数据区,观察从站数据区;在其基础上测试了 对浮点数、双精度浮点数和负数的读写

# 这是一个modbus Rtu 主站
# 使用vspd 做互联工具
# 使用modbus slave 工具 模拟 Rtu 从站
# 对于浮点数的处理
# 方案一:通过将你所得到的带小数的放大一定的倍数,都变成整数进行处理,例如:3.24  --放大100   变成 324 ,然后上位机知道我放大了100 倍就好
# 方案二:头铁,我就是要读
import serial
import struct
import logging
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_rtu as modbus_rtu
logger = modbus_tk.utils.create_logger("console")

if __name__ == '__main__':
    try:
        serial = serial.Serial(port="COM2",baudrate=9600,bytesize=8,parity='N',stopbits=1)
        master = modbus_rtu.RtuMaster(serial)
        master.set_timeout(5.0)
        master.set_verbose(True)
        logger.info("connected!")

        # 写单个寄存器
        logger.info(master.execute(1, cst.WRITE_SINGLE_REGISTER, 0, output_value=99))
        logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1))

        # 写单个寄存器 负数
        logger.info(master.execute(1, cst.WRITE_SINGLE_REGISTER, 1, output_value=-123))
        logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 1, 1))

        # 写多个寄存器 起始地址为4的保持寄存器,操作寄存器个数为4 ,根据列表长度来判断写入个数
        logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4, output_value=[3,-13, 6,24]))
        # 读也读4个寄存器
        read_data = master.execute(1, cst.READ_HOLDING_REGISTERS, 4, 4)

        # 写寄存器 起始地址为8的保持寄存器,操作寄存器个数为 4 ,一个浮点数float 占两个寄存器;
        # 写浮点数时一定要加 data_format 参数,两个ff 表示要写入两个浮点数,以此类推
        # 我这里模拟的是小端模式,具体可参考 struct 用法。和数据源保持一致即可。
        logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 8, output_value=[3.3,-6.4],data_format='<ff'))
        # 读对应的 4个寄存器,指定数据格式
        read_data = master.execute(1, cst.READ_HOLDING_REGISTERS, 8, 4,data_format='<ff')
        logger.info(read_data)

        # 写入 双精度 数据到寄存器
        logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 16, output_value=[3.313, -6.414], data_format='<dd'))
        read_data = master.execute(1, cst.READ_HOLDING_REGISTERS, 16, 8, data_format='<dd')

        # 写单个线圈,写寄存器地址为0的线圈寄存器,写入内容为1  位操作)
        logger.info(master.execute(1, cst.WRITE_SINGLE_COIL, 0, output_value= 1))
        logger.info(master.execute(1,cst.READ_COILS,0,1))

        # 写多个线圈 写寄存器地址为1的线圈寄存器,写入内容为列表内容  位操作)
        logger.info(master.execute(1, cst.WRITE_MULTIPLE_COILS,1,output_value=[0,1,1,0]))
        logger.info(master.execute(1,cst.READ_COILS,1,4))

        # 读保持寄存器,从 8 开始读 8 个,元组形式返回
        data = master.execute(1, cst.READ_HOLDING_REGISTERS, 8, 8)
        logger.info(data)

        # 读输入寄存器,从 2 开始读 5 个,元组形式返回
        logger.info(master.execute(1, cst.READ_INPUT_REGISTERS, 2, 5))

        # 读线圈寄存器
        logger.info(master.execute(1, cst.READ_COILS, 8, 8))

        # 读离散输入寄存器
        logger.info(master.execute(1, cst.READ_DISCRETE_INPUTS, 8, 8))

        # 同时读写多个寄存器
        # ??

    except modbus_tk.modbus.ModbusError as e:
        logger.error("%s-ErrCode=%d" % (e, e.get_exception_code()))

python实现modbus tcp控制 python modbus slave_python_02

总结:

1 > modbus_rtu和tcp 对数据的操作是统一的;

2> python 中struct 的理解有待提高,对于做工控这一块,和底层数据打交道的回合还是少不了的。