modbus數據獲取與數據解析

#代碼部分

首先注意一點Python版的modbus要獲取modbus值必須先裝【環境包】
pip install serial 
# serial爲串口包,需要打開串口,也就是usb
pip install crcmod
# crcmod 用來crc校驗的
pip install modbus_tk
# modbus_tk 就是滿足modbus協議的Python包
import crcmod
from binascii import unhexlify
import modbus_tk
import time
import serial
from modbus_tk import modbus_rtu
from modbus_tk import defines as cst
import logging


def crc16Add(read):
    try:
        crc16 = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
        readcrcout = hex(crc16(unhexlify(read))).upper()
        str_list = list(readcrcout)
        if len(str_list) == 5:
            str_list.insert(2, '0')  # 位數不足補0,在列表中下標爲2的加入元素0
        crc_data = "".join(str_list)
        read = read.strip() + crc_data[4:] + crc_data[2:4]
        return read
    except:
        # print("crc校驗出錯'")
        logging.warning('crc校驗出錯')

flag_value = True
def modbus_getdate(slave_id, start_addr, date_len):
    try:
        master = modbus_rtu.RtuMaster(serial.Serial(port=PORT,
                                                    baudrate=19200,
                                                    bytesize=8,
                                                    parity='N',
                                                    stopbits=1,
                                                    xonxoff=0))
        # # logger = modbus_tk.utils.create_logger(name="console", record_format="%(message)s")
        master.set_timeout(3)
        master.set_verbose(True)
        # holding_date = master.execute(slave_id, cst.READ_HOLDING_REGISTERS, start_addr, date_len)
        holding_date = master.execute(slave=slave_id,function_code=cst.READ_HOLDING_REGISTERS,quantity_of_x=date_len,starting_address=start_addr)
        holding_data125 = list()
        for i in range(len(holding_date)):
            holding_data125.append('%04x' % (holding_date)[i])  # append()在Tmp1列表末尾添加新的對象
        all_holding_data = '0103' + '%02x' % (date_len * 2) + ''.join(holding_data125)  #
        # return str(all_holding_data)
        return crc16Add(all_holding_data) #這裏crc校驗了,如果單純的看數據可以不校驗
    
    except modbus_tk.modbus_rtu.ModbusInvalidResponseError as err:
        # print(err)
        logging.warning(err)

def get_s16(val):
    '''
    作用爲解析16進制有符號數,值得注意的是modbus poll是不支持有符號數的,一會先講個modbus poll的用法
    '''
    if val > 65536:
        return val/100 
    
    elif val > 32768:
        #因爲我傳的數是需要有2位小數的,但是16進制中沒有小數點的概念,所以數本身擴大100倍,然後做處理再除以100,就得到小數點後2位
        return (val - 65536)/100
    else:
        return val/100

def f_analysis(x):
    '''
    解析4位一個的16進制數
    '''
    les = len(x)
    print(les,'數據長度')
    for i in range(les):
        if i % 4  == 0:
            # print(i,j)
            datas = int(x[i:i+4],16)
            print(i,get_s16(datas),datas) # i代表循環位置,get_s16()爲解析16進制有符號數,datas爲16進制數



if __name__ == '__main__':
    PORT = 'COM12'
    flag = True
    for i in range(2):
        if flag:
            da = modbus_getdate(slave_id=1,start_addr=0,date_len=16)
            print(da) # modbus取出的值
            # master.execute(slave=1, function_code=cst.WRITE_MULTIPLE_REGISTERS, starting_address=0,
            #                data_format='0')
            f_analysis(da[6:-4])
            # 不需要前6個和後四個原因是,前6個值是我爲了協議拼接的,後四個是crc校驗生成的,所以它們不是數據,不需要。
結果如下 ,因爲是8個溫度探頭,但只有前三個接了真正的探頭,所有隻有前三個有值,而且還重複了,不過這不影響。哈哈
01032007920793084ef510f510f510f510f51007920793084ef510f510f510f510f510B741
64 數據長度
0 19.38 1938
4 19.39 1939
8 21.26 2126
12 -28.0 62736
16 -28.0 62736
20 -28.0 62736
24 -28.0 62736
28 -28.0 62736
32 19.38 1938
36 19.39 1939
40 21.26 2126
44 -28.0 62736
48 -28.0 62736
52 -28.0 62736
56 -28.0 62736
60 -28.0 62736
講個modbus poll 的用法,其實modbus poll 和我上面的代碼的作用是一樣的,但是modbus poll 是寫好的工具,
且只支持215次 以內的數據,也就是32768,這個整數,一旦你要發送有符號數,216次 時它就不能解析了。
下面請看不能解析的部分

在這裏插入圖片描述

這不是我要的結果
正確結果爲,因爲 前3個是採集的溫度數據,所以19381956是變化的,想表示的就是19.38攝氏度。

在這裏插入圖片描述

講講modbus poll和我代碼之間的關係
modbus poll參數設置

在這裏插入圖片描述

    端口爲 com12

在這裏插入圖片描述

子站數爲1,地址從0開始,取16個寄存器的值
代碼參數設置

在這裏插入圖片描述

這個代碼參數設置,在代碼中可以找到

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章