最近项目中要使用模拟数据源通过向外发送数据, 以前都是用 C# 编写, 最近在研究 python, 所以就用 python 写了一个串口助手, 方便以后的测试.
在电脑上通过虚拟串口助手产生两个虚拟串口, 运行编写的串口助手
另外, 打开一个串口调试助手, 辅助测试
两者互发数据, 可以看到编写的串口助手能够正常接收发送, 并且在后台我们也把接收到的数据打印了出来
下面先讲解关于界面的代码, 这里只是简单的使用 tkinter 做界面, 如果想要更好的界面效果, 可以尝试一下 QT.
首先是界面中串口设置区域的代码, 界面布局统一用 grid 来布局, 当然也有其他的布局方法
- #-------------------------------------------------------------------------
- #面板布局区
- root = Tk()
- root.title('xutopia 公众号: 洛水梅家')
- #-------------------------------------------------------------------------
- #串口设置区
- label_com = Label(root, text="串口号", height=2).grid(row=0, column=0)
- label_bps = Label(root, text="波特率", height=2).grid(column=0, row=1)
- label_datBit = Label(root, text="数据位", height=2).grid(column=0, row=2)
- label_parity = Label(root, text="校验位", height=2).grid(column=0, row=3)
- label_stop_bit = Label(root, text="停止位", height=2).grid(column=0, row=4)
接下来是串口号的 combobox 的设置, 其中 serialPortFile.GetCom() 是获取所有串口号的函数, 接下来会讲解
- # 串口号
- varPort = StringVar()
- combo_com = ttk.Combobox(root, textvariable=varPort, width=8, height=2, justify=CENTER)
- serial_com = serialPortFile.GetCom()
- combo_com['values'] = serial_com
- #combo_com.bind("<<ComboboxSelected>>", lambda event: combo1_handler(var=varPort.get()))
- combo_com.current(0)
- combo_com.grid(column=1, row=0)
- # 波特率
- varBitrate = StringVar()
- combo_bps = ttk.Combobox(root, textvariable=varBitrate, width=8, height=2, justify=CENTER)
- combo_bps['values'] = ("9600", "19200", "38400", "115200")
- #combo_bps.bind("<<ComboboxSelected>>", lambda event: combo2_handler(var=varBitrate.get()))
- combo_bps.current(0)
- combo_bps.grid(column=1, row=1)
- #数据位
- combo_byteBit = ttk.Combobox(root, width=8, height=2, justify=CENTER)
- combo_byteBit['values'] = ("5", "6", "7", "8")
- combo_byteBit.current(3)
- combo_byteBit.grid(column=1, row=2)
- #奇偶校验
- combo_parity = ttk.Combobox(root, width=8, height=2, justify=CENTER)
- combo_parity['values'] = ("N", "O", "E")
- combo_parity.current(0)
- combo_parity.grid(column=1, row=3)
- #停止位
- combo_stopBit = ttk.Combobox(root, width=8, height=2, justify=CENTER)
- combo_stopBit['values'] = ("1", "1.5", "2")
- combo_stopBit.current(0)
- combo_stopBit.grid(column=1, row=4)
- serialPortFile.text_rx = Text(root,width=70,height=20)
- serialPortFile.text_rx.grid(row=0,column=3,rowspan=5)
- serialPortFile.text_rx.insert(END,'这是一个 xutopia 用 python 编写的串口助手, 公众号: 洛水梅家 \ n')
- text_tx = Text(root,width=70,height=10)
- text_tx.grid(row=5,column=3,rowspan=2)
- text_tx.insert(END,'xutopia 公众号: 洛水梅家, 发送数据 12345, 上山打老虎')
- button_send = Button(root, text='send', width=18, height=1)
- button_send.bind("<Button-1>", lambda event: serialPortFile.usart_sent(var=text_tx.get("0.0", "end")))
- button_send.grid(column=1, row=6)
- #串口开关按钮
- serialPortFile.button_var = StringVar()
- serialPortFile.button_var.set("打开串口")
- buttonOpenCom = Button(root, textvariable=serialPortFile.button_var, width=18, height=1)
- buttonOpenCom.bind("<Button-1>", lambda event: serialPortFile.usart_ctrl(combo_com.get(), combo_bps.get(),combo_parity.get(),combo_stopBit.get(),combo_byteBit.get()))
- buttonOpenCom.grid(column=1, row=5)
以上就是界面相关的代码, 最终效果也就是上图显示的效果, 很简单. 接下来介绍 python 串口的逻辑代码部分. 在另外一个模块中 serialPortFile.py
获取电脑中所有的串口号的函数, 注意这里通过 serial.tools.list_ports.comports() 获取所有的串口号之后进行了一步转换, 存在一个数组中, 这样, 传入 serial 中才能被识别.
- # 获取并存储串口号到数组
- def GetCom():
- port_list = list(serial.tools.list_ports.comports())
- print(len(port_list))
- portcnt = len(port_list)
- serial_com = []
- for m in range(portcnt):
- port_list_1 = list(port_list[m])
- serial_com.append(port_list_1[0])
- return serial_com
串口打开关闭函数, 串口打开之后创建了一个线程 threading, 线程中一直监视串口的状态, 一旦接受到数据, 就把数据显示到接受数据显示框中. 有关 python 线程 threading 的内容可以在我的公众号, 洛水梅家中查看.
注意在代码中加了一个 if ser.is_open: 的条件判断, 不加入这个条件的话, 很有可能重复打开串口而报错误.
同时在按键 Button 的状态也随着串口的开关状态而变化.
- def usart_ctrl(com, bps,parity_,stopbits_,bytesize_):
- #print(__file__, sys._getframe().f_lineno, port_, bitrate_, var.get())
- global ser, button_var
- if button_var.get() == "打开串口":
- button_var.set("关闭串口")
- ser = serial.Serial(
- port=com,
- baudrate=int(bps),
- parity=parity_,
- timeout=0.2,
- stopbits=float(stopbits_),
- bytesize=int(bytesize_))
- if ser.is_open:
- pass
- else:
- ser.open()
- recv_data = threading.Thread(target=thread_recv)
- recv_data.start()
- else:
- button_var.set("打开串口")
- if ser.is_open:
- ser.close()
- else:
- pass
- def usart_sent(var):
- #print(__file__, sys._getframe().f_lineno, "-->", var)
- print(var)
- if ser.is_open:
- ser.write(var.encode("gb2312"))
- def thread_recv():
- global text_rx
- while True:
- try:
- read = ser.readall()
- if len(read)> 0:
- print(bytes(read).decode('gb2312'))
- # print(__file__, sys._getframe().f_lineno, "<--", bytes(read).decode('ascii'))
- text_rx.insert(END,bytes(read).decode('gb2312'))
- except Exception as e:
- print(e)
- time.sleep(1)
- pass
上面就是关于串口助手的所有代码介绍, 更多详细内容, 关注公众号 洛水梅家 免费获取源码
后台回复 python_com, 免费获取源码
来源: https://www.cnblogs.com/xutopia/p/11651045.html