【C#】基础篇(2) C#实现串口助手,C#扫描串口

大家好,我是皮皮猫吖!

每文一言:愿新年,胜旧年!


本篇文章:

主要是关于C#制作简单的串口助手,实现串口之间收发数据。本篇文章制作的串口助手存在一个中文乱码问题,后期文章会解决这个问题。【后期文章:C#实现串口助手,解决中文乱码问题

功能一:串口简单实现【C#制作的串口向主流的串口助手发送数据】

功能二:C#实现简易串口助手【发送、接收数据】

功能三:C#扫描串口助手

正文如下:

一、串口简单实现【C#制作的串口向主流的串口助手发送数据】

1)设置串口控件

在这里插入图片描述

2)通过串口发送数据
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp5
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //窗体创建初始化函数
        private void Form1_Load(object sender, EventArgs e)
        {
            //存储下拉框中的内容
            string str;
            for(int i = 0; i < 256; i++)
            {
                //把0-255个数字装换成十六进制,同时变为大写
                //toString(参数1),根据参数的不同,可转换为任意进制的数据
                str = i.ToString("x").ToUpper();

                //如果得到数字的长度是1位的话,就需要在最前面加上一个0,比如0的十六进制应该是00
                if(str.Length == 1)
                {
                    //str是一位数的时候,在前面添加一个“0”
                    str = "0" + str;
                }
                //在数字的前面加上0x,变为真正的十六进制数据
                comboBox1.Items.Add("0x" + str);

            }
            //初始化多选框的值
            comboBox1.Text = "0x00";
        }

        //按键单击函数
        private void button1_Click(object sender, EventArgs e)
        {
            //存储当前下拉框选中的内容
            string data = comboBox1.Text;

            //把字符分开,截取获得十六进制的数据,去掉0x
            string convertdata = data.Substring(2, 2);

            //定义一个数组
            byte[] buffer = new byte[1];//一个字节

            //将字符串,转换为byte类型的变量,buffer[0]存储的是十六进制的数据
            buffer[0] = Convert.ToByte(convertdata, 16);

            //防止异常出错
            try
            {
                serialPort1.Open();
                //里面需要的是字节数组
                //0:从数组的第几位开始读取
                //1:读取几个数据
                serialPort1.Write(buffer, 0, 1);
                serialPort1.Close();
            }
            catch//出错就执行此代码
            {
                //串口打开了,写数据时出错,要关闭串口,等待下一次使用
                //串口都没有找到,串口未找到,串口出错
                if (serialPort1.IsOpen)
                    //如果写数据出错,此时的窗口状态时打开的,关闭串口
                    serialPort1.Close();

                MessageBox.Show("端口错误", "错误");
            }

        }
    }
}

3)由于手上没有单品机设备,我使用了虚拟串口进行模拟,很香,完全可以实现串口通信。

① 关于VSPD(虚拟串口)的安装在上一篇文章里面【vspd虚拟串口安装】,这里不做详细描述,直接使用vspd虚拟串口:

  • 【注意】:
    • VSPD是以串口的形式添加的,这里的COM1,COM2成对,COM1的数据只能发送给COM2,COM2会自动接收来自COM1的数据

在这里插入图片描述

② 串口助手效果

在这里插入图片描述
③ 使用完,删除虚拟串口

在这里插入图片描述

④ 本项目中,Visual Studio模拟的是COM1端口,需要使用vspd虚拟串口软件创建一个虚拟的COM2,设置为COM1向COM2发送数据,即可看到如下效果【C#串口助手向其他串口助手【下面有串口助手链接】发送数据】:

在这里插入图片描述

二、C#实现简易串口助手【发送、接收数据】

1)串口视图化

① 基本控件

  • groupBox1:带标题的框
  • label:文本
  • radioButton:单选
  • comboBox:多选框
  • panel【容器】:面板(内置单选框,面板内的单选框会相互影响,与面板外的单选框无相互影响)
  • button:按钮
  • textbox:
    • scrollbars:vertical、both、horizontal设置滚动条属性
    • Multiline:true / false 文本可以跨越多行
  • serialPort:串口

在这里插入图片描述

