1. 程式人生 > >串列埠基本概念和C#串列埠程式設計例子

串列埠基本概念和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、原始碼下載。見原文