1. 程式人生 > >模組----modbus_tk中TCP協議簡單應用

模組----modbus_tk中TCP協議簡單應用

被告知說會考有關modbus_tk這個模組的東東,我和小夥伴們都驚呆了,很是捉雞啊~~~

關於這個模組,基本上就是零基礎,一步步來。以下都是我的個人見解,若有錯誤請大膽地指出來吧~~

=====================================================================================================================

第一步  做好基本準備工作

=====================================================================================================================

1.查閱modbus本身相關的資料,弄清楚它大概是什麼東東

2.安裝modbus_tool,裡面有個POLL和SLAVE,盡情去除錯吧,有利於弄清楚modbus的結構,還可以測試程式哦~~

樓主當時是沒有弄modbus_tool,直接程序序瞎倒騰,後來被高手指點才跑去用modbus_tool,果然豁然開朗

=====================================================================================================================

第二步  安裝modbus_tk

=====================================================================================================================

在linux和windows上安裝會有點不一樣,其實就是windows在前面多了一個步驟。

----------------------------------------------------------------------------------------------------------------

linux:

在官網下載完modbus_tk,解壓進去就會發現有個setup.py的檔案,直接在此目錄下開啟終端,執行python setup.py  

就會有個提示help告訴你怎麼安裝,然後用install的那個引數就行了。

windows:

先下載安裝一個Modbus Tools.7z的東東,之後就和在linux的操作一樣一樣的了。

這個東西是安裝python其它模組的一個輔助軟體,就是說有了這個東西,它才能去裝其它的一些模組

linux 本來就有帶Modbus Tools,所以可以直接安裝

注:這個Modbus Tools.7z是python裡面的一個模組,不是前面說的modbus_tool哦~

=====================================================================================================================

第三步  看示例吧·~

=====================================================================================================================

示例一   前輩的示例 (被我改了一些,原始版的木有了,懶得去再打一次,將就用修改版的吧)

------------------------------------------------------------------------------------------------------------

得把slave先執行,才能用master讀取或者修改。

#!/usr/bin/python
# -*- coding: utf-8 -*-
# filename: slave.py

# ------------------------------------------------------------------------------
# 匯入外部模組
# ------------------------------------------------------------------------------

import struct
import modbus_tk.defines
import modbus_tk.modbus
import modbus_tk.modbus_tcp
import time
import random


# ------------------------------------------------------------------------------
# 主程式
# ------------------------------------------------------------------------------

try:
    server = modbus_tk.modbus_tcp.TcpServer()
    #注意,若是在linux裡面執行,埠就不能不寫了,否則就要用root才能跑,其它使用者只能用1024以上的埠
    #這裡的埠和地址都是預設的,地址是本地:
    #原來的程式:server = modbus_tk.modbus_tcp.TcpServer(port=502, address='0.0.0.0', timeout_in_sec=3)
    server.start()
    slave_1 = server.add_slave(1)
    slave_1.add_block('block1', modbus_tk.defines.ANALOG_INPUTS, 0, 2)
    #給slave_1新增一個模組(模組名,只讀,地址,長度)

    while 1:
        bb = random.random()
        aa = struct.unpack('>HH', struct.pack('>f', bb))
        print 'bb:', bb
        print "aa:", aa
        slave_1.set_values('block1', 0, aa)
        print '========='
        time.sleep(3)
except:
    print '============error==========='
finally:
    print '=========stop========'
    server.stop()

#!/usr/bin/python
# -*- coding: utf-8 -*-
# filename: master.py

# ------------------------------------------------------------------------------
# 匯入外部模組
# ------------------------------------------------------------------------------

import modbus_tk
import modbus_tk.defines
import modbus_tk.modbus
import modbus_tk.modbus_tcp
import struct
import time



# ------------------------------------------------------------------------------
# 主程式
# ------------------------------------------------------------------------------

