记录时间;2024年4月
记录如何开启虚拟串口以及进行基础串口通信。
建立虚拟串口
使用的软件是vspd,建立虚拟串口之后就可以将他们当成实际物理连接的两个串口进行通信。
之后使用我们之前给出的通信模板,建立一个稍微规矩一点的界面。
界面建立
其中添加对用户输入的检查。
配合之前打开串口的逻辑就可以开始串口应用的调试和开发了。
代码
public partial class Form1 : Form
{
//串口参数和串口工具类
public System.IO.Ports.SerialPort _serialPort = new System.IO.Ports.SerialPort();
string[] baud = { "43000", "56000", "57600", "115200", "128000", "230400", "256000", "460800" };
private void displaytext(object sender, EventArgs e)
{
string str = _serialPort.ReadExisting();
rtxreceive.AppendText(str);
}
//串口接收事件
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//串口接收事件
try
{
//串口接收数据
//if(serialPort1.IsOpen)
{
this.Invoke(new EventHandler(displaytext));
}
}
catch (Exception ex)
{
//捕获到异常,创建一个新的对象,之前的不可以再用
_serialPort = new System.IO.Ports.SerialPort();
//刷新COM口选项
comboBox1.Items.Clear();
comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
//响铃并显示异常给用户
System.Media.SystemSounds.Beep.Play();
button4.Text = "打开串口";
MessageBox.Show(ex.Message);
hintrtx.Text += "\n串口接收失败";
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
}
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//检测
try
{
string[] ports = SerialPort.GetPortNames();
if (ports.Length == 0)
{
MessageBox.Show("没有找到串口");
hintrtx.Text += "没有找到串口";
return;
}
comboBox1.Items.Clear();
comboBox1.Items.AddRange(ports);
comboBox1.SelectedIndex = 0;
comboBox2.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
comboBox4.SelectedIndex = 0;
comboBox5.SelectedIndex = 0;
//检测到串口后,使能串口参数设置
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Form1_Load(object sender, EventArgs e)
{
//界面初始化
int i;
for (i = 300; i <= 38400; i = i * 2)
{
comboBox2.Items.Add(i.ToString()); //添加波特率列表
}
comboBox2.Items.AddRange(baud);
comboBox1.Enabled = false;
comboBox2.Enabled = false;
comboBox3.Enabled = false;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
hintrtx.Text += "欢迎使用";
}
private void button4_Click(object sender, EventArgs e)
{
//开启串口
try
{
if (_serialPort.IsOpen)
{
//如果串口已经处于打开状态,则关闭串口
_serialPort.Close();
button4.Text = "打开串口";
hintrtx.Text += "\n串口已经关闭";
//关闭串口后,使能串口参数设置
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
//取消串口接收事件注册
_serialPort.DataReceived -= new SerialDataReceivedEventHandler(_serialPort_DataReceived);
return;
}
else
{
//串口已经处于关闭状态,则设置好串口属性后打开
comboBox1.Enabled = false;
comboBox2.Enabled = false;
comboBox3.Enabled = false;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
_serialPort.PortName = comboBox1.Text;
_serialPort.BaudRate = Convert.ToInt32(comboBox2.Text);
_serialPort.DataBits = Convert.ToInt16(comboBox3.Text);
_serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), comboBox4.Text);
if (comboBox5.Text.Equals("1"))
_serialPort.StopBits = System.IO.Ports.StopBits.One;
else if (comboBox5.Text.Equals("1.5"))
_serialPort.StopBits = System.IO.Ports.StopBits.OnePointFive;
else if (comboBox5.Text.Equals("2"))
_serialPort.StopBits = System.IO.Ports.StopBits.Two;
//_serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBox5.Text);
_serialPort.Open();
//注册串口接收事件
_serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
button4.Text = "关闭串口";
hintrtx.Text += "\n串口已经打开";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
hintrtx.Text += "\n串口打开失败";
}
}
private void button3_Click(object sender, EventArgs e)
{
//
try
{
//首先判断串口是否开启
if (_serialPort.IsOpen)
{
//串口处于开启状态,将发送区文本发送
_serialPort.Write(rtx_send.Text);
}
}
catch (Exception ex)
{
//捕获到异常,创建一个新的对象,之前的不可以再用
_serialPort = new System.IO.Ports.SerialPort();
//刷新COM口选项
comboBox1.Items.Clear();
comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
//响铃并显示异常给用户
System.Media.SystemSounds.Beep.Play();
button4.Text = "打开串口";
MessageBox.Show(ex.Message);
hintrtx.Text += "\n串口发送失败";
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
}
}
}
代码解释:
扫描串口:
我们使用serialport类进行串口的扫描,能够给到一个串口名称的列表。展示的中间修改页面元素的可用性,允许用户修改串口配置。
private void button1_Click(object sender, EventArgs e)
{
//检测
try
{
string[] ports = SerialPort.GetPortNames();
if (ports.Length == 0)
{
MessageBox.Show("没有找到串口");
hintrtx.Text += "没有找到串口";
return;
}
comboBox1.Items.Clear();
comboBox1.Items.AddRange(ports);
comboBox1.SelectedIndex = 0;
comboBox2.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
comboBox4.SelectedIndex = 0;
comboBox5.SelectedIndex = 0;
//检测到串口后,使能串口参数设置
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
打开/关闭串口
逻辑非常简单,判断是否已经打开,如果已经打开就关闭。
打开的逻辑是:
读取用户设置之前先锁定配置,防止调试中用户修改。
接着就是打开串口,注册串口接收事件用于执行接收指定的逻辑。
关闭串口更加简单,重新给予用户修改配置的机会,同时关闭串口,取消事件的注册。
事件机制是串口收发的核心:
C#笔记4 详细解释事件及其原型、匿名方法和委托的关系-CSDN博客
c#笔记5 详解事件的内置类型EventHandler、windows事件在winform中的运用_ceventhandler用法-CSDN博客
private void button4_Click(object sender, EventArgs e)
{
//开启串口
try
{
if (_serialPort.IsOpen)
{
//如果串口已经处于打开状态,则关闭串口
_serialPort.Close();
button4.Text = "打开串口";
hintrtx.Text += "\n串口已经关闭";
//关闭串口后,使能串口参数设置
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
//取消串口接收事件注册
_serialPort.DataReceived -= new SerialDataReceivedEventHandler(_serialPort_DataReceived);
return;
}
else
{
//串口已经处于关闭状态,则设置好串口属性后打开
comboBox1.Enabled = false;
comboBox2.Enabled = false;
comboBox3.Enabled = false;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
_serialPort.PortName = comboBox1.Text;
_serialPort.BaudRate = Convert.ToInt32(comboBox2.Text);
_serialPort.DataBits = Convert.ToInt16(comboBox3.Text);
_serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), comboBox4.Text);
if (comboBox5.Text.Equals("1"))
_serialPort.StopBits = System.IO.Ports.StopBits.One;
else if (comboBox5.Text.Equals("1.5"))
_serialPort.StopBits = System.IO.Ports.StopBits.OnePointFive;
else if (comboBox5.Text.Equals("2"))
_serialPort.StopBits = System.IO.Ports.StopBits.Two;
//_serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBox5.Text);
_serialPort.Open();
//注册串口接收事件
_serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
button4.Text = "关闭串口";
hintrtx.Text += "\n串口已经打开";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
hintrtx.Text += "\n串口打开失败";
}
}
串口接收事件:
这里主要是做了一个串口的错误处理和调用界面元素显示的方法。从不是创建这个元素的线程调用改变元素的方法需要使用invoke。
//串口接收事件
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//串口接收事件
try
{
//串口接收数据
//if(serialPort1.IsOpen)
{
this.Invoke(new EventHandler(displaytext));
}
}
catch (Exception ex)
{
//捕获到异常,创建一个新的对象,之前的不可以再用
_serialPort = new System.IO.Ports.SerialPort();
//刷新COM口选项
comboBox1.Items.Clear();
comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
//响铃并显示异常给用户
System.Media.SystemSounds.Beep.Play();
button4.Text = "打开串口";
MessageBox.Show(ex.Message);
hintrtx.Text += "\n串口接收失败";
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
}
}
display方法
这里就可以写你自己的方法了。串口的数据经过怎么处理展示到哪里。
private void displaytext(object sender, EventArgs e)
{
string str = _serialPort.ReadExisting();
rtxreceive.AppendText(str);
}