1. 程式人生 > >C#串列埠通訊助手

C#串列埠通訊助手

  簡介:

  使用C#,開發平臺VS2010,功能是串列埠通訊。功能很簡單,僅供大家學習,效果如圖:


1.使用控制元件

控制元件型別 命名 用途 說明
ComboBox cbSerival 串列埠
ComboBox cbBuadRate 波特率
ComboBox cbDataBits 資料位
ComboBox cbStop 停止位
ComboBox cbParity 校驗位
Button btnOpen 開啟
Button btnClear 清除
Button btnSend 傳送
RadioButton rbRecHEX 接收格式:HEX
RadioButton rbRecASCII 接收格式:ASCII
RadioButton rbSendHEX 傳送格式:HEX
RadioButton rbSendASCII 傳送格式:ACSII
CheckBox cbRTS RTS
CheckBox cbDTR DTR
CheckBox cbNewLine 換行
TextBox tbRec 接收編輯框 ReadOnly:True,Multiline:True
TextBox tbSend 傳送編輯框
SerialPort serialPort1 表示串列埠資源
StatusStrip statusStrip1 狀態列 LayoutStyle:Table
ToolStripStatusLabel tsslDateTime 時間 BorderSiders:Right
ToolStripStatusLabel toolStripStatusLabel1 讓R和S在狀態列的右邊 緊跟tsslDateTime後邊,Spring:True
ToolStripStatusLabel toolStripStatusLabel2 傳送位元組統計 S: BorderSiders:Left
ToolStripStatusLabel tsslSendCount 傳送總位元組數 BorderSiders:Right
ToolStripStatusLabel toolStripStatusLabel3 接收位元組統計 R:
ToolStripStatusLabel tsslRecCount 接收總位元組數

2.操作一波

(1)控制元件新增

  要做到本介面的效果需要把上面控制元件全新增進去,StatusStrip下面的控制元件,是在StatusStrip中新增的,小白請勿發懵。


(2)初始化

  說明:串列埠和控制元件初始化。

        private void Form1_Load(object sender, EventArgs e)
        {
            //串列埠
            string[] str = SerialPort.GetPortNames();

            foreach (string port in str)
            {
                cbSerial.Items.Add(port);
            }
            cbSerial.SelectedIndex = 0;

            //波特率
            cbBuadRate.Items.Add("300");
            cbBuadRate.Items.Add("1200"); 
            cbBuadRate.Items.Add("2400");
            cbBuadRate.Items.Add("4800");
            cbBuadRate.Items.Add("9600");
            cbBuadRate.Items.Add("19200");
            cbBuadRate.Items.Add("38400");
            cbBuadRate.Items.Add("43000");
            cbBuadRate.Items.Add("56000");
            cbBuadRate.Items.Add("115200");
            cbBuadRate.SelectedIndex = 4;

            //資料位
            cbDataBits.Items.Add("5");
            cbDataBits.Items.Add("6");
            cbDataBits.Items.Add("7");
            cbDataBits.Items.Add("8");
            cbDataBits.SelectedIndex = 3;

            //停止位
            cbStop.Items.Add("0");
            cbStop.Items.Add("1");
            cbStop.Items.Add("1.5");
            cbStop.Items.Add("2");
            cbStop.SelectedIndex = 1;

            //校驗位
            cbParity.Items.Add("無");
            cbParity.Items.Add("奇校驗");
            cbParity.Items.Add("偶校驗");
            cbParity.SelectedIndex = 0;

            btnSend.Enabled = false;

            rbRecASCII.Checked = true;
            rbSendASCII.Checked = true;

            //狀態控制元件
            tsslDateTime.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");

            tsslRecCount.Text = "0";
            tsslSendCount.Text = "0";
            
        }

(3)“開啟”按鈕

  

 private void btnOpen_Click(object sender, EventArgs e)
        {
            if(cbSerial.Items.Count <= 0)
            {
                MessageBox.Show("當前無可用串列埠!");
                return;
            }
            if (serialPort1.IsOpen == false)
            {
                serialPort1.PortName = cbSerial.SelectedItem.ToString();
                serialPort1.BaudRate = Convert.ToInt32(cbBuadRate.SelectedItem.ToString());
                serialPort1.DataBits = Convert.ToInt32(cbDataBits.SelectedItem.ToString());
                serialPort1.StopBits = (StopBits)Convert.ToInt32(cbStop.SelectedItem.ToString());
                serialPort1.Parity = (Parity)Convert.ToInt32(cbParity.SelectedIndex);

                try
                {
                    serialPort1.Open();
                    btnSend.Enabled = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "開啟COM錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                btnOpen.Text = "關閉";
            
            }
            else
            {
                try
                {
                    serialPort1.Close();
                    btnSend.Enabled = false;

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "關閉COM錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                btnOpen.Text = "開啟";
                
            }
            cbSerial.Enabled = !serialPort1.IsOpen;
            cbBuadRate.Enabled = !serialPort1.IsOpen;
            cbDataBits.Enabled = !serialPort1.IsOpen;
            cbStop.Enabled = !serialPort1.IsOpen;
            cbParity.Enabled = !serialPort1.IsOpen;
        }

(4)“清除”按鈕

        private void btnClear_Click(object sender, EventArgs e)
        {
            tbRec.Clear();
            tbSend.Clear();
        }

(5)“傳送”按鈕

        private void btnSend_Click(object sender, EventArgs e)
        {
            byte[] sendData = null;
            string strData = null;

            if (cbNewLine.Checked)
            {
                strData = tbSend.Text.Trim() + "\r\n";

            }
            else
            {
                strData = tbSend.Text.Trim();
            }
            if (rbSendHEX.Checked)
            {
                sendData = strToHexByte(strData);

            }
            else if (rbSendASCII.Checked)
            {
                sendData = Encoding.ASCII.GetBytes(strData);
            }

            if (this.Send(sendData))
            {
                statusStrip1.Invoke(new MethodInvoker(delegate
                {
                     if (tsslSendCount.Text == "0")
                     {
                         tsslSendCount.Text = tbSend.Text.Length.ToString();
                     }
                     else
                     {
                         try
                         {
                             tsslSendCount.Text = (int.Parse(tsslSendCount.Text) + tbSend.Text.Length).ToString();
                         }
                         catch (Exception ex)
                         {
                             MessageBox.Show(ex.Message, "傳送位元組計數錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                         }
                         
                     }
                }));

            }
            
        }

(6)格式切換

  說明:rbSendHEX和rbSendASCII新增CheckedChanged事件,接收格式同理。

private void rbSendHEX_CheckedChanged(object sender, EventArgs e)
        {
            byte[] data = null;
      
            data = System.Text.Encoding.Default.GetBytes(tbSend.Text.Trim());
            if (rbSendHEX.Checked)
            {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < data.Length; i++)
                {
                    sb.AppendFormat("{0:x2}" + " ", data[i]);

                }
                tbSend.Text = sb.ToString().ToUpper();

            }

        }

        private void rbSendASCII_CheckedChanged(object sender, EventArgs e)
        {
            if (rbSendASCII.Checked)
            {
                byte[] data = null;
                
                if (tbSend.Text == "")
                {
                    return;
                }
                data = HexStringToByte(tbSend.Text.Trim());
                tbSend.Text = new ASCIIEncoding().GetString(data);
            }
        }

3.資料型別轉換

(1) 16進位制轉位元組陣列

        public static byte[] HexStringToByte(string hexstring)
        {

            string[] tmpary = hexstring.Trim().Split(' ');
            byte[] buff = new byte[tmpary.Length];
            for (int i = 0; i < buff.Length; i++)
            {
                buff[i] = Convert.ToByte(tmpary[i], 16);
            }
            return buff;
        }

(2)字串轉換16進位制位元組陣列

    
        private byte[] strToHexByte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            try
            {

                for (int i = 0; i < returnBytes.Length; i++)
                    returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Replace(" ", ""), 16);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "轉換成HEX錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return returnBytes;

        }


4.串列埠

(1)串列埠傳送

        public bool Send(byte[] data)
        {
            if (serialPort1.IsOpen)
            {
                try 
                {
                    serialPort1.Write(data, 0, data.Length);
                    return true;
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message, "傳送資料錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

            }
            else
            {
                MessageBox.Show("未開啟串列埠", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);

            }
            return false;
        }

(2)串列埠接收

       說明:新增serialPort1的DataReceived事件

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] ReDatas = new byte[serialPort1.BytesToRead];
            serialPort1.Read(ReDatas, 0, ReDatas.Length);
            this.AddData(ReDatas);
        }

        public void AddData(byte[] data)
        {
            if (rbRecHEX.Checked)
            {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < data.Length; i ++ )
                {
                    sb.AppendFormat("{0:x2}" + " ", data[i]);

                }
                AddContent(sb.ToString().ToUpper());

            }
            else if (rbRecASCII.Checked)
            {
                AddContent(new ASCIIEncoding().GetString(data));
            }


            statusStrip1.Invoke(new MethodInvoker(delegate 
            {
                if (tsslRecCount.Text == "0")
                {
                    tsslRecCount.Text = tbRec.Text.Length.ToString();
                }
                else
                {
                    try
                    {
                        tsslRecCount.Text = (int.Parse(tsslRecCount.Text) + data.Length).ToString();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "接收位元組計數錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }

                }
            }));


        }

        private void AddContent(string content)
        {
            this.BeginInvoke(new MethodInvoker(delegate
                {
                    tbRec.AppendText(content);
                }));
        }

5.疑難點

  說明:在WinForm中使用多執行緒時,當在子執行緒中修改一個控制元件的值或者進行其它操作時,會出錯。不過此工程未使用子執行緒,可直接對控制元件控制,效果是等價的。

        
             if (tsslRecCount.Text == "0")
             {
                  tsslRecCount.Text = tbRec.Text.Length.ToString();
             }
             else
             {
    
                  tsslRecCount.Text = (int.Parse(tsslRecCount.Text) + data.Length).ToString();
   
             }
          

            statusStrip1.Invoke(new MethodInvoker(delegate
            {
                if (tsslRecCount.Text == "0")
                {
                    tsslRecCount.Text = tbRec.Text.Length.ToString();
                }
                else
                {
                    try
                    {
                        tsslRecCount.Text = (int.Parse(tsslRecCount.Text) + data.Length).ToString();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "接收位元組計數錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }

                }
            }));

注意:BeginInvoke與Invoke一個是同步執行,一個是非同步執行。簡單的可以理解為,當使用Invoke時,當前執行緒(非UI執行緒)會阻塞然後UI執行緒執行Invoke裡傳入的方法,之後再繼續執行當前執行緒。而使用BeginInvoke時,當前執行緒不會阻塞,而是繼續執行,噹噹前執行緒執行完畢後,UI執行緒才會執行BeginInvoke傳入的方法。