1. 程式人生 > >Winform 串口通訊之地磅

Winform 串口通訊之地磅

端口 cto clear tar ons 是否 edev convert nth

繼上次的讀卡之後,要做一個地磅的讀取。

下面是我在讀卡Demo上改的讀取地磅的。

地磅是一直向串口發送數據的,所以需要截取數據來一直判斷數據是否合法,然後計算出結果。

其中遇到了一個小問題,文末有介紹。

本人初學菜鳥,大牛們有意見歡迎評論。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using
System.Text; 8 using System.Windows.Forms; 9 using System.IO.Ports; 10 using System.IO; 11 using System.Threading; 12 13 namespace WindowsFormsApplicationcs 14 { 15 public partial class FormMain : Form 16 { 17 //聲明端口對象 18 SerialPort myport = null; 19 //
處理數據的數據數組 20 byte[] buf = new byte[50]; 21 //聲明委托類型 22 public delegate void Displaydelegate(byte[] buf); 23 //委托變量 24 public Displaydelegate disp_delegate; 25 26 public FormMain() 27 { 28 InitializeComponent(); 29 //
安全線程外更新空間 30 //Form.CheckForIllegalCrossThreadCalls = false; 31 } 32 33 //窗口加載 34 private void FormMain_Load(object sender, EventArgs e) 35 { 36 Form.CheckForIllegalCrossThreadCalls = false; 37 txtPort.Text = "COM3"; 38 myport = new SerialPort(); 39 disp_delegate = new Displaydelegate(DispUI); 40 } 41 42 //打開串口按鈕 43 private void button1_Click(object sender, EventArgs e) 44 { 45 try 46 { 47 48 //設置串口端口 49 myport.PortName = txtPort.Text.ToString(); 50 //設置比特率 51 myport.BaudRate = Convert.ToInt32(cmbBaud.Text); 52 //設置數據位 53 myport.DataBits = Convert.ToInt32(cmbBits.Text); 54 //設置停止位 55 switch (cmbStopBits.SelectedIndex) 56 { 57 case 0: myport.StopBits = StopBits.None; break; 58 case 1: myport.StopBits = StopBits.One; break; 59 case 2: myport.StopBits = StopBits.OnePointFive; break; 60 case 3: myport.StopBits = StopBits.Two; break; 61 } 62 63 //設置奇偶校驗位 64 switch (cmbParity.SelectedIndex) 65 { 66 case 0: myport.Parity = Parity.Even; break; 67 case 1: myport.Parity = Parity.Mark; break; 68 case 2: myport.Parity = Parity.None; break; 69 case 3: myport.Parity = Parity.Odd; break; 70 case 4: myport.Parity = Parity.Space; break; 71 } 72 73 //緩沖區只接受一個字符 74 myport.ReceivedBytesThreshold = 1; 75 //接收事件添加委托 76 myport.DataReceived += new SerialDataReceivedEventHandler(this.myport_DataReceived); 77 //打開串口 78 myport.Open(); 79 if (myport.IsOpen) 80 { 81 MessageBox.Show("端口已打開"); 82 this.tstldqzt.Text = "當前狀態:端口已打開"; 83 } 84 else 85 { 86 MessageBox.Show("端口未能打開!"); 87 } 88 } 89 catch (Exception ex) 90 { 91 MessageBox.Show("端口打開出現錯誤!\n" + ex.Message.ToString()); 92 } 93 } 94 95 //委托方法 96 //接收數據 97 private void myport_DataReceived(object sender, SerialDataReceivedEventArgs e) 98 { 99 Thread.Sleep(100); 100 if (myport.BytesToRead > 0)//如果緩沖區內有數據 101 { 102 myport.Read(buf, 0, 1);//從緩沖區讀取數據到buf暫存數組, 103 } 104 105 if (buf[0] == 0x02)//如果開頭等於2,則表明是信息開始 0x02 106 { 107 try 108 { 109 while (myport.BytesToRead == 9); 110 myport.Read(buf, 0, 9);//從緩沖區讀取一條正確數據到buf暫存數組 111 string s = string.Empty; 112 113 for (int i = 0; i < 9; i++) 114 { 115 s += (char)buf[i]; 116 } 117 118 StringBuilder b = new StringBuilder(""); 119 120 if (s.Substring(0, 1) == "-") 121 b.Append("-"); 122 123 int strint = Convert.ToInt32(s.Substring(1,7)); 124 int dianint = Convert.ToInt32(s.Substring(8,1)); 125 126 switch (dianint) 127 { 128 case 1: strint = strint / 10; break; 129 case 2: strint = strint / 100; break; 130 case 3: strint = strint / 1000; break; 131 case 4: strint = strint / 10000; break; 132 } 133 b.Append(strint); 134 txtReceive.Text += "開始" + b + "結束\r\n"; 135 136 //this.Invoke(disp_delegate, buf); 137 } 138 finally 139 { 140 myport.DiscardInBuffer();//清空緩沖區 141 } 142 } 143 } 144 145 //更新ui方法 146 public void DispUI(byte[] buf) 147 { 148 149 } 150 151 152 //關閉方法 153 private void button2_Click(object sender, EventArgs e) 154 { 155 myport.Close(); 156 if (!myport.IsOpen) 157 { 158 this.tstldqzt.Text = "當前狀態:端口已關閉"; 159 MessageBox.Show("端口已關閉"); 160 } 161 } 162 163 //清屏按鈕 164 private void button3_Click(object sender, EventArgs e) 165 { 166 this.txtReceive.Clear(); 167 } 168 169 //菜單欄關於 170 private void tsmiabout_Click(object sender, EventArgs e) 171 { 172 frmAbout frmabout = new frmAbout(); 173 frmabout.ShowDialog(); 174 } 175 176 //菜單欄保存結果 177 private void tsmisave_Click(object sender, EventArgs e) 178 { 179 if (this.txtReceive.Text == "") 180 { MessageBox.Show("當前結果為空,請先測試"); } 181 string path = Directory.GetCurrentDirectory() + "\\端口測試結果.txt"; 182 File.WriteAllText(path, this.txtReceive.Text.ToString(), Encoding.ASCII); 183 } 184 185 } 186 }

這裏其實有個問題,就是一個窗口一般會涉及到多個串口設備的通訊,

公司目前的需求也不例外,可以看到我使用了一個thread.sleep,

這樣雖然當時解決了問題,但是當一個窗口有多個串口通訊更新ui的時候應該會出現問題,

但因為當時手頭沒有設備也沒做進一步的測試,。

因為不加這句話就會無法實時更新ui,當時打了一個多小時的短點記了好多數據,

才確定了不是數據處理那部分的問題,思考一下原因應該是while把線程堵死了,一直在做運算。

但是使用invoke不是新開線程委托嗎?為什麽也是更新不了ui。

百度了發現如下解釋

invoke是在擁有此控件的基礎窗口句柄的線程上指定指定的委托

begininvoke是在創建此控件的基礎窗口句柄的線程上異步執行指定的委托

使用begininvoke應該就可以不幹擾其他的串口通訊更新ui了

Winform 串口通訊之地磅