2)通过串口发送、接收数据
  • 代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SerialPort_2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }


        //窗体初始化
        private void Form1_Load(object sender, EventArgs e)
        {
            //窗体加载前
            for (int i = 0; i < 20; i++)
            {
                //添加串口信息
                comboBox1.Items.Add("COM" + i.ToString());

            }
            //设置串口为COM1
            comboBox1.Text = "COM1";

            //设置默认波特率为9600
            comboBox2.Text = "9600";


            //手动设置串口的接收回调函数
            //当串口中有数据发送过来的时候,默认会调用回调函数
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

            button3.Enabled = false;
        }


        //串口接收数据回调函数
        private void port_DataReceived(Object sender, SerialDataReceivedEventArgs e)
        {
            //如果接收模式为字符模式
            if (radioButton3.Checked)
            {
                //读取串口中的数据:以字符串方式进行接收
                String str = serialPort1.ReadExisting();
                //在文本框中添加内容
                textBox1.AppendText(str);
            }
            else//接收模式为数值接收
            {

                byte data;

                //读取串口中的数据:读取到的是int类型的数据,需要进行一次转换。强转为byte类型
                data = (byte)serialPort1.ReadByte();

                //把data数据,转换为16进制的字符串,再转换为字符全大写
                String str = Convert.ToString(data, 16).ToUpper();

                //如果是一位数据的话,需要再数据的前面进行补0
                //比如说串口中的数据为155
                //读取到的数值为   0x0e.0x05
                textBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");
            }
        }

        //打开串口按钮
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                //设置串口号
                serialPort1.PortName = comboBox1.Text;

                //设置波特率:将字符串转换为10进制类型数据
                //参数1:需要转换的字符串
                //参数2:默认(10进制),可以是x(十六进制)
                serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text, 10);

                //打开串口
                serialPort1.Open();

                //设置打开串口为非点击状态:打开串口不可用
                button1.Enabled = false;
                //关闭串口按钮为可以点击状态:关闭串口可用
                button2.Enabled = true;
            }
            catch
            {
                MessageBox.Show("串口打开错误,请检查...", "错误");
            }
        }

        //关闭串口按钮
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                //关闭串口
                serialPort1.Close();

                //打开串口可点击
                button1.Enabled = true;
                //关闭串口不可点击
                button2.Enabled = false;
            }
            catch
            {
                MessageBox.Show("串口关闭错误,请检查...", "错误");
            }
        }

        //发送数据按钮
        private void button3_Click(object sender, EventArgs e)
        {
            byte[] Data = new byte[1];
            //判断串口是否打开
            if (serialPort1.IsOpen)
            {
                //判断发送域是否有数据
                if (textBox2.Text != "")
                {
                    
                    //以字符形式发送数据
                    if (!radioButton1.Checked)
                    {
                        try
                        {
                            //向串口中写入数据
                            serialPort1.WriteLine(textBox2.Text);
                        }
                        catch (Exception err)
                        {
                            //向串口写入数据发生错误
                            MessageBox.Show("串口写入数据错误", "错误");
                            //关闭串口
                            serialPort1.Close();

                            //打开串口按钮开启
                            button1.Enabled = true;
                            //关闭串口按钮关闭
                            button2.Enabled = false;
                        }
                    }
                    else
                    {
                        //以数值形式发送数据

                        //防止用于输入的个数为奇数个
                        for (int i = 0; i < (textBox2.Text.Length - textBox2.Text.Length % 2) / 2; i++)
                        {
                            //将字符串转换为16进制的数值
                            Data[0] = Convert.ToByte(textBox2.Text.Substring(i * 2, 2), 16);
                            //向串口中写入数据
                            serialPort1.Write(Data, 0, 1);

                        }
                        if (textBox2.Text.Length % 2 != 0)
                        {
                            //
                            Data[0] = Convert.ToByte(textBox2.Text.Substring(textBox2.Text.Length - 1, 1), 16);
                            //发送数据
                            serialPort1.Write(Data, 0, 1);
                        }
                    }

                }  
            }
        }



        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            if (textBox2.Text == "")
            {
                button3.Enabled = false;
            }
            else
            {
                button3.Enabled = true;
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            //保持文本框的滚动条移动到最下方
            textBox1.ScrollToCaret();
        }
    }
}

3)效果如下:

① C#打开串口COM1,其他串口助手打开COM2。C#串口助手向其他串口助手发送数据,其他串口助手接收到C#串口助手发送的数据。情况如下图:

在这里插入图片描述

② C#打开串口COM2,其他串口助手打开COM1。其他串口助手向C#串口助手发送数据,C#串口助手接收其他串口助手发送的数据。情况如下图:

在这里插入图片描述

4)注意:

① 使用串口之前,需要设置串口的波特率,只有当两个串口的波特率相同的时候,发送的数据才可以接收到

② 发送串口需要和接收串口设置一定的发送数据和接收数据的规则:接收数据模式,发送数据模式

③ 此串口助手有一个小缺点是,中文会出现乱码,在后续文章中会进行改正

三、C#扫描串口助手

1)串口视图化

① 基本控件

  • label:文本
  • button:按钮
  • groupBox:带标题的框
  • comboBox:下拉框
  • serialPort:串口