try:
    while 1:
        master = modbus_tk.modbus_tcp.TcpMaster()
	#('0.0.0.0', 502)   (master ip 地址,埠)
        #注意用linux的童鞋們,埠小於1024得用root才能跑起來哦~
	#為這個問題樓主曾經也折騰了一陣,後來才發現居然是這個原因·····
	#這裡有個問題就是原來我是用'0.0.0.0'這個地址的。
	#但是它應該不能算一個ip地址了,這個是代表現有的ip地址均可的意思,有種萬用字元的感覺
	#在slave中可以用它,但是在master中不行,一定要給它指明一個具體的地址,看來它也有選擇困難症
        master.set_timeout(3)  #timeout表示若超過3秒沒有連線上slave就會自動斷開
        #set_timeout(3)不知是何意----重新把timeout時間設定成3秒,在生成master那裡就可以進行初始化定義的,若沒有自定義就會用預設值
        aa = master.execute(1, modbus_tk.defines.ANALOG_INPUTS, 0, 2)
        #(slave id,只讀,block地址,長度:即位元組乘個數)
        print 'aa:', aa, 'size', len(aa)
        bb = struct.unpack('>f', struct.pack('>HH', aa[0], aa[1]))
        #在slave中,是先打包成'>f'在以'>HH'解包的,在master中剛好相反
        #struct.unpack裡解出來的是一個元組,可以用bb, = 或者輸出bb[0]
        print 'bb:', bb[0]
        time.sleep(3)
except Exception as e:
    print '=========error========='
    print e
finally:
    print '=======stop======='

檢視埠是否已經開放               (用root許可權)
/etc/init.d/iptables status
/sbin/iptables -I INPUT -p tcp --dport 5023 -j ACCEPT   # 開啟5023埠
/etc/rc.d/init.d/iptables save #儲存配置
/etc/rc.d/init.d/iptables restart #重啟服務 

示例二   官網的示例       很坑爹····好多錯誤····不知道怎麼會放在官網上的·····果斷也被我改了
---------------------------------------------------------------------------------------------------------------------

#!/usr/bin/python
# -*- coding: utf-8 -*-
# filename: server_example.py

# ------------------------------------------------------------------------------
# 匯入外部模組
# ------------------------------------------------------------------------------

import modbus_tk
import modbus_tk.modbus_tcp as modbus_tcp
import modbus_tk.defines as mdef
import threading
import sys


# ------------------------------------------------------------------------------
# 主程式
# ------------------------------------------------------------------------------

logger = modbus_tk.utils.create_logger(name='console', record_format='%(message)s')


if __name__ == '__main__':
    try:
        logger.info("running...")
        logger.info("enter 'quit' for closing the server")

        server = modbus_tcp.TcpServer(port=1152)
        server.start()
        #sever.start()可以在加了slave和模組以後,也可以不加直接裸奔~
        #creates a slave with id 0
        slave1 = server.add_slave(1)
        #add 2 blocks of holding registers
        slave1.add_block('a', mdef.HOLDING_REGISTERS, 0, 100)  #address 0, length 100
        slave1.add_block('b', mdef.HOLDING_REGISTERS, 200, 20) #address 200, length 20

        #create another slave with id 5
        slave5 = server.add_slave(5)
        slave5.add_block('c', mdef.COILS, 0, 100)
        slave5.add_block('d', mdef.HOLDING_REGISTERS, 0, 100)

        #set the values of registers at address 0
        slave1.set_values('a', 0, range(100))

        while True:
            cmd = sys.stdin.readline()
            if cmd.find('quit')==0:
                #當輸入的只有quit,程式就會退出
                sys.stdout.write('bye-bye\r\n')
                sys.exit(0)

    finally:
        server.stop()

#!/usr/bin/python
# -*- coding: utf-8 -*-
# filename: master_example.py

# ------------------------------------------------------------------------------
# 匯入外部模組
# ------------------------------------------------------------------------------
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp


