如何使用 pyserial 将文件逐行写入 com0com?

Posted

技术标签:

【中文标题】如何使用 pyserial 将文件逐行写入 com0com?【英文标题】:How can I write file line-by-line with pyserial to com0com? 【发布时间】:2019-10-19 20:31:19 【问题描述】:

我不能使用 pyserial 将文件中的多行数据写入虚拟 com 端口 (com0com)。我正在尝试逐行编写文件,以便可以同时更新 Tkinter 中的进度条。我在 Windows 上运行,并试图将写操作放在它自己的线程中(每个UART Controller with Tkinter and Python GUI)。我的程序写完一行就挂了。

相关代码:

import os
import sys
from functools import partial
import re
import time
import threading

import serial
import serial.tools.list_ports

import tkinter as tk
from tkinter import ttk, filedialog

class MainApp(tk.Tk):

    def __init__(self,
                 parent,
                 title = 'Main Application',
                 *args,
                 **kwargs):

        self.parent = parent

        #Set window title and size
        self.parent.title(title)

        #Create widget container
        container = tk.Frame(self.parent)

        #Add widgets

        # --> Create load program widgets
        load_frame = tk.LabelFrame(container,
                                   text = 'Load Program',
                                   width = 400,
                                   height = 100)

        port_dropdown = DropDown(load_frame,
                                 label = 'Port:',
                                 row = 0)

        file_browser = Browser(load_frame,
                               path_type = 'file',
                               label = 'File:',
                               row = 1)

        program_downloader = Downloader(load_frame,
                                        port_dropdown,
                                        file_browser,
                                        row = 2)

        # --> Layout load program widgets
        load_frame.grid(row = 0,
                        column= 0,
                        padx = (5,5),
                        pady = (5,5))

        #Layout widget container
        container.pack(fill = tk.BOTH,
                       padx = 10,
                       pady = 5,
                       expand = True)         
.
.
.

class Downloader(tk.Frame):

    def __init__(self,
                 parent,
                 port_dropdown,
                 file_browser,
                 row = 0):

        self.port_dropdown = port_dropdown
        self.file_browser = file_browser

        #Instantiate serial port object
        self.serial_port = None

        self.progress_bar = ttk.Progressbar(parent,
                                            orient = 'horizontal',
                                            mode = 'determinate')

        self.progress_bar.grid(row = row,
                               column = 0,
                               columnspan = 2,
                               padx = (5,5),
                               pady = (5,5),
                               sticky = 'WE')

        self.button = tk.Button(parent,
                                text = 'Download',
                                command = self.download_program)

        self.button.grid(row = row,
                         column = 2,
                         padx = (5,5),
                         pady = (5,5),
                         sticky = 'W')

    def download_program(self):

        port_full_name = self.port_dropdown.combobox.get()
        port_name = re.match('([^\s]+)', port_full_name).group(0)

        baud_rate = 9600

        program_path = self.file_browser.text.get()

        self.connect(port_name,
                     baud_rate,
                     program_path)

    def connect(self,
                port_name,
                baud_rate,
                program_path):

        self.serial_port = serial.Serial(port_name,
                                         baud_rate,
                                         timeout=1)

        t1 = threading.Thread(target = self.transfer_data,
                              args = (program_path,))
        t1.daemon = True
        t1.start()

    def transfer_data(self,
                      program_path):

        line = 1
        self.progress_bar['value'] = line

        with open(program_path, 'r') as program:

            max_lines = len(program.readlines())
            self.progress_bar['maximum'] = max_lines

        with open(program_path, 'r') as program:

            while line < max_lines:

                command = program.readline().replace('\n','\r\n')

                print(str(line) + ': ' + repr(command))

                self.serial_port.write(command.encode('ascii'))

                line += 1

                self.progress_bar['value'] = line

                self.serial_port.flush()

        print('done')
        self.disconnect()

    def disconnect(self):
        self.serial_port.close()

if __name__ == '__main__':

    #Initialize Tkinter
    root = tk.Tk()

    #Create GUI
    gui = MainApp(root,
                  'Main Application')

    #Run program
    root.mainloop()

GUI 挂起:

终端输出:

1: '@01\r\n'
2: '@02\r\n'

我能够在循环中第二次从program.txt 读取的事实告诉我,程序可能会挂起,因为端口仍停留在第一次写入时。

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

timeoutwrite_timeout 设置为0 可以防止阻塞,这似乎可以解决问题。

【讨论】:

以上是关于如何使用 pyserial 将文件逐行写入 com0com?的主要内容,如果未能解决你的问题,请参考以下文章

如何将使用PySerial收集的串行数据导出到csv文件?

无法多次写入同一端口(pyserial)

在 Windows 上使用 pyserial 将串行数据写入 Arduino

在R语言 中如何把list对象逐行写入csv文件中

不能多次写入同一个端口(pyserial)

如何使用 PySerial 从 COM 端口读写?