如何实现Python对FX5U的通讯读写?

需要实现的功能大致是这样的:Python程序实现对三菱FX5U的通讯读写,通过Python程序得到脉冲数,将脉冲数发送给FX5U,从而实现PLC对相关步进电机的旋转圈数的控制,

https://blog.csdn.net/weixin_39880318/article/details/110503673

https://blog.csdn.net/alai986/article/details/84953859?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control

author: alai
date:2018/05/01
"""

import socket
import time
import xlwt,xlrd,struct
from xlutils.copy import copy
import sys
import re,os,sys

data="ok"

           
class TcpThread(QThread):

    trigger = pyqtSignal(str)
    trigger1=pyqtSignal(str)

    def __int__(self):
        super(TcpThread, self).__init__()

    # 分离出一个函数用于循环tcp 重连

    def doConnect(self):
        with open('IP_Address.txt', 'r')as fn:
            s1 = fn.read()
        host = ''.join(re.findall(r'IP:(.*)', s1))  # 服务器IP地址取出来,并转成字符串
        port = int(''.join(re.findall(r'PORT:(.*)', s1)))  # 从文本中提取端口号转成整数
        BUFFSIZE = int(''.join(re.findall(r'BUFFSIZE:(.*)', s1)))  # 从文本中提取字符长度转整数
        ADDRESS = (''.join(re.findall(r'ADDRESS:(.*)', s1)))  # 从文本中提取字符长度转整数
        LENGTH = (''.join(re.findall(r'LENGTH:(.*)', s1)))  # 从文本中提取字符长度转整数
        print(host,port,ADDRESS,LENGTH)

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            sock.connect((host, port))
            print("connect is ok")
        except:
            print('fail to setup socket connection')
        return sock, BUFFSIZE,ADDRESS,LENGTH

    # 发送数据

    def tcpClient(self):
        global glb_tag
        glb_tag=0
        global glb_data

        sockLocal, BUFFSIZE,ADDRESS,LENGTH = self.doConnect()


        while True:

            # 等于0,那么一直查询
            if glb_tag==0:
                self.data1 = '500000FF03FF000018000004010000D*00'

                self.data = self.data1+ADDRESS+LENGTH
                # print(self.data)


                try:
                    sockLocal.send(self.data.encode())
                except socket.error:
                    print("\r\nsocket error,do reconnect ")
                    sockLocal.close()
                    time.sleep(1)
                    sockLocal, BUFFSIZE = self.doConnect()
                except:
                    sockLocal.close()
                    print("other error")
                    time.sleep(1)
                    sockLocal, BUFFSIZE = self.doConnect()

                time.sleep(0.5)
                str1 = sockLocal.recv(BUFFSIZE).decode()


                if str1[22:26]=="0001":

                    glb_tag=1
            # 等于1,写入并等待结果

            elif glb_tag==1:
                # 发射信号,连接到datadisplay

                self.trigger.emit(str1)

                self.data1 = '500000FF03FF00001C000014010000D*00499900010001'
                try:
                    sockLocal.send(self.data1.encode())

                except socket.error:
                    print("\r\nsocket error,do reconnect ")
                    sockLocal.close()
                    time.sleep(1)
                    sockLocal, BUFFSIZE = self.doConnect()
                except:
                    sockLocal.close()
                    print("other error")
                    time.sleep(1)

                    sockLocal, BUFFSIZE = self.doConnect()

                time.sleep(0.3)
                str1 = sockLocal.recv(BUFFSIZE).decode()
                # print(glb_str1[16:18])
                # 如果返回的数据长度是对应长度,那么不再写
                if str1[16:18]=="04":
                    glb_tag = 0
            # 等于2,PLC 数据查询
            elif glb_tag==2:
                self.data1='500000FF03FF000018000004010000D*00'
                # 先转成字符串,然后填满四位
                self.data2=("".join(re.findall("[D|d](\d+)",glb_data)))
                self.data3=self.data2.zfill(4)
                # print(glb_data+str(12))
                # print(self.data2)
                self.data=self.data1+self.data3+"0010"
                # print(self.data)

                try:
                    sockLocal.send(self.data.encode())

                except socket.error:
                    print("\r\nsocket error,do reconnect ")
                    sockLocal.close()
                    time.sleep(1)
                    sockLocal, BUFFSIZE = self.doConnect()
                except:
                    sockLocal.close()
                    print("other error")
                    time.sleep(1)
                    sockLocal, BUFFSIZE = self.doConnect()


                time.sleep(0.3)
                glb_tag = 0
                str1 = sockLocal.recv(BUFFSIZE).decode()
                # print(glb_str1)
                self.trigger1.emit(str1)
            #     PLC数据写入
            elif glb_tag==3:
                # print("li")
                self.data1='500000FF03FF00001C000014010000D*00'
                # 先转成字符串,然后填满四位
                self.data2=("".join(re.findall("(\d+)=",glb_data))).zfill(4)
                self.data3=("".join(re.findall("=(\d+)",glb_data))).zfill(4)
                # print(hex(int(self.data3)))
                # 先转成16进制,然后匹配出来,舍掉0x,然后转成字符串,然后填满0
                self.data4=("".join(re.findall("0x(\w+)",hex(int(self.data3))))).zfill(4)

                self.data=self.data1+self.data2+"0001"+self.data4
                # print(self.data)

                try:
                    sockLocal.send(self.data.encode())

                except socket.error:
                    print("\r\nsocket error,do reconnect ")
                    sockLocal.close()
                    time.sleep(1)
                    sockLocal, BUFFSIZE = self.doConnect()
                except:
                    sockLocal.close()
                    print("other error")
                    time.sleep(1)
                    sockLocal, BUFFSIZE = self.doConnect()


                time.sleep(0.3)
                str1 = sockLocal.recv(BUFFSIZE).decode()
                glb_tag = 2
                # glb_str1 = sockLocal.recv(BUFFSIZE).decode()


    def run(self):
        #必须从run开始启动程序

        # global data


        self.tcpClient()

三菱PLC(FX5U)和C#通讯说明

所需的软件和插件:Visual Studio 2015,GX Work3,MX Component

1.下载并安装三菱软件

GX Work3:https://pan.baidu.com/s/129VnuvQ8R9GjfY4CnuR7Hw
提取代码:5l4e
MX组件:https
://pan.baidu.com/s/1Tc2eC7vog7a7QQIBLppn6w提取代码:7n0b

三菱官方下载网址:
http ://cn.mitsubishielectric.com/fa/zh/download/dwn_idx_software.asp

如图所示,下载GX Works3和MX Component。安装序列号为:117-610768844(官方下载需要登录帐户注册,如果无法收到移动验证码完成注册,则可以在注册右侧选择非内地用户的注册方式页面,您可以通过电子邮件直接注册)


GX Work3安装:下载完成后,解压缩软件包以获取文件夹GXW3 Ver-1-065T。
依次进入文件夹GXW3 Ver.1.065T(安装包)sw1dnd-gxw3-c_1065t_f-Disk1直接运行Disk1文件目录中的setup.exe安装程序,并执行安装操作。(有关中间所需的序列号,请参见上文)安装完成后,桌面上将出现两个软件图标GX Works3和e-Manual Viewer,以指示安装成功。

MX Component安装:下载完成后,将压缩文件解压缩到新文件夹中。如图所示,首先,在EnvMEL文件夹中安装setup.exe安装程序。安装完成后,在解压缩的文件夹中运行setup.exe安装程序。默认情况下,安装过程为所有安装(中间要求的顺序)编号。

一,用于PLC设置的GXwork3软件

下载和安装完成后,打开GXworks3软件,在工具栏左上角的项目中,创建一个新项目,如图所示进行设置,确认新项目。

依次单击工具栏中的“联机”(当前连接目标),然后选择PC适配器,该IP地址将自动匹配。PC端网段必须与PLC地址一致,其中PLC端ip已设置为192.168.3.251(设置方法请参见下文),而PC端ip已设置为192.168.3.250。单击通信测试,如果成功,将出现一个提示,如图所示。(每个PC适配器可能有不同的选项。第一次连接到PLC设备时,选择适配器后,将显示PLC的默认地址。此处已为PLC设置了IP地址,因此连接的IP地址如图所示)

通讯测试成功后,依次单击从可编程控制器在线读取,单击参数+程序按钮,然后单击执行以读取PLC中的程序(由于已编写测试程序,因此新的PLC会读出该程序)是一个空程序。)

注意:如果要修改PLC的IP地址,请单击左侧工具栏参数FX5UCPU模块参数以太网端口,如图所示,可以在自节点设置中设置ip。

2. MX Component软件连接测试

下载并安装后,在计算机开始菜单中找到新安装的通信插件“通信”
。Setup Utility以管理员身份运行。

  • 1

   Set the site number, you can set any, as long as the front and back match, set it to 1.
  • 1

设置PC端参数,在下拉选项框中选择“ Ethernet”
和“ CPU modul(FX5)”

设置PLC参数并输入PLC IP地址。(必须与GXworks3中设置的地址一致)

如图所示设置站点和CPU类型。

这次设置向导的名称,只需选择一个即可。在这里,以1完成。

设置完成后,如下图所示。

单击“连接测试”,然后单击“测试”,它显示成功。

3. C#程序与PLC通讯测试

检查第二步中设置的向导相关参数。打开Communication Setup Utility软件,单击“列表
视图”,将右下角的“人机界面”切换到“程序”模式,并查看相关参数,如图所示。

切换到程序模式后,需要注意前三个参数。如图所示,这三个参数用于后续的C#程序通信参数匹配。其中StationNumber是站号,ActunitType是所选的CPU类型,这里是FX5U系列,ActProtocolType是使用的通信协议类型,这是TCP协议

打开C#-PLC程序文件夹并运行Sample2010.sln,打开Form1.cs,单击“打开”按钮,然后修改相关参数。

如图所示,找到代码块,红色框中的代码需要修改。根据功能名称对应上面记录的参数值,并更改参数值。为了方便起见,密码设置为空白。

完成后,您可以运行该程序。

如图所示,选择ActUtltype选项,使用先前设置的编号填写站点编号,此处为1,然后单击“打开”按钮,如果PLC成功连接,则右侧的输出返回值显示0x00000000
[ [十六进制]。如果再次单击打开按钮以重复连接,它将返回0xf0000003 [HEX],其余的返回值都是连接错误。
![在此处插入图片描述](https://img-blog.csdnimg.cn/20200810085500597.png

在DevicelName列中填写寄存器名称,DataSize列固定为1,DeviceData填写要写入的数据值,右侧的Data列显示已读取的寄存器值。

以下是C#与PLC程序之间的通讯测试,通过GXwork3软件的监视功能,可以在线检测PLC。如图所示,单击GXwork3中的监视开始按钮。

测试数据写入功能,数据写入功能代码的一部分如图所示:

运行程序,输入位寄存器名称M117,数据位数1,写入数据值1或0,单击Write,右边的返回值显示0x00000000 [HEX],表示写入成功。此时,从GXwork3监视功能可以看出,M117的当前值变为1,Y1的值也变为1,并且PLC数据的写入是正常的。

以相同的方式输入字寄存器名称W10,数据位数为1位,写入数据200,然后单击“写入”成功写入。观察GXworks3,发现W10的值已更改为200,并且PLC数据的写入是正常的。

同样,测试数据读取功能,读取功能代码的一部分如图所示。

输入位寄存器名称M114,数据位数为1位,然后单击“读取”以读取右侧结果框中的数据。

输入字寄存器名称W10,数据位数为1位,然后单击“读取”以读取右侧结果框中的数据。

PLC程序的一部分如图所示:

下载的三菱里有相关代码

import serial

from timeimport sleep

 

def recv(serial):

  while True:

    data= serial.read_all()

    if data== '':

      continue

    else:

      break

    sleep(0.02)

  return data

 

if __name__== '__main__':

  serial= serial.Serial('COM5',9600, timeout=0.5)#/dev/ttyUSB0

  if serial.isOpen() :

    print("open success")

  else :

    print("open failed")

 

  while True:

    data=recv(serial)

    if data != b'' :

      print("receive : ",data)

      serial.write(data)#数据写回

什么错误