# ------------------------------------------------------------------------------
# 主程式
# ------------------------------------------------------------------------------
if __name__ == '__main__':
    try:
        #Connect to the slave
        master = modbus_tcp.TcpMaster(port=1152)
        print master.execute(1, cst.READ_HOLDING_REGISTERS, 10, 3)
        master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 200, output_value=xrange(12))
        print master.execute(1, cst.READ_HOLDING_REGISTERS, 10, 3)

    except modbus_tk.modbus.ModbusError, e:
        print "Modbus error", e.get_exception_code()
    except Exception, e2:
        print "Error", str(e2)


示例三   modbus_tk檔案中本身自帶的example
---------------------------------------------------------------------------------------------------------------------

slave

#!/usr/bin/env python
# -*- coding: utf_8 -*-
"""
 Modbus TestKit: Implementation of Modbus protocol in python

 (C)2009 - Luc Jean - [email protected]
 (C)2009 - Apidev - http://www.apidev.fr

 This is distributed under GNU LGPL license, see license.txt
"""

import sys

#add logging capability
import logging
import threading

import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus as modbus
import modbus_tk.modbus_tcp as modbus_tcp

logger = modbus_tk.utils.create_logger(name="console", record_format="%(message)s")
    
if __name__ == "__main__":
        
    try:
        #Create the server
        server = modbus_tcp.TcpServer(port=1500)
        logger.info("running...")
        logger.info("enter 'quit' for closing the server")

        server.start()
        
        slave_1 = server.add_slave(1)
        slave_1.add_block('0', cst.COILS, 0, 100)
        slave_1.set_values('0', 0, range(100))
        #range(100)為0-99的列表
        while True:
            cmd = sys.stdin.readline()
            #這裡是進入程式以後,讀取每次輸入的命令:以回車來判斷命令是否輸入完畢
            args = cmd.split(' ')
            if cmd.find('quit')==0:
                #當輸入的只有quit,程式就會退出
                sys.stdout.write('bye-bye\r\n')
                break
            elif args[0]=='add_slave':
                slave_id = int(args[1])
                #slave id只能為int?是的
                server.add_slave(slave_id)
                sys.stdout.write('done: slave %d added\r\n' % (slave_id))
                #write到哪裡去了?螢幕輸出去了~~
            elif args[0]=='add_block':
                slave_id = int(args[1])
                name = args[2]
                block_type = int(args[3])
                starting_address = int(args[4])
                length = int(args[5])
                slave = server.get_slave(slave_id)
                slave.add_block(name, block_type, starting_address, length)
                sys.stdout.write('done: block %s added\r\n' % (name))
            elif args[0]=='set_values':
                slave_id = int(args[1])
                name = args[2]
                #這個name是slave_id對應的block的名字
                address = int(args[3])
                values = []
                #這裡的values只可少設不可多設,否則就報錯退出程式
                for v in args[4:]:
                    #value只能是int,就算是其他數字型別也報錯
                    #囧 好奇怪,明明平時int(0.1)也是可以的
                    values.append(int(v))
                slave = server.get_slave(slave_id)
                slave.set_values(name, address, values)
                values = slave.get_values(name, address, len(values))
                sys.stdout.write('done: values written: %s\r\n' % (str(values)))
            elif args[0]=='get_values':
                slave_id = int(args[1])
                name = args[2]
                address = int(args[3])
                length = int(args[4])
                slave = server.get_slave(slave_id)
                values = slave.get_values(name, address, length)
                sys.stdout.write('done: values read: %s\r\n' % (str(values)))
            else:
                sys.stdout.write("unknown command %s\r\n" % (args[0]))
    finally:
        server.stop()

master
#!/usr/bin/env python
# -*- coding: utf_8 -*-
"""
 Modbus TestKit: Implementation of Modbus protocol in python

 (C)2009 - Luc Jean - [email protected]
 (C)2009 - Apidev - http://www.apidev.fr

 This is distributed under GNU LGPL license, see license.txt
"""

import sys

#add logging capability
import logging

