2023年最后一天,来一波C#中的串口通讯SerialPort基本操作

开篇碎碎念

今天要要写的是 C# 中可以用来实现串口通信的 SerialPort 类。这个 demo 在很久之前就写了,当时是需要调试串口间发送和接收的消息,后面用到了 sscom 工具,心血来潮模仿这个工具写了一个pdd版的串口调试工具。

串口通信在各领域都有广泛的应用,下面我将使用 System.IO.Ports 命名空间提供的 SerialPort 类来简单演示如何在 C# 中使用串口通信。

基本认识

在使用 SerialPort 类进行串口通信时,可以配置的属性有:

  • PortName: 串口名称,如"COM1"
  • BaudRate:波特率,表示每秒发送的位数,常见的波特率有9600、115200等
  • Parity:奇偶校验位。可以选择 None(无校验)、Even(偶校验)和Odd(奇校验)
  • DataBits:数据位的位数,常见值为8
  • StopBits:停止位的位数,常见值由None(无停止位)、One(1位停止位)、Two(2位停止位)
  • readTimeout:读取操作的超时时间
  • writeTimeout:写入操作的超时时间

常用方法:

  • public static string[] GetPortNames()

    获取当前计算机上可用的串口名称数组

  • public void Open()

    打开串口以建立连接

  • public int Read(byte[] buffer, int offset, int count)

    从串口读取指定数量的字节数据,并存储到缓冲区中

  • public int ReadChar()

    从串口读取一个字符

  • BytesToRead()

    获取当前串口接收缓冲区中可用的字节数

  • public int Read(char[] buffer, int offset, int count)

    从串口读取指定数量的字符,并存储到指定的缓冲区中

  • BytesToWrite()

    获取当前串口发送缓冲区中待发送的bytes

  • public void Write(string text)

    向串口写入字符串

  • public void Write(char[] buffer, int offset, int count)

    向串口写入指定数量的字符数据

  • public void WriteLine(string text)

    向串口写入字符串并在末尾添加换行符

  • public void DiscardInBuffer()

    清空串口接收缓冲区中的数据

  • public void DiscardOutBuffer()

    清空串口发送缓冲区中的数据

  • public void Close()

    关闭串口连接

正餐开始

UI界面

新建窗体应用,创建 SerialPort 控件,并在工具箱中拉出button等相关控件,创建如下 WinForm 应用界面

串口扫描

先写一个活动串口扫描,实现自动扫描COM口,并设置 comboBox 初始值。由于本机上只有一个串口COM3,这里我使用虚拟串口工具Virtual Serial Port Driver 创建了4个串口。

ini 复制代码
private void getAvailablePort()
{
    try
    {
        string[] serialPorts = SerialPort.GetPortNames();
        if(serialPorts.Length == 0)
        {
            throw (new System.IO.IOException("this device doesn't have any port!"));
        }
        if(serialPorts != null && serialPorts.Length != 0)
        {
            Array.Sort<String>(serialPorts);
            foreach(String port in serialPorts)
            {
                if(port != null && port.Length != 0)
                {
                    comboBox1.Items.Add(port);
                }
                Console.WriteLine(port);
            }
            comboBox1.SelectedIndex = 0;
        }
    }
    catch(System.IO.IOException e)
    {
        MessageBox.Show(e.Message);
    }
}
​
private void portInit()
{
    getAvailablePort();
    //设置初始显示的值
    comboBox2.SelectedIndex = 6;
    comboBox3.SelectedIndex = 2;
    comboBox4.SelectedIndex = 0;
    comboBox5.SelectedIndex = 0;
}

打开串口

扫描到COM口后,选择一个打开,下面选择COM1,并写好波特率、数据位等对应的配置,进行配置,最后调用Open()方法打开串口

数据发送和接收

接下来写发送按钮click事件处理程序,获取到发送框输入的数据并存储在str中,再使用String.Split方法将输入字符串按空格拆分为十六进制数,并将所有的十六进制数对存储在一个List中。后面在转换过程中,使用了byte.Parse方法,用来接收一个字符串和一个指定的十六进制格式的参数来解析十六进制数对。

接收框获取数据这里,由于想减少UI刷新,便先将接收到的数据先存储在一个缓冲区中,并在合适时机使用BeginInvoke方法将UI刷新放到UI线程执行。

csharp 复制代码
private List<string> GetHexPairs(string str)
{
    List<string> hexPairs = new List<string>();
    string[] strArray = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    foreach(string hexPair in strArray)
    {
        hexPairs.Add(hexPair);
    }
    return hexPairs;
}
private byte ConvertHexPairToByte(string hexPair)
{
    return Convert.ToByte(hexPair, 16);
}
private void button1_Click(object sender, EventArgs e)
{
    string str = textBox7.Text.Trim();
    if (serialPort1.IsOpen)
    {
        try
        {
            foreach(var hexPair in GetHexPairs(str))
            {
                byte data = ConvertHexPairToByte(hexPair);
                serialPort1.Write(new byte[] { data }, 0, 1);
            }
        }
        catch (FormatException)
        {
            MessageBox.Show("输入的16进制数数据格式错误!");
        }
        catch (Exception ex)
        {
            MessageBox.Show($"串口发送失败,系统将关闭当前串口错误!\n {ex.Message}");
            serialPort1.Close();
        }
    }
}
​
private StringBuilder receivedDataBuffer = new StringBuilder();
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    int bufferSize = serialPort1.BytesToRead;
    byte[] buffer = new byte[bufferSize];
    serialPort1.Read(buffer, 0, bufferSize);
​
    foreach(byte data in buffer)
    {
        string hex = data.ToString("X2"); 
        // 以空格分割并添加到缓冲区,避免频繁UI更新
        receivedDataBuffer.Append(hex).Append(' ');
    }
    // 将UI更新操作放入UI线程执行
    BeginInvoke(new Action(() =>
    {
        textBox6.AppendText(receivedDataBuffer.ToString());
        textBox6.AppendText(Environment.NewLine);
    }));
    serialPort1.DiscardInBuffer(); 
}

最终效果如下:

最后

本示例只是简单介绍了 C# 中 SerialPort 串口控件的扫描、打开、数据发送和接收。对这方面有兴趣的伙伴可以参考一下,对于文中出现的不足或可优化之处,欢迎大家评论吐槽!最后,祝大家新年快乐,工作顺心,同事有趣~

相关推荐
2401_8576363925 分钟前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
2401_857610035 小时前
多维视角下的知识管理:Spring Boot应用
java·spring boot·后端
代码小鑫5 小时前
A027-基于Spring Boot的农事管理系统
java·开发语言·数据库·spring boot·后端·毕业设计
颜淡慕潇6 小时前
【K8S问题系列 | 9】如何监控集群CPU使用率并设置告警?
后端·云原生·容器·kubernetes·问题解决
独泪了无痕6 小时前
WebStorm 如何调试 Vue 项目
后端·webstorm
怒放吧德德8 小时前
JUC从实战到源码:JMM总得认识一下吧
java·jvm·后端
代码小鑫8 小时前
A025-基于SpringBoot的售楼管理系统的设计与实现
java·开发语言·spring boot·后端·毕业设计
前端SkyRain8 小时前
后端SpringBoot学习项目-项目基础搭建
spring boot·后端·学习
梦想画家8 小时前
理解Rust 生命周期、所有权和借用机制
开发语言·后端·rust