串列埠基本概念和C#串列埠程式設計例子
相信很多網友在學習C#程式設計時,遇到串列埠通訊的一系列問題。目前我也在學習C#串列埠程式設計類的基礎知識,在網上也找了一些資料,但都存在一些問題,現在他們基礎上再進行一定的修改,且更詳細的表達如何實現串列埠程式設計,實現串列埠的傳送與接收。本文目的在於:
1)總結C# 程式設計串列埠的屬性定義、成員變數以及方法等問題;
2)掌握串列埠的傳送與接收,利用虛擬串列埠來進行通訊,體驗串列埠通訊;
實施步驟如下:
1、程式主介面如下:
2、啟動VS2005程式設計工具,新建一個專案,並自擬定專案名稱和存放路徑。
3、按主介面樣式設計好各個控制元件。
4、程式碼實施(簡單介紹——具體實驗請參見原始碼,下文可下載):
(1)在Form1.cs程式標頭檔案處新增程式碼:
using System.Threading;//用於啟用執行緒類;
using System.IO.Ports;//用於呼叫串列埠類函式
(2)新增成員變數
串列埠的基本引數有:串列埠號,波特率,資料位,停止位等,如圖所示:
public string iPort = "com1"; //預設為串列埠1
public int iRate = 9600; //波特率1200,2400,4800,9600
public byte bSize = 8; //8 bits
public int iTimeout = 1000; //延時時長
public SerialPort serialPort1 = new SerialPort();//定義一個串列埠類的串列埠變數
string serialReadString; //用於串列埠接收資料
public bool IsCirlce;//判斷是否選用迴圈傳送資料
public Thread Thd_Send; //開闢一個專用於傳送資料的執行緒
public byte[] recb; //用於存放接收資料的陣列
(3)程式開啟,串列埠初始化
private void Form1_Load(object sender, EventArgs e)
{
Microsoft.VisualBasic.Devices.Computer cmbCOM = new Microsoft.VisualBasic.Devices.Computer();
foreach (string s in cmbCOM.Ports.SerialPortNames)
{
cmb_port.Items.Add(s);
}
IsCirlce = false;
}
(4)開啟/關閉串列埠按鈕程式碼
//開啟/關閉串列埠
private void button5_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
btnOpenCloseCOM.Text = "開啟串列埠";
msg.AppendText("串列埠被關閉……\r\n");
}
else
{
Parity myParity = Parity.None; //奇偶校驗物件
StopBits MyStopBits = StopBits.One; //停止位物件
serialPort1.PortName = cmb_port.Text;
serialPort1.BaudRate = iRate; //波特率
serialPort1.DataBits = bSize; //資料位的長度
serialPort1.Parity = myParity; //奇偶校驗位
serialPort1.StopBits = MyStopBits; //停止位
serialPort1.ReadTimeout = iTimeout; //讀取超時【從有資料開始,讀取的時間超過這個設定的值,則引發異常】
serialPort1.Open();
btnOpenCloseCOM.Text = "關閉串列埠";
msg.AppendText("串列埠成功開啟……\r\n");
}
}
//開串列埠
public bool OpenCom()
{
try
{
if (serialPort1.IsOpen)
{
//mycom1.Close();
//mycom1.Open(); //開啟串列埠
msg.AppendText("串列埠已開啟\r\n");
}
else
{
serialPort1.Open();//開啟串列埠
}
return true;
}
catch (Exception e)
{
MessageBox.Show("錯誤:" + e.Message);
return false;
}
}
(5)傳送按鈕(主程式)
//傳送按鈕
private void button1_Click(object sender, EventArgs e)
{
if (t_send.Text == "")
{ MessageBox.Show("傳送資料為空!"); return; }
Thd_Send = new Thread(new ThreadStart(SendData));
Thd_Send.Start();
}
//傳送資料函式
public void SendData() //主要看SubSendData函式,這個函式本身不用太過於關注,無法是控制元件的非同步呼叫修改控制元件的屬性
{
if (System.Convert.ToBoolean(btnSend.Text == "傳送"))
{
if (IsCirlce)
{
btnSend.Invoke(new MethodInvoker(delegate { btnSend.Text="停止"; }));
//MethodInvoker是無引數的系統定義好的簡單方法委託,這裡使用了匿名方法,此句執行結果是修改按鈕的文字為“停止”
while (true)
{
if (IsCirlce && serialPort1.IsOpen && (System.Convert.ToBoolean(btnSend.Text =="停止")))
{
SubSendData();
}
else
{ goto L1; }
}
}
else
{
SubSendData();
}
}
else
{
btnSend.Invoke(new MethodInvoker(delegate { btnSend.Text = "傳送"; }));
}
L1:
btnSend.Invoke(new MethodInvoker(delegate { btnSend.Text = "傳送"; }));
}
//傳送資料子函式,實際上是在新開的執行緒中執行這個函式
public void SubSendData()
{
//byte[] ZhengHeHouData = new byte[mycom1.ReadBufferSize];
//定義一個無空格二位16進位制排列的陣列,這樣可控制使用者輸入
byte[] ZhengHeHouData = NoSpace_2Hex_SendData_ZhengHe(); //這裡是整合後的傳送的陣列,每二位組成一個16進位制的數排列【sting轉換為Byte型別】
int SendNumB = 0;
try
{
serialPort1.WriteLine(Dis_Package(ZhengHeHouData)); //Dis_Package函式是Byte型別轉換為string型別【通過ASC2碼把字串自動轉為位元組陣列傳送】
SendNumB = serialPort1.BytesToWrite;
msg.Invoke(new MethodInvoker(delegate { msg.AppendText("\r\n傳送資料!(" + serialPort1.BytesToWrite + "):" + Dis_Package(ZhengHeHouData)); }));
Thread.Sleep(System.Convert.ToInt32(txtTimeGas.Text));
}
//mycom1.Read(ZhengHeHouData,1,1);
//recb = mycom1.BytesToRead;
//msg.AppendText("\r\n接收到資料包:" + Dis_Package(recb));
//mycom1.Read(ZhengHeHouData, 0, ZhengHeHouData.Length);
//if(recb.Length!=0)
//msg.AppendText("\r\n接收到資料包:" + Dis_Package(recb));
catch
{
//msg.AppendText("\r\n傳送失敗!");
msg.Invoke(new MethodInvoker(delegate { msg.AppendText("\r\n傳送失敗!"); }));
return;
}
}
//去掉髮送陣列中的空格
public string Delspace(string txt_SendData)
{
string Infact_SendData = "";
for (int i = 0; i < txt_SendData.Length; i++) //txt_SendData.Length為傳送框內的資料
{
if (txt_SendData[i] != ' ')
Infact_SendData += txt_SendData[i];
}
return Infact_SendData;
}
//提取資料包--陣列函式,返回整合後的資料,無空格二位16進位制排列的陣列
public byte[] NoSpace_2Hex_SendData_ZhengHe()
{
string NoSpace_SendData = Delspace(t_send.Text); //去掉所有空格,整合資料
byte[] SendData = new byte[50];
int j = 0;
for (int i = 0; i < NoSpace_SendData.Length; i = i + 2, j++) //將無空格傳送的資料每二位組成一個數,存放在新的陣列SendData中
SendData[j] = Convert.ToByte(NoSpace_SendData.Substring(i, 2), 16);
byte[] Last_SendData = new byte[j]; //Last_SendData最終返回的傳送資料
Array.Copy(SendData, Last_SendData, j); //複製整合後的資料,放入最終返回的數組裡,以便呼叫
return Last_SendData; //最終返回的傳送資料
}
//顯示包資訊,以每二位加一個空格顯示資料
public string Dis_Package(byte[] reb)
{
string temp = "";
foreach (byte b in reb)
temp += b.ToString("X2") + " "; //以每二位加一個空格顯示資料
return temp;
}
(6) 清空列表顯示
private void button3_Click(object sender, EventArgs e)
{
t_send.Text = string.Empty; //清空傳送端
msg.Text = string.Empty; //清空資訊列表框
}
(7)應用設定按鈕的程式碼
//應用設定
private void button2_Click(object sender, EventArgs e) //串列埠初始化,對應圖中“應用設定”按鈕
{
Parity myParity = Parity.None;
StopBits MyStopBits = StopBits.One;
if (serialPort1.IsOpen)
{
//msg.AppendText("串列埠處於開啟狀態,若要重新更換埠,請先關閉!\r\n");
serialPort1.Close();
}
if (cmb_port.Text == "")
{
msg.AppendText("串列埠不能為空,請選擇串列埠!\r\n");
}
else
{
serialPort1.PortName = Convert.ToString(cmb_port.Text); //1,2,3,4
serialPort1.BaudRate = Convert.ToInt16(t_rate.Text); //1200,2400,4800,9600
serialPort1.DataBits = Convert.ToByte(t_bytesize.Text, 10); //8 bits
serialPort1.Parity = myParity; // 0-4=no,odd,even,mark,space
serialPort1.StopBits = MyStopBits;
//iTimeout=3;
if (this.OpenCom())
msg.AppendText("串列埠初始化成功……\r\n");
else
msg.AppendText("串列埠初始化失敗!\r\n");
}
}
(8) 程式關閉,結束串列埠
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
serialPort1.Close();
}
(9) 用於顯示接收資料,這個事件處理程式會自動開一個執行緒然後執行
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
serialReadString = "";
serialReadString += serialPort1.ReadExisting(); //讀取所有資料,返回字串【位元組陣列通過ASC2碼翻譯成字串】
msg.Invoke(new MethodInvoker(delegate { msg.AppendText("\r\n接收資料:" + serialReadString); }));
}
(10)控制輸入
//傳送文字框內限制輸入,須偶數位
private void t_send_TextChanged(object sender, EventArgs e)
{
btnSend.Enabled = false;
string SendDataLength = Delspace(t_send.Text); //去掉所有空格,整合資料
if (SendDataLength.Length % 2 != 0)
{
t_send.Focus();
}
else
{
btnSend.Enabled = true;
}
}
(11)複選框程式(是否啟用無限迴圈)
private void chkCircle_CheckedChanged(object sender, EventArgs e)
{
if (IsCirlce)
{
IsCirlce = false;
}
else
{
IsCirlce = true;
}
}
5、虛擬串列埠配置(可下載此軟體,按照下載後的軟體進行配置說明即可使用)
6、開啟UartAssist.exe軟體,執行如下所示:
7、在配置好VSPM後,虛擬串列埠有3、4、5、6共四個串列埠,啟動VSPM後,再執行串列埠通訊選擇串列埠4,此時串列埠通訊程式與上面的 UartAssist.exe軟體串列埠3進行了互聯,如下圖所示。選擇串列埠4後,點選[應用設定]按鈕,此時文字框顯示:串列埠初始化成功....
8、傳送測試,在設定資料包文字框內輸入:12345678
9、接收資料,如圖:
10、原始碼下載。見原文