import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp

logger = modbus_tk.utils.create_logger("console")

if __name__ == "__main__":
    try:
        #Connect to the slave
        master = modbus_tcp.TcpMaster(port=1500)
        master.set_timeout(5.0)
        logger.info("connected")
        #logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 100, 100))
        #(slave id,Modbus資料模型,block地址,長度:即位元組乘個數)
        #同一個slave下,不同block的Modbus資料模型可以是不一樣的

##################################################################################################
#下面的例子都需要自己在slave裡面新增slave(需要改下面的id)或block才能實現

#-------------------------------------------------------------------------------------------------
        print cst.COILS                              #1-----1位讀寫
        print cst.READ_COILS                         #1-----1位只讀
        print cst.WRITE_SINGLE_COIL                  #5-----1位只寫
        print cst.WRITE_MULTIPLE_COILS               #15----1位寫

        logger.info(master.execute(1, cst.READ_COILS, 0, 10))
        #一位:所以個數是10,位元組是1     若給非0值,均會以1存入   預設值是(0,0,0,0,0,0,0,0,0,0)

        #只寫的,這裡會輸出modbus的可識別的格式'>HH',即有兩個元素的元組:
        a = logger.info(master.execute(1, cst.WRITE_SINGLE_COIL, 7, output_value=0))
        #將slave的地址7的value改成1。
        logger.info(master.execute(1, cst.READ_COILS, 0, 10))
        #logger.info(master.execute(1, cst.WRITE_MULTIPLE_COILS, 5, output_value=xrange(12)))

        print 'a =', a # a=None


#-------------------------------------------------------------------------------------------------
        print cst.DISCRETE_INPUTS                    #2-----1位只讀
        print cst.READ_DISCRETE_INPUTS               #2-----1位只讀

        #logger.info(master.execute(1, cst.READ_DISCRETE_INPUTS, 0, 8))
        #一位:所以個數是8,位元組是1     若給非0值,均會以1存入    預設值是(0,0,0,0,0,0,0,0)



#-------------------------------------------------------------------------------------------------
        print cst.HOLDING_REGISTERS           #3-----16位讀寫
        print cst.READ_HOLDING_REGISTERS      #3-----16位只讀
        print cst.WRITE_SINGLE_REGISTER       #6-----16位寫
        print cst.WRITE_MULTIPLE_REGISTERS    #16----16位寫



        #這裡讀取的是之前的資訊
        #logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 3))
        #16位:所以個數是3,位元組是16     若給負值,會出錯         預設值是(0,0,0)
        #logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 100))

        #logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 0, output_value=[50, 1, 1, 1, 1, 1, 1, 1]))
        #從地址0開始,後面8為全是1
        #logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 5, output_value=xrange(12)))
        #從地址5開始,後面12位是xrange(12)

        #這裡讀取的是改變後的資訊
        #logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 3))
        #logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 100))

        #logger.info(master.execute(1, cst.WRITE_SINGLE_REGISTER, 5, output_value=1))


#-------------------------------------------------------------------------------------------------
        print cst.ANALOG_INPUTS               #4-----16位只讀
        print cst.READ_INPUT_REGISTERS        #4-----16位只讀

        #logger.info(master.execute(1, cst.READ_INPUT_REGISTERS, 10, 12))
        #16位:所以個數是3,位元組是16     若給負值,會出錯         預設值是(0,0,0,0,0,0,0,0,0,0,0,0)



##################################################################################################


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


更多資料   後來才發現原來modbus_tk檔案中自帶的doc資料夾下面有原始碼的   囧   看那個應該會很不錯

=====================================================================================================================
第四步  小總結
=====================================================================================================================
1.在linux上執行除了要注意埠,還要注意的就是防火牆的問題,我是直接把防火牆給關了的。


2.modbus本身可以傳輸16位無符號整數,如果要傳輸浮點數或者是32位無符號整數就要進行打包,具體看struct模組。


