python的modbus-rtu串口通讯
前言:
主要使用模块:
import serial
import serial sendbytes = ' ' # 报文内容 # 连接端口 'com6', 超时0.8,比特率9600、8字节、无校验、停止位1 com = serial.Serial(port="com6", baudrate=9600, timeout=0.8, bytesize=8, parity='N', stopbits=1) if com.is_open: # 检测端口 print("端口已打开") # 将hexstr导入bytes对象 报文需要是字节格式 sendbytes = bytes.fromhex(sendbytes) # 发送报文 com.write(sendbytes) print(com.readall())
关键点突破:
一、端口设置
二、报文获得
三、报文收发
一、端口设置
1、接线
设备:系统win11、24V直流电源、模拟量输出模块1个、USB转485/232转换器1个、万用表1块
模拟量输出模块 USB转485/232转换器
接线请按照具体说明书
2、端口设置(注意驱动,有些设备需要按照特定驱动)
连接端口 com6, 比特率9600、8字节、无校验、停止位1
二、报文获得
1、基础知识:Modbus 通讯协议 (RTU传输模式)_csdn_dx的博客-CSDN博客_modbus rtu
作者通过查询 模拟量输出模块通讯手册如下
01(设备地址)03(读保持寄存器)00 40(起始地址) 00 01(预读取数量) XX XX (校验码,见下)
READ_CH0_AO 01 03 00 40 00 01
READ_CH1_AO 01 03 00 41 00 01
READ_CH2_AO 01 03 00 42 00 01
READ_CH3_AO 01 03 00 43 00 01OUTPUT_CH0_AO 01 06 00 00 00 00
OUTPUT_CH1_AO 01 06 00 01 00 00
OUTPUT_CH2_AO 01 06 00 02 00 00
OUTPUT_CH3_AO 01 06 00 03 00 00ps:校验码 是非常重要的
2、校验码的获取
a.通过 常用的串口调试工具等软件 下方校验按钮 获得
b. python 有例如crcmod的库,可获取对应的CRC校验码
官方文档: crcmod documentation — crcmod v1.7 documentation
c.自写CRC校验码算法文件(难度不大)
算法逻辑:怎么计算crc16校验数据的校验码_qq_37591637的博客-CSDN博客_crc校验码计算器在线
# 进制转化实现 class Binary: """ 自定义进制转化 """ @staticmethod def Hex2Dex(e_hex): """ 十六进制转换十进制 :param e_hex: :return: """ return int(e_hex, 16) @staticmethod def Hex2Bin(e_hex): """ 十六进制转换二进制 :param e_hex: :return: """ return bin(int(e_hex, 16)) @staticmethod def Dex2Bin(e_dex): """ 十进制转换二进制 :param e_dex: :return: """ return bin(e_dex) # 校验方法实现 class CRC: """ CRC验证 """ def __init__(self): self.Binary = Binary() def CRC16(self,hex_num): """ CRC16校验 """ crc = '0xffff' crc16 = '0xA001' # test = '01 06 00 00 00 00' test = hex_num.split(' ') print(test) crc = self.Binary.Hex2Dex(crc) # 十进制 crc16 = self.Binary.Hex2Dex(crc16) # 十进制 for i in test: temp = '0x' + i # 亦或前十进制准备 temp = self.Binary.Hex2Dex(temp) # 十进制 # 亦或 crc ^= temp # 十进制 for i in range(8): if self.Binary.Dex2Bin(crc)[-1] == '0': crc >>= 1 elif self.Binary.Dex2Bin(crc)[-1] == '1': crc >>= 1 crc ^= crc16 # print('crc_D:{}\ncrc_B:{}'.format(crc, self.Binary.Dex2Bin(crc))) crc = hex(crc) crc_H = crc[2:4] # 高位 crc_L = crc[-2:] # 低位 return crc, crc_H, crc_L
校验返回结果:
基础报文:01 03 00 40 00 01
完整报文:
01 03 00 40 00 01 85 DE 一般校验码采取低位在前
三、报文收发
import serial import time # 基础报文 sendbytes = '01 03 00 40 00 01' # 生成CRC16校验码 CRC = CRC() crc, crc_H, crc_L = CRC.CRC16(sendbytes) # 生成完整报文 sendbytes = sendbytes + ' ' + crc_L + ' ' + crc_H print(sendbytes) # 连接端口 'com6', 超时0.8,比特率9600、8字节、无校验、停止位1 com = serial.Serial(port="com6", baudrate=9600, timeout=0.8, bytesize=8, parity='N', stopbits=1) if com.is_open: print("port open success") # 将hexstr导入bytes对象 报文需要是字节格式 sendbytes = bytes.fromhex(sendbytes) # 发送报文 com.write(sendbytes) return_res = com.readall() print(return_res )
打印结果:
['01', '03', '00', '40', '00', '01']
01 03 00 40 00 01 85 de
port open success
b'\x01\x03\x02\x13\x88\xb5\x12'
\x13\x88 可以使用window自带计算器转化以下 16进制 13 88 对应10进制 4000
由于该产品返回值=实际值*1000,所以实际值为4ma, 经过万用表测量电流3.98ma,由于测量误差的存在,该结果没问题
完整代码如下:
# -*- coding: utf-8 -*- """ @File : 3.py @Author : raymood @Time : 2022/5/6 14:53 @description : NULL """ import serial import time class Binary: """ 自定义进制转化 """ @staticmethod def Hex2Dex(e_hex): """ 十六进制转换十进制 :param e_hex: :return: """ return int(e_hex, 16) @staticmethod def Hex2Bin(e_hex): """ 十六进制转换二进制 :param e_hex: :return: """ return bin(int(e_hex, 16)) @staticmethod def Dex2Bin(e_dex): """ 十进制转换二进制 :param e_dex: :return: """ return bin(e_dex) class CRC: """ CRC验证 """ def __init__(self): self.Binary = Binary() def CRC16(self, hex_num): """ CRC16校验 :param hex_num: :return: """ crc = '0xffff' crc16 = '0xA001' # test = '01 06 00 00 00 00' test = hex_num.split(' ') print(test) crc = self.Binary.Hex2Dex(crc) # 十进制 crc16 = self.Binary.Hex2Dex(crc16) # 十进制 for i in test: temp = '0x' + i # 亦或前十进制准备 temp = self.Binary.Hex2Dex(temp) # 十进制 # 亦或 crc ^= temp # 十进制 for i in range(8): if self.Binary.Dex2Bin(crc)[-1] == '0': crc >>= 1 elif self.Binary.Dex2Bin(crc)[-1] == '1': crc >>= 1 crc ^= crc16 # print('crc_D:{}\ncrc_B:{}'.format(crc, self.Binary.Dex2Bin(crc))) crc = hex(crc) crc_H = crc[2:4] crc_L = crc[-2:] return crc, crc_H, crc_L if __name__ == '__main__': # 基础报文 sendbytes = '01 03 00 40 00 01' # 生成CRC16校验码 CRC = CRC() crc, crc_H, crc_L = CRC.CRC16(sendbytes) # 生成完整报文 sendbytes = sendbytes + ' ' + crc_L + ' ' + crc_H print(sendbytes) # 连接端口 'com6', 超时0.8,比特率9600、8字节、无校验、停止位1 com = serial.Serial(port="com6", baudrate=9600, timeout=0.8, bytesize=8, parity='N', stopbits=1) if com.is_open: print("port open success") # 将hexstr导入bytes对象 报文需要是字节格式 sendbytes = bytes.fromhex(sendbytes) # 发送报文 com.write(sendbytes) print(com.readall())
注意:若要不断的进行通讯,请在发送前加上 睡眠延迟
来源:raymoodlmd