加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
wxSpdt.py 17.04 KB
一键复制 编辑 原始数据 按行查看 历史
shuanglongzimu 提交于 2016-03-28 23:05 . first commit
# coding=utf-8
import wx
import os
import time
import serial
import binascii
import datetime
import serial.tools.list_ports as list_ports
global echo
echo = False
sendData = []
stopbitsList = ['0', '1', '2']
databitsList = ['5', '6', '7', '8']
checkbitsList = ['None', 'Old', 'Even']
baudrateList = ['300', '600', '1200', '2400', '4800', '9600', '19200', '38400', '115200']
Serial = serial.Serial(port=None, baudrate=9600, bytesize=8, parity='E', stopbits=1, timeout=0)
class ParamsFrame(wx.Panel):
'''
串口参数配置:
1.包括端口号,波特率,数据位,校验位,停止位和开关按钮;
2.点击端口号的下拉框时自动检测当前有效的端口号名称.
3.串口打开失败会弹出错误对话框.
'''
def __init__(self, parent):
wx.Panel.__init__(self, parent)
StaticBox = wx.StaticBox(self, -1, u"串口配置")
sizer = wx.StaticBoxSizer(StaticBox, wx.HORIZONTAL)
portLable = wx.StaticText(StaticBox, -1, u"端口号:")
self.port = wx.ComboBox(StaticBox, -1, "", wx.DefaultPosition, (80, -1), "", wx.CB_DROPDOWN)
self.CheckValidPorts(None) # 初始化检查有效的端口号
baudrateLable = wx.StaticText(StaticBox, -1, u"波特率:")
self.baudrate = wx.ComboBox(StaticBox, -1, "9600", wx.DefaultPosition, (80, -1), baudrateList, wx.CB_DROPDOWN)
parityLable = wx.StaticText(StaticBox, -1, u"校验位:")
self.parity = wx.ComboBox(StaticBox, -1, "Even", wx.DefaultPosition, (70, -1), checkbitsList, wx.CB_DROPDOWN)
bytesizeLable = wx.StaticText(StaticBox, -1, u"数据位:")
self.bytesize = wx.ComboBox(StaticBox, -1, "8", wx.DefaultPosition, (70, -1), databitsList, wx.CB_DROPDOWN)
stopbitsLable = wx.StaticText(StaticBox, -1, u"停止位:")
self.stopbits = wx.ComboBox(StaticBox, -1, "1", wx.DefaultPosition, (70, -1), stopbitsList, wx.CB_DROPDOWN)
sizer.Add(portLable, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.port, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 15)
sizer.Add(baudrateLable, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.baudrate, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 15)
sizer.Add(parityLable, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.parity, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 15)
sizer.Add(bytesizeLable, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.bytesize, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 15)
sizer.Add(stopbitsLable, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.stopbits, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 45)
self.switchBtn = wx.Button(StaticBox, -1, u"打开串口")
sizer.Add(self.switchBtn)
self.SetSizer(sizer)
self.Bind(wx.EVT_COMBOBOX_DROPDOWN, self.CheckValidPorts, self.port)
self.Bind(wx.EVT_BUTTON, self.SwitchPort, self.switchBtn)
def CheckValidPorts(self, evt):
GetItems = self.port.GetItems()
Items_list = []
for buf in list(list_ports.comports()):
if buf[0].find('usbserial') != -1:
Items_list.append(buf[0])
if len(Items_list) == 0:
Items_list.append('None')
if GetItems != Items_list:
self.port.Clear()
self.port.SetItems(Items_list)
self.port.Select(0)
def SwitchPort(self, evt):
Serial.port = self.port.GetValue().encode('utf-8')
Serial.baudrate = int(self.baudrate.GetValue())
Serial.parity = self.parity.GetValue()[0].encode('utf-8')
Serial.bytesize = int(self.bytesize.GetValue())
Serial.stopbits = int(self.stopbits.GetValue())
if self.switchBtn.GetLabel() == u'打开串口':
try:
Serial.open()
self.switchBtn.SetLabel(u'关闭串口')
except:
dlg = wx.MessageDialog(None, u'打开失败,请检查串口是否有效或被占用!', u'错误提示:\n', wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
else:
Serial.close()
self.switchBtn.SetLabel(u'打开串口')
class RecvFrame(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
StaticBox = wx.StaticBox(self, -1, u"接收数据")
sizer = wx.StaticBoxSizer(StaticBox, wx.VERTICAL)
configSizer = wx.FlexGridSizer(rows=1, hgap=5, vgap=5)
self.hexDisplay = wx.CheckBox(StaticBox, -1, u"十六进制")
configSizer.Add(self.hexDisplay, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
self.stopRecv = wx.CheckBox(StaticBox, -1, u"暂停接收")
configSizer.Add(self.stopRecv, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
self.addTime = wx.CheckBox(StaticBox, -1, u"增加时标")
self.addTime.SetValue(True)
configSizer.Add(self.addTime, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
self.saveLog = wx.CheckBox(StaticBox, -1, u"保存记录")
configSizer.Add(self.saveLog, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 22)
recvTimeoutLable = wx.StaticText(StaticBox, -1, u"接收超时(ms):")
configSizer.Add(recvTimeoutLable, 0, wx.ALIGN_CENTER_VERTICAL)
self.recvTimeout = wx.TextCtrl(StaticBox, -1, "50", size=(45, -1), style=wx.TE_CENTER)
configSizer.Add(self.recvTimeout, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 25)
recvBytesNumLable = wx.StaticText(StaticBox, -1, u"接收字节:")
configSizer.Add(recvBytesNumLable, 0, wx.ALIGN_CENTER_VERTICAL)
self.recvBytesNum = wx.StaticText(StaticBox, -1, "0", size=(50, -1))
configSizer.Add(self.recvBytesNum, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
clearBytesBtn = wx.Button(StaticBox, -1, u"重置计数")
configSizer.Add(clearBytesBtn, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 15)
clearDataBtn = wx.Button(StaticBox, -1, u"清空数据")
configSizer.Add(clearDataBtn, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
sizer.Add(configSizer, 0, wx.EXPAND | wx.BOTTOM, 5)
self.recvText = wx.TextCtrl(StaticBox, -1, style=wx.TE_MULTILINE | wx.TE_RICH2)
sizer.Add(self.recvText, 1, wx.EXPAND | wx.RIGHT, 2)
self.SetSizer(sizer)
self.Bind(wx.EVT_BUTTON, self.ClearRecvBytesNum, clearBytesBtn)
self.Bind(wx.EVT_BUTTON, self.ClearRecvData, clearDataBtn)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.recvData, self.timer)
self.timer.Start(1)
self.readingData = False
self.lastReadTime = 0.0
def recvData(self, evt):
global echo
if Serial.isOpen():
if echo and len(sendData):
if not self.stopRecv.IsChecked():
if self.addTime.IsChecked(): # 判断是否增加时标
recvTime = time.strftime("[%H:%M:%S ", time.localtime()) + \
str(datetime.datetime.now().microsecond)[0:3] + "] Tx: "
else:
recvTime = "Tx: "
tmp_str = sendData[0].decode('gbk')
self.recvText.AppendText(recvTime + tmp_str)
if self.saveLog.IsChecked():
self.SaveDataLog(recvTime.encode('utf8') + tmp_str.encode('utf-8'))
x = self.recvText.GetInsertionPoint()
self.recvText.SetStyle(x - len(tmp_str) - len(recvTime), x - 1, wx.TextAttr('blue'))
sendData.pop()
if len(sendData):
sendData.remove(sendData[0])
else:
sendData.pop()
tmp_buf = ''
recvTime = ''
data = Serial.readall()
dataLen = len(data)
if dataLen != 0:
if not self.readingData:
if self.addTime.IsChecked(): # 判断是否增加时标
recvTime = time.strftime("[%H:%M:%S ", time.localtime()) + \
str(datetime.datetime.now().microsecond)[0:3] + "] Rx: "
else:
recvTime = "Rx: "
else:
recvTime = ''
self.readingData = True
self.lastReadTime = time.time()
if self.hexDisplay.IsChecked(): # 数据格式,判断是否显示16进制
data = binascii.b2a_hex(data)
for i in range(len(data) / 2):
tmp_buf += data[2 * i: 2 * (i + 1)] + ' '
else:
tmp_buf = data.decode('gbk', errors='replace')
tmp_buf = tmp_buf.encode('utf-8', errors='replace')
if self.readingData:
timeout = float(self.recvTimeout.GetValue()) / 1000
if time.time() - self.lastReadTime > timeout: # 判断接收帧间隔时间,若超出判定接收完成并换行
self.readingData = False
tmp_buf += '\r'
if not self.stopRecv.IsChecked() and len(tmp_buf) != 0:
if len(recvTime):
self.recvText.AppendText(recvTime)
try:
self.recvText.AppendText(tmp_buf)
# x = self.recvText.GetInsertionPoint()
# self.recvText.SetStyle(x - len(tmp_buf) - len(recvTime), x, wx.TextAttr('white', 'black'))
except:
pass
if self.saveLog.IsChecked():
self.SaveDataLog(recvTime.encode('utf8') + tmp_buf)
if tmp_buf != '\r':
self.recvBytesNum.Label = str(int(self.recvBytesNum.Label) + dataLen) # 累计接收数据的个数
def ClearRecvBytesNum(self, event):
self.recvBytesNum.Label = "0"
def ClearRecvData(self, event):
self.recvText.Clear()
def SaveDataLog(self, data):
log_dir = os.getcwd() + '/log'
if not os.path.exists(log_dir):
os.makedirs(log_dir)
file_name = log_dir + '/' + time.strftime("%Y%m%d", time.localtime())
fp = open(file_name, 'a+')
fp.write(data)
fp.close()
class SendFrame(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
comBox = wx.StaticBox(self, -1, u"发送数据")
sizer = wx.StaticBoxSizer(comBox, wx.VERTICAL)
configSizer = wx.FlexGridSizer(rows=1, hgap=5, vgap=5)
self.hexCheckBox = wx.CheckBox(comBox, -1, u"十六进制")
configSizer.Add(self.hexCheckBox, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
self.echo = wx.CheckBox(comBox, -1, u"回显发送")
configSizer.Add(self.echo, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
self.reSendStart = wx.CheckBox(comBox, -1, u"启动重发")
configSizer.Add(self.reSendStart, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
reSendCntLable = wx.StaticText(comBox, -1, u"重发次数:")
configSizer.Add(reSendCntLable, 0, wx.ALIGN_CENTER_VERTICAL)
self.reSendCnt = wx.TextCtrl(comBox, -1, "0", size=(38, -1), style=wx.TE_CENTER)
configSizer.Add(self.reSendCnt, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
reSendIntervalLable = wx.StaticText(comBox, -1, u"重发间隔(ms):")
configSizer.Add(reSendIntervalLable, 0, wx.EXPAND)
self.reSendTime = wx.TextCtrl(comBox, -1, "1000", size=(45, -1), style=wx.TE_CENTER)
configSizer.Add(self.reSendTime, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
recvBytesNumLable = wx.StaticText(comBox, -1, u"发送字节:")
configSizer.Add(recvBytesNumLable, 0, wx.ALIGN_CENTER_VERTICAL)
self.sendBytesNum = wx.StaticText(comBox, -1, "0", size=(50, -1))
configSizer.Add(self.sendBytesNum, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 4)
clearBytesNumBtn = wx.Button(comBox, -1, u"重置计数")
configSizer.Add(clearBytesNumBtn, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 15)
sendDataBtn = wx.Button(comBox, -1, u"发送数据")
configSizer.Add(sendDataBtn)
sizer.Add(configSizer, 0, wx.EXPAND | wx.BOTTOM, 5)
self.SendText = wx.TextCtrl(comBox, -1, "", style=wx.TE_MULTILINE | wx.TE_RICH2)
sizer.Add(self.SendText, 1, wx.EXPAND | wx.RIGHT, 2)
self.SetSizer(sizer)
self.Bind(wx.EVT_BUTTON, self.ClearSendBytesNum, clearBytesNumBtn)
self.Bind(wx.EVT_BUTTON, self.StartSendData, sendDataBtn)
self.Bind(wx.EVT_CHECKBOX, self.StartResend, self.reSendStart)
self.Bind(wx.EVT_CHECKBOX, self.SendDataMode, self.hexCheckBox)
self.Bind(wx.EVT_CHECKBOX, self.EchoSendData, self.echo)
# self.Bind(wx.EVT_TEXT, self.SendTextMode, self.SendText)
self.SendText.Bind(wx.EVT_LEFT_DOWN, self.test)
self.time = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.reSendTask, self.time)
self.SendCount = 0
# acceltbl = wx.AcceleratorTable([(wx.ACCEL_SHIFT, wx.WXK_F5, self.EchoSendData().GetId())])
# self.SetAcceleratorTable(acceltbl)
def test(self, evt):
evt.Skip()
def SendTextMode(self, evt):
pass
def SendDataMode(self, evt):
data = self.SendText.GetValue().encode("gbk")
if self.hexCheckBox.IsChecked():
data = binascii.b2a_hex(data)
tmp_str = ''
for i in range(len(data) / 2):
tmp_str += data[2 * i: 2 * (i + 1)]
if i != len(data) / 2 - 1:
tmp_str += ' '
self.SendText.Clear()
self.SendText.write(tmp_str)
else:
try:
data = data.replace(' ', '')
data = binascii.a2b_hex(data)
data = data.decode("gbk")
self.SendText.Clear()
self.SendText.write(data)
except Exception, e:
dlg = wx.MessageDialog(None, str(e), u'Error:\n', wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
def EchoSendData(self, evt):
global echo
if self.echo.IsChecked():
echo = True
else:
echo = False
def StartResend(self, evt):
if not self.reSendStart.IsChecked():
self.time.Stop()
def ClearSendBytesNum(self, evt):
self.sendBytesNum.Label = "0"
def StartSendData(self, evt):
if Serial.isOpen():
if self.reSendStart.IsChecked():
self.SendCount = 1
tmp = int(self.reSendTime.GetValue())
self.time.Start(tmp)
self.SendSerialData()
else:
dlg = wx.MessageDialog(None, u'串口没有被打开,不能发送数据!', u'错误提示:\n', wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
def SendSerialData(self):
global echo
data = self.SendText.GetValue().encode("gbk")
if echo and len(data):
sendData.append(data + '\r') # 添加发送数据到列表
if self.hexCheckBox.IsChecked(): # 十六进制发送,转换数据编码
data = data.replace(' ', '').decode('hex')
if len(data):
Serial.write(data)
self.sendBytesNum.Label = str(int(self.sendBytesNum.Label) + len(data)) # 累计发送数据的个数
else:
dlg = wx.MessageDialog(None, u'发送区未输入要发送的数据!', u'告警提示:\n', wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
def reSendTask(self, evt):
if not Serial.isOpen():
self.time.Stop()
else:
TotalCount = int(self.reSendCnt.GetValue())
self.SendCount += 1
if self.SendCount >= TotalCount and TotalCount != 0:
self.time.Stop()
else:
self.SendSerialData()
class SplitterFrame(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
sp = wx.SplitterWindow(self, style=wx.SP_3DSASH | wx.SP_LIVE_UPDATE)
p1 = RecvFrame(sp)
p2 = SendFrame(sp)
sp.SetMinimumPaneSize(200)
sp.SplitHorizontally(p1, p2)
sp.SetSashGravity(1)
sizer = wx.BoxSizer()
sizer.Add(sp, 1, wx.EXPAND)
self.SetSizer(sizer)
class SerialFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Serial Tool")
configFrame = ParamsFrame(self)
spFrame = SplitterFrame(self)
Sizer = wx.BoxSizer(wx.VERTICAL)
Sizer.Add(configFrame, 0, wx.EXPAND | wx.ALL, 0)
Sizer.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 3)
Sizer.Add(spFrame, 1, wx.EXPAND | wx.ALL, 0)
self.SetSizer(Sizer)
Sizer.Fit(self)
self.statusbar = self.CreateStatusBar()
self.statusbar.SetFieldsCount(4)
self.statusbar.SetStatusWidths([-7, -1, -1, -1])
self.statusbar.SetStatusText(u"就绪", 0)
self.statusbar.SetStatusText(u"长度: 0", 1)
self.statusbar.SetStatusText(u"行: 0", 2)
self.statusbar.SetStatusText(u"列: 0", 3)
self.Bind(wx.EVT_CLOSE, self.CloseWindows)
def CloseWindows(self, evt): #关闭窗口的事件处理函数
self.Destroy()
if Serial.isOpen():
Serial.close()
if __name__ == "__main__":
app = wx.App()
frame = SerialFrame()
frame.Show()
app.MainLoop()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化