自己做串口调试助手

协议介绍

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

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


    串口通信时序图

程序编写

编程语言我使用的是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();
  }

功能介绍

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

界面如下,界面和功能主要都是模仿了正点原子的XCOM。


界面图

具体代码可见我的GitHub

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容