c# 使用线程对串口serialPort进行收发数据(四种)

下面将给出“C# 使用线程对串口SerialPort进行收发数据(四种)”的详细攻略。

一、准备工作

在进行串口收发数据的处理前,需要进行一些准备工作:

  1. 引入System.IO.Ports命名空间;
  2. 创建SerialPort对象,配置串口参数;
  3. 确保串口已正常打开。

二、使用线程进行串口数据收发

1. 使用Thread

使用Thread类可以使代码执行在一个单独的线程上,从而不影响UI的响应。以SerialPort为例,在线程中使用SerialPort对串口进行数据读取和写入。

using System.IO.Ports;
using System.Threading;

private SerialPort serialPort;

// 在构造函数中初始化SerialPort并打开串口
public Form1()
{
    InitializeComponent();
    serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
    serialPort.Open();
}

// 线程函数:读取串口数据
private void ReadSerialPort()
{
    while (true)
    {
        int length = serialPort.BytesToRead;
        if (length > 0)
        {
            byte[] buffer = new byte[length];
            serialPort.Read(buffer, 0, length);
            // 处理接收到的数据
        }
    }
}

// 线程函数:写入串口数据
private void WriteSerialPort(byte[] data)
{
    if (serialPort != null && serialPort.IsOpen)
    {
        serialPort.Write(data, 0, data.Length);
    }
}

// 在需要的地方启动串口数据读取线程
Thread readThread = new Thread(ReadSerialPort);
readThread.Start();

// 在需要写入串口数据的地方调用该函数,注意要在UI线程中调用
private void SendMessage()
{
    byte[] data = Encoding.ASCII.GetBytes("hello");
    Thread writeThread = new Thread(() => WriteSerialPort(data));
    writeThread.Start();
}

2. 使用BackgroundWorker

BackgroundWorker类提供了一些简单的方法和事件,使使用线程变得更加容易。它还带有取消和进度更新的支持。以SerialPort为例,在BackgroundWorkerDoWork事件中使用SerialPort对串口进行数据读取和写入。

using System.ComponentModel;
using System.IO.Ports;

private SerialPort serialPort;
private BackgroundWorker readWorker;

// 在构造函数中初始化SerialPort并打开串口
public Form1()
{
    InitializeComponent();
    serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
    serialPort.Open();
    readWorker = new BackgroundWorker();
    readWorker.DoWork += new DoWorkEventHandler(ReadSerialPort);
    readWorker.RunWorkerAsync();
}

// 事件处理函数:读取串口数据
private void ReadSerialPort(object sender, DoWorkEventArgs e)
{
    while (true)
    {
        int length = serialPort.BytesToRead;
        if (length > 0)
        {
            byte[] buffer = new byte[length];
            serialPort.Read(buffer, 0, length);
            // 处理接收到的数据
        }
    }
}

// 在需要写入串口数据的地方调用该函数,注意要在UI线程中调用
private void SendMessage()
{
    byte[] data = Encoding.ASCII.GetBytes("hello");
    serialPort.Write(data, 0, data.Length);
}

3. 使用Task

Task类将代替Thread,是一个高层次的异步API,旨在简化异步编程模式并提高可重用性和互操作性。可以使用Task.Run方法,将一个异步方法运行在新的Task上下文中。以SerialPort为例,在Task中使用SerialPort对串口进行数据读取和写入。

using System.IO.Ports;
using System.Threading.Tasks;

private SerialPort serialPort;
private CancellationTokenSource readCancellationTokenSource;

// 在构造函数中初始化SerialPort并打开串口
public Form1()
{
    InitializeComponent();
    serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
    serialPort.Open();
    readCancellationTokenSource = new CancellationTokenSource();
    Task.Run(() => ReadSerialPortAsync(readCancellationTokenSource.Token));
}

// 异步函数:读取串口数据
private async Task ReadSerialPortAsync(CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        int length = serialPort.BytesToRead;
        if (length > 0)
        {
            byte[] buffer = new byte[length];
            serialPort.Read(buffer, 0, length);
            // 处理接收到的数据
        }
        await Task.Delay(10);
    }
}

