完整代码链接:https://download.youkuaiyun.com/download/qq_34162147/54904655
本章节是续上一篇(界面篇)。如未搭建界面,请查阅以下链接。
本章节主要是实现串口功能,实现串口收发。类似串口调试助手。如未安装串口模块,可在Python根目录通过命令pip install pyserial进行安装。
1、打开串口
Python使用串口功能以及线程功能,需要在开头引入。结合前篇(界面篇),需要在开头引入全局变量。
import serial #串口
import threading #线程
# 全局变量
global ser
global com_text
global trans_cu
将以下代码替换到界面篇的com_ctrl函数。整体替换。
这个函数中cn_var,cp_var,cr_var,cl_var,p0,p1都是通过按钮操作传递过来,读取下拉菜单的值。
cn_var是按钮控件名
cp_var是端口号
cr_var是波特率
cl_var是指示灯控件
p0是红灯图片
p1是绿灯图片
函数中,recv_com_data是用来定义接收线程。接收函数是thread_com_recv,后续有讲解。创建线程是为了实现接收一直起作用,程序并与界面显示并行运行。
代码经过优化,经测试达到0错误。代码中多次使用if和else pass组合。是因为参考其他程序时,发现有错误,无法正常停止串口。而且在else之后绑定串口的ser无法继续使用。如有大神能够知道原因,请在评论区告知,在此感谢!
# 串口打开关闭函数
def com_ctrl(cn_var,cp_var,cr_var,cl_var,p0,p1):
global ser
global com_state
global com_text
if cn_var.get() == "打开串口":
ser = serial.Serial(
port = cp_var,
baudrate=int(cr_var),
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=0.2,
xonxoff=False,
rtscts=False,
interCharTimeout=None
)
if ser.is_open:
com_state=1
else:
ser.open()
com_state=1
com_text.delete(1.0,END)
recv_com_data = threading.Thread(target=thread_com_recv)#创建接收线程
recv_com_data.start()
else :
pass
if ser.is_open and cn_var.get() == "关闭串口":
com_state=0
ser.close() # 关闭传口
cn_var.set("打开串口")
cl_var.configure(image=p0)
else:
pass
if ser.is_open :
cn_var.set("关闭串口")
cl_var.configure(image=p1)
else:
pass
2、接收
接收函数整体添加即可。这部分对应打开串口的thread_com_recv函数。
特别注意:read_com = ser.read_all()后面是read_all,而不是readall。其他地方很多代码都存在这个问题。如果写成readall,可以使用。但是快速传输时,每包数据小于500ms,问题就暴露了,接收出错。实际官方是read_all。
代码中com_text.see(END),see是用于ScrolledText滚动条文本框控件的光标移动,使得滚动条随着接收数据的增多而移动至最后。此部分结合界面篇的带滚动条文本框部分。
代码中使用了try和except Exception:break的组合,作用在于接收时,防止接收函数read_all()导致出错。出错时会有退出机制。其他网上代码存在此部分不完善的地方。这部分导致停止运行时无法正常停止。必须强制关闭运行进程。
代码中“停止接收线程”备注那部分,作用是点击按钮关闭时,能够跳出线程,并终止。因为接收代码运行时,一直在while循环。其他网上代码存在此部分不完善的地方。必须强制关闭运行进程,否则串口一直出错而占用。
代码中的decode是解码,用于串口接收到十六进制ACSII码的解码。
此部分代码提到的com_send函数,后续会讲解到。只测试接收时,可以先屏蔽。
特别注意:此部分代码测试时,不能直接点击窗口右上角关闭,必须优先点击关闭串口按钮,再关闭窗口。
# 串口数据接收线程
def thread_com_recv():
global ser
global com_text
global com_state
global trans_cu
while True:
try:
read_com = ser.read_all()
if len(read_com) > 0:
trans_cu=bytes(read_com).decode('ascii')
com_text.insert(END,trans_cu)
com_text.insert(END,'\n')
com_text.see(END)#滚动条移动到最新输入位置
# net_send(trans_cu)
com_send('I have received your data')
print("COM 接收到的数据:%s" % read_com)
print("COM 接收到的数据:%s" % trans_cu)
else:
pass
except Exception:
break
if(com_state==0):
break #停止wihile循环,停止接收线程
else:
pass
插节
如果程序一直运行,不知道什么错误,如图所示,可以强制停止。我用的是VScode+python3.8
3、发送
这部分的代码直接添加即可。此部分结合接收函数使用测试。
代码中encode是编码。
def com_send(cs_var):
s = ser.isOpen()
if s == True:
ser.write(cs_var.encode("utf-8"))
4、测试
可用串口助手与虚拟串口两个小软件配合从测试。测试效果如图所示。
5、拓展
在学习过程,参考了不少资料,也填了不少坑。在此感谢各位前辈们的付出。经过整理筛选后,同样将有用的分享给大家!
Python实现串口通信(pyserial) - -零 - 博客园