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日

相关文章

  • IIS6 安装与配置.net 2.0过程的详细图解

    IIS6安装与配置.net2.0过程的详细图解 IIS6是Windows Server 2003操作系统中自带的Web服务器软件,可以用于托管ASP.NET应用程序。本文将提供详细的“IIS6安装与配置.net2.0过程的详细图解”的完整攻略,包括如何安装IIS6和配置.net2.0,以及示例。 安装IIS6 以下是安装IIS6的步骤: 打开“控制面板”-&…

    C# 2023年5月15日
    00
  • C#连接到sql server2008数据库的实例代码

    下面是连接到SQL Server 2008数据库的C#代码实例。 示例1:使用SQLConnection连接数据库 添加引用:在Visual Studio中,选择“解决方案资源管理器”,右键单击“引用”文件夹,选择“添加引用”,在“添加引用”对话框中选择“System.Data.SqlClient”引用,点击“确定”按钮。 编写C#代码:代码实现步骤如下: …

    C# 2023年6月2日
    00
  • WinForm中DefWndProc、WndProc与IMessageFilter的区别

    WinForm是Windows Forms的缩写,是基于Windows的用户界面框架,提供了一个可视化的设计工具。在WinForm中,程序的窗口消息都是通过消息循环和窗口过程来处理的。其中DefWndProc、WndProc和IMessageFilter都是处理窗口消息的重要概念。接下来我将针对这三个概念进行详细讲解: DefWndProc DefWndPr…

    C# 2023年6月7日
    00
  • C#中TransactionScope的使用小结

    C#中TransactionScope的使用小结 1. 什么是TransactionScope TransactionScope是C#中一个用于管理事务的类,位于System.Transactions命名空间中。它可以让多条语句成为一个事务,从而保证在一个事务中,要么所有语句都执行成功,要么全部失败。 2. TransactionScope的使用方法 步骤1…

    C# 2023年5月15日
    00
  • 详解ASP.NET Core 之 Identity 入门(一)

    下面是“详解ASP.NET Core 之 Identity 入门(一)”的完整攻略: 什么是ASP.NET Core Identity? ASP.NET Core Identity是一个身份验证和授权框架,用于管理用户身份验证和授权。它提供了一组API和UI组件,用于注册、登录、注销、管理用户和角色等方面。 如何使用ASP.NET Core Identity…

    C# 2023年5月16日
    00
  • 一文带你吃透C#中面向对象的相关知识

    一文带你吃透C#中面向对象的相关知识 什么是面向对象 面向对象编程是一种编程方法和思想,它的核心是将事物抽象为对象,并通过对象之间的交互来完成任务。在C#中,一切皆为对象,包括类和结构体等用户定义的类型,以及基本类型如int,float等。 类与对象 类是创建对象的模板,它定义了对象的属性和方法。对象是类的实例,它是内存中分配的一块区域,可以存储类的属性值。…

    C# 2023年5月14日
    00
  • C# Clear():从 ICollection中移除所有元素

    C#Clear()方法详解 在C#中,Clear()是一个常用的方法,其函数签名为:public void Clear()。这个方法用于清除List集合中的所有元素,使其变为空集合。 具体而言,Clear()方法做两个主要方面的操作:删除所有元素,以及释放元素占用的存储空间。 下面,我们就详细介绍Clear()方法的使用。 基础用法 在 List 的对象上,…

    C# 2023年4月19日
    00
  • 在.NET中读取嵌入和使用资源文件的方法

    在.NET开发中,嵌入和使用资源文件是一个非常有用的技巧。利用资源文件,可以将特定的文件嵌入到程序集(.dll或.exe文件)中,使得程序的部署和维护更加方便。本文将详细讲解在.NET中读取嵌入和使用资源文件的方法。 嵌入资源文件 1.创建资源文件 需要将待嵌入的文件添加到资源文件中。创建资源文件的方法有两种: 手动创建:在Visual Studio中右键项…

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