您尚未登录。

楼主 # 2022-11-28 13:35:58

LinjieGuo
Moderator
注册时间: 2019-07-24
已发帖子: 583
积分: 587
个人网站

尝试使用C#开发一款串口调试工具

嵌入式产品一般出场前要经过参数设定、参数校准、终端号设置等操作,单片机上面没有太多的设置接口,一般而言,只有一个串口可以使用,我尝试使用VS2019+WinForm,C#开发开发一款串口调试工具,用于配置产品的参数。
1、建立好工厂后,布局,给控件命名
uart_001.png
2、编写代码
2.1 实现端口号扫描

        private void ReflashPortToComboBox(SerialPort serialPort, ComboBox comboBox)
        {
            if (!serialPort.IsOpen)
            {//串口处于关闭状态
                comboBox.Items.Clear();
                string[] str = SerialPort.GetPortNames();
                if (str == null)
                {
                    MessageBox.Show("本机没有串口!", "Error");
                    return;
                }
                //添加串口
                foreach (string s in str)
                {
                    comboBox.Items.Add(s);
                    Console.WriteLine(s);
                }
            }
            else
            {
                MessageBox.Show("串口处于打开状态下,不能刷新串口列表", "Error");
            }
        }

2.2 打开串口按钮代码

        private void btn_open_com_Click(object sender, EventArgs e)
        {
            Int32 ibaudrate = Convert.ToInt32(cb_select_baudrate.SelectedItem.ToString());
            serialPort1.PortName = cb_select_com.SelectedItem.ToString();
            serialPort1.BaudRate = ibaudrate;
            serialPort1.Parity = (System.IO.Ports.Parity)Enum.Parse(typeof(System.IO.Ports.Parity), cb_select_check_bit.Text);
            serialPort1.StopBits = (System.IO.Ports.StopBits)Enum.Parse(typeof(System.IO.Ports.StopBits), cb_select_stop_bit.Text);
            serialPort1.DataBits = Convert.ToInt16(cb_select_data_bits.Text);

            //添加串口事件处理
            serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(ReceiveData);


            try
            {
                serialPort1.Open();
                btn_open_com.Enabled = false;
                btn_close_com.Enabled = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("串口打开失败"+ex, "Error");
            }


        }

2.3 串口接收事件代码

//串口接收事件
        private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
        {
            string content = serialPort1.ReadExisting();        //从串口中读取输入流,返回string
            
            ShowData(content);
        }
        private void ShowData(string text)
        {
            string receiveText = text;
            
            //更新接收数据计数
            recv_cntr += (UInt32)receiveText.Length;
            lab_recv_cntr.Text = recv_cntr.ToString();

            textBox_debug.AppendText("接收到了"+ receiveText.Length.ToString()+ "个数据: "+ text+"\r\n");

            if (rbtn_recv_hex.Checked)
            {//按HEX模式 展示接收到的内容 
                byte[] recData = System.Text.Encoding.Default.GetBytes(receiveText);// 将接受到的字符串据转化成数组;  

                foreach (byte str in recData)
                {
                    textBox_recv.AppendText(string.Format("{0:X2} ", str));
                }
            }
            else
            {//按ASCII模式 展示接收到的内容
                
                textBox_recv.AppendText(text);                   //将收到的字符串追加展示出来
            }

        }

2.4 发送按钮代码

        private void btn_send_Click(object sender, EventArgs e)
        {
            //串口打开的情况下,才能进行下一步操作
            if (!serialPort1.IsOpen) return;
            
            //发送内容不能为空 
            if ("" == textBox_send.Text) return;

            string sendData = textBox_send.Text;    //复制发送数据

            if (true == rbtn_send_ascii.Checked)
            {//字符模式
                try
                {
                    serialPort1.Write( sendData );
                    //更新发送数据计数
                    send_cntr += (UInt32)sendData.Length;
                    lab_send_cntr.Text = send_cntr.ToString();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "串口数据发送错误");
                    serialPort1.Close();
                    btn_open_com.Enabled = true;
                    btn_close_com.Enabled = false;
                }

            }
            else
            {//HEX模式 
                try
                {
                    sendData.Replace("0x", "");   //去掉0x
                    sendData.Replace("0X", "");   //去掉0X

                    string[] strArray = sendData.Split(new char[] { ',', ',', '\r', '\n', ' ', '\t' });
                    byte[] sendBuffer = new byte[strArray.Length];  //发送数据缓冲区
                    int decNum = 0,i = 0;
                    foreach (string str in strArray)
                    {
                        try
                        {
                            decNum = Convert.ToInt16(str, 16);
                            sendBuffer[i] = Convert.ToByte(decNum);
                            i++;
                        }
                        catch
                        {
                            //MessageBox.Show("字节越界,请逐个字节输入!", "Error");                          
                        }
                    }

                    serialPort1.Write(sendBuffer, 0, sendBuffer.Length);

                    //更新发送数据计数
                    send_cntr += (UInt32)sendBuffer.Length;
                    lab_send_cntr.Text = send_cntr.ToString();
                   
                }
                catch 
                {
                    MessageBox.Show("当前为16进制发送模式,请输入16进制数据");
                }
            }
   
        }