3.server和master的功能碼對應表
===================================================================
對於server(slave):


  modbus_tk.defines.COILS:               1位讀寫                  1
  modbus_tk.defines.DISCRETE_INPUTS:     1位只讀                  2
  modbus_tk.defines.HOLDING_REGISTERS:   16位讀寫                 3
  modbus_tk.defines.ANALOG_INPUTS:       16位只讀                 4
===================================================================
對於master(要於server對應起來):


  modbus_tk.defines.COILS:                       1-----1位讀寫
  modbus_tk.defines.READ_COILS                   1-----1位只讀
  modbus_tk.defines.WRITE_SINGLE_COIL            5-----1位只寫,一個個寫的,更穩定,但效率低
  modbus_tk.defines.WRITE_MULTIPLE_COILS         15----1位只寫,多個一起寫,穩定性一般,效率高
-------------------------------------------------------------------
  modbus_tk.defines.DISCRETE_INPUTS:             2-----1位只讀
  modbus_tk.defines.READ_DISCRETE_INPUTS         2-----1位只讀
 
-------------------------------------------------------------------
  modbus_tk.defines.HOLDING_REGISTERS:           3-----16位讀寫
  modbus_tk.defines.READ_HOLDING_REGISTERS       3-----16位只讀
  modbus_tk.defines.WRITE_SINGLE_REGISTER        6-----16位寫,一個個寫的,更穩定,但效率低
  modbus_tk.defines.WRITE_MULTIPLE_REGISTERS     16----16位寫,多個一起寫,穩定性一般,效率高
-------------------------------------------------------------------
  modbus_tk.defines.ANALOG_INPUTS:               4-----16位只讀
  modbus_tk.defines.READ_INPUT_REGISTERS         4-----16位只讀


===================================================================


相關推薦

模組----modbus_tkTCP協議簡單應用

被告知說會考有關modbus_tk這個模組的東東,我和小夥伴們都驚呆了,很是捉雞啊~~~ 關於這個模組,基本上就是零基礎,一步步來。以下都是我的個人見解,若有錯誤請大膽地指出來吧~~ =======================================

Http協議TCP協議簡單理解( 轉 )

art 這也 這一 傳輸協議 方便 編寫 庫服務器 為我 之間 在C#編寫代碼,很多時候會遇到Http協議或者TCP協議,這裏做一個簡單的理解。TCP協議對應於傳輸層,而HTTP協議對應於應用層,從本質上來說,二者沒有可比性。Http協議是建立在TCP協議基礎之上的,當瀏覽

【網絡協議TCP協議簡單介紹

tis sim 發生 ron html tcp協議 緩沖 應用程序 不可 ? ? 本文僅僅是對TCP協議做個簡要的介紹。? ? TCP協議,即傳輸控制協議。與UDP協

基於TCP協議簡單qq聊天

pre inf 基於 port byte while enc == con #server端 import socket ip_port = (‘127.0.0.1‘,8080) sk = socket.socket() sk.setsockopt(socket.SOL

pythonproperty的簡單應用場景

python color per 註意 print ddc cfa img shadow 多註意看最後的兩個print,一個是name,一個是name2當然可以再增加個name3python中property的簡單應用場景

UnityMVC的簡單應用

model using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 模型委託(當用戶資訊發生變化時執行) /// </summ

javaMongoDB的簡單應用例項

1 首先載入 MongoDB的jar包。下載Jar包連結 2然後進行相應的配置。如我當前專案是在web-pom.xml 的的節點下配置。 <dependency> <groupId>org.mo

TCP協議簡單講解

TCP協議 TCP(Transmission Control Protocol 傳輸控制協議)是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議。  TCP包頭格式   首先,源埠號和目標埠號是不可少的,埠號的存在,資料就知道應該發給哪個應用。

maven(五)在eclipsemaven的簡單應用

