接上一篇《串口通信入门笔记》。上一篇把五个参数讲明白了,这一篇动手做一个最简版的串口助手窗口。

目标很明确:做出来的程序能选串口、选波特率、打开串口、发数据、看收到的数据、关闭串口。


一、先想清楚界面长什么样

界面分四个区域,从上往下:

  1. 顶部:两个下拉框(选串口号、选波特率)+ 两个按钮(打开、关闭)
  2. 中间:一个大的文本框,专门显示收到的数据
  3. 底部:一个输入框(写要发的内容)+ 一个按钮(发送)

对应关系就是这张表:

界面上的东西 控件类型 作用
串口号选择 下拉框 ComboBox 选 COM 几
波特率选择 下拉框 ComboBox 选速度
打开按钮 按钮 Button 打开串口
关闭按钮 按钮 Button 关闭串口
接收显示区 文本框 TextBox 显示收到的数据
发送输入框 文本框 TextBox 输入要发的内容
发送按钮 按钮 Button 把内容发出去

一共 7 个控件,全部用拖的方式放上去,不用写一行界面代码。


二、第一步:新建项目

  1. 打开 Visual Studio
  2. 菜单里选「文件」→「新建」→「项目」
  3. 找模板「Windows 窗体应用」

这里有一个关键点要注意:

  • 如果你的 VS 里有「Windows 窗体应用(.NET Framework)」这个模板,选它,最省事,串口功能直接就能用
  • 如果只有「Windows 窗体应用」(后面不带 .NET Framework,是基于 .NET 5 或更高版本的),也能用,但串口功能要额外装一个组件,后面会单独说明
  1. 项目名字填 SerialAssistant(或者随便起个你喜欢的),点创建

创建完,你会看到一个空白窗口,叫 Form1。我们的代码都是写在它的背后。


三、第二步:拖控件

在窗口 Form1 上,按上面的界面图,拖 7 个控件上去。

控件都在左边的「工具箱」里:

  • ComboBox(下拉框)拖 2 个
  • Button(按钮)拖 3 个
  • TextBox(文本框)拖 2 个

摆放位置参考:

  • 上面一排:串口号下拉框、波特率下拉框、打开按钮、关闭按钮,横着放一行
  • 中间:一个大的文本框(这个是接收区,拖大一点)
  • 下面一排:发送输入框(长一点)、发送按钮,横着放一行

放好后先别急着写代码,先把每个控件改个名字,代码里才能认出来。


四、第三步:给控件改名

选中一个控件,看右下角的「属性」面板,最上面一行就是名字(Name)。

按这个表一个个改:

控件 改成这个名字 好记的含义
串口号下拉框 cmbPort port 是端口
波特率下拉框 cmbBaud baud 是波特率
打开按钮 btnOpen open 是打开
关闭按钮 btnClose close 是关闭
接收显示区 txtReceive receive 是接收
发送输入框 txtSend send 是发送
发送按钮 btnSend 发送按钮

顺便把接收显示区(txtReceive)做两个小设置,让它能显示多行:

  1. 选中 txtReceive
  2. 属性面板里找 Multiline,改成 True
  3. 找 ReadOnly,改成 True(防止手误改掉内容)

名字和属性都改好后,才能开始写代码。

image-20260829080929506


image-20260829080944117


五、第四步:写代码

双击窗口空白处,会进入 Form1_Load 这个方法。它就是「窗口一打开就自动执行」的地方。

再分别双击「打开」「关闭」「发送」三个按钮,会各生成一个方法。这些方法就是「点了这个按钮就执行」的地方。

然后照着下面的完整代码,把你 Form1 里的代码替换成这份。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
using System;
using System.IO.Ports;
using System.Windows.Forms;