// 在需要写入串口数据的地方调用该函数,注意要在UI线程中调用
private void SendMessage()
{
    byte[] data = Encoding.ASCII.GetBytes("hello");
    serialPort.Write(data, 0, data.Length);
}

4. 使用ThreadPool

ThreadPool是一个多线程执行的技巧,可重复使用的线程池。使用ThreadPool可避免线程创建和销毁所带来的额外消耗,提高线程利用率。以SerialPort为例,在ThreadPool线程池中使用SerialPort对串口进行数据读取和写入。

using System.IO.Ports;
using System.Threading;

private SerialPort serialPort;

// 在构造函数中初始化SerialPort并打开串口
public Form1()
{
    InitializeComponent();
    serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
    serialPort.Open();
    ThreadPool.QueueUserWorkItem(new WaitCallback(ReadSerialPort));
}

// 线程函数:读取串口数据
private void ReadSerialPort(Object stateInfo)
{
    while (true)
    {
        int length = serialPort.BytesToRead;
        if (length > 0)
        {
            byte[] buffer = new byte[length];
            serialPort.Read(buffer, 0, length);
            // 处理接收到的数据
        }
    }
}

// 在需要写入串口数据的地方调用该函数,注意要在UI线程中调用
private void SendMessage()
{
    byte[] data = Encoding.ASCII.GetBytes("hello");
    ThreadPool.QueueUserWorkItem(new WaitCallback(WriteSerialPort), data);
}

// 线程函数:写入串口数据
private void WriteSerialPort(Object stateInfo)
{
    byte[] data = (byte[])stateInfo;
    if (serialPort != null && serialPort.IsOpen)
    {
        serialPort.Write(data, 0, data.Length);
    }
}

三、线程安全

在对串口进行读写操作时,需要注意线程安全。

  1. 对于读操作,先检查缓冲区中的数据是否可供读取,若可读,则读取串口数据;否则等待新数据到达。
  2. 对于写操作,建议使用线程安全的队列来存储将要写入串口的数据,使用线程安全的方式在SerialPort.DataReceived事件中写入队列。

示例代码:

using System.Collections.Concurrent;
using System.IO.Ports;
using System.Threading;

private SerialPort serialPort;
private ConcurrentQueue<byte[]> dataQueue;

// 在构造函数中初始化SerialPort并打开串口
public Form1()
{
    InitializeComponent();
    serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
    serialPort.Open();
    dataQueue = new ConcurrentQueue<byte[]>();
    serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
}

// 事件处理函数:串口数据到达
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    byte[] buffer = new byte[serialPort.BytesToRead];
    serialPort.Read(buffer, 0, buffer.Length);
    dataQueue.Enqueue(buffer); // 加入队列
}

// 线程函数:处理串口数据
private void ProcessSerialData()
{
    while (true)
    {
        byte[] data;
        if (dataQueue.TryDequeue(out data))
        {
            // 处理接收到的数据
        }
        else
        {
            Thread.Sleep(10); // 队列为空,延时等待
        }
    }
}

// 在需要写入串口数据的地方调用该函数,注意要在UI线程中调用
private void SendMessage()
{
    byte[] data = Encoding.ASCII.GetBytes("hello");
    dataQueue.Enqueue(data);
}

// 在需要处理串口数据的地方启动线程
Thread processThread = new Thread(ProcessSerialData);
processThread.Start();

以上就是使用线程进行串口收发数据的详细攻略,希望对您有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c# 使用线程对串口serialPort进行收发数据(四种) - Python技术站

(0)
上一篇 2023年6月7日
下一篇 2023年6月7日

