bug现象:打开串口时正常,再切换到关闭串按钮口后,按下按钮要等待很久的时间才能恢复到正常的界面,这其中按任何一个按钮都没用。
参考博客:
解决方案:首先我们先来整理一下思路,搞清楚整个的工作流程,串口调试的上位机主要由两部分控制,一个是UI进程一个串口监视进程(优先级别高),UI进程主要是通过消息循环来控制整个的功能实现,在读数据阶段,若果此时要关闭串口,那就很尴尬了,一般的工作流程都是等待数据传送完成之后,执行invoke调用UI线程,更新界面,才能结束监视进程,这就让两个线程都一直卡在Invoke这个地方,所以这个地方就需要用到Application.DoEvents()(消息循环),提前的结束循环,但还是有问题,因为监控进程的优先级别比较高,还是会卡住,所以在程序里面就需要对异常状态进行捕获,具体代码如下:

void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
 {
 if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
 try
 {
 Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。
 int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
 byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
 received_count += n;//增加接收计数
 comm.Read(buf, 0, n);//读取缓冲数据
 builder.Clear();//清除字符串构造器的内容
 //因为要访问ui资源,所以需要使用invoke方式同步ui。
 this.Invoke((EventHandler)(delegate
 {
 //判断是否是显示为16禁止
 if (checkBoxHexView.Checked)
 {
 //依次的拼接出16进制字符串
 foreach (byte b in buf)
 {
 builder.Append(b.ToString(“X2”) + " ");
 }
 }
 else
 {
 //直接按ASCII规则转换成字符串
 builder.Append(Encoding.ASCII.GetString(buf));
 }
 //追加的形式添加到文本框末端,并滚动到最后。
 this.txGet.AppendText(builder.ToString());
 //修改接收计数
 labelGetCount.Text = “Get:” + received_count.ToString();
 }));
 }
 finally
 {
 Listening = false;//我用完了,ui可以关闭串口了。
 }
 }
 private void buttonOpenClose_Click(object sender, EventArgs e)
 {
 //根据当前串口对象,来判断操作
 if (comm.IsOpen)
 {
 Closing = true;
 while (Listening) Application.DoEvents();
 //打开时点击,则关闭串口
 comm.Close();
 Closing = false;
 }
 else
 {
 //关闭时点击,则设置好端口,波特率后打开
 comm.PortName = comboPortName.Text;
 comm.BaudRate = int.Parse(comboBaudrate.Text);
 try
 {
 comm.Open();
 }
 catch(Exception ex)
 {
 //捕获到异常信息,创建一个新的comm对象,之前的不能用了。
 comm = new SerialPort();
 //现实异常信息给客户。
 MessageBox.Show(ex.Message);
 }
 }
 //设置按钮的状态
 buttonOpenClose.Text = comm.IsOpen ? “Close” : “Open”;
 buttonSend.Enabled = comm.IsOpen;
 }