1、匯入maven專案 在4中寫了maven的專案,現在把他匯入進來。選擇選單項 File,然後選擇 Import,我們會看到一個 Import 對話方塊,在該對話方塊中選擇 Maven目錄下的 Maven Projects,然後點選Next, 就會出現 Im

Http協議TCP協議簡單理解後續

大約2年前寫了一篇關於HTTP協議與TCP協議的文章,原文連結。最近再次簡單讀了一遍《TCP/IP協議卷》,有了一些新的理解。這篇文章沒有一個很好的連貫性,都是我在讀書過程中總結的知識點,整體比較鬆散,但是個人感覺知識點都是非常重要,有很多地方讓我明白了迷惑很久的問題。

QT:HTTP協議簡單應用

HTTP協議 QNetworkAccessManager QNetworkReply 《案例》QT實現HTTP文字瀏覽器 /* HTTP文字瀏覽器 - 程式碼演示 */// HttpDialog.h #ifndef HTTPDIALOGH #define HTTPDIAL

python lxmletree的簡單應用1

我一般都是通過xpath解析DOM樹的時候會使用lxml的etree,可以很方便的從html原始碼中得到自己想要的內容。 這裡主要介紹一下我常用到的兩個方法,分別是etree.HTML()和etree.tostrint()。 1.etree.HTML() etree.H

python lxmletree的簡單應用3

本次主要介紹,無論使用的xpath表示式中是否包含text()方法,最後都可以獲取目標標籤下的文字。使用的依然是etree.HTML和etree.tostring方法。1.思路首先將字串原始碼轉換成_Element物件,然後使用_Element物件的xpath()方法解析xp

計算機網路TCP協議與UDP協議的比較

在計算機網路層次結構的運輸層中,TCP協議、UDP協議解決了端到端的通訊問題。 在這裡的協議即為軟體,用以解決計算機網路的通訊互聯問題。 計算機網路層次結構概述 現代計算機網路基本層次結構由5個層次組成,自頂向下為:應用層、運輸層、網路層、資料

Asp.net coreRedisMQ的簡單應用

最近一個外部的專案,使用到了訊息佇列,本來是用rabbitmq實現的,但是由於是部署到別人家的伺服器上,想盡量簡化一些,專案中本來也要接入了redis快取,就嘗試使用redis來實現簡單的訊息佇列。 使用redis做訊息佇列有兩種方法,一種是使用pub/sub,另一種是使用list結構,配合brpop來

利用node.js的net模組使用tcp協議

一、單向通訊 server.js 使用net模組建立一個tcp server監聽tcp連線事件 var net=require('net') var server=net.createServ

TCP-IP之應用協議

傳輸協議 images gateway 1-1 大學 表示 進制 技術 dom 應用層協議是多種多樣的,比如 DNS、FTP、Telnet、SMTP、HTTP、RIP、NFS 一、DNS DNS (Domain Name Service 域名服務) 協議基於 UDP,使用

python3實現TCP協議簡單服務器和客戶端

由於 轉載 while encoding ont ans 令行 cti 數據 利用python3來實現TCP協議,和UDP類似。UDP應用於及時通信,而TCP協議用來傳送文件、命令等操作,因為這些數據不允許丟失,否則會造成文件錯誤或命令混亂。下面代碼就是模擬客戶端通過命令行

網絡編程----------SOCKET編程實現簡單TCP協議

water 實現 保活定時器 log 超時重傳 color 斷開連接 超時 面向連接 首先我們須要大致了解TCP的幾點知識: 1.TCP的特點:面向連接的可靠性傳輸 2.TCP的三次握手建立連接和四次揮手釋放連接。但為什麽TCP要三次握手建立連接呢? 答:由於

TCP協議的三次握手和四次揮手(圖解)(轉)

繼續 丟失 get 所有 如果 idt 請求報文 網絡 center 轉自:http://blog.csdn.net/whuslei/article/details/6667471 建立TCP需要三次握手才能建立,而斷開連接則需要四次握手。整個過程如下圖所示: 先來看看如