SerialPort串口通信
C#数据类型及字节长度和取值范围:
| 类型名称 | 类型说明 | 字节长度(bytes数) | 取值范围 | .NET框架类型(包装类) | 默认值 |
| sbyte | 8位有符号整数 | 1bytes | -128~127 | System.SByte | 0 |
| byte | 8位无符号整数 | 1bytes | 0~255 | System.Byte | 0 |
| short | 16位有符号整数 | 2bytes | -32768~32767 | System.Int16 | 0 |
| ushort | 16位无符号整数 | 2bytes | 0~65535 | System.UInt16 | 0 |
| int | 32位有符号整数 | 4bytes | -2,147,483,648~2,147,483,647 | System.Int32 | 0 |
| uint | 32位无符号整数 | 4bytes | 0~4,294,967,295 | System.UInt32 | 0 |
| long | 64位有符号整数 | 8bytes |
-9,223,372,036,854,775,808 ~9,223,372,036,854,775,807 |
System.Int64 | 0 |
| ulong | 64位无符号整数 | 8bytes | 0~18,446,744,073,709,551,615 | System.UInt64 | 0 |
| nint | 带符号的32位或64位整数 | (在32位进程中是4bytes,在64位进程中是8bytes) | 取决于(在运行时计算的)平台 | System.IntPtr | - |
| nuint | 无符号的32位或64位整数 | (在32位进程中是4bytes,在64位进程中是8bytes) | 取决于(在运行时计算的)平台 | System.UIntPtr | - |
| float | 单精度浮点数 (精度为大约6-9位有效小数位) |
4bytes | 1.5×10 -45 ~3.4×10 38 | System.Single | 0.0f |
| double | 双精度浮点数 (精度为大约15-17位有效小数位) |
8bytes | ±5.0×10 -324 ~±1.7×10 308 | System.Double | 0.0d |
| decimal | 实数类型 (精度为28-29位有效小数位) |
16bytes | ±1.0×10 28 ~±7.9228×10 28 | System.Decimal | 0m |
| bool | 布尔值 | 1bytes(实际仅需1bit) | true /false | System.Boolean | false |
| char | Unicode字符串 | U+0000~U+ffff | System.Char | \x0000 | |
| object | 所有其他类型的基类,包括简单类型 | System.Object | |||
| string | 0个或多个Unicode字符所组成的序列 | System.String | |||
| dynamic | 使用动态类型语言编写的程序集时使用 | 无相应的.NET类型 |
串口通信(Serial Communication)是一种点对点的通信方式,通过串行传输逐位发送数据。常见的串口协议包括 RS-232、RS-485 和 RS-422。
RS-232: 特点:早期串口标准,通信距离短(15 米以内),点对点连接。 适用场景:低速短距离通信,如老式工业设备或 PC 与设备的直接连接。 RS-485 特点:支持多点通信,最大支持 32 个设备,通信距离长(1,200 米)。 适用场景:多设备总线通信,如传感器网络和工业总线。 RS-422 特点:点对点连接,抗干扰能力强,适合长距离高速传输。 适用场景:设备间长距离高速通信
优点:
(1) 稳定可靠:通信协议简单,干扰少。 (2) 硬件成本低:硬件接口通用,广泛支持。 (3) 通信距离可达 1,200 米(RS-485/RS-422),适合长距离场景。
缺点:
(1) 带宽低:数据传输速率较低,最高通常不超过 10Mbps。 (2) 点对点限制(RS-232):难以实现多设备通信。 (3) 协议缺乏灵活性:需要额外开发应用层协议。
应用场景:
(1) 工业设备调试(通过 RS-232)。 (2) 传感器网络通信(通过 RS-485)。 (3) 长距离数据采集和监控。
NuGet包:System.IO.Ports
常用属性:
| 属性名 | 类型/说明 |
|---|---|
| PortName | string — 串口名称(如 COM1、COM3) |
| BaudRate | int — 波特率,表示数据传输速率。常用有 9600、19200、38400、57600、115200 等 |
| Parity | Parity — 奇偶校验类型(如 None 无奇偶校验、Even 偶校验、Odd 奇校验) |
| DataBits | int — 数据位数,常见为 8 位;也可设置为 5、6、7 位 |
| StopBits | StopBits — 停止位(如 None 不使用、One 1 个、Two 2 个、OnePointFive 1.5 个) |
| Handshake | Handshake — 握手协议(如 None、RequestToSend、XOnXOff) |
| Encoding | Encoding — 数据编码方式(如 Encoding.UTF8) |
| ReadTimeout | int — 读取操作超时时间(毫秒),默认为 InfiniteTimeout |
| WriteTimeout | int — 写入操作超时时间(毫秒),默认为 InfiniteTimeout |
| IsOpen | bool — 表示串口是否已打开 |
| NewLine | string — 定义行结束符(如 "\r\n"),用于 ReadLine() 和 WriteLine() |
| DtrEnable | bool — 控制数据终端就绪(DTR)信号状态 |
| RtsEnable | bool — 控制请求发送(RTS)信号状态 |
| ReceivedBytesThreshold | int — 触发 DataReceived 事件的最小字节数 |
常用方法:
| 方法名 | 说明 |
|---|---|
| Open() | 打开串口。 |
| Close() | 关闭已打开的串口。 |
| Read(byte[] buffer, int offset, int count) | 从串口读取指定字节数到缓冲区。 |
| ReadByte() | 读取单个字节(返回 int,范围 0-255,失败返回 -1)。 |
| ReadLine() | 读取一行数据,直到遇到 NewLine 定义的结束符。 |
| ReadExisting() | 读取接收缓冲区中所有可用数据(不阻塞)。 |
| Write(string text) | 写入字符串到串口(自动按 Encoding 编码)。 |
| Write(byte[] buffer, int offset, int count) | 写入字节数组到串口。 |
| DiscardInBuffer() | 清空输入缓冲区中的数据。 |
| DiscardOutBuffer() | 清空输出缓冲区中的数据。 |
常用事件:
| 事件名 | 说明 |
|---|---|
| DataReceived | 当接收到数据且字节数达到 ReceivedBytesThreshold 时触发。 |
| ErrorReceived | 当串口发生错误(如奇偶校验错误)时触发。 |
其它重要扩展属性:
| 属性名 | 类型/说明 |
|---|---|
| BytesToRead | int — 接收缓冲区中已接收的字节数。 |
| BytesToWrite | int — 输出缓冲区中待发送的字节数。 |
| ReadBufferSize | int — 设置输入缓冲区大小(默认 4096)。 |
| WriteBufferSize | int — 设置输出缓冲区大小(默认 2048)。 |
.xaml代码
<Window x:Class="StudySerialPort.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:StudySerialPort" mc:Ignorable="d" Title="串口案例" Height="450" Width="800"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"></ColumnDefinition> <ColumnDefinition Width="4*"></ColumnDefinition> </Grid.ColumnDefinitions> <!--左边--> <Grid Background="Azure"> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="1.5*"></ColumnDefinition> <ColumnDefinition Width="2.5*"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,5">串口</TextBlock> <ComboBox x:Name="cbbSpName" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,5"></ComboBox> <TextBlock Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,5">波特率</TextBlock> <ComboBox x:Name="cbbBaud" SelectedIndex="0" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,5"> <ComboBoxItem>9600</ComboBoxItem> <ComboBoxItem>19200</ComboBoxItem> <ComboBoxItem>38400</ComboBoxItem> </ComboBox> <TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,5">数据位</TextBlock> <ComboBox x:Name="cbbDataBit" SelectedIndex="0" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,5"> <ComboBoxItem>8</ComboBoxItem> <ComboBoxItem>7</ComboBoxItem> <ComboBoxItem>6</ComboBoxItem> </ComboBox> <TextBlock Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,5">校验位</TextBlock> <ComboBox x:Name="cbbParity" SelectedIndex="0" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,5"> <ComboBoxItem>无</ComboBoxItem> <ComboBoxItem>奇校验</ComboBoxItem> <ComboBoxItem>偶校验</ComboBoxItem> </ComboBox> <TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,5">停止位</TextBlock> <ComboBox Grid.Row="4" x:Name="cbbStopBit" SelectedIndex="0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,5"> <ComboBoxItem>1</ComboBoxItem> <ComboBoxItem>1.5</ComboBoxItem> <ComboBoxItem>2</ComboBoxItem> </ComboBox> <Button x:Name="BtnOpen" Grid.Row="5" Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,10,5" Click="BtnOpen_Click">打开串口</Button> <Button x:Name="BtnClose" Grid.Row="5" Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,10,5" Visibility="Collapsed" Click="BtnClose_Click">关闭串口</Button> </Grid> <!--右边--> <Grid Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> </Grid.RowDefinitions> <RichTextBox Height="300" x:Name="txtShowContent" VerticalScrollBarVisibility="Visible"></RichTextBox> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*"></ColumnDefinition> <ColumnDefinition Width="1*"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBox Height="80" x:Name="txtSendContent"></TextBox> <Button x:Name="BtnSend" Grid.Column="1" Click="BtnSend_Click">发送</Button> </Grid> </Grid> </Grid> </Window>
.xaml.cs代码
using System.IO.Ports; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace StudySerialPort; public partial class MainWindow : Window { //创建串口 SerialPort serialPort = new SerialPort(); public MainWindow() { InitializeComponent(); BindPort();//绑定串口到下拉 //异步读取 Task.Run(async () => { while (true) { _ = Dispatcher.Invoke(async () => { await ReadAsync(); }); await Task.Delay(1000); } }); } /// <summary> /// 绑定串口到下拉 /// </summary> private void BindPort() { //绑定串口到下拉 string[] portList = SerialPort.GetPortNames(); cbbSpName.ItemsSource = portList; if (portList.Length > 0) { cbbSpName.SelectedIndex = 0;//默认选择第一个 } } /// <summary> /// 打开串口 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnOpen_Click(object sender, RoutedEventArgs e) { //核心代码。输入验证 serialPort.PortName = cbbSpName.Text;//串口名称 serialPort.BaudRate = Convert.ToInt32(cbbBaud.Text);//波特率 serialPort.DataBits = Convert.ToInt32(cbbDataBit.Text);//数据位 //校验位 serialPort.Parity = Parity.None; if (cbbParity.SelectedIndex == 1) { serialPort.Parity = Parity.Odd; } if (cbbParity.SelectedIndex == 2) { serialPort.Parity = Parity.Even; } //停止位 serialPort.StopBits = StopBits.One; if (cbbStopBit.SelectedIndex == 1) { serialPort.StopBits = StopBits.OnePointFive; } if (cbbStopBit.SelectedIndex == 2) { serialPort.StopBits = StopBits.Two; } //打开串口 try { serialPort.Open(); //隐藏打开按钮,显示关闭按钮 BtnOpen.Visibility = Visibility.Collapsed;//隐藏打开按钮 BtnClose.Visibility = Visibility.Visible;//显示关闭按钮 //显示打开消息 AppendTxt($"{DateTime.Now.ToString("yyyy-MM-dd")} 打开串口{cbbSpName.Text}成功", Colors.Green); } catch (Exception) { BtnOpen.Visibility = Visibility.Visible; BtnClose.Visibility = Visibility.Collapsed; //显示打开异常消息 AppendTxt($"{DateTime.Now.ToString("yyyy-MM-dd")} 打开串口{cbbSpName.Text}失败", Colors.Red); } } /// <summary> /// 关闭串口 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnClose_Click(object sender, RoutedEventArgs e) { if (serialPort.IsOpen) { serialPort.Close(); BtnOpen.Visibility = Visibility.Visible; BtnClose.Visibility = Visibility.Collapsed; //显示关闭信息 AppendTxt($"{DateTime.Now.ToString("yyyy-MM-dd")} 关闭串口{cbbSpName.Text}", Colors.Red); } } /// <summary> /// 发送数据 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnSend_Click(object sender, RoutedEventArgs e) { if (serialPort.IsOpen)//打开了才能发送数据 { byte[] bytes = Encoding.UTF8.GetBytes(txtSendContent.Text); serialPort.Write(bytes, 0, bytes.Length); //显示 AppendTxt($"{DateTime.Now.ToString("yyyy-MM-dd")} 发送消息 {txtSendContent.Text}成功", Colors.Black); } else { MessageBox.Show("请先打开串口"); } } /// <summary> /// 异步读取并显示在richtextbox里 /// </summary> private async Task ReadAsync() { if (serialPort.IsOpen) { byte[] readBytes = new byte[1024];//存放读的结果 if (serialPort.BytesToRead>0)//接收缓冲区有数据 { int readCount = await serialPort.BaseStream.ReadAsync(readBytes, 0, readBytes.Length); if (readCount > 0) { string data = Encoding.UTF8.GetString(readBytes);//转成字符串 //ui操作 AppendTxt($"{DateTime.Now.ToString("yyyy-MM-dd")} 读取数据 {data}", Colors.Blue); } } } } FlowDocument doc = new FlowDocument(); /// <summary> /// 将string追加richtextbox里 /// </summary> /// <param name="txt"></param> /// <param name="txtColor">颜色</param> private void AppendTxt(string txt, Color txtColor) { var p = new Paragraph(); // Paragraph 类似于 html 的 P 标签 var r = new Run(txt); // Run 是一个 Inline 的标签 p.Inlines.Add(r); p.Foreground = new SolidColorBrush(txtColor);//设置字体颜色 doc.Blocks.Add(p); txtShowContent.Document = doc; txtShowContent.ScrollToEnd(); } }

浙公网安备 33010602011771号