一、串口助手是什么?
通过电脑串口(包括USB口)收发数据并且显示的应用软件,一般用于电脑与嵌入式系统的通讯,借助于它来调试串口通讯或者系统的运行状态。也可以用于采集其他系统的数据,用于观察系统的运行情况。
简单的串口助手只能用来接收可发送串口数据,但是当你学会了如何开发串口助手,就可以根据通信协议开发上位机控制硬件和查看硬件的状态,先介绍如何开发一个简单的串口助手。
二、开发环境
- Visual Stdio
- C#
开发串口助手会用到Winform的相关知识,想要学习Winform的相关知识可以点击链接学习:http://c.biancheng.net/csharp/winform/
三、开发步骤
1. 串口参数
要连接上串口让并实现串口通信我们首先要搜索并选择需要进行通信的串口号,然后设置好波特率、数据位、停止位和检验位,串口号、波特率、数据位、停止位和检验位相当于打开特定串口的简单的密码,设置好之后就能打开串口进行通信。
名称 | 作用 | 常用数值 |
---|
波特率 | 串口通信的速率(发送和接收各数据位的间隔时间) | 4800 9600 14400 19200 38400 56000 57600 115200 128000 256000 |
数据位 | 表示一组数据实际包含的数据位数 | 5 6 7 8 |
停止位 | 停止位在最后,用以标志一个字符传送的结束,表示数据帧之间的间隔 | 1 1.5 2 None |
校验位 | 用于数据验证 | Even Odd None |
数据位概述图 | | |
| | |
2.UI设计
一个串口助手界面主要由参数设置、接收框、发送框三个部分以及一些控制按钮组成,参数设置使用ComboBox组件实现,接收和发送数据框使用RichTextBox组件实现,按钮使用Button组件实现,还有串口可以使用自带的SerialPort组件。
3.创建工程
(1)点击新建项目->选择Windows窗体应用->点击下一步->填写好项目名称和什么位置->点击创建
(2)实现UI
创建好项目后左边是工具栏,可以直接拖拉组件,里面有我们要用到的Label、ComboBox、RichTextBox、Button组件,可以根据字母排序查找需要的组件。右边是用来设置组件参数,按F4可以出现该框,可以设置组件名称、文件内容、颜色、大小、位置、字体、图标等参数,点击闪电标志里面可以设置绑定事件。
注意UI实现的过程中要设置好组件的Name,下面是我设置的一些Name参数
组件 | Name |
---|
ComboBox | comboBox_PortNames comboBox_BaudRate comboBox_DataBit comboBox_StopBit comboBox_Parity
|
RichTextBox | richTextBox_Receive richTextBox_Send |
Button | button_Serach button_OpenOrClose button_CLEAR button_Send |
串口波特率、数据位、停止位和校验位参数可以预先设置好,这里给出波特率参数设置,其他参数设置的方法一样
SerialPort组件使用方法
基本实现好的UI(审美不在线),大家可以自行优化
点击启动的运行效果
(3)功能代码实现
代码要实现的功能主要有:
- 1.初始化函数
编写初始化函数时要在Form1.Designer.cs文件的Windows 窗体设计器生成的代码里面添加this.Load += new System.EventHandler(this.Form1_Load);
如下图所示
#region 初始化窗体
private void Form1_Load(object sender, EventArgs e)
{
try
{
string[] str = SerialPort.GetPortNames();
comboBox_PortNames.Items.Clear();
comboBox_PortNames.Items.AddRange(str);
if (str.Length > 0)
{
comboBox_PortNames.SelectedIndex = 0;
comboBox_BaudRate.SelectedIndex = 7;
comboBox_DataBit.SelectedIndex = 3;
comboBox_StopBit.SelectedIndex = 1;
comboBox_Parity.SelectedIndex = 2;
}
else
{
MessageBox.Show("当前无串口连接!");
}
}
catch
{
MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!");
}
}
#endregion
#region 搜索串口(与初始化函数一样)
private void button_Serach_Click(object sender, EventArgs e)
{
try
{
string[] str = SerialPort.GetPortNames();
comboBox_PortNames.Items.Clear();
comboBox_PortNames.Items.AddRange(str);
if (str.Length > 0)
{
comboBox_PortNames.SelectedIndex = 0;
comboBox_BaudRate.SelectedIndex = 7;
comboBox_DataBit.SelectedIndex = 3;
comboBox_StopBit.SelectedIndex = 1;
comboBox_Parity.SelectedIndex = 2;
}
else
{
MessageBox.Show("当前无串口连接!");
}
}
catch
{
MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!");
}
}
#endregion
#region 打开串口
private void button_OpenOrClose_Click(object sender, EventArgs e)
{
if (!serialPort1.IsOpen)
{
if (comboBox_PortNames.SelectedItem == null)
{
MessageBox.Show("请选择正确的串口", "提示");
return;
}
serialPort1.PortName = comboBox_PortNames.Text.ToString();
serialPort1.BaudRate = Convert.ToInt32(comboBox_BaudRate.SelectedItem.ToString());
serialPort1.DataBits = Convert.ToInt32(comboBox_DataBit.SelectedItem.ToString());
if (comboBox_StopBit.Text == "One")
{
serialPort1.StopBits = StopBits.One;
} else if (comboBox_StopBit.Text == "Two")
{
serialPort1.StopBits = StopBits.Two;
} else if (comboBox_StopBit.Text == "OnePointFive")
{
serialPort1.StopBits = StopBits.OnePointFive;
} else if (comboBox_StopBit.Text == "None")
{
serialPort1.StopBits = StopBits.None;
}
if (comboBox_Parity.Text == "Odd")
{
serialPort1.Parity = Parity.Odd;
}
else if (comboBox_Parity.Text == "Even")
{
serialPort1.Parity = Parity.Even;
}
else if (comboBox_Parity.Text == "None")
{
serialPort1.Parity = Parity.None;
}
try
{
comboBox_PortNames.Enabled = false;
comboBox_BaudRate.Enabled = false;
comboBox_DataBit.Enabled = false;
comboBox_StopBit.Enabled = false;
comboBox_Parity.Enabled = false;
button_Serach.Enabled = false;
serialPort1.Open();
button_OpenOrClose.Text = "Close";
}
catch
{
MessageBox.Show("串口打开失败!");
}
serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceive);
}
else if (button_OpenOrClose.Text == "Close")
{
try
{
comboBox_PortNames.Enabled = true;
comboBox_BaudRate.Enabled = true;
comboBox_DataBit.Enabled = true;
comboBox_StopBit.Enabled = true;
comboBox_Parity.Enabled = true;
button_Serach.Enabled = true;
serialPort1.DiscardInBuffer();
serialPort1.Close();
button_OpenOrClose.Text = "Open";
}
catch
{
MessageBox.Show("串口打开失败!");
}
}
}
#endregion
#region 接收串口数据
List<byte> sp_buffer = new List<byte>(4096);
int sp_buffer_max = 4096;
private void SerialDataReceive(object sender, SerialDataReceivedEventArgs e)
{
if (serialPort1.IsOpen == false)
{
serialPort1.Close();
return;
}
int Byte_len = serialPort1.BytesToRead;
byte[] Rc_byte = new byte[Byte_len];
serialPort1.Read(Rc_byte,0,Byte_len);
if (sp_buffer.Count > sp_buffer_max)
sp_buffer.RemoveRange(0,sp_buffer_max);
sp_buffer.AddRange(Rc_byte);
byte[] ruffer = new byte[9192];
if (sp_buffer.Count > 4)
{
sp_buffer.CopyTo(0,ruffer,0,sp_buffer.Count);
Task.Run(()=>printf_data(ruffer, sp_buffer.Count, 1));
}
}
#endregion
#region 打印数据流
void printf_data(byte[] Frame, int Length, int T_R)
{
Int16 i_len;
StringBuilder s = new StringBuilder();
if (T_R == 0)
s.Append("发送:");
else
s.Append("接收:");
for (i_len = 0; i_len < Length; i_len++)
{
s.Append(Frame[i_len].ToString("X2"));
s.Append(" ");
}
s.Append("[" + DateTime.Now.ToString("HH:mm:ss fff") + "]");
s.Append("\r\n");
string str_show = s.ToString();
MethodInvoker mi = new MethodInvoker(() =>
{
if (richTextBox_ReceiveBox.Lines.Count() > 20)
richTextBox_ReceiveBox.Clear();
richTextBox_ReceiveBox.AppendText(str_show);
});
BeginInvoke(mi);
}
#endregion
#region 发送数据
private void button_Send_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
string[] sendbuff = richTextBox1.Text.Split();
int Buff_Len = sendbuff.Length;
byte[] buff = new byte[Buff_Len];
for (int i = 0; i < sendbuff.Length; i++)
{
buff[i] = byte.Parse(sendbuff[i], System.Globalization.NumberStyles.HexNumber);
}
try
{
serialPort1.Write(buff, 0, buff.Length);
Task.Run(()=>printf_data(buff, Buff_Len, 0));
}
catch
{
MessageBox.Show("发送失败!!");
}
}
else
{
MessageBox.Show("串口未打开!");
}
}
#endregion
#region 清除输出框
private void Clear_Click(object sender, EventArgs e)
{
richTextBox_ReceiveBox.Clear();
}
#endregion
功能函数写好后绑定按钮和函数
(4)全部代码整合
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
namespace Serial
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region 初始化窗体
private void Form1_Load(object sender, EventArgs e)
{
try
{
string[] str = SerialPort.GetPortNames();
comboBox_PortNames.Items.Clear();
comboBox_PortNames.Items.AddRange(str);
if (str.Length > 0)
{
comboBox_PortNames.SelectedIndex = 0;
comboBox_BaudRate.SelectedIndex = 7;
comboBox_DataBit.SelectedIndex = 3;
comboBox_StopBit.SelectedIndex = 0;
comboBox_Parity.SelectedIndex = 2;
}
else
{
MessageBox.Show("当前无串口连接!");
}
}
catch
{
MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!");
}
}
#endregion
#region 搜索串口(与初始化函数一样)
private void button_Serach_Click(object sender, EventArgs e)
{
try
{
string[] str = SerialPort.GetPortNames();
comboBox_PortNames.Items.Clear();
comboBox_PortNames.Items.AddRange(str);
if (str.Length > 0)
{
comboBox_PortNames.SelectedIndex = 0;
comboBox_BaudRate.SelectedIndex = 7;
comboBox_DataBit.SelectedIndex = 3;
comboBox_StopBit.SelectedIndex = 0;
comboBox_Parity.SelectedIndex = 2;
}
else
{
MessageBox.Show("当前无串口连接!");
}
}
catch
{
MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!");
}
}
#endregion
#region 打开串口
private void button_OpenOrClose_Click(object sender, EventArgs e)
{
if (!serialPort1.IsOpen)
{
if (comboBox_PortNames.SelectedItem == null)
{
MessageBox.Show("请选择正确的串口", "提示");
return;
}
serialPort1.PortName = comboBox_PortNames.Text.ToString();
serialPort1.BaudRate = Convert.ToInt32(comboBox_BaudRate.SelectedItem.ToString());
serialPort1.DataBits = Convert.ToInt32(comboBox_DataBit.SelectedItem.ToString());
if (comboBox_StopBit.Text == "One")
{
serialPort1.StopBits = StopBits.One;
}
else if (comboBox_StopBit.Text == "Two")
{
serialPort1.StopBits = StopBits.Two;
}
else if (comboBox_StopBit.Text == "OnePointFive")
{
serialPort1.StopBits = StopBits.OnePointFive;
}
else if (comboBox_StopBit.Text == "None")
{
serialPort1.StopBits = StopBits.None;
}
if (comboBox_Parity.Text == "Odd")
{
serialPort1.Parity = Parity.Odd;
}
else if (comboBox_Parity.Text == "Even")
{
serialPort1.Parity = Parity.Even;
}
else if (comboBox_Parity.Text == "None")
{
serialPort1.Parity = Parity.None;
}
try
{
comboBox_PortNames.Enabled = false;
comboBox_BaudRate.Enabled = false;
comboBox_DataBit.Enabled = false;
comboBox_StopBit.Enabled = false;
comboBox_Parity.Enabled = false;
button_Serach.Enabled = false;
serialPort1.Open();
button_OpenOrClose.Text = "Close";
}
catch
{
MessageBox.Show("串口打开失败!");
}
serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceive);
}
else if (button_OpenOrClose.Text == "Close")
{
try
{
comboBox_PortNames.Enabled = true;
comboBox_BaudRate.Enabled = true;
comboBox_DataBit.Enabled = true;
comboBox_StopBit.Enabled = true;
comboBox_Parity.Enabled = true;
button_Serach.Enabled = true;
serialPort1.DiscardInBuffer();
serialPort1.Close();
button_OpenOrClose.Text = "Open";
}
catch
{
MessageBox.Show("串口打开失败!");
}
}
}
#endregion
#region 接收串口数据
List<byte> sp_buffer = new List<byte>(4096);
int sp_buffer_max = 4096;
private void SerialDataReceive(object sender, SerialDataReceivedEventArgs e)
{
if (serialPort1.IsOpen == false)
{
serialPort1.Close();
return;
}
int Byte_len = serialPort1.BytesToRead;
byte[] Rc_byte = new byte[Byte_len];
serialPort1.Read(Rc_byte, 0, Byte_len);
if (sp_buffer.Count > sp_buffer_max)
sp_buffer.RemoveRange(0, sp_buffer_max);
sp_buffer.AddRange(Rc_byte);
byte[] ruffer = new byte[9192];
if (sp_buffer.Count > 4)
{
sp_buffer.CopyTo(0, ruffer, 0, sp_buffer.Count);
Task.Run(() => printf_data(ruffer, sp_buffer.Count, 1));
}
}
#endregion
#region 打印数据流
void printf_data(byte[] Frame, int Length, int T_R)
{
Int16 i_len;
StringBuilder s = new StringBuilder();
if (T_R == 0)
s.Append("发送:");
else
s.Append("接收:");
for (i_len = 0; i_len < Length; i_len++)
{
s.Append(Frame[i_len].ToString("X2"));
s.Append(" ");
}
s.Append("[" + DateTime.Now.ToString("HH:mm:ss fff") + "]");
s.Append("\r\n");
string str_show = s.ToString();
MethodInvoker mi = new MethodInvoker(() =>
{
if (richTextBox_ReceiveBox.Lines.Count() > 20)
richTextBox_ReceiveBox.Clear();
richTextBox_ReceiveBox.AppendText(str_show);
});
BeginInvoke(mi);
}
#endregion
#region 发送数据
private void button_Send_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
string[] sendbuff = richTextBox_Send.Text.Split();
int Buff_Len = sendbuff.Length;
byte[] buff = new byte[Buff_Len];
for (int i = 0; i < sendbuff.Length; i++)
{
buff[i] = byte.Parse(sendbuff[i], System.Globalization.NumberStyles.HexNumber);
}
try
{
serialPort1.Write(buff, 0, buff.Length);
Task.Run(() => printf_data(buff, Buff_Len, 0));
}
catch
{
MessageBox.Show("发送失败!!");
}
}
else
{
MessageBox.Show("串口未打开!");
}
}
#endregion
#region 清除输出框
private void Clear_Click(object sender, EventArgs e)
{
richTextBox_ReceiveBox.Clear();
}
#endregion
}
}
(5)实现效果
到这我们就完整地做一个简单的串口助手了,我们可以进行二次开发,添加按钮绑定特定的的指令,每次可以通过点击按钮控制硬件,或者对接收到的数据流进行解析并显示出来,这样就能够做出项目需要的上位机了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)