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 loggingdef 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的加入元素0crc_data = "".join(str_list)read = read.strip() + crc_data[4:] + crc_data[2:4]return readexcept:# 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)/100else:return val/100def 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 = Truefor 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个寄存器的值
代码参数设置

这个代码参数设置,在代码中可以找到

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
