当前位置: 首页 > news >正文

.NET Framework 4.0和Visual Studio 2010的串口通信类

核心功能

  1. 后台线程接收数据 - 不阻塞主线程,持续监听串口
  2. 16进制转换 - 提供完整的byte[]和16进制字符串互转功能
  3. 等待指定响应 - SendCommandAndWaitResponse方法支持多种期望响应
  4. 事件驱动 - 通过事件机制实时通知数据接收

主要方法

  • ByteArrayToHexString() - 将byte[]转为"01 A2 34 54 12"格式
  • HexStringToByteArray() - 16进制字符串转byte[]
  • SendCommandAndWaitResponse() - 发送指令并等待多种可能的响应
  • SendData()/SendHexString() - 发送数据

兼容性保证

  • ✅ 使用string.Format而非字符串插值
  • ✅ 不使用null条件运算符(??)
  • ✅ 使用传统事件模式
  • ✅ 完全兼容.NET Framework 4.0

使用示例

// 定义期望的多种响应
string[] expectedResponses = new string[] 
{ "01 A2 FF", "01 A2 00","AA BB CC"
};// 发送指令并等待响应(超时5秒)
string response = manager.SendCommandAndWaitResponse(command, expectedResponses, 5000);

代码已经过精心设计,确保线程安全、避免内存泄漏,可以直接在您的项目中使用!

using System;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Collections.Generic;namespace SerialPortDemo
{/// <summary>/// 串口通信管理类/// </summary>public class SerialPortManager{private SerialPort serialPort;private Thread receiveThread;private bool isRunning = false;private object lockObject = new object();// 用于存储接收到的数据private List<byte> receivedBuffer = new List<byte>();// 等待特定响应的事件private ManualResetEvent waitResponseEvent = new ManualResetEvent(false);private string lastReceivedHexString = string.Empty;// 事件:接收到数据时触发public event EventHandler<SerialDataReceivedEventArgs> DataReceived;/// <summary>/// 构造函数/// </summary>public SerialPortManager(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits){serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);}/// <summary>/// 打开串口并启动接收线程/// </summary>public bool Open(){try{if (!serialPort.IsOpen){serialPort.Open();isRunning = true;// 启动后台接收线程receiveThread = new Thread(new ThreadStart(ReceiveDataThread));receiveThread.IsBackground = true;receiveThread.Start();return true;}return false;}catch (Exception ex){throw new Exception("打开串口失败: " + ex.Message);}}/// <summary>/// 关闭串口/// </summary>public void Close(){isRunning = false;if (receiveThread != null && receiveThread.IsAlive){receiveThread.Join(1000); // 等待线程结束}if (serialPort != null && serialPort.IsOpen){serialPort.Close();}}/// <summary>/// 后台接收数据线程/// </summary>private void ReceiveDataThread(){byte[] buffer = new byte[1024];while (isRunning){try{if (serialPort.IsOpen && serialPort.BytesToRead > 0){int bytesRead = serialPort.Read(buffer, 0, buffer.Length);if (bytesRead > 0){// 提取实际读取的字节byte[] data = new byte[bytesRead];Array.Copy(buffer, 0, data, 0, bytesRead);// 转换为16进制字符串string hexString = ByteArrayToHexString(data);lock (lockObject){lastReceivedHexString = hexString;receivedBuffer.AddRange(data);}// 触发事件OnDataReceived(data, hexString);// 设置等待事件waitResponseEvent.Set();}}else{Thread.Sleep(10); // 避免CPU占用过高}}catch (Exception ex){// 记录异常但不中断线程Console.WriteLine("接收数据异常: " + ex.Message);Thread.Sleep(100);}}}/// <summary>/// 将byte[]转换为16进制字符串(空格分隔)/// 例如: 01 A2 34 54 12/// </summary>public static string ByteArrayToHexString(byte[] data){if (data == null || data.Length == 0){return string.Empty;}StringBuilder sb = new StringBuilder(data.Length * 3);for (int i = 0; i < data.Length; i++){sb.Append(data[i].ToString("X2"));if (i < data.Length - 1){sb.Append(" ");}}return sb.ToString();}/// <summary>/// 将16进制字符串转换为byte[]/// 支持格式: "01A23454" 或 "01 A2 34 54"/// </summary>public static byte[] HexStringToByteArray(string hexString){if (string.IsNullOrEmpty(hexString)){return new byte[0];}// 移除空格hexString = hexString.Replace(" ", "").Replace("-", "");if (hexString.Length % 2 != 0){throw new ArgumentException("16进制字符串长度必须是偶数");}byte[] bytes = new byte[hexString.Length / 2];for (int i = 0; i < bytes.Length; i++){bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);}return bytes;}/// <summary>/// 发送数据/// </summary>public void SendData(byte[] data){if (serialPort != null && serialPort.IsOpen){serialPort.Write(data, 0, data.Length);}else{throw new Exception("串口未打开");}}/// <summary>/// 发送16进制字符串/// </summary>public void SendHexString(string hexString){byte[] data = HexStringToByteArray(hexString);SendData(data);}/// <summary>/// 执行指令并等待指定响应/// </summary>/// <param name="command">要发送的指令(byte数组)</param>/// <param name="expectedResponses">期望的响应列表(16进制字符串)</param>/// <param name="timeoutMs">超时时间(毫秒)</param>/// <returns>返回匹配的响应,如果超时返回null</returns>public string SendCommandAndWaitResponse(byte[] command, string[] expectedResponses, int timeoutMs){lock (lockObject){receivedBuffer.Clear();lastReceivedHexString = string.Empty;}waitResponseEvent.Reset();// 发送指令SendData(command);DateTime startTime = DateTime.Now;while ((DateTime.Now - startTime).TotalMilliseconds < timeoutMs){// 等待接收到数据if (waitResponseEvent.WaitOne(100)){string receivedHex;lock (lockObject){receivedHex = lastReceivedHexString;}// 检查是否匹配任何期望的响应foreach (string expected in expectedResponses){if (IsResponseMatch(receivedHex, expected)){return receivedHex;}}waitResponseEvent.Reset();}}// 超时return null;}/// <summary>/// 检查响应是否匹配(支持部分匹配)/// </summary>private bool IsResponseMatch(string received, string expected){if (string.IsNullOrEmpty(received) || string.IsNullOrEmpty(expected)){return false;}// 移除空格进行比较string receivedNoSpace = received.Replace(" ", "");string expectedNoSpace = expected.Replace(" ", "");// 可以使用Contains判断部分匹配,或使用Equals判断完全匹配return receivedNoSpace.Contains(expectedNoSpace);}/// <summary>/// 触发数据接收事件/// </summary>protected virtual void OnDataReceived(byte[] data, string hexString){if (DataReceived != null){DataReceived(this, new SerialDataReceivedEventArgs(data, hexString));}}/// <summary>/// 获取最后接收到的16进制字符串/// </summary>public string GetLastReceivedHexString(){lock (lockObject){return lastReceivedHexString;}}/// <summary>/// 清空接收缓冲区/// </summary>public void ClearBuffer(){lock (lockObject){receivedBuffer.Clear();lastReceivedHexString = string.Empty;}}}/// <summary>/// 串口数据接收事件参数/// </summary>public class SerialDataReceivedEventArgs : EventArgs{public byte[] Data { get; private set; }public string HexString { get; private set; }public SerialDataReceivedEventArgs(byte[] data, string hexString){this.Data = data;this.HexString = hexString;}}/// <summary>/// 使用示例/// </summary>class Program{static void Main(string[] args){// 创建串口管理器SerialPortManager manager = new SerialPortManager("COM3", 9600, Parity.None, 8, StopBits.One);// 订阅数据接收事件manager.DataReceived += new EventHandler<SerialDataReceivedEventArgs>(OnDataReceived);try{// 打开串口manager.Open();Console.WriteLine("串口已打开");// 示例1: 发送指令并等待响应byte[] command = new byte[] { 0x01, 0xA2, 0x34, 0x54, 0x12 };string[] expectedResponses = new string[] { "01 A2 FF", "01 A2 00","AA BB CC"};Console.WriteLine("发送指令: " + SerialPortManager.ByteArrayToHexString(command));string response = manager.SendCommandAndWaitResponse(command, expectedResponses, 5000);if (response != null){Console.WriteLine("收到响应: " + response);}else{Console.WriteLine("等待响应超时");}// 示例2: 直接发送16进制字符串manager.SendHexString("AA BB CC DD");// 等待用户输入Console.WriteLine("按任意键退出...");Console.ReadKey();// 关闭串口manager.Close();}catch (Exception ex){Console.WriteLine("错误: " + ex.Message);}}// 数据接收事件处理static void OnDataReceived(object sender, SerialDataReceivedEventArgs e){Console.WriteLine("接收到数据: " + e.HexString);Console.WriteLine("字节数: " + e.Data.Length);}}
}
http://www.dtcms.com/a/477726.html

