Winform/C#入门编程之第五部分应用(一:串口调试助手)

  简介:

  使用C#,开发环境VS2012,功能是串口调试助手。功能很简单,仅供大家学习。如果对其中的控件不熟悉的,可以在本人博客或专栏中查看相应控件的介绍。

代码下载链接:https://download.csdn.net/download/c_gyl/10878545。

Winform/C#入门编程之第五部分应用(一:串口调试助手)_第1张图片 串口通信助手
​​​​​

 

1.控件介绍

 

主要控件
命名 功能
cbxSerial 串口号
cbxBuadRate 波特率
cbxDataBits 数据位
cbxStop 停止位
cbxParity 校验位
btnOpen 打开或关闭
btnSend 发送数据
tbxRec 接收显示
tbxSend 发送显示

 

2.控件操作

(1)控件添加

  添加控件。设置对应的属性。

Winform/C#入门编程之第五部分应用(一:串口调试助手)_第2张图片 添加控件

(2)初始化

  在窗体的Load事件中,初始化窗体。

        private void Form1_Load(object sender, EventArgs e)
        {
            //串口
            string[] str = SerialPort.GetPortNames();
            foreach (string port in str)
            {
                cbxSerial.Items.Add(port);
            }
            cbxSerial.SelectedIndex = 0;

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

            //数据位
            cbxDataBits.Items.Add("5");
            cbxDataBits.Items.Add("6");
            cbxDataBits.Items.Add("7");
            cbxDataBits.Items.Add("8");
            cbxDataBits.SelectedIndex = 3;

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

            //校验位
            cbxParity.Items.Add("无");
            cbxParity.Items.Add("奇校验");
            cbxParity.Items.Add("偶校验");
            cbxParity.SelectedIndex = 0;


            //格式
            rbnRecASCII.Checked = true;
            rbnSendASCII.Checked = true;


            //发送按钮
            btnSend.Enabled = false;
        }

 

(3)打开

按钮的Click事件中,设置串口。

        private void btnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                if (!serialPort1.IsOpen)
                {
                    serialPort1.PortName = cbxSerial.SelectedItem.ToString();
                    serialPort1.BaudRate = Convert.ToInt32(cbxBuadRate.SelectedItem.ToString());
                    serialPort1.DataBits = Convert.ToInt32(cbxDataBits.SelectedItem.ToString());
                    serialPort1.StopBits = (StopBits)Convert.ToInt32(cbxStop.SelectedItem.ToString());
                    serialPort1.Parity = (Parity)Convert.ToInt32(cbxParity.SelectedIndex);
                    serialPort1.ReadTimeout = 1000;
                    serialPort1.WriteTimeout = 1000;
                    
                    serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);

                    serialPort1.Open();
                    if (serialPort1.IsOpen)
                    {
                        btnSend.Enabled = true;
                    }

                    btnOpen.Text = "关闭";

                }
                else
                {
                    serialPort1.DataReceived -= new SerialDataReceivedEventHandler(serialPort1_DataReceived);
                    serialPort1.Close();
                    btnSend.Enabled = false;

                    btnOpen.Text = "打开";
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "操作串口错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

        }

 

(4)清除

通过右键菜单,关联接收编辑框。

        private void 清除ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tbxRec.Clear();
        }

 

(5)发送

通过发送按钮的Click事件。

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

            if (rbnSendHEX.Checked)
            {
                sendData = strToHexByte(strData);

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

            if (Send(sendData))
            {
                tsslSendCount.Text = (int.Parse(tsslSendCount.Text) + tbxSend.Text.Length).ToString();
            }

        }


 

(6)格式

  接收和发送格式,通过CheckedChanged事件,判断格式。

        private void rbSendASCII_CheckedChanged(object sender, EventArgs e)
        {
            if (rbnSendASCII.Checked)
            {
                byte[] data = null;

                if (tbxSend.Text == "")
                {
                    return;
                }
                data = HexStringToByte(tbxSend.Text.Trim());
                tbxSend.Text = new ASCIIEncoding().GetString(data);
            }
        }



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

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

        private void rbRecASCII_CheckedChanged(object sender, EventArgs e)
        {
            if (rbnRecASCII.Checked)
            {
                byte[] data = null;

                if (string.IsNullOrEmpty(tbxRec.Text))
                {
                    return;
                }
                data = HexStringToByte(tbxRec.Text.Trim());
                tbxRec.Text = new ASCIIEncoding().GetString(data);
            }
        }

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

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

 

3.格式转换

(1) 16进制转字节数组

        private 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), 16);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "转换成HEX错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return returnBytes;
        }

 

4.串口

(1)串口发送

        private bool Send(byte[] data)
        {
            if (serialPort1.IsOpen)
            {
                try
                {
                    serialPort1.Write(data, 0, data.Length);
                    Thread.Sleep(10);
                    serialPort1.WriteLine("\r\n");
                    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.疑难点

            statusStrip1.Invoke(new MethodInvoker(delegate
                {
                    if (tsslRecCount.Text == "0")
                    {
                        tsslRecCount.Text = tbxRec.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);
                        }

                    }
                }));

在Winform中不能直接跨线程操作控件,一般通过Invoke,在拥有此控件的基础窗口句柄的线程上执行委托。

从 SerialPort 对象接收数据时,将在辅助线程上引发 DataReceived 事件。 由于此事件在辅助线程而非主线程上引发,因此尝试修改主线程中的一些元素(如 UI 元素)时会引发线程异常。 如果有必要修改主 Form 或 Control 中的元素,请使用 Invoke 回发更改请求,这将在正确的线程上执行。

BeginInvoke与Invoke一个是同步执行,一个是异步执行。简单的可以理解为,当使用Invoke时,当前线程(非UI线程)会阻塞然后UI线程执行Invoke里传入的方法,之后再继续执行当前线程。而使用BeginInvoke时,当前线程不会阻塞,而是继续执行,当当前线程执行完毕后,UI线程才会执行BeginInvoke传入的方法。

 

6.验证

借助虚拟串口软件,把机台可用的其中两个COM关联起来。

VSPD下载链接:https://download.csdn.net/download/c_gyl/10878572。

Winform/C#入门编程之第五部分应用(一:串口调试助手)_第3张图片 关联串口
Winform/C#入门编程之第五部分应用(一:串口调试助手)_第4张图片 收发测试

 

你可能感兴趣的:(Winform/C#入门编程,-,集合,Winform/C#入门编程)