因项目需要,简单写了一个python的串口通信demo
效果图:


简单实现了打开后自动搜索存在的串口,也可以点击扫描端口进行扫描,默认9600波特率,8数据位,偶校验,1停止位。大家可以自行修改,或者通过载入json文件修改(只做了入口没实现)。
发送数据的话调用以下语句即可
python
data_to_send = bytes.fromhex('AA BB CC 00 0A D0 1F')
ser.write(data_to_send)
关于数据接收,demo用的serial库需要自己主动去读取,不想主动读取的话可以用python的多线程,或者改用异步的串口库。
检验,停止位,数据位参考:自己安装目录下的python\Lib\site-packages\serial\serialutil.py

源代码如下:
python
import warnings
import PySimpleGUI as sg
import json
import serial
import serial.tools.list_ports
warnings.simplefilter(action='ignore', category=FutureWarning)
sg.theme('DarkAmber') # Keep things interesting for your users
sg.SetOptions(font=('微软雅黑Light', 10))
default_port_droplist=['--']
default_baudrate_droplist=['9600','115200']
default_bytesize_droplist=['7','8','9']
default_parity_droplist=['奇','偶','无']
default_stopbits_droplist=['0','1']
layout = [[sg.Text('-----------------------test------------------------')],
#载入配置文件
[sg.Text('载入配置文件:')],[sg.InputText(key='-OPEN_FILE-')],
[sg.FileBrowse('浏览',target='-OPEN_FILE-',size=(8, 1)),sg.Button('确定',size=(8, 1))],
[sg.Text('-----------------------------------------------------')],
[sg.Button('扫描端口',size=(8,1)),sg.Button('恢复默认',size=(8,1))],
[sg.Drop(default_port_droplist, default_value='--',size=(8,6),key='-drop_port-',readonly=True),sg.Text('端口号')],
[sg.Drop(default_baudrate_droplist, default_value='9600',size=(8,6),key='-drop_baudrate-',readonly=True),sg.Text('波特率')],
[sg.Drop(default_bytesize_droplist, default_value='8',size=(8,6),key='-drop_bytesize-',readonly=True),sg.Text('数据位')],
[sg.Drop(default_parity_droplist, default_value='偶',size=(8,6),key='-drop_parity-',readonly=True),sg.Text('校验位')],
[sg.Drop(default_stopbits_droplist, default_value='1',size=(8,6),key='-drop_stopbits-',readonly=True),sg.Text('停止位')],
[sg.Button('打开端口',size=(8,1)),sg.Button('关闭端口',size=(8,1))],
#退出
[sg.Exit()]]
window = sg.Window('window title', layout)
#更新UI内容
drop_list_port = window['-drop_port-']
drop_list_baudrate = window['-drop_baudrate-']
drop_list_bytesize = window['-drop_bytesize-']
drop_list_parity = window['-drop_parity-']
drop_list_stopbits = window['-drop_stopbits-']
sg.Print('-------------log output-------------', do_not_reroute_stdout=False)
#读取json文件
def read_json_file(file_path):
with open(file_path, 'r',encoding='utf-8') as file:
data = json.load(file)
return data
def main():
global default_port_droplist
global flg_read
global ser
flg_read = 0
ports = list(serial.tools.list_ports.comports())
if len(ports) != 0:
print('自动搜索到以下端口')
for port in ports:
print(f"设备名: {port.device}, 描述: {port.description}")#设备名: COM4, 描述: USB Serial Port (COM4)
else:
print(f"未找到端口")
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
if event == 'Exit':
print('您点击了Exit')
break
if event == '扫描端口':
print('您点击了扫描端口')
ports = list(serial.tools.list_ports.comports())
if len(ports) != 0:
default_port_droplist=[]
for port in ports:
print(f"发现设备! 设备名: {port.device}, 描述: {port.description}") #设备名: COM4, 描述: USB Serial Port (COM4)
default_port_droplist.append(port.device)
print(f"default_port_droplist:{default_port_droplist}")
drop_list_port.update(values = default_port_droplist)
drop_list_port.update(value = default_port_droplist[0])
else:
print(f"未找到端口")
if event == '恢复默认':
print('您点击了恢复默认')
if len(default_port_droplist)!= 0:
drop_list_port.update(value=default_port_droplist[0])
else:
drop_list_port.update(value='--')
drop_list_baudrate.update(value='9600')
drop_list_bytesize.update(value='8')
drop_list_parity.update(value='偶')
drop_list_stopbits.update(value='1')
if event == '确定':
#打印选择的json文件内容
print(read_json_file(values['-OPEN_FILE-']))
if event == '打开端口':
print('您点击了打开端口')
if flg_read == 0:
if len(default_port_droplist) and (default_port_droplist[0]!='--'):
ser = serial.Serial(
port = values['-drop_port-'], # 串口号(需要选择)
baudrate=values['-drop_baudrate-'], # 波特率(需要选择)
bytesize=serial.EIGHTBITS, # 数据位:8 位
parity=serial.PARITY_EVEN, # 校验位:偶校验
stopbits=serial.STOPBITS_ONE, # 停止位:1 位
timeout=0.5 # 读取超时时间(秒)
)
print(ser)
if ser.is_open:
flg_read = 1
print(f"串口 {ser.port} 已成功打开")
else:
flg_read = 0
print(f"无法打开串口 {ser.port}")
else:
flg_read = 0
print('请先扫描端口')
else:
print('请先关闭串口')
if event == '关闭端口':
print('您点击了关闭端口')
if flg_read == 1:
if ser.is_open:
ser.close()
flg_read = 0
print(f"串口{ser.port}已成功关闭")
else:
print("串口未打开,不需要关闭")
else:
print("串口未打开,不需要关闭")
if __name__ == '__main__':
main()