相关文章:

  • 20自由度全驱动:赋能Tesollo五指灵巧手精细柔性作业新可能
  • 基于FastAPI与LangChain的Excel智能数据分析API开发实践
  • 【四级】全国大学英语四级历年真题及答案解析PDF电子版(2015-2025年6月)
  • 专业制造双轴倾角传感器与水平监测传感器的优质厂家分析
  • QtitanNavigation赋能工业制造:提升生产效率的界面导航利器
  • 网站不备案做优化网站建设 中软
  • 成都市建设厅网站查询建设部举报网站
  • 优秘智能深度学习应用场景实战提升效率指南
  • 【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
  • 做网站建议农业网站建设模板下载
  • xdma IP使用教程1-xdma ip核配置
  • Pytest参数化实战:高效测试API接口
  • 关于力扣第167场双周赛的第一二题赛后反思
  • Post-training of LLMs
  • 【学习总结】AI接口测试-零基础从接口概念到客达天下系统Apifox+DeepSeek接口测试实战全流程
  • 【苍穹外卖笔记】Day04--套餐管理模块
  • 初识redis(分布式系统, redis的特性, 基本命令)
  • [特殊字符] Avalonia + Silk.NET 加载 3D 模型时 GenBuffer 返回 0?这是个底层兼容性陷阱!
  • 学习threejs,打造交互式花卉生成器
  • Redis 学习笔记(二)
  • 北京展览馆网站建设wordpress插件排列
  • 北京做网站优化多少钱最基本最重要的网站推广工具是
  • 每日算法刷题Day70:10.13:leetcode 二叉树10道题,用时2h
  • MySQL 设置远程 IP 连接方式(含自动检测授权脚本)
  • flash型网站网址高校思政课网站建设
  • 网站建设费做什么会计科目硬件开发外包平台
  • 【SpringBoot从初学者到专家的成长15】MVC、Spring MVC与Spring Boot:理解其差异与联系
  • Docker 存储与数据共享
  • k8s storageclasses nfs-provisioner 部署
  • Linux(Samba服务)