上位機開發常用到串口通信來控制設備,串口通信的主要參數:COM口,波特率(9600),停止位(One),數據位(8),校驗位(None),括號中的是常用值,具體意思我也不太懂,會用能實現功能就行哈哈;
開發工具:VS2012; 開發前需要添加以下服務引用:
....... using System.IO.Ports;
窗體搭建,因為沒有串口設備供調試 ,所以我用虛擬串口即兩個串口互相連接來實現通信,窗體分為上下兩部分,對應兩個串口區,上圖為虛擬串口設置,下圖為Winform樣式:
首先創建一個baseCom類:
1.聲明變量,構造函數:

public delegate void delegateOnShowMsg(comType type,string msg); public delegate void delegateOnOpenCom(comType type, bool onOff); public event delegateOnShowMsg OnShow; public event delegateOnOpenCom OnOpen; comType type; string baudRate = string.Empty; string parity = string.Empty; string stopBits = string.Empty; string dataBits = string.Empty; string portName = string.Empty; public System.IO.Ports.SerialPort comPort = new System.IO.Ports.SerialPort(); public baseCom(string portName, string baudRate, string stopBits, string dataBits, string parity,comType type) { this.portName = portName; this.baudRate = baudRate; this.stopBits = stopBits; this.dataBits = dataBits; this.parity = parity; this.type = type; }
2.打開串口和關閉串口函數:

public void OpenPort() { try { if (comPort.IsOpen) comPort.Close(); comPort.BaudRate = int.Parse(baudRate); comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), stopBits); comPort.DataBits = int.Parse(dataBits); comPort.Parity = (Parity)Enum.Parse(typeof(Parity), parity); comPort.PortName = portName; comPort.Handshake = Handshake.None; comPort.Open(); if (comPort.IsOpen) { showOnoff(true); comPort.Handshake = Handshake.None; comPort.DataReceived += comPort_DataReceived; } showMsg(portName + " Open Success"); } catch (Exception ex) { showMsg("Unable to Open " + portName); showMsg(ex.Message); showOnoff(false); } } public void ClosePort() { if (comPort.IsOpen) { comPort.Close(); comPort.Dispose(); showOnoff(false); showMsg(portName + " Close Success"); } }
3.接受數據和發送數據函數:

public void comPort_DataReceived(object sender,SerialDataReceivedEventArgs e) { try { int n = comPort.BytesToRead; if (n == 0) return; byte[] buffer = new byte[n]; comPort.Read(buffer, 0, n); string rcv = Encoding.Default.GetString(buffer, 0, buffer.Length); showMsg("RECV:" + rcv); } catch (Exception ex) { ClosePort(); showMsg("Com Closed:" + ex.Message); } } public void comPort_SendData(string msg) { if (msg == "") { showMsg("CAN Not EMPTY"); return; } if (comPort == null) { showMsg("First Open Port"); return; } if (!comPort.IsOpen) { showMsg("COM Not Open"); return; } byte[] data = Encoding.Default.GetBytes(msg); comPort.Write(data, 0, data.Length); showMsg("SEND:" + msg); }
4.顯示信息,顯示狀態函數:

public void showMsg(string msg) { if (OnShow != null) OnShow(type, msg); } public void showOnoff(bool flag) { if (OnOpen != null) OnOpen(type, flag); } public enum comType { _up, _down }
OK,baseCOM類已定義完成,現在編寫窗體各控件的功能函數:
1.初始化控件,主要是下拉菜單的Item的添加,初始值,初始狀態:

