项目场景:
python与plc进行串口通信,寄存器写数据,适用于需要用串口通信的plc,如欧姆龙plc
问题描述:
python语言与plc建立串口通信时,无法直接读写。
用到python的serial 模块
在创建串口对象时需要定义其属性与plc一致:
self.main_engine.baudrate = self.bps
self.main_engine.bytesize = 7
self.main_engine.parity = 'E'
self.main_engine.stopbits = 2
重点:在写入数据后,需要写16进制数"0D",结束标志位
self.main_engine.write("@00WD1010000152*".encode())
self.main_engine.write(binascii.a2b_hex("0D"))
解决方案:
import serial #导入模块
import serial.tools.list_ports
import time
import binascii
class myserial():
def __init__(self, com, bps, timeout=0.5):
self.port = com
self.bps = bps
self.timeout = timeout
global Ret
try:
# 打开串口,并得到串口对象
#self.main_engine= serial.Serial(self.port,self.bps,timeout=self.timeout)
self.main_engine= serial.Serial()
self.main_engine.port = self.port
self.main_engine.baudrate = self.bps
self.main_engine.bytesize = 7
self.main_engine.parity = 'E'
self.main_engine.stopbits = 2
self.Open_Engine()
# 判断是否打开成功
if (self.main_engine.is_open):
Ret = True
except Exception as e:
print("---异常---:", e)
# 打印设备基本信息
def Print_Name(self):
print(self.main_engine.name) #设备名字
print(self.main_engine.port)#读或者写端口
print(self.main_engine.baudrate)#波特率
print(self.main_engine.bytesize)#字节大小
print(self.main_engine.parity)#校验位
print(self.main_engine.stopbits)#停止位
print(self.main_engine.timeout)#读超时设置
print(self.main_engine.writeTimeout)#写超时
print(self.main_engine.xonxoff)#软件流控
print(self.main_engine.rtscts)#软件流控
print(self.main_engine.dsrdtr)#硬件流控
print(self.main_engine.interCharTimeout)#字符间隔超时
#打开串口
def Open_Engine(self):
self.main_engine.open()
#关闭串口
def Close_Engine(self):
self.main_engine.close()
print(self.main_engine.is_open) # 检验串口是否打开
# 打印可用串口列表
@staticmethod
def Print_Used_Com():
port_list = list(serial.tools.list_ports.comports())
print(port_list)
if len(port_list) == 0:
print('无可用串口')
else:
for i in range(0,len(port_list)):
print(port_list[i])
#接收指定大小的数据
#从串口读size个字节。如果指定超时,则可能在超时后返回较少的字节;如果没有指定超时,则会一直等到收完指定的字节数。
def Read_Size(self,size):
return self.main_engine.read(size=size)
#接收一行数据
# 使用readline()时应该注意:打开串口时应该指定超时,否则如果串口没有收到新行,则会一直等待。
# 如果没有超时,readline会报异常。
def Read_Line(self):
return self.main_engine.readline()
#发数据
def Send_data(self,data):
self.main_engine.write(data)
#更多示例
# self.main_engine.write(chr(0x06).encode("utf-8")) # 十六制发送一个数据
# print(self.main_engine.read().hex()) # # 十六进制的读取读一个字节
# print(self.main_engine.read())#读一个字节
# print(self.main_engine.read(10).decode("gbk"))#读十个字节
# print(self.main_engine.readline().decode("gbk"))#读一行
# print(self.main_engine.readlines())#读取多行,返回列表,必须匹配超时(timeout)使用
# print(self.main_engine.in_waiting)#获取输入缓冲区的剩余字节数
# print(self.main_engine.out_waiting)#获取输出缓冲区的字节数
# print(self.main_engine.readall())#读取全部字符。
#接收数据
#一个整型数据占两个字节
#一个字符占一个字节
def Recive_data(self,way):
# 循环接收数据,此为死循环,可用线程实现
print("开始接收数据:")
while True:
try:
# 一个字节一个字节的接收
if self.main_engine.in_waiting:
if(way == 0):
for i in range(self.main_engine.in_waiting):
print("接收ascii数据:"+str(self.Read_Size(1)))
data1 = self.Read_Size(1).hex()#转为十六进制
data2 = int(data1,16)#转为十进制print("收到数据十六进制:"+data1+" 收到数据十进制:"+str(data2))
if(way == 1):
#整体接收
# data = self.main_engine.read(self.main_engine.in_waiting).decode("utf-8")#方式一
data = self.main_engine.read_all()#方式二print("接收ascii数据:", data)
except Exception as e:
print("异常报错:",e)
def send_ccd1_OK(self):
# self.main_engine.write("@00WD1000000153*".encode())
self.main_engine.write("@00WD1000000250*".encode())
self.main_engine.write(binascii.a2b_hex("0D"))
print("CCD1_OK")
def send_ccd1_NG(self):
self.main_engine.write("@00WD1000000153*".encode())
self.main_engine.write(binascii.a2b_hex("0D"))
print("CCD1_NG")
def send_ccd2_OK(self):
self.main_engine.write("@00WD1010000251*".encode())
self.main_engine.write(binascii.a2b_hex("0D"))
print("CCD2_OK")
def send_ccd2_NG(self):
self.main_engine.write("@00WD1010000152*".encode())
self.main_engine.write(binascii.a2b_hex("0D"))
#print(self.main_engine.write("@00WD1010000151*".encode()))
print("CCD2_NG")
def recv(self):
while True:
data = self.main_engine.read_all()
if data == b'':
continue
else:
break
time.sleep(0.02)
return data
if __name__ == "__main__":
myserial.Print_Used_Com()
Ret =False #是否创建成功标志
Engine1 = myserial("COM5",115200,0.5)
if Engine1.main_engine.isOpen():
print("open success")
if (Ret):
Engine1.Print_Name()
Engine1.send_ccd2_OK()
data = Engine1.recv()
print(data)
data = Engine1.recv()
print(data)