相关文章

  • 你了解C#的协变和逆变吗,看完这篇就懂了

    C#的协变和逆变是在面向对象里面的类型系统中的概念。在C# 2.0之前,这两个概念是不存在的,开发者只能通过强制类型转换来满足某些需求。在C# 2.0之后,引入了这两个概念,通过它们可以更加安全地进行类型转换,同时也提升了代码的可读性。 一、协变: 协变指的是能够将一个派生类的变量赋值给基类的变量,或者能够将一个方法的返回值类型声明为基类的类型。它的形态如下…

    C# 2023年5月15日
    00
  • 关于C# 5.0 CallerMemberName CallerFilePath CallerLineNumber 在.NET4中的使用介绍方法

    C# 5.0 CallerMemberName CallerFilePath CallerLineNumber 在.NET4中的使用介绍方法 在C# 5.0及以上版本中,通过使用CallerMemberName、CallerFilePath和CallerLineNumber特性,可以在方法内部获取调用该方法的成员、代码文件名以及代码行号等信息,便于对代码进行…

    C# 2023年6月1日
    00
  • c# WPF如何实现滚动显示的TextBlock

    要实现滚动显示的TextBlock,可以使用WPF中的ScrollViewer和TextBlock结合使用。ScrollViewer是一个滚动视图容器,可以将其在需要滚动的控件周围包装起来,从而实现滚动效果。 下面是实现过程: 第一步:在XAML文件中,在需要滚动显示的TextBlock周围加入ScrollViewer容器,同时设置VerticalScrol…

    C# 2023年6月6日
    00
  • C# 输出参数out问题

    当我们在C#中使用方法时,有时需要从方法中返回多个值。但是,C#中的方法只能够返回单个值。为了解决这一问题,我们可以使用输出参数(out parameter)。在这篇攻略中,我会详细讲解“C# 输出参数out问题”的相关内容。 输出参数(out parameter)是什么? 输出参数是C#中一种特殊的参数类型,用于从方法中返回多个值。和普通参数不同,输出参数…

    C# 2023年6月7日
    00
  • C# Linq的Select()方法 – 将序列中的每个元素投影到新形式中

    C# Linq中的Select()是一个用于在查询中选择特定数据,提取它们并创建新的数据结构的方法。该方法可以将集合、列表、数组等多种数据类型中的数据进行选择、投影、转换和过滤,在实际应用中非常实用。下面是详细讲解C#Linq的Select()的完整攻略: 一、Select()简介 Select()方法是Linq中最常用的方法之一,用于对序列中的每个元素应用…

    C# 2023年4月19日
    00
  • asp .net core静态文件资源的深入讲解

    ASP.NET Core静态文件资源的深入讲解 在ASP.NET Core应用程序中,静态文件资源是非常重要的方面。静态文件资源包括CSS、JavaScript、图像和其他文件,它们通常不需要经过服务器端处理,可以直接从磁盘或CDN中提供给客户端。在本攻略中,我们将深入讲解如何在ASP.NET Core应用程序中使用静态文件资源,并提供两个示例说明。 准备工…

    C# 2023年5月17日
    00
  • Asp.Net MVC学习总结之过滤器详解

    Asp.Net MVC学习总结之过滤器详解 在Asp.Net MVC中,过滤器是一种用于在请求处理过程中执行某些操作的机制。过滤器可以用于实现各种功能,例如身份验证、授权、日志记录等。本文将详细介绍Asp.Net MVC中的过滤器,并提供两个示例说明。 过滤器类型 在Asp.Net MVC中,有以下几种过滤器类型: Authorization Filter:…

    C# 2023年5月17日
    00
  • C#模拟实现QQ窗体功能

    C#模拟实现QQ窗体功能攻略 简介 随着互联网的发展,”QQ社交”已经成为我们日常生活中不可或缺的一部分。在众多QQ客户端中,QQ窗口是其中一款使用最为频繁,且功能最为复杂的应用程序。 本文将详细介绍如何使用C#模拟实现QQ窗体功能,并将分步骤以示例的形式进行说明。 准备设备和环境 在开始实验之前,需要准备好以下基本设备和环境: 一台Windows PC V…

    C# 2023年6月7日
    00
合作推广
合作推广
分享本页
返回顶部