作技术的通病,什么都想学,什么都想亲手作一遍。否则总感受内心不踏实。git
考研期间,利用晚上一点时间,照葫芦画瓢,练习使用c#快速开发一个简单的串口小助手。github
这种先后端分离的设计方法,大大提升了开发速度,比Python的wxPython写软件方便不少。编程
可是使用c#写软件在软件群里问问题的时候,却被人家用qt的嘲笑。(悲伤脸)c#
好吧,无论怎样,亲手实践一下总不会错的。简单介绍一下吧。界面设计:后端
首先注册一个接收事件,至关于单片机中的串口中断函数。数组
接下来为了完成接收字节的计数,须要串口按照字节接收,并区分HEX和ASCII接收形式。安全
下面是接收函数的实现,其中包括可选择显示接收时间:多线程
//串口接受事件处理 private void SerialPort1_DataReceieved(object sender, SerialDataReceivedEventArgs e) { //方法2:按字节读取 int num = serialPort1.BytesToRead; //获取缓冲区字节数 byte[] received_buf = new byte[num]; receieve_count += num; serialPort1.Read(received_buf, 0, num); //将缓冲区数据读取到received_buf sb.Clear(); //防止出错,先清空字符串构造器 if(radioButton2.Checked) //以HEX形式接收 { foreach(byte b in received_buf) { sb.Append(b.ToString("X2") + " "); //byte转化为2位16进制文本进行显示,中间用空格隔开 } } else //默认ascii形式接收 { sb.Append(Encoding.ASCII.GetString(received_buf));//将接收数组解码为ascii数组 } //显示到接收文本框内 try { Invoke((EventHandler)(delegate { if(checkBox1.Checked) { //显示时间 current_time = System.DateTime.Now; textBox_R.AppendText(current_time.ToString("HH:mm:ss") + " " + sb.ToString()); } else { textBox_R.AppendText(sb.ToString()); } if (checkBox2.Checked) { //接收自动换行 textBox_R.AppendText(Environment.NewLine); } //更新状态栏 label9.Text = "Rx:" + receieve_count.ToString() + "Bytes"; })); } catch (Exception ex) { //响铃并显示异常信息 System.Media.SystemSounds.Beep.Play(); MessageBox.Show(ex.Message); } }
还有一个重要的问题就是如何解决接收过程当中实时显示接收的字符串,而不是等接收完毕后在显示的问题。前后端分离
由于在当前工做线程中直接修改文本框的话会出现错误。函数
在多线程编程中,咱们常常要在工做线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的作法,Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使得多线程中安全的更新界面显示。
正确的作法是将工做线程中涉及更新界面的代码封装为一个方法,经过 Invoke 或者 BeginInvoke 去调用,二者的区别就是一个致使工做线程等待,而另一个则不会。
而所谓的“一面响应操做,一面添加节点”永远只能是相对的,使 UI 线程的负担不至于太大而已,由于界面的正确更新始终要经过 UI 线程去作,咱们要作的事情是在工做线程中包揽大部分的运算,而将对纯粹的界面更新放到 UI 线程中去作,这样也就达到了减轻 UI 线程负担的目的了。
//自动定时发送 private void checkBox3_CheckedChanged(object sender, EventArgs e) { if(checkBox3.Checked) { //选择自动发送 numericUpDown1.Enabled = false; timer1.Interval = (int)numericUpDown1.Value; //定时器赋值,单位:毫秒 timer1.Start(); label7.Text = "串口已打开" + "自动发送中..."; }
和使用单片机时差很少,这里至关于设置了一个定时器,只不过默认定时单位是1ms,因此,按照单片机编程的思想,设置了定时器确定还须要定时器中断函数,所以还须要注册一个定时器事件:
//定时时间到 private void timer1_tick(object sender, EventArgs e) { button2_Click(button2, new EventArgs());//调用发送按钮的回调函数 }
完整工程: