# C#基于SerialPort類實現串口通訊
## 一、串口通訊基礎概念
### 1.1 串行通信簡介
串行通信(Serial Communication)是指通過單根數據線將數據一位一位順序傳輸的通信方式。與并行通信相比,雖然速度較慢,但具有布線簡單、成本低、適合遠距離傳輸等優勢。
常見串口標準:
- RS-232:最傳統的串口標準(DB9接口)
- RS-422:差分傳輸,抗干擾能力強
- RS-485:支持多點通信,工業領域廣泛應用
### 1.2 串口通信參數
實現串口通信需要配置以下關鍵參數:
- 波特率(Baud Rate):1200/2400/4800/9600/19200/38400/57600/115200等
- 數據位(Data Bits):通常為5-8位(默認8位)
- 停止位(Stop Bits):1、1.5或2位
- 校驗位(Parity):None/Odd/Even/Mark/Space
- 流控制(Flow Control):None/XonXoff/RTS/CTS
## 二、.NET中的SerialPort類
### 2.1 SerialPort類概述
System.IO.Ports命名空間下的SerialPort類提供了同步I/O和事件驅動的I/O、對管腳和中斷狀態的訪問以及對串行驅動程序屬性的訪問。
主要功能:
- 支持同步和異步讀寫操作
- 提供數據接收事件通知
- 可配置超時設置
- 支持流控制
### 2.2 常用屬性說明
```csharp
public class SerialPort : Component
{
// 基礎配置屬性
public string PortName { get; set; } // 端口名稱(COM1、COM2等)
public int BaudRate { get; set; } // 波特率
public Parity Parity { get; set; } // 校驗位
public int DataBits { get; set; } // 數據位
public StopBits StopBits { get; set; } // 停止位
// 流控制相關
public Handshake Handshake { get; set; } // 握手協議
// 超時設置
public int ReadTimeout { get; set; } // 讀取超時(毫秒)
public int WriteTimeout { get; set; } // 寫入超時(毫秒)
// 狀態檢測
public bool IsOpen { get; } // 端口是否打開
public int BytesToRead { get; } // 接收緩沖區中數據字節數
public int BytesToWrite { get; } // 發送緩沖區中數據字節數
// 其他重要屬性
public Encoding Encoding { get; set; } // 字符編碼
public string NewLine { get; set; } // 換行符(默認為\n)
}
using System.IO.Ports;
public class SerialPortHelper
{
private SerialPort _serialPort;
private readonly Action<string> _dataReceivedCallback;
public SerialPortHelper(Action<string> dataReceivedCallback)
{
_dataReceivedCallback = dataReceivedCallback;
}
// 初始化串口配置
public void Initialize(string portName, int baudRate = 9600,
Parity parity = Parity.None, int dataBits = 8,
StopBits stopBits = StopBits.One)
{
_serialPort = new SerialPort
{
PortName = portName,
BaudRate = baudRate,
Parity = parity,
DataBits = dataBits,
StopBits = stopBits,
ReadTimeout = 500,
WriteTimeout = 500
};
// 訂閱數據接收事件
_serialPort.DataReceived += SerialPortDataReceived;
}
// 打開串口
public bool Open()
{
try
{
if (!_serialPort.IsOpen)
{
_serialPort.Open();
return true;
}
return false;
}
catch (Exception ex)
{
Console.WriteLine($"打開串口失敗: {ex.Message}");
return false;
}
}
// 關閉串口
public void Close()
{
if (_serialPort.IsOpen)
{
_serialPort.Close();
}
}
// 發送數據
public void SendData(string data)
{
if (_serialPort.IsOpen)
{
try
{
_serialPort.WriteLine(data);
}
catch (TimeoutException)
{
Console.WriteLine("發送超時!");
}
}
}
// 數據接收事件處理
private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (_serialPort.BytesToRead > 0)
{
try
{
string receivedData = _serialPort.ReadExisting();
_dataReceivedCallback?.Invoke(receivedData);
}
catch (Exception ex)
{
Console.WriteLine($"數據接收異常: {ex.Message}");
}
}
}
// 獲取可用串口列表
public static string[] GetAvailablePorts()
{
return SerialPort.GetPortNames();
}
}
public partial class MainForm : Form
{
private readonly SerialPortHelper _serialHelper;
public MainForm()
{
InitializeComponent();
// 初始化串口助手
_serialHelper = new SerialPortHelper(OnDataReceived);
// 加載可用串口
RefreshPortList();
}
private void RefreshPortList()
{
cmbPorts.Items.Clear();
var ports = SerialPortHelper.GetAvailablePorts();
cmbPorts.Items.AddRange(ports);
if (ports.Length > 0) cmbPorts.SelectedIndex = 0;
}
private void btnOpen_Click(object sender, EventArgs e)
{
if (cmbPorts.SelectedItem == null) return;
_serialHelper.Initialize(
portName: cmbPorts.SelectedItem.ToString(),
baudRate: int.Parse(txtBaudRate.Text)
);
if (_serialHelper.Open())
{
AppendLog($"串口 {cmbPorts.SelectedItem} 已打開");
btnOpen.Enabled = false;
btnClose.Enabled = true;
btnSend.Enabled = true;
}
}
private void btnSend_Click(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(txtSendData.Text))
{
_serialHelper.SendData(txtSendData.Text);
AppendLog($"發送: {txtSendData.Text}");
txtSendData.Clear();
}
}
private void OnDataReceived(string data)
{
// 跨線程更新UI
this.Invoke((MethodInvoker)delegate {
AppendLog($"接收: {data}");
});
}
private void AppendLog(string message)
{
txtLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}{Environment.NewLine}");
}
private void btnRefresh_Click(object sender, EventArgs e)
{
RefreshPortList();
}
private void btnClose_Click(object sender, EventArgs e)
{
_serialHelper.Close();
AppendLog("串口已關閉");
btnOpen.Enabled = true;
btnClose.Enabled = false;
btnSend.Enabled = false;
}
}
當需要處理二進制數據而非文本時:
// 發送字節數組
public void SendBytes(byte[] data)
{
if (_serialPort.IsOpen)
{
_serialPort.Write(data, 0, data.Length);
}
}
// 接收二進制數據
private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
int bytesToRead = _serialPort.BytesToRead;
byte[] buffer = new byte[bytesToRead];
_serialPort.Read(buffer, 0, bytesToRead);
// 處理二進制數據...
string hexString = BitConverter.ToString(buffer);
_dataReceivedCallback?.Invoke(hexString);
}
_serialPort.ReadBufferSize = 1024 * 8; // 8KB
必須通過Control.Invoke方式更新UI組件:
this.Invoke((MethodInvoker)delegate {
// 更新UI代碼
});
// MODBUS RTU協議請求示例
public byte[] CreateModbusRequest(byte deviceId, byte functionCode, ushort startAddress, ushort length)
{
byte[] request = new byte[8];
// 設備地址
request[0] = deviceId;
// 功能碼
request[1] = functionCode;
// 起始地址
request[2] = (byte)(startAddress >> 8);
request[3] = (byte)startAddress;
// 寄存器數量
request[4] = (byte)(length >> 8);
request[5] = (byte)length;
// CRC校驗
ushort crc = CalculateCRC(request, 6);
request[6] = (byte)crc;
request[7] = (byte)(crc >> 8);
return request;
}
可擴展功能: - 十六進制顯示/發送 - 自動發送定時器 - 數據記錄到文件 - 自定義協議解析插件
本文詳細介紹了在C#中使用SerialPort類實現串口通信的完整方案,包括: 1. 串口通信基礎概念與參數配置 2. SerialPort類的核心API詳解 3. 同步/異步通信實現方式 4. 實際開發中的常見問題解決方案 5. 性能優化與高級應用建議
通過合理運用SerialPort類,開發者可以快速構建穩定可靠的串口通信應用,滿足工業控制、設備調試、物聯網等領域的通信需求。
注意:實際開發中請根據具體硬件設備的通信協議要求進行適當調整,并做好異常處理和資源釋放工作。 “`
這篇文章共計約4500字,涵蓋了從基礎概念到高級應用的完整內容,采用Markdown格式編寫,包含代碼示例、注意事項和實際應用案例,可以直接用于技術文檔或博客發布。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。