public string[] baudRates = { "2400", "4800", "9600", "19200", "39400", "43000", "56000" }; public string[] paritys = { "None", "ODD", "Even" }; public string[] dataBits = { "5", "6", "7", "8" }; public string[] stopBits = { "None", "One", "Two", "OnePointFive" } ; public void InitControls() { comboBox_com.Items.Clear(); comboBox_baudRate.Items.Clear(); comboBox_dataBits.Items.Clear(); comboBox_parity.Items.Clear(); comboBox_StopBit.Items.Clear(); comboBox_com2.Items.Clear(); foreach (var v in baudRates) comboBox_baudRate.Items.Add(v); foreach (var v in stopBits) comboBox_StopBit.Items.Add(v); foreach (var v in paritys) comboBox_parity.Items.Add(v); foreach (var v in dataBits) comboBox_dataBits.Items.Add(v); foreach (var v in System.IO.Ports.SerialPort.GetPortNames()) { comboBox_com.Items.Add(v); comboBox_com2.Items.Add(v); } comboBox_com.SelectedIndex = 0; comboBox_baudRate.SelectedIndex = 2; comboBox_dataBits.SelectedIndex = 3; comboBox_parity.SelectedIndex = 0; comboBox_StopBit.SelectedIndex = 1; comboBox_com2.SelectedIndex = 0; }
2.聲明兩個COM類,comUp和comDown:
public delegate void delegateOnOff(comType type,bool onoff);//定義兩個委托 public delegate void delegateShow(comType type,string msg);//為了防止報錯“從不是創建控件的線程控制它” baseCom comUp; // 定義上串口COM baseCom comDown; //定義下串口COM Image imgOn, imgOff; //指示燈 Thread th; //線程用來實現自動發送
3.編寫打開(關閉)串口按鈕點擊事件(打開comUp和打開comDown代碼一樣,只貼出comUp):

private void button_OpenCom_Click(object sender, EventArgs e) { string cmd = ((Button)sender).Text.Split(' ')[0]; if (comUp != null) comUp.ClosePort(); if (cmd == "Close") return; string s1 = comboBox_com.SelectedItem.ToString(); string s2 = comboBox_baudRate.SelectedItem.ToString(); string s3 = comboBox_StopBit.SelectedItem.ToString(); string s4 = comboBox_dataBits.SelectedItem.ToString(); string s5 = comboBox_parity.SelectedItem.ToString(); comUp = new baseCom(s1, s2, s3, s4, s5,comType._up); comUp.OnOpen += SignalState; comUp.OnShow += ShowMsg; comUp.OpenPort(); }
4.編寫發送數據按鈕點擊事件:
private void button_Send_Click(object sender, EventArgs e) { if (comUp != null) comUp.comPort_SendData(textBox_ComSend.Text); }
5.編寫數據接受發送顯示到文本框及狀態指示燈變化函數:

public void SignalState(comType type,bool onoff) { if (this.InvokeRequired) { delegateOnOff d = new delegateOnOff(SignalState); this.Invoke(d,new object[]{type,onoff}); } else { if (type == comType._up) { pictureBox_ComSignal.Image = onoff ? imgOn : imgOff; button_OpenCom.Text = onoff ? "Close COM" : "Open COM"; } else { pictureBox_Com2.Image = onoff ? imgOn : imgOff; button_OpenCom2.Text = onoff ? "Close COM" : "Open COM"; } } } public void ShowMsg(comType type, string msg) { if (this.InvokeRequired) { delegateShow d = new delegateShow(ShowMsg); this.Invoke(d, new object[] { type, msg }); } else { string date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\r\n"; if (type == comType._up) { textBox_serialPort.Text += (date + msg + "\r\n"); } else { textBox_serialPort2.Text += (date + msg + "\r\n"); } } }
6.Monitor函數,即線程函數,用來實現數據自動發送(沒有進行准確定時,大概設了個間隔):

public void Monitor() { double i =0; while (i++<10000000000) { if (i == 1000000000) { i = 0; if (checkBox_AutoSend.Checked) { if (comUp != null) comUp.comPort_SendData(textBox_ComSend.Text); } if (checkBox_AutoSend2.Checked) { if (comDown != null) comDown.comPort_SendData(textBox_comSend2.Text); } } } }
至此,串口通信功能已基本實現,可在此框架上進行實際應用開發,編碼新手,歡迎大家批評指正!看下效果圖(COM1和COM11虛擬連接):