namespace SerialAssistant
{
public partial class Form1 : Form
{
// 串口对象,整个窗口共用这一个
SerialPort sp = new SerialPort();

public Form1()
{
InitializeComponent();
}

// 窗口一打开就执行:填下拉框、挂接收事件
private void Form1_Load(object sender, EventArgs e)
{
// 填串口号:COM1 到 COM10
for (int i = 1; i <= 10; i++)
{
cmbPort.Items.Add("COM" + i);
}

// 填波特率
cmbBaud.Items.Add("9600");
cmbBaud.Items.Add("19200");
cmbBaud.Items.Add("38400");
cmbBaud.Items.Add("57600");
cmbBaud.Items.Add("115200");

// 默认选第一项
cmbPort.SelectedIndex = 0;
cmbBaud.SelectedIndex = 0;

// 挂上接收事件
sp.DataReceived += sp_DataReceived;
}

// 点「打开」按钮
private void btnOpen_Click(object sender, EventArgs e)
{
try
{
sp.PortName = cmbPort.Text;
sp.BaudRate = int.Parse(cmbBaud.Text);
sp.DataBits = 8;
sp.StopBits = StopBits.One;
sp.Parity = Parity.None;

sp.Open();
MessageBox.Show("串口打开成功");
}
catch (Exception ex)
{
MessageBox.Show("打开失败:" + ex.Message);
}
}

// 点「关闭」按钮
private void btnClose_Click(object sender, EventArgs e)
{
if (sp.IsOpen)
{
sp.Close();
MessageBox.Show("串口已关闭");
}
}

// 点「发送」按钮
private void btnSend_Click(object sender, EventArgs e)
{
if (!sp.IsOpen)
{
MessageBox.Show("请先打开串口");
return;
}

sp.Write(txtSend.Text);
}

// 串口收到数据时自动执行
private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string msg = sp.ReadExisting();

// 数据在后台线程收到,要切回界面线程才能更新文本框
this.Invoke(new Action(() =>
{
txtReceive.AppendText(msg);
}));
}
}
}

代码分块讲一下(不用背,看懂就行)

打开串口(btnOpen_Click)

和上一篇学的完全一样:把五个参数填好,然后 Open。外面套一层 try 和 catch,是为了防止串口被占用或者填了不存在的串口号时程序直接崩掉。出错会弹一个框告诉你,而不是整个程序闪退。

发送(btnSend_Click)

先判断串口开了没有,没开就提醒你。开了就把发送框里的文字写出去,一行搞定。

接收(sp_DataReceived)

这是这篇里唯一需要多留意的部分。

串口收到数据时,程序会自己调用 sp_DataReceived 这个方法,我们不用管它什么时候来。

但这里有个坑:这个方法是在一个「后台线程」里跑的,而文本框是属于「界面线程」的。后台线程不能直接去碰界面,会报错。

解决办法就是外面包一层 this.Invoke,它的作用就一句话:把「更新文本框」这件事,交给界面线程去做。

你暂时不用理解线程是什么,先记住:接收到的数据要显示到文本框,就必须套上 this.Invoke 这一层。等基础扎实了,线程我们单独讲。


六、运行测试

按 F5 运行程序。

  1. 先选好串口号和波特率
  2. 点「打开」,应该弹出「串口打开成功」
  3. 在发送框输入 hello,点「发送」

如果手头有真实的串口设备,就能看到对方收到 hello;对方回数据时,接收区会显示出来。

如果手头暂时没有设备,可以用一个叫「虚拟串口」的工具,在电脑上模拟出一对串口(比如 COM1 和 COM2 连成一条线),自己发自己收,也能看到效果。这一步你可以先跳过,等下一篇我们再专门做。


七、如果卡住了,看这里

  • 点「打开」报「端口不存在」:说明串口号选错了,去设备管理器看看设备插的是 COM 几
  • 点「打开」报「拒绝访问」:说明这个串口被别的程序占用了,先关掉别的串口软件
  • 编译报「找不到 SerialPort」:说明你建的是 .NET 5 以上版本的项目,需要装一个组件。在「项目」→「管理 NuGet 程序包」里搜索 System.IO.Ports,点安装,问题就解决了
  • 收到数据但程序崩了:检查接收代码有没有套上 this.Invoke 那一层

八、小结

这一篇你做出了第一个能跑的上位机程序,总共就干了两件事:

  1. 拖 7 个控件,改好名字
  2. 把五个参数填进 Open 之前,Write 发数据,DataReceived 收数据

上一篇的五个参数,在这一篇里变成了实实在在的三行代码。串口通信的骨架,你已经摸到了。


下一步

下一篇可以做两件小事,任选一个:

  1. 把收到的数据显示成十六进制(工业上很常用)
  2. 加一个「自动发送」「定时发送」功能

你先跑通这一篇,有卡住的地方随时来问我。