串口通訊(Serial Communication)是一種常見的硬件設備與計算機之間的數據傳輸方式,廣泛應用于工業控制、嵌入式系統、傳感器數據采集等領域。本文將詳細介紹如何使用C#實現基于串口通訊的數據發送和接收,并結合代碼示例解析其實現過程。
1. 概述
串口通訊的核心是System.IO.Ports.SerialPort類,它封裝了串口操作的底層細節,提供了簡單易用的接口。以下是串口通訊的基本流程:
1.初始化串口:設置串口參數(如波特率、數據位、停止位等)。
2.打開串口:通過SerialPort.Open方法打開串口。
3.發送數據:通過SerialPort.Write方法向串口發送數據。
4.接收數據:通過SerialPort.DataReceived事件異步接收數據。
5.處理數據:對接收到的數據進行解析和處理。
2. 關鍵技術點
2.1 SerialPort類
SerialPort是C#中用于實現串口通訊的核心類,提供了發送和接收數據的方法。
2.2 異步接收數據
通過SerialPort.DataReceived事件異步接收數據,避免阻塞主線程。
2.3 數據解析
接收到的數據通常是字節數組(byte[]),需要根據協議格式進行解析。
2.4 事件機制
通過事件機制將接收到的數據傳遞給其他模塊處理。
3. 代碼實現
以下是基于串口通訊實現數據發送和接收的代碼示例。
3.1 SerialPortHelper類
SerialPortHelper類負責初始化串口、發送數據、接收數據以及處理數據。
public class SerialPortHelper
{private SerialPort serialPort; // 串口對象private List<byte> _buffer = new List<byte>(); // 數據緩沖區/// <summary>/// 自定義串口消息接收事件/// </summary>public event ReceiveDataEventHandler ReceiveDataEvent;public SerialPortHelper(){serialPort = new SerialPort();}/// <summary>/// 獲取當前計算機所有的串行端口名/// </summary>public static string[] GetPortArray(){return SerialPort.GetPortNames(); // 獲取所有可用串口}/// <summary>/// 設置串口參數/// </summary>public void SetSerialPort(string portName, int baudrate, Parity parity, int databits, StopBits stopBits){serialPort.PortName = portName; // 端口名serialPort.BaudRate = baudrate; // 波特率serialPort.Parity = parity; // 奇偶校驗serialPort.DataBits = databits; // 數據位serialPort.StopBits = stopBits; // 停止位serialPort.DataReceived += ReceiveDataMethod; // 訂閱數據接收事件}/// <summary>/// 打開串口/// </summary>public void Open(){try{serialPort.Open(); // 打開串口}catch (Exception ex){Console.WriteLine("Error opening serial port: " + ex.Message);}}/// <summary>/// 關閉串口/// </summary>public void Close(){serialPort.Close(); // 關閉串口}/// <summary>/// 發送數據(字節數組)/// </summary>public void SendDataMethod(byte[] data){if (!serialPort.IsOpen){Open(); // 如果串口未打開,則先打開}serialPort.Write(data, 0, data.Length); // 發送數據}/// <summary>/// 發送數據(字符串)/// </summary>public void SendDataMethod(string data){if (!serialPort.IsOpen){Open(); // 如果串口未打開,則先打開}serialPort.Write(data); // 發送字符串}/// <summary>/// 數據接收事件處理方法/// </summary>private void ReceiveDataMethod(object sender, SerialDataReceivedEventArgs e){try{byte[] dataChunk = new byte[serialPort.BytesToRead]; // 讀取緩沖區中的數據serialPort.Read(dataChunk, 0, dataChunk.Length);_buffer.AddRange(dataChunk); // 將數據添加到緩沖區while (_buffer.Count >= 3) // 確保緩沖區中有足夠的數據{byte thirdByte = _buffer[1]; // 獲取第三個字節(功能碼)if (thirdByte == 0x03) // 功能碼0x03{if (_buffer.Count >= 19) // 檢查是否有完整的數據包{byte[] completePacket = _buffer.GetRange(0, 19).ToArray(); // 提取完整數據包TriggerReceiveDataEvent(completePacket); // 觸發接收事件_buffer.RemoveRange(0, 19); // 移除已處理的數據}else{break; // 數據不足,等待更多數據}}else if (thirdByte == 0x10 || thirdByte == 0x06) // 功能碼0x10或0x06{byte[] dataToProcess = _buffer.ToArray(); // 處理整個緩沖區TriggerReceiveDataEvent(dataToProcess); // 觸發接收事件_buffer.Clear(); // 清空緩沖區}else{_buffer.RemoveRange(0, 3); // 移除無法識別的數據}}}catch (Exception ex){Console.WriteLine("Error processing serial port data: " + ex.Message);}}/// <summary>/// 觸發接收數據事件/// </summary>private void TriggerReceiveDataEvent(byte[] data){if (ReceiveDataEvent != null){ReceiveDataEventArg arg = new ReceiveDataEventArg(data); // 創建事件參數ReceiveDataEvent.Invoke(this, arg); // 觸發事件}}
}
3.2 ReceiveDataEventArg類
ReceiveDataEventArg類用于封裝接收到的數據,并作為事件參數傳遞。
public class ReceiveDataEventArg : EventArgs
{public byte[] Data { get; set; } // 接收到的數據public ReceiveDataEventArg(byte[] data){Data = data; // 初始化數據}
}
3.3 主窗體(MainWindow)
主窗體負責初始化SerialPortHelper并處理接收到的數據。
public partial class MainWindow : Window
{private SerialPortHelper serialPortHelper;public MainWindow(){InitializeComponent();SettingComPorts(); // 初始化串口}private void SettingComPorts(){string portName = "COM8"; // 串口名稱int baudRate = 115200; // 波特率Parity parity = Parity.None; // 奇偶校驗int dataBits = 8; // 數據位StopBits stopBits = StopBits.One; // 停止位serialPortHelper = new SerialPortHelper();serialPortHelper.SetSerialPort(portName, baudRate, parity, dataBits, stopBits); // 設置串口參數serialPortHelper.Open(); // 打開串口serialPortHelper.ReceiveDataEvent += ReceiveDataEvent; // 訂閱接收數據事件}/// <summary>/// 接收數據事件處理方法/// </summary>private void ReceiveDataEvent(object sender, ReceiveDataEventArg e){byte[] receivedData = e.Data; // 獲取接收到的數據if (receivedData[1] == 0x03) // 功能碼0x03{int receiveDataLength = receivedData[2]; // 獲取有效數據長度byte[] receiveDataBuffer = new byte[receiveDataLength];Array.Copy(receivedData, 3, receiveDataBuffer, 0, receiveDataLength); // 提取有效數據ushort[] units = messageData.GetUnitsFromByteArray(receiveDataBuffer); // 解析數據if (units != null){List<ChannelData> channelDatas = databaseHelper.GetUUTInfo(units); // 獲取設備信息UpdateDeviceInfo(channelDatas); // 更新UI}}}
}
4. 數據傳遞流程詳解
4.1 初始化串口
在SettingComPorts方法中,設置串口參數并打開串口。
訂閱ReceiveDataEvent事件以接收數據。
4.2 發送數據
通過SendDataMethod方法向串口發送數據。
4.3 接收數據
串口接收到數據后,觸發ReceiveDataMethod方法。
將接收到的數據添加到緩沖區,并根據功能碼解析數據。
4.4 處理數據
在ReceiveDataEvent方法中,解析接收到的數據并更新UI。
5. 關鍵技術解析
5.1 異步接收數據
通過SerialPort.DataReceived事件異步接收數據,避免阻塞主線程。
5.2 數據解析
根據功能碼(如0x03、0x06)解析接收到的字節數組,提取有效數據。
5.3 事件機制
通過事件將接收到的數據傳遞給主窗體或其他模塊處理。
6. 總結
本文詳細介紹了如何使用C#實現基于串口通訊的數據發送和接收。通過SerialPort類,我們可以輕松實現串口通訊,并結合事件機制實現數據的傳遞和處理。串口通訊適用于硬件設備與計算機之間的數據傳輸,是工業控制和嵌入式系統開發中的重要技術。
希望這篇文章對您有所幫助!如果有任何問題,歡迎在評論區留言討論。