.NET Framework 4.0和Visual Studio 2010的串口通信类
核心功能
- 后台线程接收数据 - 不阻塞主线程,持续监听串口
- 16进制转换 - 提供完整的byte[]和16进制字符串互转功能
- 等待指定响应 -
SendCommandAndWaitResponse
方法支持多种期望响应 - 事件驱动 - 通过事件机制实时通知数据接收
主要方法
- 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);}}
}