如何使用C#串口通訊實(shí)現(xiàn)數(shù)據(jù)的發(fā)送和接收
串口通訊(Serial Communication)是一種常見的硬件設(shè)備與計(jì)算機(jī)之間的數(shù)據(jù)傳輸方式,廣泛應(yīng)用于工業(yè)控制、嵌入式系統(tǒng)、傳感器數(shù)據(jù)采集等領(lǐng)域。本文將詳細(xì)介紹如何使用C#實(shí)現(xiàn)基于串口通訊的數(shù)據(jù)發(fā)送和接收,并結(jié)合代碼示例解析其實(shí)現(xiàn)過程。
1. 概述
串口通訊的核心是System.IO.Ports.SerialPort類,它封裝了串口操作的底層細(xì)節(jié),提供了簡(jiǎn)單易用的接口。以下是串口通訊的基本流程:
1.初始化串口:設(shè)置串口參數(shù)(如波特率、數(shù)據(jù)位、停止位等)。
2.打開串口:通過SerialPort.Open方法打開串口。
3.發(fā)送數(shù)據(jù):通過SerialPort.Write方法向串口發(fā)送數(shù)據(jù)。
4.接收數(shù)據(jù):通過SerialPort.DataReceived事件異步接收數(shù)據(jù)。
5.處理數(shù)據(jù):對(duì)接收到的數(shù)據(jù)進(jìn)行解析和處理。
2. 關(guān)鍵技術(shù)點(diǎn)
2.1 SerialPort類
SerialPort是C#中用于實(shí)現(xiàn)串口通訊的核心類,提供了發(fā)送和接收數(shù)據(jù)的方法。
2.2 異步接收數(shù)據(jù)
通過SerialPort.DataReceived事件異步接收數(shù)據(jù),避免阻塞主線程。
2.3 數(shù)據(jù)解析
接收到的數(shù)據(jù)通常是字節(jié)數(shù)組(byte[]),需要根據(jù)協(xié)議格式進(jìn)行解析。
2.4 事件機(jī)制
通過事件機(jī)制將接收到的數(shù)據(jù)傳遞給其他模塊處理。
3. 代碼實(shí)現(xiàn)
以下是基于串口通訊實(shí)現(xiàn)數(shù)據(jù)發(fā)送和接收的代碼示例。
3.1 SerialPortHelper類
SerialPortHelper類負(fù)責(zé)初始化串口、發(fā)送數(shù)據(jù)、接收數(shù)據(jù)以及處理數(shù)據(jù)。
public class SerialPortHelper { private SerialPort serialPort; // 串口對(duì)象 private List<byte> _buffer = new List<byte>(); // 數(shù)據(jù)緩沖區(qū) /// <summary> /// 自定義串口消息接收事件 /// </summary> public event ReceiveDataEventHandler ReceiveDataEvent; public SerialPortHelper() { serialPort = new SerialPort(); } /// <summary> /// 獲取當(dāng)前計(jì)算機(jī)所有的串行端口名 /// </summary> public static string[] GetPortArray() { return SerialPort.GetPortNames(); // 獲取所有可用串口 } /// <summary> /// 設(shè)置串口參數(shù) /// </summary> public void SetSerialPort(string portName, int baudrate, Parity parity, int databits, StopBits stopBits) { serialPort.PortName = portName; // 端口名 serialPort.BaudRate = baudrate; // 波特率 serialPort.Parity = parity; // 奇偶校驗(yàn) serialPort.DataBits = databits; // 數(shù)據(jù)位 serialPort.StopBits = stopBits; // 停止位 serialPort.DataReceived += ReceiveDataMethod; // 訂閱數(shù)據(jù)接收事件 } /// <summary> /// 打開串口 /// </summary> public void Open() { try { serialPort.Open(); // 打開串口 } catch (Exception ex) { Console.WriteLine("Error opening serial port: " + ex.Message); } } /// <summary> /// 關(guān)閉串口 /// </summary> public void Close() { serialPort.Close(); // 關(guān)閉串口 } /// <summary> /// 發(fā)送數(shù)據(jù)(字節(jié)數(shù)組) /// </summary> public void SendDataMethod(byte[] data) { if (!serialPort.IsOpen) { Open(); // 如果串口未打開,則先打開 } serialPort.Write(data, 0, data.Length); // 發(fā)送數(shù)據(jù) } /// <summary> /// 發(fā)送數(shù)據(jù)(字符串) /// </summary> public void SendDataMethod(string data) { if (!serialPort.IsOpen) { Open(); // 如果串口未打開,則先打開 } serialPort.Write(data); // 發(fā)送字符串 } /// <summary> /// 數(shù)據(jù)接收事件處理方法 /// </summary> private void ReceiveDataMethod(object sender, SerialDataReceivedEventArgs e) { try { byte[] dataChunk = new byte[serialPort.BytesToRead]; // 讀取緩沖區(qū)中的數(shù)據(jù) serialPort.Read(dataChunk, 0, dataChunk.Length); _buffer.AddRange(dataChunk); // 將數(shù)據(jù)添加到緩沖區(qū) while (_buffer.Count >= 3) // 確保緩沖區(qū)中有足夠的數(shù)據(jù) { byte thirdByte = _buffer[1]; // 獲取第三個(gè)字節(jié)(功能碼) if (thirdByte == 0x03) // 功能碼0x03 { if (_buffer.Count >= 19) // 檢查是否有完整的數(shù)據(jù)包 { byte[] completePacket = _buffer.GetRange(0, 19).ToArray(); // 提取完整數(shù)據(jù)包 TriggerReceiveDataEvent(completePacket); // 觸發(fā)接收事件 _buffer.RemoveRange(0, 19); // 移除已處理的數(shù)據(jù) } else { break; // 數(shù)據(jù)不足,等待更多數(shù)據(jù) } } else if (thirdByte == 0x10 || thirdByte == 0x06) // 功能碼0x10或0x06 { byte[] dataToProcess = _buffer.ToArray(); // 處理整個(gè)緩沖區(qū) TriggerReceiveDataEvent(dataToProcess); // 觸發(fā)接收事件 _buffer.Clear(); // 清空緩沖區(qū) } else { _buffer.RemoveRange(0, 3); // 移除無法識(shí)別的數(shù)據(jù) } } } catch (Exception ex) { Console.WriteLine("Error processing serial port data: " + ex.Message); } } /// <summary> /// 觸發(fā)接收數(shù)據(jù)事件 /// </summary> private void TriggerReceiveDataEvent(byte[] data) { if (ReceiveDataEvent != null) { ReceiveDataEventArg arg = new ReceiveDataEventArg(data); // 創(chuàng)建事件參數(shù) ReceiveDataEvent.Invoke(this, arg); // 觸發(fā)事件 } } }
3.2 ReceiveDataEventArg類
ReceiveDataEventArg類用于封裝接收到的數(shù)據(jù),并作為事件參數(shù)傳遞。
public class ReceiveDataEventArg : EventArgs { public byte[] Data { get; set; } // 接收到的數(shù)據(jù) public ReceiveDataEventArg(byte[] data) { Data = data; // 初始化數(shù)據(jù) } }
3.3 主窗體(MainWindow)
主窗體負(fù)責(zé)初始化SerialPortHelper并處理接收到的數(shù)據(jù)。
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; // 奇偶校驗(yàn) int dataBits = 8; // 數(shù)據(jù)位 StopBits stopBits = StopBits.One; // 停止位 serialPortHelper = new SerialPortHelper(); serialPortHelper.SetSerialPort(portName, baudRate, parity, dataBits, stopBits); // 設(shè)置串口參數(shù) serialPortHelper.Open(); // 打開串口 serialPortHelper.ReceiveDataEvent += ReceiveDataEvent; // 訂閱接收數(shù)據(jù)事件 } /// <summary> /// 接收數(shù)據(jù)事件處理方法 /// </summary> private void ReceiveDataEvent(object sender, ReceiveDataEventArg e) { byte[] receivedData = e.Data; // 獲取接收到的數(shù)據(jù) if (receivedData[1] == 0x03) // 功能碼0x03 { int receiveDataLength = receivedData[2]; // 獲取有效數(shù)據(jù)長(zhǎng)度 byte[] receiveDataBuffer = new byte[receiveDataLength]; Array.Copy(receivedData, 3, receiveDataBuffer, 0, receiveDataLength); // 提取有效數(shù)據(jù) ushort[] units = messageData.GetUnitsFromByteArray(receiveDataBuffer); // 解析數(shù)據(jù) if (units != null) { List<ChannelData> channelDatas = databaseHelper.GetUUTInfo(units); // 獲取設(shè)備信息 UpdateDeviceInfo(channelDatas); // 更新UI } } } }
4. 數(shù)據(jù)傳遞流程詳解
4.1 初始化串口
在SettingComPorts方法中,設(shè)置串口參數(shù)并打開串口。
訂閱ReceiveDataEvent事件以接收數(shù)據(jù)。
4.2 發(fā)送數(shù)據(jù)
通過SendDataMethod方法向串口發(fā)送數(shù)據(jù)。
4.3 接收數(shù)據(jù)
串口接收到數(shù)據(jù)后,觸發(fā)ReceiveDataMethod方法。
將接收到的數(shù)據(jù)添加到緩沖區(qū),并根據(jù)功能碼解析數(shù)據(jù)。
4.4 處理數(shù)據(jù)
在ReceiveDataEvent方法中,解析接收到的數(shù)據(jù)并更新UI。
5. 關(guān)鍵技術(shù)解析
5.1 異步接收數(shù)據(jù)
通過SerialPort.DataReceived事件異步接收數(shù)據(jù),避免阻塞主線程。
5.2 數(shù)據(jù)解析
根據(jù)功能碼(如0x03、0x06)解析接收到的字節(jié)數(shù)組,提取有效數(shù)據(jù)。
5.3 事件機(jī)制
通過事件將接收到的數(shù)據(jù)傳遞給主窗體或其他模塊處理。
6. 總結(jié)
本文詳細(xì)介紹了如何使用C#實(shí)現(xiàn)基于串口通訊的數(shù)據(jù)發(fā)送和接收。通過SerialPort類,我們可以輕松實(shí)現(xiàn)串口通訊,并結(jié)合事件機(jī)制實(shí)現(xiàn)數(shù)據(jù)的傳遞和處理。串口通訊適用于硬件設(shè)備與計(jì)算機(jī)之間的數(shù)據(jù)傳輸,是工業(yè)控制和嵌入式系統(tǒng)開發(fā)中的重要技術(shù)。
希望這篇文章對(duì)您有所幫助!如果有任何問題,歡迎在評(píng)論區(qū)留言討論。
到此這篇關(guān)于如何使用C#串口通訊實(shí)現(xiàn)數(shù)據(jù)的發(fā)送和接收的文章就介紹到這了,更多相關(guān)c#數(shù)據(jù)的發(fā)送和接收內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C# SerialPort實(shí)現(xiàn)串口通訊的代碼詳解
- C#基于WinForm實(shí)現(xiàn)串口通訊
- C#實(shí)現(xiàn)簡(jiǎn)單串口通訊實(shí)例
- C#基于SerialPort類實(shí)現(xiàn)串口通訊詳解
- c# 實(shí)現(xiàn)簡(jiǎn)單的串口通訊
- C#串口通訊概念及簡(jiǎn)單的實(shí)現(xiàn)方法
- C#遠(yuǎn)程發(fā)送和接收數(shù)據(jù)流生成圖片的方法
- C#使用post發(fā)送和接收數(shù)據(jù)的方法
- C#使用Socket發(fā)送和接收TCP數(shù)據(jù)實(shí)例
相關(guān)文章
C#獲取兩個(gè)數(shù)的最大公約數(shù)和最小公倍數(shù)示例
本文介紹了使用C#獲取兩個(gè)數(shù)的最大公約數(shù)和最小公倍數(shù)的示例,大家參考使用吧2014-01-01C#中Request.Cookies 和 Response.Cookies 的區(qū)別分析
本文通過實(shí)例代碼向我們展示了C#中Request.Cookies 和 Response.Cookies 的區(qū)別,文章淺顯易懂,這里推薦給大家。2014-11-11C#實(shí)現(xiàn)簡(jiǎn)單的Login窗口實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)簡(jiǎn)單的Login窗口,實(shí)例分析了C#顯示及關(guān)閉登陸Login窗口的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-08-08C#裝飾器模式(Decorator Pattern)實(shí)例教程
這篇文章主要介紹了C#裝飾器模式(Decorator Pattern),以一個(gè)完整實(shí)例形式講述了C#裝飾器模式的實(shí)現(xiàn)過程,有助于深入理解C#程序設(shè)計(jì)思想,需要的朋友可以參考下2014-09-09C#中實(shí)現(xiàn)PriorityQueue優(yōu)先級(jí)隊(duì)列的代碼
這篇文章主要介紹了C#中PriorityQueue優(yōu)先級(jí)隊(duì)列的實(shí)現(xiàn),構(gòu)造初始化這部分主要介紹關(guān)鍵的字段和方法,比較器的初始化以及堆的初始化,需要的朋友可以參考下2021-12-12