作技術的通病,什麼都想學,什麼都想親手作一遍。否則總感受內心不踏實。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());//調用發送按鈕的回調函數 }
完整工程: