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传入的方法。

猜你喜欢

转载自blog.csdn.net/C_gyl/article/details/78134311