-
2021-12-12 22:32:57
目录
Python Qt GUI设计系列博文终于到了实战篇,本篇博文将贯穿之前的基础知识点实现一款串口调试助手。
关注【公众号】 美男子玩编程,回复关键字:串口调试助手,获取项目源码~
资源下载:PythonQt串口调试助手-嵌入式文档类资源-CSDN下载
1、UI设计
UI设计使用Qt Creator实现,组件布局如下所示:
2、将UI文件转换为Py文件
这里使用Python脚本的方式将UI文件转换为Python文件,代码如下所示:
import os import os.path dir ='./' #文件所在的路径 #找出路径下所有的.ui文件 def listUiFile(): list = [] files = os.listdir(dir) for filename in files: #print(filename) if os.path.splitext(filename)[1] == '.ui': list.append(filename) return list #把扩展名未.ui的转换成.py的文件 def transPyFile(filename): return os.path.splitext(filename)[0] + '.py' #通过命令把.ui文件转换成.py文件 def runMain(): list = listUiFile() for uifile in list: pyfile = transPyFile(uifile) cmd = 'pyuic5 -o {pyfile} {uifile}'.format(pyfile=pyfile, uifile=uifile) os.system(cmd) if __name__ =="__main__": runMain()
3、逻辑功能实现
3.1、初始化程序
首先初始化一些组件和标志位的状态,设置信号与槽的关系,实现代码如下所示:
# 初始化程序 def __init__(self): super(Pyqt5_Serial, self).__init__() self.setupUi(self) self.init() self.ser = serial.Serial() self.port_check() # 设置Logo和标题 self.setWindowIcon(QIcon('Com.png')) self.setWindowTitle("串口调试助手 【公众号】美男子玩编程") # 设置禁止拉伸窗口大小 self.setFixedSize(self.width(), self.height()) # 发送数据和接收数据数目置零 self.data_num_sended = 0 self.Lineedit2.setText(str(self.data_num_sended)) self.data_num_received = 0 self.Lineedit3.setText(str(self.data_num_received)) # 串口关闭按钮使能关闭 self.Pushbuttom3.setEnabled(False) # 发送框、文本框清除 self.Text1.setText("") self.Text2.setText("") # 建立控件信号与槽关系 def init(self): # 串口检测按钮 self.Pushbuttom2.clicked.connect(self.port_check) # 串口打开按钮 self.Pushbuttom1.clicked.connect(self.port_open) # 串口关闭按钮 self.Pushbuttom3.clicked.connect(self.port_close) # 定时发送数据 self.timer_send = QTimer() self.timer_send.timeout.connect(self.data_send) self.Checkbox7.stateChanged.connect(self.data_send_timer) # 发送数据按钮 self.Pushbuttom6.clicked.connect(self.data_send) # 加载日志 self.Pushbuttom4.clicked.connect(self.savefiles) # 加载日志 self.Pushbuttom5.clicked.connect(self.openfiles) # 跳转链接 self.commandLinkButton1.clicked.connect(self.link) # 清除发送按钮 self.Pushbuttom7.clicked.connect(self.send_data_clear) # 清除接收按钮 self.Pushbuttom8.clicked.connect(self.receive_data_clear)
3.2、串口检测程序
检测电脑上所有串口,实现代码如下所示:
# 串口检测 def port_check(self): # 检测所有存在的串口,将信息存储在字典中 self.Com_Dict = {} port_list = list(serial.tools.list_ports.comports()) self.Combobox1.clear() for port in port_list: self.Com_Dict["%s" % port[0]] = "%s" % port[1] self.Combobox1.addItem(port[0]) # 无串口判断 if len(self.Com_Dict) == 0: self.Combobox1.addItem("无串口")
3.3、 设置及打开串口程序
检测到串口后进行配置,打开串口,并且启动定时器一直接收用户输入,实现代码如下所示:
# 打开串口 def port_open(self): self.ser.port = self.Combobox1.currentText() # 串口号 self.ser.baudrate = int(self.Combobox2.currentText()) # 波特率 flag_data = int(self.Combobox3.currentText()) # 数据位 if flag_data == 5: self.ser.bytesize = serial.FIVEBITS elif flag_data == 6: self.ser.bytesize = serial.SIXBITS elif flag_data == 7: self.ser.bytesize = serial.SEVENBITS else: self.ser.bytesize = serial.EIGHTBITS flag_data = self.Combobox4.currentText() # 校验位 if flag_data == "None": self.ser.parity = serial.PARITY_NONE elif flag_data == "Odd": self.ser.parity = serial.PARITY_ODD else: self.ser.parity = serial.PARITY_EVEN flag_data = int(self.Combobox5.currentText()) # 停止位 if flag_data == 1: self.ser.stopbits = serial.STOPBITS_ONE else: self.ser.stopbits = serial.STOPBITS_TWO flag_data = self.Combobox6.currentText() # 流控 if flag_data == "No Ctrl Flow": self.ser.xonxoff = False #软件流控 self.ser.dsrdtr = False #硬件流控 DTR self.ser.rtscts = False #硬件流控 RTS elif flag_data == "SW Ctrl Flow": self.ser.xonxoff = True #软件流控 else: if self.Checkbox3.isChecked(): self.ser.dsrdtr = True #硬件流控 DTR if self.Checkbox4.isChecked(): self.ser.rtscts = True #硬件流控 RTS try: time.sleep(0.1) self.ser.open() except: QMessageBox.critical(self, "串口异常", "此串口不能被打开!") return None # 串口打开后,切换开关串口按钮使能状态,防止失误操作 if self.ser.isOpen(): self.Pushbuttom1.setEnabled(False) self.Pushbuttom3.setEnabled(True) self.formGroupBox1.setTitle("串口状态(开启)") # 定时器接收数据 self.timer = QTimer() self.timer.timeout.connect(self.data_receive) # 打开串口接收定时器,周期为1ms self.timer.start(1)
3.4、定时发送数据程序
通过定时器,可支持1ms至30s之间数据定时,实现代码如下所示:
# 定时发送数据 def data_send_timer(self): try: if 1<= int(self.Lineedit1.text()) <= 30000: # 定时时间1ms~30s内 if self.Checkbox7.isChecked(): self.timer_send.start(int(self.Lineedit1.text())) self.Lineedit1.setEnabled(False) else: self.timer_send.stop() self.Lineedit1.setEnabled(True) else: QMessageBox.critical(self, '定时发送数据异常', '定时发送数据周期仅可设置在30秒内!') except: QMessageBox.critical(self, '定时发送数据异常', '请设置正确的数值类型!')
3.5、发送数据程序
可以发送ASCII字符和十六进制类型数据,并且可以在数据前显示发送的时间,在数据后进行换行,发送一个字节,TX标志会自动累加,实现代码如下所示:
# 发送数据 def data_send(self): if self.ser.isOpen(): input_s = self.Text2.toPlainText() # 判断是否为非空字符串 if input_s != "": # 时间显示 if self.Checkbox5.isChecked(): self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ") # HEX发送 if self.Checkbox1.isChecked(): input_s = input_s.strip() send_list = [] while input_s != '': try: num = int(input_s[0:2], 16) except ValueError: QMessageBox.critical(self, '串口异常', '请输入规范十六进制数据,以空格分开!') return None input_s = input_s[2:].strip() send_list.append(num) input_s = bytes(send_list) # ASCII发送 else: input_s = (input_s).encode('utf-8') # HEX接收显示 if self.Checkbox2.isChecked(): out_s = '' for i in range(0, len(input_s)): out_s = out_s + '{:02X}'.format(input_s[i]) + ' ' self.Text1.insertPlainText(out_s) # ASCII接收显示 else: self.Text1.insertPlainText(input_s.decode('utf-8')) # 接收换行 if self.Checkbox6.isChecked(): self.Text1.insertPlainText('\r\n') # 获取到Text光标 textCursor = self.Text1.textCursor() # 滚动到底部 textCursor.movePosition(textCursor.End) # 设置光标到Text中去 self.Text1.setTextCursor(textCursor) # 统计发送字符数量 num = self.ser.write(input_s) self.data_num_sended += num self.Lineedit2.setText(str(self.data_num_sended)) else: pass
3.6、接收数据程序
可以接收ASCII字符和十六进制类型数据,并且可以在数据前显示发送的时间,在数据后进行换行,接收一个字节,RX标志会自动累加,实现代码如下所示:
# 接收数据 def data_receive(self): try: num = self.ser.inWaiting() if num > 0: time.sleep(0.1) num = self.ser.inWaiting() #延时,再读一次数据,确保数据完整性 except: QMessageBox.critical(self, '串口异常', '串口接收数据异常,请重新连接设备!') self.port_close() return None if num > 0: data = self.ser.read(num) num = len(data) # 时间显示 if self.Checkbox5.isChecked(): self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ") # HEX显示数据 if self.Checkbox2.checkState(): out_s = '' for i in range(0, len(data)): out_s = out_s + '{:02X}'.format(data[i]) + ' ' self.Text1.insertPlainText(out_s) # ASCII显示数据 else: self.Text1.insertPlainText(data.decode('utf-8')) # 接收换行 if self.Checkbox6.isChecked(): self.Text1.insertPlainText('\r\n') # 获取到text光标 textCursor = self.Text1.textCursor() # 滚动到底部 textCursor.movePosition(textCursor.End) # 设置光标到text中去 self.Text1.setTextCursor(textCursor) # 统计接收字符的数量 self.data_num_received += num self.Lineedit3.setText(str(self.data_num_received)) else: pass
3.7、保存日志程序
将接收框中收发的数据保存到TXT文本中,实现代码如下所示:
# 保存日志 def savefiles(self): dlg = QFileDialog() filenames = dlg.getSaveFileName(None, "保存日志文件", None, "Txt files(*.txt)") try: with open(file = filenames[0], mode='w', encoding='utf-8') as file: file.write(self.Text1.toPlainText()) except: QMessageBox.critical(self, '日志异常', '保存日志文件失败!')
3.8、加载日志程序
加载保存到TXT文本中的数据信息到发送框中,实现代码如下所示:
# 加载日志 def openfiles(self): dlg = QFileDialog() filenames = dlg.getOpenFileName(None, "加载日志文件", None, "Txt files(*.txt)") try: with open(file = filenames[0], mode='r', encoding='utf-8') as file: self.Text2.setPlainText(file.read()) except: QMessageBox.critical(self, '日志异常', '加载日志文件失败!')
3.9、打开博客、公众号程序
点击按钮,打开我的公众号二维码和博客主页,实现代码如下所示:
# 打开博客链接和公众号二维码 def link(self): dialog = QDialog() label_img = QLabel() label_img.setAlignment(Qt.AlignCenter) label_img.setPixmap(QPixmap("./img.jpg")) vbox = QVBoxLayout() vbox.addWidget(label_img) dialog.setLayout(vbox) dialog.setWindowTitle("快扫码关注公众号吧~") dialog.setWindowModality(Qt.ApplicationModal) dialog.exec_() webbrowser.open('https://blog.csdn.net/m0_38106923')
3.10、清除发送和接收数据显示程序
清除发送数据框和接收数据框的内容和计数次数,实现代码如下所示:
# 清除发送数据显示 def send_data_clear(self): self.Text2.setText("") self.data_num_sended = 0 self.Lineedit2.setText(str(self.data_num_sended)) # 清除接收数据显示 def receive_data_clear(self): self.Text1.setText("") self.data_num_received = 0 self.Lineedit3.setText(str(self.data_num_received))
3.11、关闭串口程序
关闭串口,停止定时器,重置组件和标志状态,实现代码如下所示:
# 关闭串口 def port_close(self): try: self.timer.stop() self.timer_send.stop() self.ser.close() except: QMessageBox.critical(self, '串口异常', '关闭串口失败,请重启程序!') return None # 切换开关串口按钮使能状态和定时发送使能状态 self.Pushbuttom1.setEnabled(True) self.Pushbuttom3.setEnabled(False) self.Lineedit1.setEnabled(True) # 发送数据和接收数据数目置零 self.data_num_sended = 0 self.Lineedit2.setText(str(self.data_num_sended)) self.data_num_received = 0 self.Lineedit3.setText(str(self.data_num_received)) self.formGroupBox1.setTitle("串口状态(关闭)")
更多相关内容 -
Python Qt 串口调试助手
2022-04-27 21:45:04Python Qt开发的串口调试助手,包括:COM、波特率、流控、停止位、定时发送等自定义设置,具有保存、读取日志文件等功能。 项目可完美运行,资源中包含可修改的UI文件,开发者可以快速进行二次开发。 -
VB串口调试助手
2017-08-23 17:42:43自己编写实际测试改进的心血之作,有源码,可直接运行,看懂它,你就全明白VB串口调试了 -
XCOM串口调试助手
2017-10-12 16:49:16XCOM串口调试助手,支持高波特率以及协议传输,稳定好用 -
友善串口调试助手
2016-10-25 11:46:30比较好用的调试工具,带激活码,永久激活,界面比较干净 -
labview编写的串口调试助手
2018-05-11 23:06:57labview编写的串口调试助手,含CRC校验。运行事件机制提高效率。 -
RS485/232串口调试助手.zip
2021-08-19 17:47:49RS485/232串口调试助手.zip -
串口调试助手
2018-10-30 20:48:19pc端串口调试工具 测试单片机串口工具 自己用 上传存档 -
MATLAB开发的串口调试助手源代码,matlab串口通信教程,matlab
2021-09-10 23:15:05matlab环境下的串口调试工具,串口通信 -
C#串口调试助手
2019-04-20 20:31:58用C#写的串口调试助手,支持多种功能,经测试能稳定运行 -
友善串口调试助手,非常好用的串口调试工具
2021-03-25 14:24:58友善串口调试助手很好的串口调试助手,友善串口调试助手支持终端窗口和远程访问,能够与串口进行通信,访问、修改串行端口,还能够自动识别、自动搜索串口。友善串口调试助手还可以用ASCII码或十六进制接收或发送... -
经典串口调试助手开发必备
2022-04-01 15:47:46经典串口调试助手开发必备 -
串口工具(虚拟串口+串口调试助手).zip
2018-05-02 15:39:58最近贮备串口程序开发,笔记本没有串口。搜到虚拟串口工具感觉还不错,调试助手找了好几个都不能配合使用,找到这个就分享了。 -
Win10串口调试助手.rar
2019-07-07 12:44:56win10系统串口调试助手,方便实用,推荐给大家学习! -
win10串口调试助手
2020-12-29 09:09:01本资源由自己用qt写的一个简单界面,已打包好,下载后可直接运行。注意波特率为9600,它可以自己识别你接在电脑上的串口,接收发射0-255的整数(8位),方便大家调试串口。 -
串口调试助手[VC源码]
2016-03-24 17:05:26优化了 SerialPort类, 自己写了一个RingBuffer 类, 两个类结合用在串口收发上基本上是无敌了. -
C#开发串口调试助手的详细教程
2022-03-22 09:58:58通过电脑串口(包括USB口)收发数据并且显示的应用软件,一般用于电脑与嵌入式系统的通讯,借助于它来调试串口通讯或者系统的运行状态。也可以用于采集其他系统的数据,用于观察系统的运行情况。 简单的串口助手只能...一、串口助手是什么?
通过电脑串口(包括USB口)收发数据并且显示的应用软件,一般用于电脑与嵌入式系统的通讯,借助于它来调试串口通讯或者系统的运行状态。也可以用于采集其他系统的数据,用于观察系统的运行情况。
简单的串口助手只能用来接收可发送串口数据,但是当你学会了如何开发串口助手,就可以根据通信协议开发上位机控制硬件和查看硬件的状态,先介绍如何开发一个简单的串口助手。
二、开发环境
- Visual Stdio
- C#
开发串口助手会用到Winform的相关知识,想要学习Winform的相关知识可以点击链接学习:http://c.biancheng.net/csharp/winform/
三、开发步骤
1. 串口参数
要连接上串口让并实现串口通信我们首先要搜索并选择需要进行通信的串口号,然后设置好波特率、数据位、停止位和检验位,串口号、波特率、数据位、停止位和检验位相当于打开特定串口的简单的密码,设置好之后就能打开串口进行通信。
名称 作用 常用数值 波特率 串口通信的速率(发送和接收各数据位的间隔时间) 4800
9600
14400
19200
38400
56000
57600
115200
128000
256000数据位 表示一组数据实际包含的数据位数 5
6
7
8停止位 停止位在最后,用以标志一个字符传送的结束,表示数据帧之间的间隔 1
1.5
2
None校验位 用于数据验证 Even
Odd
None数据位概述图
2.UI设计
一个串口助手界面主要由参数设置、接收框、发送框三个部分以及一些控制按钮组成,参数设置使用ComboBox组件实现,接收和发送数据框使用RichTextBox组件实现,按钮使用Button组件实现,还有串口可以使用自带的SerialPort组件。
3.创建工程
(1)点击新建项目->选择Windows窗体应用->点击下一步->填写好项目名称和什么位置->点击创建
(2)实现UI
创建好项目后左边是工具栏,可以直接拖拉组件,里面有我们要用到的Label、ComboBox、RichTextBox、Button组件,可以根据字母排序查找需要的组件。右边是用来设置组件参数,按F4可以出现该框,可以设置组件名称、文件内容、颜色、大小、位置、字体、图标等参数,点击闪电标志里面可以设置绑定事件。
注意UI实现的过程中要设置好组件的Name,下面是我设置的一些Name参数组件 Name ComboBox comboBox_PortNames
comboBox_BaudRate
comboBox_DataBit
comboBox_StopBit
comboBox_ParityRichTextBox richTextBox_Receive
richTextBox_SendButton button_Serach
button_OpenOrClose
button_CLEAR
button_Send
串口波特率、数据位、停止位和校验位参数可以预先设置好,这里给出波特率参数设置,其他参数设置的方法一样
SerialPort组件使用方法
基本实现好的UI(审美不在线),大家可以自行优化
点击启动的运行效果
(3)功能代码实现
代码要实现的功能主要有:
- 1.初始化函数
编写初始化函数时要在Form1.Designer.cs文件的Windows 窗体设计器生成的代码里面添加this.Load += new System.EventHandler(this.Form1_Load);
如下图所示
/**************************************************************************/ #region 初始化窗体 private void Form1_Load(object sender, EventArgs e) //加载界面程序 { try { string[] str = SerialPort.GetPortNames(); //获取连接到电脑的串口号并存进数组 comboBox_PortNames.Items.Clear(); //清除串口号下拉框的内容 comboBox_PortNames.Items.AddRange(str); //将串口号添加到下拉框 if (str.Length > 0) { comboBox_PortNames.SelectedIndex = 0; //设置ComboBox框的初始值 comboBox_BaudRate.SelectedIndex = 7; comboBox_DataBit.SelectedIndex = 3; comboBox_StopBit.SelectedIndex = 1; comboBox_Parity.SelectedIndex = 2; } else { MessageBox.Show("当前无串口连接!"); } } catch { MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!"); } } #endregion /**************************************************************************/
- 2.搜索串口
/**************************************************************************/ #region 搜索串口(与初始化函数一样) private void button_Serach_Click(object sender, EventArgs e) { try { string[] str = SerialPort.GetPortNames(); comboBox_PortNames.Items.Clear(); comboBox_PortNames.Items.AddRange(str); if (str.Length > 0) { comboBox_PortNames.SelectedIndex = 0; comboBox_BaudRate.SelectedIndex = 7; comboBox_DataBit.SelectedIndex = 3; comboBox_StopBit.SelectedIndex = 1; comboBox_Parity.SelectedIndex = 2; } else { MessageBox.Show("当前无串口连接!"); } } catch { MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!"); } } #endregion /**************************************************************************/
- 3.打开/关闭串口
/**************************************************************************/ #region 打开串口 private void button_OpenOrClose_Click(object sender, EventArgs e) { if (!serialPort1.IsOpen) { if (comboBox_PortNames.SelectedItem == null) { MessageBox.Show("请选择正确的串口", "提示"); return; } //设置串口参数 serialPort1.PortName = comboBox_PortNames.Text.ToString(); //serialPort1是serialPort组件的Name serialPort1.BaudRate = Convert.ToInt32(comboBox_BaudRate.SelectedItem.ToString()); serialPort1.DataBits = Convert.ToInt32(comboBox_DataBit.SelectedItem.ToString()); //设置停止位 if (comboBox_StopBit.Text == "One") { serialPort1.StopBits = StopBits.One; } else if (comboBox_StopBit.Text == "Two") { serialPort1.StopBits = StopBits.Two; } else if (comboBox_StopBit.Text == "OnePointFive") { serialPort1.StopBits = StopBits.OnePointFive; } else if (comboBox_StopBit.Text == "None") { serialPort1.StopBits = StopBits.None; } //设置奇偶校验位 if (comboBox_Parity.Text == "Odd") { serialPort1.Parity = Parity.Odd; } else if (comboBox_Parity.Text == "Even") { serialPort1.Parity = Parity.Even; } else if (comboBox_Parity.Text == "None") { serialPort1.Parity = Parity.None; } try { //禁止操作组件 comboBox_PortNames.Enabled = false; comboBox_BaudRate.Enabled = false; comboBox_DataBit.Enabled = false; comboBox_StopBit.Enabled = false; comboBox_Parity.Enabled = false; button_Serach.Enabled = false; serialPort1.Open(); //设置完参数后打开串口 button_OpenOrClose.Text = "Close"; //更改Open按钮文本内容 } catch { MessageBox.Show("串口打开失败!"); } serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceive); //打开串口后绑定数据接收 } else if (button_OpenOrClose.Text == "Close") { try { //允许操作组件 comboBox_PortNames.Enabled = true; comboBox_BaudRate.Enabled = true; comboBox_DataBit.Enabled = true; comboBox_StopBit.Enabled = true; comboBox_Parity.Enabled = true; button_Serach.Enabled = true; serialPort1.DiscardInBuffer(); //清除缓冲区的数据 serialPort1.Close(); button_OpenOrClose.Text = "Open"; //更改Close按钮文本内容 } catch { MessageBox.Show("串口打开失败!"); } } } #endregion /**************************************************************************/
- 4.接收数据
/**************************************************************************/ #region 接收串口数据 /* 开辟缓存区 根据具体协议内容获取一帧数据进行接收中断处理 */ //变量 List<byte> sp_buffer = new List<byte>(4096); //串口缓存区 int sp_buffer_max = 4096; //串口缓存区最大缓存字节数 private void SerialDataReceive(object sender, SerialDataReceivedEventArgs e) { if (serialPort1.IsOpen == false) { serialPort1.Close(); return; } int Byte_len = serialPort1.BytesToRead; //读取缓存的数据长度 byte[] Rc_byte = new byte[Byte_len]; serialPort1.Read(Rc_byte,0,Byte_len); //将缓存数据存储进字节数组里面 if (sp_buffer.Count > sp_buffer_max) //缓存超过字节数 先丢弃前面的字节 sp_buffer.RemoveRange(0,sp_buffer_max); //丢弃前面的字节0到sp_buffer_max sp_buffer.AddRange(Rc_byte); //存入缓存区 byte[] ruffer = new byte[9192]; //用来存放缓冲区的数据流 //对数据流进行筛选,缓冲区每一组数据个数大于4则为我们想要的数据流 if (sp_buffer.Count > 4) { sp_buffer.CopyTo(0,ruffer,0,sp_buffer.Count); Task.Run(()=>printf_data(ruffer, sp_buffer.Count, 1)); //打印数据流 } } #endregion /**************************************************************************/
- 5.打印数据流
/**************************************************************************/ #region 打印数据流 void printf_data(byte[] Frame, int Length, int T_R) //打印串口数据 { Int16 i_len; StringBuilder s = new StringBuilder(); if (T_R == 0) s.Append("发送:"); else s.Append("接收:"); for (i_len = 0; i_len < Length; i_len++) //打印字符串 { s.Append(Frame[i_len].ToString("X2")); s.Append(" "); } s.Append("[" + DateTime.Now.ToString("HH:mm:ss fff") + "]"); s.Append("\r\n"); string str_show = s.ToString(); MethodInvoker mi = new MethodInvoker(() => { if (richTextBox_ReceiveBox.Lines.Count() > 20) richTextBox_ReceiveBox.Clear(); richTextBox_ReceiveBox.AppendText(str_show); }); BeginInvoke(mi); /* textBox_com_data.Focus(); //获取焦点 textBox_com_data.Select(textBox_com_data.TextLength, 0);//光标 textBox_com_data.ScrollToCaret(); //滚动条*/ } #endregion /**************************************************************************/
- 6.发送数据
/**************************************************************************/ #region 发送数据 private void button_Send_Click(object sender, EventArgs e) { if (serialPort1.IsOpen) { string[] sendbuff = richTextBox1.Text.Split(); //分割输入的字符串,判断有多少个字节需要发送 int Buff_Len = sendbuff.Length; byte[] buff = new byte[Buff_Len]; for (int i = 0; i < sendbuff.Length; i++) { buff[i] = byte.Parse(sendbuff[i], System.Globalization.NumberStyles.HexNumber); //格式化字符串为十六进制数值 } try { serialPort1.Write(buff, 0, buff.Length); //写数据 Task.Run(()=>printf_data(buff, Buff_Len, 0)); } catch { MessageBox.Show("发送失败!!"); } } else { MessageBox.Show("串口未打开!"); } } #endregion /**************************************************************************/
- 7.清除接收框
/**************************************************************************/ #region 清除输出框 private void Clear_Click(object sender, EventArgs e) { richTextBox_ReceiveBox.Clear(); //清楚数据接收框数据 } #endregion /**************************************************************************/
功能函数写好后绑定按钮和函数
(4)全部代码整合using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; using System.IO; namespace Serial { public partial class Form1 : Form { public Form1() { InitializeComponent(); } /**************************************************************************/ #region 初始化窗体 private void Form1_Load(object sender, EventArgs e) //加载界面程序 { try { string[] str = SerialPort.GetPortNames(); //获取连接到电脑的串口号并存进数组 comboBox_PortNames.Items.Clear(); //清除串口号下拉框的内容 comboBox_PortNames.Items.AddRange(str); //将串口号添加到下拉框 if (str.Length > 0) { comboBox_PortNames.SelectedIndex = 0; //设置ComboBox框的初始值 comboBox_BaudRate.SelectedIndex = 7; comboBox_DataBit.SelectedIndex = 3; comboBox_StopBit.SelectedIndex = 0; comboBox_Parity.SelectedIndex = 2; } else { MessageBox.Show("当前无串口连接!"); } } catch { MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!"); } } #endregion /**************************************************************************/ /**************************************************************************/ #region 搜索串口(与初始化函数一样) private void button_Serach_Click(object sender, EventArgs e) { try { string[] str = SerialPort.GetPortNames(); comboBox_PortNames.Items.Clear(); comboBox_PortNames.Items.AddRange(str); if (str.Length > 0) { comboBox_PortNames.SelectedIndex = 0; comboBox_BaudRate.SelectedIndex = 7; comboBox_DataBit.SelectedIndex = 3; comboBox_StopBit.SelectedIndex = 0; comboBox_Parity.SelectedIndex = 2; } else { MessageBox.Show("当前无串口连接!"); } } catch { MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!"); } } #endregion /**************************************************************************/ /**************************************************************************/ #region 打开串口 private void button_OpenOrClose_Click(object sender, EventArgs e) { if (!serialPort1.IsOpen) { if (comboBox_PortNames.SelectedItem == null) { MessageBox.Show("请选择正确的串口", "提示"); return; } //设置串口参数 serialPort1.PortName = comboBox_PortNames.Text.ToString(); //serialPort1是serialPort组件的Name serialPort1.BaudRate = Convert.ToInt32(comboBox_BaudRate.SelectedItem.ToString()); serialPort1.DataBits = Convert.ToInt32(comboBox_DataBit.SelectedItem.ToString()); //设置停止位 if (comboBox_StopBit.Text == "One") { serialPort1.StopBits = StopBits.One; } else if (comboBox_StopBit.Text == "Two") { serialPort1.StopBits = StopBits.Two; } else if (comboBox_StopBit.Text == "OnePointFive") { serialPort1.StopBits = StopBits.OnePointFive; } else if (comboBox_StopBit.Text == "None") { serialPort1.StopBits = StopBits.None; } //设置奇偶校验位 if (comboBox_Parity.Text == "Odd") { serialPort1.Parity = Parity.Odd; } else if (comboBox_Parity.Text == "Even") { serialPort1.Parity = Parity.Even; } else if (comboBox_Parity.Text == "None") { serialPort1.Parity = Parity.None; } try { //禁止操作组件 comboBox_PortNames.Enabled = false; comboBox_BaudRate.Enabled = false; comboBox_DataBit.Enabled = false; comboBox_StopBit.Enabled = false; comboBox_Parity.Enabled = false; button_Serach.Enabled = false; serialPort1.Open(); //设置完参数后打开串口 button_OpenOrClose.Text = "Close"; //更改Open按钮文本内容 } catch { MessageBox.Show("串口打开失败!"); } serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceive); //打开串口后绑定数据接收 } else if (button_OpenOrClose.Text == "Close") { try { //允许操作组件 comboBox_PortNames.Enabled = true; comboBox_BaudRate.Enabled = true; comboBox_DataBit.Enabled = true; comboBox_StopBit.Enabled = true; comboBox_Parity.Enabled = true; button_Serach.Enabled = true; serialPort1.DiscardInBuffer(); //清除缓冲区的数据 serialPort1.Close(); button_OpenOrClose.Text = "Open"; //更改Close按钮文本内容 } catch { MessageBox.Show("串口打开失败!"); } } } #endregion /**************************************************************************/ /**************************************************************************/ #region 接收串口数据 /* 开辟缓存区 根据具体协议内容获取一帧数据进行接收中断处理 */ //变量 List<byte> sp_buffer = new List<byte>(4096); //串口缓存区 int sp_buffer_max = 4096; //串口缓存区最大缓存字节数 private void SerialDataReceive(object sender, SerialDataReceivedEventArgs e) { if (serialPort1.IsOpen == false) { serialPort1.Close(); return; } int Byte_len = serialPort1.BytesToRead; //读取缓存的数据长度 byte[] Rc_byte = new byte[Byte_len]; serialPort1.Read(Rc_byte, 0, Byte_len); //将缓存数据存储进字节数组里面 if (sp_buffer.Count > sp_buffer_max) //缓存超过字节数 先丢弃前面的字节 sp_buffer.RemoveRange(0, sp_buffer_max); //丢弃前面的字节0到sp_buffer_max sp_buffer.AddRange(Rc_byte); //存入缓存区 byte[] ruffer = new byte[9192]; //用来存放缓冲区的数据流 //对数据流进行筛选,缓冲区每一组数据个数大于4则为我们想要的数据流 if (sp_buffer.Count > 4) { sp_buffer.CopyTo(0, ruffer, 0, sp_buffer.Count); Task.Run(() => printf_data(ruffer, sp_buffer.Count, 1)); //打印数据流 } } #endregion /**************************************************************************/ /**************************************************************************/ #region 打印数据流 void printf_data(byte[] Frame, int Length, int T_R) //打印串口数据 { Int16 i_len; StringBuilder s = new StringBuilder(); if (T_R == 0) s.Append("发送:"); else s.Append("接收:"); for (i_len = 0; i_len < Length; i_len++) //打印字符串 { s.Append(Frame[i_len].ToString("X2")); s.Append(" "); } s.Append("[" + DateTime.Now.ToString("HH:mm:ss fff") + "]"); s.Append("\r\n"); string str_show = s.ToString(); MethodInvoker mi = new MethodInvoker(() => { if (richTextBox_ReceiveBox.Lines.Count() > 20) richTextBox_ReceiveBox.Clear(); richTextBox_ReceiveBox.AppendText(str_show); }); BeginInvoke(mi); /* textBox_com_data.Focus(); //获取焦点 textBox_com_data.Select(textBox_com_data.TextLength, 0);//光标 textBox_com_data.ScrollToCaret(); //滚动条*/ } #endregion /**************************************************************************/ /**************************************************************************/ #region 发送数据 private void button_Send_Click(object sender, EventArgs e) { if (serialPort1.IsOpen) { string[] sendbuff = richTextBox_Send.Text.Split(); //分割输入的字符串,判断有多少个字节需要发送 int Buff_Len = sendbuff.Length; byte[] buff = new byte[Buff_Len]; for (int i = 0; i < sendbuff.Length; i++) { buff[i] = byte.Parse(sendbuff[i], System.Globalization.NumberStyles.HexNumber); //格式化字符串为十六进制数值 } try { serialPort1.Write(buff, 0, buff.Length); //写数据 Task.Run(() => printf_data(buff, Buff_Len, 0)); } catch { MessageBox.Show("发送失败!!"); } } else { MessageBox.Show("串口未打开!"); } } #endregion /**************************************************************************/ /**************************************************************************/ #region 清除输出框 private void Clear_Click(object sender, EventArgs e) { richTextBox_ReceiveBox.Clear(); //清楚数据接收框数据 } #endregion /**************************************************************************/ } }
(5)实现效果
到这我们就完整地做一个简单的串口助手了,我们可以进行二次开发,添加按钮绑定特定的的指令,每次可以通过点击按钮控制硬件,或者对接收到的数据流进行解析并显示出来,这样就能够作出项目需要的上位机了。最后,这是我第一次写博客,如果文件内容有什么错误的地方或者有什么不足的地方,希望各位大佬能帮忙指点一下。
-
自己用C#做的串口调试助手,完整源码
2018-12-10 17:51:00用C#开发的串口调试助手,代码部分大多数已经注释;测试串口可以通过安装Configure Virtual Serial Port Driver来虚拟串口号测试。 -
STC单片机+DS18B20温度传感器 - 串口调试助手显示.rar
2021-04-22 14:26:38STC单片机+DS18B20温度传感器 - 串口调试助手显示 -
38.利用“29-德飞莱-DHT11 数字温湿度模块”实现温湿度采集并通过 串口调试助手输出。
2020-12-22 16:44:2038.利用“29-德飞莱-DHT11 数字温湿度模块”实现温湿度采集并通过 串口调试助手输出。 -
串口调试助手C++源码(VS 2008)
2018-07-22 13:49:13本项目博客地址:https://blog.csdn.net/wu9797/article/details/81151033 里面有编译好的Debug和Release