码迷,mamicode.com
首页 > Windows程序 > 详细

C#串口调试助手

时间:2020-07-28 00:27:42      阅读:108      评论:0      收藏:0      [点我收藏+]

标签:防止   href   字节数组   发送16进制   eve   基础上   箭头   点击   group   

说明

 这节教给用户使用C#做一个串口调试助手,

 用户可在此基础上依据自己的需求做修改

 本人的其它关于串口通信的上位机也会在此基础上做修改,

 请用户认真学习本节.

技术图片

 

 

 

 

 

新建工程

技术图片

 

 

 

布局串口配置页面

1.拖拽上来一个 GroupBox

技术图片

 

 

 

 2.重新命名

技术图片

 

 

 

 3.拖拽上去6个Label,位置和显示如下

技术图片

 

 

 

4. 拖拽上去5个ComboBox,1个Button,位置如下

设置Button的显示改为打开串口

技术图片

 

 

 

 

-----------------------------------------------------------------------------------------------以上需要嵌入视频演示

 

5. 添加ComboBox显示的内容

5.1:以波特率的ComboBox详细叙述

技术图片

 

 

 

技术图片

 

 

 

1382400
921600
460800
256000
230400
128000
115200
76800
57600
43000
38400
19200
14400
9600
4800
1200


运行一下

技术图片

 

 

 

 

5.2:设置停止位的ComboBox里面的数据

 

 

技术图片

 

 

 

 

1
1.5
2

 

5.3:设置数据位的ComboBox里面的数据

 技术图片

 

 

8
7
6
5

 

5.4:设置校验位的ComboBox里面的数据

技术图片

 

 

 


奇校验
偶校验

 

----------------------------------以上需要录制演示视频

 

 

 

拖拽串口控件

技术图片

 

 

 

 

技术图片

 

 

 

 

获取电脑上可用串口,并显示在端口号的ComboBox里面

1.双击窗体,进入窗体加载回调函数

技术图片

 

 

 

2.在页面加载函数中填写以下程序

技术图片

 

 

 

            string[] ports = System.IO.Ports.SerialPort.GetPortNames();//获取电脑上可用串口号
            comboBox1.Items.AddRange(ports);//给comboBox1添加数据
            comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//如果里面有数据,显示第0个

 

 

警告:请选择对应的comboBox

comboBox1 

技术图片

 

 

 

3.启动

comboBox里面显示当前电脑上可用串口号

技术图片

 

4. 设置下默认显示的配置

技术图片

 

 

 

            comboBox2.Text = "115200";/*默认波特率:115200*/
            comboBox3.Text = "1";/*默认停止位:1*/
            comboBox4.Text = "8";/*默认数据位:8*/
            comboBox5.Text = "无";/*默认奇偶校验位:无*/

 

5.启动

技术图片

 

 

 

 

打开关闭串口

1.双击按钮进入按钮点击事件

技术图片

 

 

 

2.按钮点击事件函数内部程序如下

技术图片

 

 

 

技术图片
            if (button1.Text == "打开串口"){//如果按钮显示的是打开串口
                try{//防止意外错误
                    serialPort1.PortName = comboBox1.Text;//获取comboBox1要打开的串口号
                    serialPort1.BaudRate = int.Parse(comboBox2.Text);//获取comboBox2选择的波特率
                    serialPort1.DataBits = int.Parse(comboBox4.Text);//设置数据位
                    /*设置停止位*/
                    if (comboBox3.Text == "1") { serialPort1.StopBits = StopBits.One; }
                    else if (comboBox3.Text == "1.5") { serialPort1.StopBits = StopBits.OnePointFive; }
                    else if (comboBox3.Text == "2") { serialPort1.StopBits = StopBits.Two; }
                    /*设置奇偶校验*/
                    if (comboBox5.Text == "无") { serialPort1.Parity = Parity.None; }
                    else if (comboBox5.Text == "奇校验") { serialPort1.Parity = Parity.Odd; }
                    else if (comboBox5.Text == "偶校验") { serialPort1.Parity = Parity.Even; }

                    serialPort1.Open();//打开串口
                    button1.Text = "关闭串口";//按钮显示关闭串口
                }
                catch (Exception err)
                {
                    MessageBox.Show("打开失败"+ err.ToString(), "提示!");//对话框显示打开失败
                }
            }
            else{//要关闭串口
                try{//防止意外错误
                    serialPort1.Close();//关闭串口
                }
                catch (Exception){}
                button1.Text = "打开串口";//按钮显示打开
            }
技术图片

 

提示:serialPort1

技术图片

 

 

 

 

 

3.启动测试

技术图片  技术图片

 

 

检测串口热插拔

1.在串口模块拔插的时候,重新更新下串口comboBox的内容

然后:

如果热插拔的是用户刚打开的串口,则按钮显示 "打开串口",comboBox显示初始化的串口号

如果热插拔的不是用户刚打开的串口,则comboBox还是显示咱刚才的串口号

 

2.用一个变量记录用户打开的串口号

技术图片

 

 

 

 

 

 

String serialPortName;

 

 

 

 

serialPortName = comboBox1.Text;

 

 

 

2.添加系统函数 protected override void WndProc(ref Message m)

技术图片

 

 

 

技术图片
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0219){//设备改变
                if (m.WParam.ToInt32() == 0x8004){//usb串口拔出
                    string[] ports = System.IO.Ports.SerialPort.GetPortNames();//重新获取串口
                    comboBox1.Items.Clear();//清除comboBox里面的数据
                    comboBox1.Items.AddRange(ports);//给comboBox1添加数据
                    if (button1.Text == "关闭串口"){//用户打开过串口
                        if (!serialPort1.IsOpen){//用户打开的串口被关闭:说明热插拔是用户打开的串口
                            button1.Text = "打开串口";
                            serialPort1.Dispose();//释放掉原先的串口资源
                            comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//显示获取的第一个串口号
                        }
                        else{
                            comboBox1.Text = serialPortName;//显示用户打开的那个串口号
                        }
                    }
                    else{//用户没有打开过串口
                        comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//显示获取的第一个串口号
                    }
                }
                else if (m.WParam.ToInt32() == 0x8000){//usb串口连接上
                    string[] ports = System.IO.Ports.SerialPort.GetPortNames();//重新获取串口
                    comboBox1.Items.Clear();
                    comboBox1.Items.AddRange(ports);
                    if (button1.Text == "关闭串口"){//用户打开过一个串口
                        comboBox1.Text = serialPortName;//显示用户打开的那个串口号
                    }
                    else{
                        comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//显示获取的第一个串口号
                    }
                }
            }
            base.WndProc(ref m);
        }
技术图片

 

提示:C#常用事件对应值

技术图片 View Code

 

 

3.启动测试 :用户自己测试热插拔

 

串口接收数据

1.拖拽上来一个TextBox

技术图片

 

 

 

 

2.点击TextBox上面的箭头,选择MultiLine (允许显示多行)

技术图片

 

技术图片

 

 

 2.拖拽TextBox使其达到自己满意的长宽,

设置TextBox的Scrollbars属性为Vertical  (显示竖直滚动条,可以滚动显示接收数据)

技术图片

 

 

 

 

 

 

3.为了更好看些,设置TextBox的背景色为黑色 (Black) 

显示的字体颜色为草绿色 (LawnGreen)

技术图片

 

 

 

4.选择serialPort1 -> 选择事件 -> 双击DataReceived

生成串口接收回调函数

技术图片

 

 

 

 

技术图片

 

 

 

5.在回调函数中接收数据,然后把接收数据显示在TextBox

技术图片

 

 

 

技术图片
            int len = serialPort1.BytesToRead;//获取可以读取的字节数
            byte[] buff = new byte[len];//创建缓存数据数组
            serialPort1.Read(buff, 0, len);//把数据读取到buff数组
            string str = Encoding.Default.GetString(buff);//Byte值根据ASCII码表转为 String
            Invoke((new Action(() => //C# 3.0以后代替委托的新方法
            {
                textBox1.AppendText(str);//对话框追加显示数据
            })));
技术图片

 

 

6.测试接收数据

为了测试接收数据,可以安装虚拟串口软件

https://qqqqqbucket.oss-cn-beijing.aliyuncs.com/LearnC%23/VSPD6.9.zip

安装好以后

技术图片

 

 

 

技术图片

 

 

提示:

按照上面的操作以后

电脑上便会有了COM1和COM2

COM1发送的数据将会自动发送给COM2

COM2发送的数据将会自动发送给COM1

 

7.测试

技术图片

 

 

 

 

技术图片

 

 

8.增加选择16进制显示(CheckBox),增加数据清除按钮

技术图片

 

 

 

 

 

9.关于显示字符串和显示16进制说明

 

在上面的测试接收中COM1那个串口调试助手发送的

数据为字符串 123456

实际传输是按照ASCii码表传输的对应的16进制

技术图片

 

 

 

实际上buff数组

buff[0] = 49 = 0x31

执行 string str = Encoding.Default.GetString(buff); 以后

str = 0 (字符串0)

所以接收显示为:123456

 

 

当COM1选择16进制传输的时候

假设传输的是0x01 0x02 0x03 0x04 0x05 0x06

技术图片

 

 

COM1实际发送也是:0x01 0x02 0x03 0x04 0x05 0x06

不过ASCII码表中显示的字符是乱码

技术图片

 

 

 

所以咱们需要另外添加转换程序

程序如下:

技术图片
        /// <字节数组转16进制字符串>
        /// <param name="bytes"></param>
        /// <returns> String 16进制显示形式</returns>
        public static string byteToHexStr(byte[] bytes)
        {
            string returnStr = "";
            try
            {
                if (bytes != null)
                {
                    for (int i = 0; i < bytes.Length; i++)
                    {
                        returnStr += bytes[i].ToString("X2");
                        returnStr += " ";//两个16进制用空格隔开,方便看数据
                    }
                }
                return returnStr;
            }
            catch (Exception)
            {
                return returnStr;
            }
        }
技术图片

 

实际上就一句话:

bytes[i].ToString("X2");  

如果变量是 0x01

则经过函数以后会返回 "01" ,字符串形式

 

 

10.如果用户选择16进制,则接收的数据按照16进制显示

技术图片

 

 

 

技术图片
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int len = serialPort1.BytesToRead;//获取可以读取的字节数
            byte[] buff = new byte[len];//创建缓存数据数组
            serialPort1.Read(buff, 0, len);//把数据读取到buff数组
            
            Invoke((new Action(() =>{//C# 3.0以后代替委托的新方法
                if (checkBox1.Checked){//16进制显示
                    textBox1.AppendText(byteToHexStr(buff));
                }
                else{
                    textBox1.AppendText(Encoding.Default.GetString(buff));//对话框追加显示数据
                }
            })));
        }

        /// <字节数组转16进制字符串>
        /// <param name="bytes"></param>
        /// <returns> String 16进制显示形式</returns>
        public static string byteToHexStr(byte[] bytes)
        {
            string returnStr = "";
            try{
                if (bytes != null){
                    for (int i = 0; i < bytes.Length; i++){
                        returnStr += bytes[i].ToString("X2");
                        returnStr += " ";//两个16进制用空格隔开,方便看数据
                    }
                }
                return returnStr;
            }
            catch (Exception){
                return returnStr;
            }
        }
技术图片

 

 

 

11.测试

技术图片

 

 

技术图片

 

 

12.双击清除接收按钮,生成按钮点击事件

写上 textBox1.Clear(); //清除接收对话框显示的数据

技术图片

 

 

技术图片

 

 

 

 

 

 

串口发送数据

1.页面布局如下:

技术图片

 

 

 

 

