自己做串口调试助手

一、协议介绍

串口调试助手应该都比较熟悉了,主要用于和下位机通信(如单片机),使用的通信协议就是串口通讯协议。首先先介绍下这个协议。
串口通信属于异步的串行通信,有如下几个特点。

1 . 物理上的连线至少三根,分别是tx数据发送线,rx数据接收线,GND共用的地线
2. 0与1的约定。RS232电平,约定﹣5V至﹣25V之间的电压信号为1,﹢5V至﹢25V之间的电压信号为0 。TTL电平,约定5V的电压信号为1,0V电压信号为0 。CMOS电平,约定3.3V的电压信号为1,0V电压信号为0 。其中,CMOS电平一般用于ARM芯片中。
3. 发送的顺序,串口是LSB->MSB
4. 波特率,收发双方共同约定的一个数据位(0或1)在数据传输线上维持的时间。也可理解为每秒可以传输的位数。常用的波特率有2400,9600,14400,19200,115200等。
5. 通信协议,串口通信分为起始位,数据位,校验位,停止位,时序如下图所示。
这里写图片描述

二、程序编写

编程语言我使用的是C#,C#对这种桌面的图形化编程有着很好的支持,可以迅速编写一些桌面的小工具。
IDE使用visual studio 2015。

1.串口类的使用
串口的库C#已经为我们编写好了 我们可以直接使用,配置如下

   serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
   serialPort1.PortName = comboBox1.Text;
   serialPort1.StopBits = (StopBits)Convert.ToInt32(stopBox.Text);
   serialPort1.DataBits = Convert.ToInt32(dataBox.Text);
   serialPort1.Parity = (Parity)0;
   //解决中文乱码的问题
   serialPort1.Encoding = System.Text.Encoding.GetEncoding("GB2312");
   serialPort1.Open();

设置串口通信的几个重点参数,如数据位,奇偶校验位,停止位,波特率等,同时设置
了串口的编码为GB2312,这样就能解决中文乱码的问题。

为了实时获取可用的端口号,可使用一个定时器,1s更新一次可用串口列表

string[] ports = SerialPort.GetPortNames();//获得可用串口列表 
string selectCom = comboBox1.Text;
            //更新可用串口列表
            if (comboBox1.Items.Count > 0)
            {
                comboBox1.Items.Clear();
            }
            foreach (string port in ports)  
            {
                comboBox1.Items.Add(port);
                if (port.Equals(selectCom))
                {
                    comboBox1.Text = selectCom;
                }
            }

配置好了后就可以添加数据接收事件,编写数据接收函数

 serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);

最简单的串口调试助手到此就完成了,不过我们可以再添加一些小功能。

串口调试助手都是和底层通信,那么经常使用的就是十六进制的数据,所以我们编写字符串转16进制和16进制转字符串这两个函数。

        public static String stringToOxTool(String str)
        {
            StringBuilder sb = new StringBuilder();
            Encoding gb = Encoding.GetEncoding("GB2312");
            //按照GB2312的编码方式把字符串转换为byte型数据
            byte[] values = gb.GetBytes(str);

            foreach (byte item in values)
            {
                int value = Convert.ToInt32(item);
                //对每个数据按照16进制去格式化
                string newstr = String.Format("{0:X}", value) + " ";
                sb.Append(newstr);
            }
            return sb.ToString();
        }
         public static String oxToStringTool(String str)
        {
            List<byte> list = new List<byte>();
            StringBuilder sb = new StringBuilder();
            String[] data= str.Split(' ');
            Encoding gb = Encoding.GetEncoding("GB2312");

            foreach (String item in data)
            {
                if (item == " ")
                {
                    list.Add(0x20);
                }
                else if (item == "\r")
                {
                    list.Add(0x0d);
                }
                else if (item == "\n")
                {
                    list.Add(0x0a);
                }
                else
                {
                    try
                    {
                        byte value = Convert.ToByte(item, 16);
                        list.Add(value);
                    }
                    catch
                    {
                        list.AddRange((gb.GetBytes(item)));
                    }
                }

            }
            return gb.GetString(list.ToArray());
        }

如果发送的过程是在主线程里运行的话,那么发送大文件时就会导致界面无法点击,所以数据的发送新建一个从线程,让数据在后台发送。

 Thread t = new Thread(sendDataThread);
            t.Start();
 private void sendDataThread()
{
    String str = sendDataBox.Text;

    //如果数据是16进制格式的先转换为字符串格式
    if (send_0x.Checked)
    {
        str = tool.oxToStringTool(sendDataBox.Text);
    }
     /*
        按换行符去分割字符串,
        即存在多行数据分行发送
     */
    String[] data = str.Split('\n');
    for (int i = 0; i < data.Length; i++)
    {
        //如果存在\r符,则得到它的位置并删除
        int pos = data[i].LastIndexOf('\r');
        if (pos != -1)
        {
            sendData(data[i].Remove(pos));
        }
        else
        {
            sendData(data[i]);
        }
        //发送间隔
        Thread.Sleep(20);
    }

}

一些发送的配置本来打算使用xml文件,不过搜索了下发现C#自己有一个设置文件,非常好用,而且配置方便。直接新建设置文件,然后配置就能在程序里使用了

//初始化时从设置文件中读取历史配置值
comboBox2.Text = config.Default.portBps;  
sendDataBox.Text = config.Default.sendDataText;
stopBox.Text = config.Default.portStop;
dataBox.Text = config.Default.portData;
checkoutBox.Text = config.Default.portCheck;
comboBox1.Items.Add(config.Default.com);
comboBox1.Text = config.Default.com;

sendPeriodValue.Text = config.Default.periodValue.ToString();
sendNewLineBox.Checked = config.Default.sendNewLineFlag;
send_0x.Checked = config.Default.hexSendFlag;
hexShowBox.Checked = config.Default.hexSendFlag;
timeTickBox.Checked = config.Default.timeTickFlag;
checkBox2.Checked = config.Default.rxBoxBkColor;

//在窗口关闭事件中把配置数据保留下来
 private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  {
    //保存数据
     config.Default.Save();
  }

三、功能介绍

  1. 16进制显示,勾选后将显示16进制的字节,如果之前接收到了数据,会自动转换.
  2. 显示界面可以黑底白字或者白底黑字
  3. 时间戳功能,当数据帧中含有”\r\n”时会自动添加当前时间[yyyy-MM-dd hh:mm:ss].
  4. 点击保存窗口可以将接收到的数据存为txt文件,编码格式为GB2312.
  5. 点击清除按钮,可以清除窗口显示的内容,并且清除发送和接收字节计数
  6. 支持16进制发送,勾选16进制发送的时候将对发送区的内容进行16进制和字符互转
  7. 发送换行勾选后,每次发送数据时会自动添加”\r\n”.
  8. 支持发送文件(txt),勾选发送新行后,会自动给文件每一行数据加上换行回车符.
  9. 支持定时发送,可以自定义发送周期
  10. 采用配置文件,记录上一次使用软件时的配置.

界面如下,界面和功能主要都是模仿了正点原子的XCOM。
自己做串口调试助手_第1张图片

代码托管地址: https://github.com/yuanluw/princomputer

你可能感兴趣的:(C#,串口通信,上位机,c#)