【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
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
学习以c#的必备书 本书介绍了如何使用Visual C++ 6.0编写Windows应用程序。全书内容全面、结构清晰、由浅入深、注重实用,并结合了大量的实例,以方便读者理解。本书既包含菜单、鼠标、键盘等基本操作,又包含图形编程、Internet程序设计、数据库编程等高级主题。每章讲述一个主题,在展示知识点的同时,提供具体的演示实例,最后两章详细讲解了两个综合实例,以使读者对Visual C++编程技术有整体的认识。 目 录 第一 Visual C++基础 第1章 Visual C++集成开发环境 2 1.1 Visual C++的版本 2 1.2 安装Visual C++ 6.0 3 1.3 Visual C++集成开发环境 6 1.3.1 菜单栏 7 1.3.2 工具栏 11 1.3.3 工作区窗口 13 1.3.4 输出窗口 14 1.4 编写第一个程序Hello World 14 1.4.1 创建Hello World工程 15 1.4.2 编译并执行程序 16 1.5 小结 16 第2章 使用Visual C++创建基本应用程序 17 2.1 理解Visual C++工程 17 2.2 Visual C++中应用程序的类型 18 2.2.1 控制台应用程序 18 2.2.2 基于对话框的应用程序 19 2.2.3 单文档应用程序 19 2.2.4 多文档应用程序 19 2.2.5 基于HTML文档的应用程序 19 2.3 创建应用程序框架 20 2.3.1 创建基于对话框的应用程序 20 2.3.2 创建单文档应用程序 21 2.3.3 创建多文档应用程序 23 2.3.4 创建基于HTML的应用程序 24 2.4 小结 25 第3章 面向对象程序设计基础 26 3.1 面向过程与面向对象 26 3.1.1 面向过程的问题 26 3.1.2 面向对象的特性 27 3.2 C++类的基本概念 27 3.2.1 结构体与类 27 3.2.2 类与对象 29 3.2.3 类的声明、定义和实现 29 3.2.4 成员变量 31 3.2.5 成员函数 32 3.2.6 静态成员 34 3.2.7 this指针 35 3.3 构造函数 37 3.3.1 使用构造函数的原因 37 3.3.2 构造函数的使用 37 3.3.3 重载构造函数 40 3.3.4 析构函数 41 3.4 继承 43 3.4.1 继承的概念 43 3.4.2 继承的工作机制 43 3.4.3 公有继承 44 3.4.4 私有继承 46 3.4.5 保护继承 47 3.4.6 多重继承 49 3.5 异常处理 51 3.5.1 异常的概念 51 3.5.2 异常处理机制 51 3.5.3 基本异常处理方法 52 3.5.4 多个异常处理方法 54 3.6 小结 56 第4章 Visual C++调试技术 57 4.1 Debug与Release 57 4.2 调试的过程 58 4.2.1 设置断点 58 4.2.2 控制程序的运行 60 4.3 使用查看工具 60 4.3.1 弹出式调试信息泡泡 61 4.3.2 变量窗口 61 4.3.3 观察窗口 61 4.3.4 快速查看窗口 62 4.3.5 内存查看窗口 62 4.3.6 寄存器窗口 62 4.3.7 调用堆栈窗口 63 4.4 其他调试技术 63 4.4.1 TRACE宏 63 4.4.2 ASSERT宏 64 4.4.3 VERIFY宏 64 4.5 小结 64 第二 Windows编程 第5章 Windows程序设计 66 5.1 Windows编程简介 66 5.1.1 Windows API概述 66 5.1.2 Windows应用程序中的常用术语 69 5.2 Windows应用程序运行机制 71 5.2.1 生成Windows应用程序框架 71 5.2.2 在Windows应用程序中添加代码 71 5.2.3 编译并执行程序 74 5.3 程序入口:WinMain()函数 74 5.3.1 WinMain()函数的定义 75 5.3.2 定义和注册窗口类 76 5.3.3 创建窗口 77 5.3.4 显示和更新窗口 78 5.3.5 消息循环 78 5.4 窗口过程函数和消息处理 80 5.4.1 窗口过程函数 80 5.4.2 常用消息的处理 82 5.5 小结 84 第6章 MFC编程概述 85 6.1 MFC概述 85 6.1.1 MFC设计原理 85 6.1.2 MFC特点 86 6.1.3 MFC AppWizard向导 86 6.2 MFC层次结构设计 88 6.2.1 单文档应用程序的构成 88 6.2.2 CObject类 90 6.2.3 CCmdTarget
C#自定义控件滚动条的实现方法有多种。根据提供的引用内容,我可以为您提供以下方法和步骤来实现滚动条功能: 方法一: 1. 创建一个控件类,可以继承自Panel或者UserControl。该类将作为滚动条的容器。 2. 在该控件类中添加需要滚动的控件作为子控件。 3. 为该控件类添加滚动条控件,可以使用VScrollBar(竖向滚动条)或HScrollBar(横向滚动条)控件。 4. 设置滚动条控件的属性,如Maximum(可滚动范围的上限值)、SmallChange(小距离移动值)、LargeChange(大距离移动值)和Value(滚动条的当前位置)。 5. 给滚动条控件的Scroll事件添加处理方法,以便在滚动时对子控件进行相应操作。 方法二: 1. 创建一个视图类,为自定义控件动态添加滚动条,并处理滚动条的显示、隐藏和滚动事件。 2. 在该视图类的构造函数中传入自定义控件实例。 3. 在视图类中创建VScrollBar(竖向滚动条)和HScrollBar(横向滚动条)控件,并将其添加到自定义控件中。 4. 设置滚动条控件的属性,如Dock(使滚动条固定在底部或右侧)、Maximum(可滚动范围的上限值)和LargeChange(大距离移动值)。 5. 订阅滚动条控件的事件,如Scroll(滚动条发生滚动时触发事件)和MouseWheel(根据滚轮滚动方向滚动滚动条)。 6. 在事件处理方法中,根据滚动条的值和滚动方向,对自定义控件进行滚动操作。 以上是两种常见的实现滚动条功能的方法。您可以根据自己的需求选择其中一种或根据具体情况进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值