2.双击点击发送按钮,生成按钮点击事件

技术图片

3.事件函数中,程序如下

技术图片

 

 

技术图片
            String Str = textBox2.Text.ToString();//获取发送文本框里面的数据
            try
            {
                if (Str.Length > 0)
                {
                    serialPort1.Write(Str);//串口发送数据
                }
            }
            catch (Exception){ }
技术图片

 

 

4.测试发送数据

技术图片

 

 技术图片

 

 

 

5.发送16进制数据说明

首先需要明确

技术图片

 

 

 

假设文本框里面填写的是:01 02 03 04 05 06

Str获取的是01 02 03 04 05 06  是字符串

咱所希望的是把01转为0x01

02转为0x02

.

.

.

然后发送

 

首先先说思路

默认把文本框每隔两个字符作为一个16进制数

假设文本框中是

010203040506   (偶数个数据)

则01 ,02 ,03 ,04 ,05 ,06 分别作为16进制

 

如果文本框中的字符个数是奇数个

1115268

则默认先把前面每隔两个作为一个16进制数

最后一个数前面补零

0x11,0x15,0x26,0x08

 

 

封装的解析转换程序如下:

技术图片
        /// <字符串转16进制格式,不够自动前面补零>
        /// 
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] strToToHexByte(String hexString)
        {
            int i;
            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)//奇数个
            {
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];
                try
                {
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, ‘0‘), 16);
                }
                catch
                {
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                return returnBytes;
            }
            else
            {
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch
                {
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                return returnBytes;
            }
        }
技术图片

 

 

6.完善发送16进制程序

技术图片

 

 

 

 

 

技术图片
        private void button3_Click(object sender, EventArgs e)
        {
            String Str = textBox2.Text.ToString();//获取发送文本框里面的数据
            try
            {
                if (Str.Length > 0)
                {
                    if (checkBox2.Checked)//16进制发送
                    {
                        byte[] byt = strToToHexByte(Str);
                        serialPort1.Write(byt, 0, byt.Length);
                    }
                    else
                    {
                        serialPort1.Write(Str);//串口发送数据
                    }
                }
            }
            catch (Exception){ }
        }


        /// <字符串转16进制格式,不够自动前面补零>
        /// 
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] strToToHexByte(String hexString)
        {
            int i;
            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)//奇数个
            {
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];
                try
                {
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, ‘0‘), 16);
                }
                catch
                {
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                return returnBytes;
            }
            else
            {
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch
                {
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                return returnBytes;
            }
        }
技术图片

 

 

 

7.测试

技术图片

 

 

 

 

技术图片

 

 

 

 

 

8.双击 清除发送 按钮,生成按钮点击事件

textBox2.Clear();//清除发送文本框里面的内容

技术图片

 技术图片

 

 

 

提醒

提醒

提醒

技术图片

 

 

 

 

C#的串口中断回调函数也是不定个数的进入

假设另一个串口发送的数据为 123456

int len = serialPort1.BytesToRead;//获取可以读取的字节数
byte[] buff = new byte[len];//创建缓存数据数组

serialPort1.Read(buff, 0, len);//把数据读取到buff数组

 

len 可能等于 2

则存入buff 的数据为 

buff [0] = ‘1‘

buff [1] = ‘2‘

 

然后接着又进来这个函数

len 可能等于 4

则存入buff 的数据为 

buff [0] = ‘3‘

buff [1] = ‘4‘

buff [2] = ‘5‘

buff [3] = ‘6‘

 

如若想接收到一条完整的数据以后再进行处理

可参考: https://www.cnblogs.com/yangfengwu/p/11669373.html

 

增加一个定时器,用于空闲时间检测

 

 

转载自:https://www.cnblogs.com/yangfengwu/p/12382103.html

C#串口调试助手

标签:防止   href   字节数组   发送16进制   eve   基础上   箭头   点击   group   

原文地址:https://www.cnblogs.com/pmsmcontrol/p/13387817.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!