当前位置:   article > 正文

python modbus-tk 实现三菱FX5U modbus-tcp 从站通讯_三菱fx5umodbustcp通讯程序

三菱fx5umodbustcp通讯程序

一、三菱FX5U 从站设置

        1. 打开GX works3 软件

        2. 新建项目

        3.按向导流程指示设置modbus-tcp从站功能

                                                 

                 

 

         4.下载模块参数到PLC,并断电重启PLC。

注意:部分PLC会发生模块参数报警,需要PLC做固件升级。

二、PC端设置

        1. pip install modbus-tk,struct

        2. main.py

  1. import modbus_tk
  2. import modbus_tk.defines as cst
  3. import modbus_tk.modbus_tcp as modbus_tcp
  4. from shuJuZhuangHuang import WriteDint as wd
  5. import os
  6. import tkinter as tk
  7. import tkinter.font as tkFont
  8. import tkinter.ttk as ttk
  9. import csv
  10. from socket import *
  11. import sys
  12. import threading
  13. import time,random,queue
  14. import pickle
  15. import re
  16. from configparser import ConfigParser
  17. logger = modbus_tk.utils.create_logger("console")
  18. # 读取配置文件
  19. cfg = ConfigParser()
  20. cfg.read('config.ini')
  21. SERVER= cfg.get('Server','IP')
  22. PORT= cfg.getint('Server','PORT')
  23. MACROFILE = cfg.get('File','macroFile')
  24. MACROCOPY = cfg.get('File','macroCopy')
  25. timeSave = os.path.getmtime(MACROFILE)
  26. # 打包函数
  27. def thread_it(func,*args):
  28. '''将函数打包进程'''
  29. # 创建进程
  30. t = threading.Thread(target=func,args=args)
  31. # 守护进程
  32. t.setDaemon(True)
  33. # 启动
  34. t.start()
  35. class GuiPart():
  36. def __init__(self):
  37. self.threadFlg1 = True
  38. self.caiLiao = 0
  39. self.jiaGongZongShu = 0
  40. self.gongJianChanDu = 0
  41. self.qiShiWeiZhi1 = 0
  42. self.jieShuWeiZhi1 = 0
  43. self.qiShiWeiZhi2 = 0
  44. self.jieShuWeiZhi2 = 0
  45. self.qiShiWeiZhi3 = 0
  46. self.jieShuWeiZhi3 = 0
  47. self.qiShiWeiZhi4 = 0
  48. self.jieShuWeiZhi4 = 0
  49. self.tuiHuoCiShu = 0
  50. self.xieRuFlg = 0 # 写入允许-0 禁止-1
  51. # 连接MODBUS TCP从机
  52. try:
  53. master = modbus_tcp.TcpMaster(host=SERVER,port=PORT)
  54. master.set_timeout(5.0)
  55. self.master = master
  56. except modbus_tk.modbus.ModbusError as e:
  57. logger.error("%s- Code=%d" % (e, e.get_exception_code()))
  58. thread_it(self.readMacro)
  59. self.guiProcess()
  60. # 调整屏幕
  61. def center_window(self,root,w,h):
  62. '''
  63. 窗口居于屏幕中央
  64. :param root: root
  65. :param w: 窗口宽度
  66. :param h: 窗口高度
  67. :return:
  68. '''
  69. # 获取屏幕 宽、高
  70. ws = root.winfo_screenwidth()
  71. hs = root.winfo_screenheight()
  72. # 计算x、y位置
  73. x = (ws/2) - (w/2)
  74. y = (hs/2) - (h/2)
  75. root.geometry('%dx%d+%d+%d' %(w,h,x,y))
  76. def send(self):
  77. try:
  78. # # 写寄存器起始地址为500的保持寄存器,操作寄存器个数为1
  79. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 500 , output_value=[self.caiLiao]))
  80. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 604, output_value=[self.jiaGongZongShu]))
  81. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 608, output_value=wd(self.gongJianChanDu)))
  82. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4606, output_value=wd(self.qiShiWeiZhi1)))
  83. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4608, output_value=wd(self.jieShuWeiZhi1)))
  84. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4610, output_value=wd(self.qiShiWeiZhi2)))
  85. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4612, output_value=wd(self.jieShuWeiZhi2)))
  86. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4614, output_value=wd(self.qiShiWeiZhi3)))
  87. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4616, output_value=wd(self.jieShuWeiZhi3)))
  88. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4618, output_value=wd(self.qiShiWeiZhi4)))
  89. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4620, output_value=wd(self.jieShuWeiZhi4)))
  90. logger.info(self.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 4622, output_value=[self.tuiHuoCiShu]))
  91. except modbus_tk.modbus.ModbusError as e:
  92. logger.error("%s- Code=%d" % (e, e.get_exception_code()))
  93. def reset(self):
  94. print('reset')
  95. self.threadFlg1 = True
  96. thread_it(self.readMacro)
  97. def readMacro(self):
  98. global timeSave
  99. while self.threadFlg1:
  100. time.sleep(0.2)
  101. # 读取PLC M4606 写入标志
  102. try:
  103. self.xieRuFlg = self.master.execute(2, cst.READ_COILS, 9228, 1)[0]
  104. except modbus_tk.modbus.ModbusError as e:
  105. logger.error("%s- Code=%d" % (e, e.get_exception_code()))
  106. """
  107. # print("flg: " )
  108. self.xieRuFlg = 1
  109. print(self.xieRuFlg)
  110. """
  111. # 如果写入标志==0可以写入,否则禁止更新。
  112. if self.xieRuFlg == 0:
  113. timeLast = os.path.getmtime(MACROFILE)
  114. # print(timeLast,' > ',timeSave)
  115. if timeLast > timeSave:
  116. # print('time change')
  117. timeSave = timeLast
  118. os.system(r'copy %s %s'%(MACROFILE,MACROCOPY))
  119. f = open (MACROCOPY,'r')
  120. fileLines = f.readlines()
  121. f.close()
  122. # 读取数据
  123. for item in fileLines:
  124. patt = r'(\d+)\D+?((-)?\d+\.?\d{0,3})' # 匹配 500 = 34 500=34 500 = 34. 500 =34.5 500 = -34.565 不完全匹配 34.34352345
  125. m = re.match(patt,item)
  126. if m:
  127. shapu = m.group(1)
  128. data = m.group(2)
  129. # 读取变量
  130. if shapu == '500':
  131. self.caiLiao = int(data)
  132. elif shapu == '501':
  133. self.jiaGongZongShu = int(data)
  134. elif shapu == '502':
  135. self.gongJianChanDu = int(float (data) * 10000)
  136. elif shapu == '503':
  137. self.qiShiWeiZhi1 = int(float (data) * 10000)
  138. elif shapu == '504':
  139. self.jieShuWeiZhi1 =int(float (data) * 10000)
  140. elif shapu == '505':
  141. self.qiShiWeiZhi2 =int(float (data) * 10000)
  142. elif shapu == '506':
  143. self.jieShuWeiZhi2 =int(float (data) * 10000)
  144. elif shapu == '507':
  145. self.qiShiWeiZhi3 =int(float (data) * 10000)
  146. elif shapu == '508':
  147. self.jieShuWeiZhi3 =int(float (data) * 10000)
  148. elif shapu == '509':
  149. self.qiShiWeiZhi4 =int(float (data) * 10000)
  150. elif shapu == '510':
  151. self.jieShuWeiZhi4 =int(float (data) * 10000)
  152. elif shapu == '511':
  153. self.tuiHuoCiShu = int(data)
  154. self.send()
  155. self.l_0_state.configure(bg = 'green')
  156. self.varState.set("数据已更新!")
  157. else:
  158. #设置标签为红色
  159. # print("help")
  160. self.l_0_state.configure(bg = 'red')
  161. self.varState.set("设备运行中,禁止写入。设备停止后自动更新数据,请注意!")
  162. self.threadFlg1 = False
  163. # 定义Gui界面
  164. def guiProcess(self):
  165. '''
  166. GUI主界面
  167. :param
  168. :retuen
  169. '''
  170. root=tk.Tk()
  171. self.root = root
  172. # 设置窗口位置
  173. root.title('********* V1')
  174. self.center_window(root,400,120)
  175. root.resizable(0,0)# 窗体大小可调整,分别表示x、y方向的可变性
  176. # 设置字体
  177. ft20 =tkFont.Font(family = 'Fixdsys',size = 20,weight = tkFont.BOLD)
  178. ft30 =tkFont.Font(family = 'Fixdsys',size = 30,weight = tkFont.BOLD)
  179. ft40 =tkFont.Font(family = 'Fixdsys',size = 40,weight = tkFont.BOLD)
  180. ft50 =tkFont.Font(family = 'Fixdsys',size = 50,weight = tkFont.BOLD)
  181. ft55 =tkFont.Font(family = 'Fixdsys',size = 55,weight = tkFont.BOLD)
  182. ft80 =tkFont.Font(family = 'Fixdsys',size = 80,weight = tkFont.BOLD)
  183. # 设置标签窗体
  184. labelFm1= tk.LabelFrame(root)
  185. labelFm1.pack(padx=5,pady=5,side=tk.TOP,fill=tk.X)
  186. self.labelFm1 = labelFm1
  187. # labelFm1
  188. self.varState = tk.StringVar()
  189. self.varState.set('*'*10)
  190. l_0_state = tk.Label(labelFm1,textvariable =self.varState )
  191. l_0_state.grid(row=0,column=0,padx=5,pady=5)
  192. self.l_0_state = l_0_state
  193. self.l_0_state.configure(bg = 'green')
  194. button1 = tk.Button(labelFm1,text= "RESET" ,font=ft20)
  195. button1.grid(row=3,column=0,padx = 5,pady=5)
  196. self.button1 = button1
  197. # 定义事件响应
  198. button1.configure(command=self.reset) # 系统复位
  199. root.mainloop()
  200. self.threadFlg1 = False
  201. print('self.threadFlg1 = ',self.threadFlg1)
  202. if __name__=='__main__':
  203. ui = GuiPart()

         3. shuJuZhuangHuang.py   作为数据转换模块使用

  1. import struct
  2. def ReadFloat(*args,reverse=False):
  3. for n,m in args:
  4. n,m = '%04x'%n,'%04x'%m
  5. if reverse:
  6. v = n + m
  7. else:
  8. v = m + n
  9. y_bytes = bytes.fromhex(v)
  10. y = struct.unpack('!f',y_bytes)[0]
  11. y = round(y,6)
  12. return y
  13. def WriteFloat(value,reverse=False):
  14. y_bytes = struct.pack('!f',value)
  15. # y_hex = bytes.hex(y_bytes)
  16. y_hex = ''.join(['%02x' % i for i in y_bytes])
  17. n,m = y_hex[:-4],y_hex[-4:]
  18. n,m = int(n,16),int(m,16)
  19. if reverse:
  20. v = [n,m]
  21. else:
  22. v = [m,n]
  23. return v
  24. def ReadDint(*args,reverse=False):
  25. for n,m in args:
  26. n,m = '%04x'%n,'%04x'%m
  27. if reverse:
  28. v = n + m
  29. else:
  30. v = m + n
  31. y_bytes = bytes.fromhex(v)
  32. y = struct.unpack('!i',y_bytes)[0]
  33. return y
  34. def WriteDint(value,reverse=False):
  35. y_bytes = struct.pack('!i',value)
  36. # y_hex = bytes.hex(y_bytes)
  37. y_hex = ''.join(['%02x' % i for i in y_bytes])
  38. n,m = y_hex[:-4],y_hex[-4:]
  39. n,m = int(n,16),int(m,16)
  40. if reverse:
  41. v = [n,m]
  42. else:
  43. v = [m,n]
  44. return v
  45. if __name__ == "__main__":
  46. print(ReadFloat((15729,16458)))
  47. print(WriteFloat(3.16))
  48. print(ReadDint((1734,6970)))
  49. print(WriteDint(456787654))

        4. 添加配置文件 config.ini

  1. ;config.ini
  2. [Server]
  3. IP=192.168.3.39
  4. PORT=502
  5. [File]
  6. macroFile=c:\\macro\\macro.txt
  7. macroCopy=macro.txt

        5.添加macro.txt文本

  1. 500 = 2
  2. 501 = 3
  3. 502 = 40.03
  4. 503 = 5.5
  5. 504 = 6.6
  6. 505 = 7.8
  7. 506 = 8.8
  8. 507 = 9.6
  9. 508 = 8.7
  10. 509 = 7.7
  11. 510 = 6.7
  12. 511 = 3

       6.添加指令定义

  1. #modbus exception codes
  2. ILLEGAL_FUNCTION = 1
  3. ILLEGAL_DATA_ADDRESS = 2
  4. ILLEGAL_DATA_VALUE = 3
  5. SLAVE_DEVICE_FAILURE = 4
  6. COMMAND_ACKNOWLEDGE = 5
  7. SLAVE_DEVICE_BUSY = 6
  8. MEMORY_PARITY_ERROR = 8
  9. #supported modbus functions
  10. RAW = 0
  11. READ_COILS = 1
  12. READ_DISCRETE_INPUTS = 2
  13. READ_HOLDING_REGISTERS = 3
  14. READ_INPUT_REGISTERS = 4
  15. WRITE_SINGLE_COIL = 5
  16. WRITE_SINGLE_REGISTER = 6
  17. READ_EXCEPTION_STATUS = 7
  18. DIAGNOSTIC = 8
  19. REPORT_SLAVE_ID = 17
  20. WRITE_MULTIPLE_COILS = 15
  21. WRITE_MULTIPLE_REGISTERS = 16
  22. READ_FILE_RECORD = 20
  23. READ_WRITE_MULTIPLE_REGISTERS = 23
  24. DEVICE_INFO = 43
  25. #supported block types
  26. COILS = 1
  27. DISCRETE_INPUTS = 2
  28. HOLDING_REGISTERS = 3
  29. ANALOG_INPUTS = 4

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/500603
推荐阅读
相关标签
  

闽ICP备14008679号