Python版的Arduino USB端口调试终端程序,用了wxPython图形界面库。便于将PC作为上位机,去控制Arduino。

main.py

import wx
from MainFrame import MainFrame

if __name__ == '__main__':
    app = wx.App()
    frm = MainFrame(None)
    frm.Show()
    app.MainLoop()

UsbInterface.py

import serial
import serial.tools.list_ports

# 取USB设备列表
def getUsbDeviceList():
    #取串口列表
    serialPortList = serial.tools.list_ports.comports()

    deviceList = []
    i = 0
    for nowPort in serialPortList:
        #取出串口设备信息
        nowUsbDev = {
            'id': i,                        #设备编号
            'label': nowPort.description,   #设备标题
            'port': nowPort.device,         #设备端口
            'idVendor': nowPort.vid,        #设备Vendor Id
            'idProduct': nowPort.pid,       #设备Product Id
        }
        deviceList.append(nowUsbDev)
        i += 1
    return deviceList


# 连接USB设备
def connectUsbDevice(port):
    #连接串口设备
    nowSerical = serial.Serial(port, 9600)
    return nowSerical

# 关闭USB设备
def closeUsbDevice(serical):
    #关闭串口
    serical.close()

MainFrame.py

import wx
import _thread
import UsbInterface


class MainFrame(wx.Frame):
    # Frame标题
    labelFrame = "Arduino USB串口终端"
    # 当前选择的USB的vid
    idVendorUsbDevice = None
    # 当前选择的USB的pid
    idProductUsbDevice = None
    # 当前选择的USB的标题
    labelUsbDevice = None
    # 当前选择的USB的端口
    portUsbDevice = None
    # 当前串口设备连接
    serialUsbDevice = None
    # 当前串口设备状态
    statusSerialUsbDevice = 0 #0.未连接 1.已连接

    # 构造函数
    def __init__(self, *args, **kw):
        super(MainFrame, self).__init__(*args, **kw)

        pnl = wx.Panel(self)

        # 标题
        stTitle = wx.StaticText(pnl, label=self.labelFrame, pos=(10, 10))
        font = stTitle.GetFont()
        font.PointSize += 5
        font = font.Bold()
        stTitle.SetFont(font)

        # USB设备
        wx.StaticText(pnl, label="USB设备:", pos=(30, 53))
        tcUsbDev = wx.TextCtrl(pnl, 1, '',
                                pos=(110, 50),
                                style=wx.TE_READONLY,
                                size=(250, 25)
                                )

        # 连接USB设备按钮
        btnConnect = wx.Button(pnl, 2, '连接USB设备',
                                pos=(110, 90),
                                size=(250, 25)
                                )
        btnConnect.Disable()
        btnConnect.Bind(wx.EVT_BUTTON, self.OnCheckButtonConnect)

        # 接收到的信息列表
        wx.StaticText(pnl, label="接收的信息:", pos=(30, 133))
        tcRecv = wx.TextCtrl(pnl, 3, '', pos=(110, 130),
                                size=(250,300),
                                style=wx.TE_MULTILINE|wx.TE_READONLY)
        tcRecv.Disable()

        # 待发送信息框
        wx.StaticText(pnl, label="待发送信息:", pos=(380, 53))
        tcSend = wx.TextCtrl(pnl, 4, '',
                                pos=(460, 50),
                                size=(250, 25)
                                )
        tcSend.Disable()

        # 发送信息按钮
        btnSend = wx.Button(pnl, 5, '发送信息',
                                pos=(460, 90),
                                size=(250, 25)
                                )
        btnSend.Disable();
        btnSend.Bind(wx.EVT_BUTTON, self.OnCheckButtonSend)

        # 已发送的信息列表
        wx.StaticText(pnl, label="已发送信息:", pos=(380, 133))
        tcSended = wx.TextCtrl(pnl, 6, '', pos=(460, 130),
                                size=(250, 300),
                                style=wx.TE_MULTILINE | wx.TE_READONLY)
        tcSended.Disable()


        self.makeMenuBar()
        self.Title = self.labelFrame
        self.CreateStatusBar()
        self.SetStatusText("设备未连接!")
        self.SetSize(800,550)

    # 构造菜单栏
    def makeMenuBar(self):
        SystemMenu = wx.Menu()
        setupItem = SystemMenu.Append(-1, "设置...\tCtrl-S",
                "设置USB端口等资料")
        SystemMenu.AppendSeparator()
        exitItem = SystemMenu.Append(wx.ID_EXIT)

        helpMenu = wx.Menu()
        aboutItem = helpMenu.Append(wx.ID_ABOUT)

        menuBar = wx.MenuBar()
        menuBar.Append(SystemMenu, "系统")
        menuBar.Append(helpMenu, "帮助")

        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.OnSetup, setupItem)
        self.Bind(wx.EVT_MENU, self.OnExit,  exitItem)
        self.Bind(wx.EVT_MENU, self.OnAbout, aboutItem)

    # 退出
    def OnExit(self, event):
        self.Close(True)

    # 设置
    def OnSetup(self, event):

        #取串口设备列表
        nowDevList = UsbInterface.getUsbDeviceList()
        devLabelList = []
        for nowDev in nowDevList:
            devLabelList.append(nowDev['label'])

        #选择需要连接的设备
        dialogSetup = wx.SingleChoiceDialog(None, "选择USB端口", "设置", devLabelList)
        dialogSetup.ShowModal()
        labelUsbDevSelect = dialogSetup.GetStringSelection()
        indexUsbDevSelect = dialogSetup.GetSelection()

        #设置当前选择的设备信息
        self.labelUsbDevice = nowDevList[indexUsbDevSelect]['label']
        self.idProductUsbDevice = nowDevList[indexUsbDevSelect]['idProduct']
        self.idVendorUsbDevice = nowDevList[indexUsbDevSelect]['idVendor']
        self.portUsbDevice = nowDevList[indexUsbDevSelect]['port']
        self.SetStatusText("当前设备 " + labelUsbDevSelect + ":未连接")


        stUsbDev = wx.FindWindowById(1)
        stUsbDev.SetValue(labelUsbDevSelect)

        btnConnect = wx.FindWindowById(2)
        btnConnect.Enable()


    # 关于
    def OnAbout(self, event):
        wx.MessageBox("说明幻想中......",
                      "关于" + self.labelFrame,
                      wx.OK|wx.ICON_INFORMATION)
    # 设计USB设备
    def OnCheckButtonConnect(self, event):
        btnConnect = wx.FindWindowById(2)
        if self.statusSerialUsbDevice == 0:
            #连接设备
            btnConnect.SetLabel('断开USB设备')
            self.serialUsbDevice = UsbInterface.connectUsbDevice(self.portUsbDevice)
            self.statusSerialUsbDevice = 1
            try:
                #开启新线程接收USB信息
                _thread.start_new_thread(self.RecvUsbInfo, ())
            except:
                print("Error: 无法启动线程")

            tcRecv = wx.FindWindowById(3)
            tcRecv.Enable()

            tcSend = wx.FindWindowById(4)
            tcSend.Enable()

            btnSend = wx.FindWindowById(5)
            btnSend.Enable()

            tcSended = wx.FindWindowById(6)
            tcSended.Enable()
            self.SetStatusText("当前设备 " + self.labelUsbDevice + ":已连接")

        else:
            #断开连接
            btnConnect.SetLabel('连接USB设备')
            self.statusSerialUsbDevice = 0
            self.serialUsbDevice.close()

            tcRecv = wx.FindWindowById(3)
            tcRecv.Disable()

            tcSend = wx.FindWindowById(4)
            tcSend.Disable()

            btnSend = wx.FindWindowById(5)
            btnSend.Disable()

            tcSended = wx.FindWindowById(6)
            tcSended.Disable()
            self.SetStatusText("当前设备 " + self.labelUsbDevice + ":未连接")

    # 发送信息
    def OnCheckButtonSend(self, event):
        tcSend = wx.FindWindowById(4)
        tcSended = wx.FindWindowById(6)
        nowOutput = tcSend.GetValue()

        if len(nowOutput) > 0:
            #判断有输入,发送串口信号
            self.serialUsbDevice.write(bytes(nowOutput, encoding="utf8"))
            tcSended.AppendText(nowOutput + "\n")
            tcSend.SetValue("");

    #接收信息(线程)
    def RecvUsbInfo(self):
        #不断循环读取端口信号,直至USB设备断开
        while self.statusSerialUsbDevice == 1:
            #读取多行串口信息
            contentList = self.serialUsbDevice.readlines(1)
            tcRecv = wx.FindWindowById(3)
            strText = ""
            for content in contentList:
                strText += content.decode("UTF-8")
            tcRecv.AppendText(strText)