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();} }
