上位機開發常用到序列埠通訊來控制裝置,序列埠通訊的主要引數:COM口,波特率(9600),停止位(One),資料位(8),校驗位(None),括弧中的是常用值,具體意思我也不太懂,會用能實現功能就行哈哈;
開發工具:VS2012; 開發前需要新增以下服務引用:
.......using System.IO.Ports;
窗體建置,因為沒有序列埠裝置供除錯 ,所以我用虛擬序列埠即兩個序列埠互相連接來實現通訊,窗體分為上下兩部分,對應兩個序列埠區,上圖為虛擬序列埠設定,下圖為Winform樣式:

首先建立一個baseCom類:
1.宣告變數,建構函式:


public delegate void delegateOnShowMsg(comType type,stringmsg);public delegate void delegateOnOpenCom(comType type, boolonOff);public eventdelegateOnShowMsg OnShow;public eventdelegateOnOpenCom 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 = newSystem.IO.Ports.SerialPort();public baseCom(string portName, string baudRate, string stopBits, string dataBits, stringparity,comType type)
{this.portName =portName;this.baudRate =baudRate;this.stopBits =stopBits;this.dataBits =dataBits;this.parity =parity;this.type =type;
}
View Code
2.開啟序列埠和關閉序列埠函式:


public voidOpenPort()
{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 voidClosePort()
{if(comPort.IsOpen)
{
comPort.Close();
comPort.Dispose();
showOnoff(false);
showMsg(portName+ "Close Success");
}
}
View Code
3.接受資料和發送資料函式:


public void comPort_DataReceived(objectsender,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(stringmsg)
{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);
}
View Code
4.顯示訊息,顯示狀態函式:


public void showMsg(stringmsg)
{if (OnShow != null)
OnShow(type, msg);
}public void showOnoff(boolflag)
{if (OnOpen != null)
OnOpen(type, flag);
}public enumcomType
{
_up,
_down
}
View Code
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 voidInitControls()
{
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 inbaudRates)
comboBox_baudRate.Items.Add(v);foreach (var v instopBits)
comboBox_StopBit.Items.Add(v);foreach (var v inparitys)
comboBox_parity.Items.Add(v);foreach (var v indataBits)
comboBox_dataBits.Items.Add(v);foreach (var v inSystem.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;
}
View Code
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(objectsender, 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= newbaseCom(s1, s2, s3, s4, s5,comType._up);
comUp.OnOpen+=SignalState;
comUp.OnShow+=ShowMsg;
comUp.OpenPort();
}
View Code
4.撰寫發送資料按鈕點選事件:
private void button_Send_Click(objectsender, EventArgs e)
{if (comUp != null)
comUp.comPort_SendData(textBox_ComSend.Text);
}
5.撰寫資料接受發送顯示到文字框及狀態指示燈變化函式:


public void SignalState(comType type,boolonoff)
{if (this.InvokeRequired)
{
delegateOnOff d= newdelegateOnOff(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, stringmsg)
{if (this.InvokeRequired)
{
delegateShow d= newdelegateShow(ShowMsg);this.Invoke(d, new object[] { type, msg });
}else{string date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "
";if (type ==comType._up)
{
textBox_serialPort.Text+= (date + msg + "
");
}else{
textBox_serialPort2.Text+= (date + msg + "
");
}
}
}
View Code
6.Monitor函式,即執行緒函式,用來實現資料自動發送(沒有進行準確定時,大概設了個間隔):


public voidMonitor()
{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);
}
}
}
}
View Code
至此,序列埠通訊功能已基本實現,可在此框架上進行實際應用開發,編碼新手,歡迎大家批評指正!看下效果圖(COM1和COM11虛擬連接):
