C#做一个串口调试助手

2022-07-15 10:17:11

C#做一个串口调试助手

在这里插入图片描述

新建工程

选择visual c#---->窗体应用程序

布局串口配置页面

GroupBox
拖拽上去6个Label,位置和显示如下
在这里插入图片描述
拖拽上去5个ComboBox,1个Button,位置如下

设置Button的显示改为打开串口
在这里插入图片描述
添加ComboBox显示的内容

5.1:以波特率的ComboBox详细叙述
在这里插入图片描述
在这里插入图片描述
拖拽串口控件
在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
在页面加载函数中填写以下程序
在这里插入图片描述

设置下默认显示的配置

在这里插入图片描述

启动

在这里插入图片描述

打开关闭串口

双击按钮进入按钮点击事件
在这里插入图片描述

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

在这里插入图片描述
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进制字符串>
///
/// String 16进制显示形式
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进制格式,不够自动前面补零>
///
///
///
///
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’

  • 作者:windows已登入
  • 原文链接:https://blog.csdn.net/weixin_44547715/article/details/105958317
    更新时间:2022-07-15 10:17:11