#代碼部分
首先注意一點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 是寫好的工具,
且只支持2的15次 以內的數據,也就是32768,這個整數,一旦你要發送有符號數,2的 16次 時它就不能解析了。
下面請看不能解析的部分
這不是我要的結果
正確結果爲,因爲 前3個是採集的溫度數據,所以1938和1956是變化的,想表示的就是19.38攝氏度。
講講modbus poll和我代碼之間的關係
modbus poll參數設置
端口爲 com12
子站數爲1,地址從0開始,取16個寄存器的值
代碼參數設置
這個代碼參數設置,在代碼中可以找到