在这里插入图片描述

2)代码
  • 【注意】:
    • 扫描按键的部分设计非常的巧妙。一个一个的试探哪一个串口是打开的,是通过异常试探的方式来实现串口扫描的功能的。然后把打开的串口的名字,加入到comboBox里面即可。本串口助手只扫描到COM20,可以自行更改扫描的上限。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SerialPort_3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //扫描当前哪个串口是打开状态
            SearchAndAddSerialToComboBox(serialPort1, comboBox1);
        }


        //串口打开 / 关闭按钮
        private void button2_Click(object sender, EventArgs e)
        {
            //如果当前串口是打开的
            if (serialPort1.IsOpen)
            {
                try
                {
                    //关闭串口
                    serialPort1.Close();

                    radioButton1.Checked = false;
                }
                catch
                {

                }
                //文字设置为打开串口
                button2.Text = "打开串口";
            }
            else
            {
                try
                {
                    //此时串口是关闭状态:连接当前扫描到的串口
                    serialPort1.PortName = comboBox1.Text;
                    //打开指定串口号的串口
                    serialPort1.Open();

                    
                    radioButton1.Checked = true;

                    //按钮设置为关闭串口
                    button2.Text = "关闭串口";
                }
                catch
                {
                    MessageBox.Show("串口打开失败", "错误");
                }
            }
        }



        //扫描按键的作用:扫描当前电脑中,串口打开状态
        private void SearchAndAddSerialToComboBox(SerialPort MySerialPort, ComboBox comboBox)
        {
            string buffer;

            //清除下拉框的内容
            comboBox.Items.Clear();

            //获取当前计算机打开的串口
            for(int i = 1; i < 20; i++)
            {
                try
                {
                    buffer = "COM" + i.ToString();

                    //假设COM+i是打开状态
                    MySerialPort.PortName = buffer;
                    //如果当前串口真的处于打开状态,会成功开启串口;否则会打开串口失败,直接跳到catch那边
                    MySerialPort.Open();

                    //把打开的串口名字,添加到下拉框中
                    comboBox.Items.Add(buffer);

                    //关闭打开的串口
                    MySerialPort.Close();
                }
                catch
                {

                }
            }

        }

        private void button1_Click(object sender, EventArgs e)
        {
            SearchAndAddSerialToComboBox(serialPort1, comboBox1);
        }


        //向串口写入数据
        private void writeByteToSerialPort(byte data)
        {
            //封装这写入的数据
            byte[] buffer = new byte[1] {data};

            if (serialPort1.IsOpen)
            {
                try
                {
                    //向串口中写入数值数据
                    serialPort1.Write(buffer, 0, 1);
                }
                catch
                {


                    MessageBox.Show("串口发送数据错误", "错误");
                }
            }
        }

        //NO.1的开按钮
        private void button4_Click(object sender, EventArgs e)
        {
            writeByteToSerialPort(Convert.ToByte("11", 10));
        }

        //NO.1的关按钮
        private void button3_Click(object sender, EventArgs e)
        {
            writeByteToSerialPort(Convert.ToByte("10", 10));
        }

        private void button6_Click(object sender, EventArgs e)
        {
            writeByteToSerialPort(Convert.ToByte("21", 10));
        }

        private void button5_Click(object sender, EventArgs e)
        {
            writeByteToSerialPort(Convert.ToByte("20", 10));
        }

        private void button8_Click(object sender, EventArgs e)
        {
            writeByteToSerialPort(Convert.ToByte("31", 10));
        }

        private void button7_Click(object sender, EventArgs e)
        {
            writeByteToSerialPort(Convert.ToByte("30", 10));
        }
    }
}

3)实现效果

① 其他串口助手占用COM1端口,C#串口助手只扫描到COM2

在这里插入图片描述

② 其他串口助手不使用串口,C#串口助手扫描到COM1、COM2

在这里插入图片描述

③ C#串口助手向其他串口助手发送数据:

十进制:11、10、21、20、31、30

十六进制:0B、0A、15、14、1F、1E

在这里插入图片描述
在这里插入图片描述

4)注意

① 主要是如何实现串口助手的扫描。使用异常的方式,来搜索电脑上面可以使用的串口,通过试错的方式找到可以使用的串口助手。


其他串口助手资源链接:https://pan.baidu.com/s/1agi_IXcSI3L4URVlDzDXUw

提取码:x9i3


希望本篇文章对大家有所帮助,后续会继续分享C#串口助手相关知识…

如果文章内容有错误的地方,请在留言处留下你的见解,方便大家共同学习。谢谢。

作者:皮皮猫吖


`

  • 9
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值