C# 实现串口通讯实现方式以及用途(二)

前面大概讲了说到串口类型的特性、优缺点外,当下看看怎么通过C#代码,如何建立串口通讯。以下是 ​​C# 串口通信​​简单实现,有基础配置、数据收发、错误处理及完整代码示例

一、实现方案

1. 基础实现步骤
  1. 添加引用
    在项目中添加对System.IO.Ports的引用(默认已包含在.NET Framework中,.NET Core/5+需手动添加)。
    如打开/关闭端口、读写数据、配置参数等

  2. 配置串口参数

    using System.IO.Ports;
    
    SerialPort serialPort = new SerialPort
    {
        PortName = "COM3",    // 串口号(根据设备实际端口修改)
        BaudRate = 9600,      // 波特率(需与设备一致)
        Parity = Parity.None, // 校验位(None/Even/Odd/Mark/Space)
        DataBits = 8,         // 数据位(5~8)
        StopBits = StopBits.One, // 停止位(One/Two/OnePointFive)
        Handshake = Handshake.None, // 流控制(None/XOnXOff/RequestToSend等)
        ReadTimeout = 500,    // 读取超时(毫秒,-1为无限)
        WriteTimeout = 500    // 写入超时(毫秒)
    };
    
  3. 打开串口

    try
    {
        serialPort.Open();
        Console.WriteLine("串口已打开");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"打开串口失败: {ex.Message}");
    }
    
  4. 发送数据

    // 发送字符串(自动转换为字节)
    serialPort.WriteLine("Hello SerialPort!");
    
    // 发送字节数组
    byte[] data = { 0x01, 0x02, 0x03 };
    serialPort.Write(data, 0, data.Length);
    
  5. 接收数据(事件驱动)

    serialPort.DataReceived += (sender, e) =>
    {
        // 在单独线程中触发,需注意线程安全
        try
        {
            string receivedData = serialPort.ReadExisting();
            Console.WriteLine($"接收到数据: {receivedData}");
        }
        catch (TimeoutException)
        {
            Console.WriteLine("读取超时");
        }
    };
    
  6. 关闭串口

    if (serialPort.IsOpen)
    {
        serialPort.Close();
        Console.WriteLine("串口已关闭");
    }
    

2. 异步操作优化
  • 异步读写
    使用异步方法避免阻塞主线程(适用于UI应用如WinForms/WPF):

    await serialPort.BaseStream.WriteAsync(data, 0, data.Length);
    await serialPort.BaseStream.FlushAsync();
    
  • 异步流(.NET 6+)
    使用ReadAsyncWriteAsync结合异步流处理大数据:

    public async Task ReadAsync()
    {
        var buffer = new byte[1024];
        while (serialPort.IsOpen)
        {
            int bytesRead = await serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length);
            if (bytesRead > 0)
            {
                // 处理接收到的数据
            }
        }
    }
    

二、注意事项

  1. 端口冲突

    • 确保串口未被其他程序占用(如设备管理器或后台服务)。
    • 使用SerialPort.GetPortNames()获取可用端口列表。
  2. 参数一致性

    • 波特率、数据位、停止位、校验位必须与设备完全一致,否则数据可能损坏。
  3. 线程安全

    • DataReceived事件在后台线程触发,更新UI时需使用InvokeDispatcher
      // 在WPF中
      Application.Current.Dispatcher.Invoke(() => 
      {
          textBox.Text += receivedData;
      });
      
  4. 超时处理

    • 设置合理的ReadTimeoutWriteTimeout,避免无限等待。
  5. 异常处理

    • 捕获UnauthorizedAccessException(端口被占用)、IOException(端口不存在或损坏)等异常。
  6. 资源释放

    • 使用using语句确保SerialPort正确关闭:
      using (SerialPort sp = new SerialPort("COM3", 9600))
      {
          // 配置并打开端口
      } // 自动关闭端口
      

三、扩展技术

1. 跨平台与现代化框架
  • .NET MAUI/Blazor
    在跨平台应用中使用System.IO.Ports(需依赖平台特定库,如Linux的/dev/ttyACM0)。
  • .NET Core/5+的异步流
    利用IAsyncEnumerable<T>实现流式数据处理:
    public async IAsyncEnumerable<byte[]> ReadStream()
    {
        while (serialPort.IsOpen)
        {
            byte[] buffer = new byte[1024];
            int bytesRead = await serialPort.BaseStream.ReadAsync(buffer);
            if (bytesRead > 0)
            {
                yield return buffer;
            }
        }
    }
    
2. 协议与数据处理
  • 协议解析框架
    使用开源库如Modbus.NETNModbus处理工业协议(如Modbus RTU/ASCII)。
  • 数据校验与加密
    在应用层添加CRC校验(如BitConverter计算CRC16)或AES加密。
3. 与物联网集成
  • 边缘计算与云平台
    将串口数据通过MQTT或HTTP协议发送到云平台(如Azure IoT Hub、AWS IoT)。
  • 设备网关
    将串口设备数据桥接到其他协议(如WebSocket、gRPC)。
4. 自动化与监控
  • 日志与监控
    使用SerilogNLog记录通讯日志,结合Prometheus/Grafana监控串口状态。
  • 单元测试与模拟
    使用Moq模拟SerialPort类,编写单元测试验证业务逻辑。
5. 低功耗与实时性优化
  • DMA传输(硬件级)
    在嵌入式设备中利用DMA(直接内存访问)提升传输效率。
  • 硬件流控制(RTS/CTS)
    启用硬件流控制(Handshake.RequestToSendXOnXOff)减少数据丢失。

四、代码示例

以下是一个完整的串口通讯示例(控制台应用):

using System;
using System.IO.Ports;

class Program
{
    static SerialPort serialPort;

    static void Main()
    {
        serialPort = new SerialPort("COM3", 9600);
        serialPort.DataReceived += SerialPort_DataReceived;

        try
        {
            serialPort.Open();
            Console.WriteLine("串口已打开,输入内容发送(输入exit退出)");

            while (true)
            {
                string input = Console.ReadLine();
                if (input.ToLower() == "exit")
                {
                    break;
                }
                serialPort.WriteLine(input);
            }
        }
        finally
        {
            serialPort.Close();
        }
    }

    private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        string data = serialPort.ReadExisting();
        Console.WriteLine($"接收数据: {data}");
    }
}

五、总结

  • 核心要点:正确配置参数、处理线程安全、异常和资源管理。
  • 未来方向:结合云平台、边缘计算、协议解析库以及自动化测试工具,提升系统可靠性与扩展性。
  • 注意事项:始终确保串口参数与设备匹配,避免硬件冲突。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜空晚星灿烂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值