离线

楼主 #1 2022-11-28 13:44:51

LinjieGuo
Moderator
注册时间: 2019-07-24
已发帖子: 583
积分: 587
个人网站

Re: 尝试使用C#开发一款串口调试工具

3、测试
    工程跑起来后,插入CH340G,将TX RX短接,
(1)设置为ascii模式,收发一切正常。
(2)设置为HEX模式,发送0x01、0x02 、0x99等不带字母的十六进制数,正常。
但是发送0xA0,这样带字母的十六进制数,就会出现以下情况。
uart_002.png

(为了调试方便,我加入了日志打印区。在发生接收事件时,做2件事情,①在接收区显示收到的数据,②在日志区显示收到了多长的数据)

[1]第一次发送0xA0,触发了接收事件,①显示区没有任何显示;②数据长度是0
[2]第二次发送0xA0,触发了接收事件,①显示区显示了2个A0;②数据长度是1
结果是,数据长度对不上。。。请问有没有大神懂这是什么原因呢?
附上工程:uart_tool_base_v001_20221128.zip
外链免费下载:uart_tool_base_v001_20221128.zip

最近编辑记录 LinjieGuo (2022-11-28 13:51:02)

离线

#2 2022-11-29 14:54:13

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 660
积分: 793
个人网站

Re: 尝试使用C#开发一款串口调试工具

虽然我没搞过C#,但很明显 textBox_debug应该要像textBox_recv那样AppendText时要区分HEX和ASCII

离线

楼主 #3 2022-11-29 21:49:58

LinjieGuo
Moderator
注册时间: 2019-07-24
已发帖子: 583
积分: 587
个人网站

Re: 尝试使用C#开发一款串口调试工具

海石生风 说:

虽然我没搞过C#,但很明显 textBox_debug应该要像textBox_recv那样AppendText时要区分HEX和ASCII

嗯嗯,你说的这一点也是对的。
不过问题不是出在这个地方,问题是:数据内容接收到了,但是出现读取到的长度却不一致的情况。
后来在@周正的指导下,解决这个问题。
(1)使用ReadExisting()这个方法从串口接收中取数据,适用于字符串,可能不太适合面向字节流的数据。
(2)所以,接收代码修改为:

//串口接收事件
        private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] datas = new byte[serialPort1.BytesToRead];
            int len = serialPort1.Read(datas, 0, datas.Length);

            //数据写入环形缓冲区
            recv_lp.write_data(datas, len);

            show_recv_data(datas, len);
            /*
                        string content = serialPort1.ReadExisting();        //从串口中读取输入流,返回string
                        ShowData(content);
            */
        }
        private void show_recv_data(byte[] data, int len)
        {
            //更新接收数据计数
            recv_cntr += (UInt32)len;
            lab_recv_cntr.Text = recv_cntr.ToString();

            if (rbtn_recv_hex.Checked)
            {//按HEX模式 展示接收到的内容 

                for (int i = 0; i < len; i++)
                {
                    textBox_recv.AppendText(string.Format("{0:X2} ", data[i]));
                }
            }
            else
            {//按ASCII模式 展示接收到的内容
                string str = System.Text.Encoding.Default.GetString(data);
                textBox_recv.AppendText(str);
            }

        }

最近编辑记录 LinjieGuo (2022-11-29 21:50:26)

离线

#4 2022-11-30 02:45:40

演技担当黄晓明
会员
注册时间: 2017-10-17
已发帖子: 184
积分: 122.5

Re: 尝试使用C#开发一款串口调试工具

字符串直接拼接效率比较低,试试stringbuilder

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn