借鉴了很大部分下面文章的内容,我也修改了很多,最后完善成了一个完整的串口助手。
C#编写串口助手
1.UI设置
文件—新建—项目,选择Visual C#,选择Windows窗体应用程序,名称:项目名称"调试串口助手",位置:保存项目的路径,解决方案:创建新的解决方案(添加到解决方案),解决方案名称:自动生成与项目名称相同,框架:.NET Framework 4.7,默认勾选为解决方案创建目录,点击确定。
创建新项目后可以看到Form1.cs[设计],这是自动生成的窗体应用,在这个页面利用左边工具栏和对应UI的属性可以设计UI。
找到解决中的Form1.cs,右键->查看代码,可以代码文件。
Form1窗体添加三个GroupBox控件,Text分别设置为:串口设置、接收数据、发送数据。
Form1窗体添加五个Lable控件,Text分别设置为:串口号:、波特率:、停止位:、奇偶校验:、数据位:。
Form1窗体添加五个ComoBox控件,Name分别设置为:cbxCOMPort、cbxBaudRate、cbxStopBits、cbxParity、cbxDataBits。
Form1窗体添加两个RadioButton控件,Text分别设置为:字符显示、HEX显示,Name分别设置为:rbnChar、rbnHex,
Checked分别为:True、False。
Form1窗体添加八个Button控件,Text分别设置为:检测串口、打开串口、清空数据、发送数据、AT、ATI8、选择文件、发送文件。
注:笔者截图里发送AT命令远不止两个按钮是因为此类命令代码非常相似,于是就只写了两个。
Name分别设置为:btnCheckCom、btnOpenCom、btnClearData、btnSendData。
Form1窗体添加三个TextBox控件,Name分别设置为:tbxRecvData、tbxSendData、filename_test_box,filename_test_box、tbxRecvData和的ReadOnly属性设置为True。
Fomr1窗体的AcceptButton属性设置为btnSendData,在窗体上回车关联到发送数据按钮。
代码+注释如下:
//新手可以下载一个vspn创建虚拟串口搭配使用:)
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 调试串口工具
{
public partial class Form1 : Form
{
bool isHex = false;//十六进制显示标志位
bool isOpen = false;//打开串口标志位
bool isSetProperty = false;//属性设置标志位
bool isfiletranfers = false;//文件传输标志位
SerialPort serialportcom = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//设置窗口大小
this.MaximizeBox = true; //影藏最大化按钮
this.MaximumSize = this.Size; //固定窗口尺寸最大为当前尺寸
this.MinimumSize = this.Size; //固定窗口尺寸最小为当前尺寸
//Form1.refresh();
//设置波特率
cbxBaudRate.Items.Add("1200");
cbxBaudRate.Items.Add("2400");
cbxBaudRate.Items.Add("4800");
cbxBaudRate.Items.Add("9600");
cbxBaudRate.Items.Add("19200");
cbxBaudRate.Items.Add("38400");
cbxBaudRate.Items.Add("115200");
cbxBaudRate.SelectedIndex = 3;
//列出停止位
cbxStopBits.Items.Add("0");
cbxStopBits.Items.Add("1");
cbxStopBits.Items.Add("1.5");
cbxStopBits.Items.Add("2");
cbxStopBits.SelectedIndex = 1;
//列出数据位
cbxDataBits.Items.Add("8");
cbxDataBits.Items.Add("7");
cbxDataBits.Items.Add("6");
cbxDataBits.Items.Add("5");
cbxDataBits.SelectedIndex = 0;
//列出奇偶检验
cbxParity.Items.Add("无");
cbxParity.Items.Add("奇校验");
cbxParity.Items.Add("偶校验");
cbxParity.SelectedIndex = 0;
//默认接受到的数据用字符显示
rbnChar.Checked = true;
}
private void btnCheckCom_Click(object sender, EventArgs e)
{
bool comExistence = false;//有可用串口标志位
cbxCOMPort.Items.Clear();
//将读取到的串口号写入选项框
foreach (string sPortName in SerialPort.GetPortNames())
{
try
{
cbxCOMPort.Items.Add(sPortName);
comExistence = true;
}
catch (Exception)
{
continue;
}
}
if (comExistence)
{
cbxCOMPort.SelectedIndex = 0;
}
else
{
MessageBox.Show("没有找到可用的串口!", "错误提示");
}
}
private bool checkPortSetting()//检测串口设置
{
if (cbxCOMPort.Text.Trim() == "") return false;
if (cbxBaudRate.Text.Trim() == "") return false;
if (cbxDataBits.Text.Trim() == "") return false;
if (cbxParity.Text.Trim() == "") return false;
if (cbxStopBits.Text.Trim() == "") return false;
return true;
}
private bool CheckSendData()//检测发送数据是否输入
{
if (tbxSendData.Text.Trim() == "") return false;
return true;
}
private bool CheckFileSendData()
{
if (filename_test_box.Text.Trim() == "") return false;
return true;
}
private void SetPortProperty()//设置串口的属性
{
//创建串口
serialportcom = new SerialPort();
//设置串口名
serialportcom.PortName = cbxCOMPort.Text.Trim();
//设置串口波特率
serialportcom.BaudRate = Convert.ToInt32(cbxBaudRate.Text.Trim());
//设置串口数据位
serialportcom.DataBits = Convert.ToInt32(cbxDataBits.Text.Trim());
//设置串口停止位
if (cbxStopBits.Text.Trim() == "0")
{
serialportcom.StopBits = StopBits.None;
}
if (cbxStopBits.Text.Trim() == "1")
{
serialportcom.StopBits = StopBits.One;
}
if (cbxStopBits.Text.Trim() == "1.5")
{
serialportcom.StopBits = StopBits.OnePointFive;
}
if (cbxStopBits.Text.Trim() == "2")
{
serialportcom.StopBits = StopBits.Two;
}
//设置校验
if (cbxParity.Text.Trim() == "无")
{
serialportcom.Parity = Parity.None;
}
if (cbxParity.Text.Trim() == "奇校验")
{
serialportcom.Parity = Parity.Odd;
}
if (cbxParity.Text.Trim() == "偶校验")
{
serialportcom.Parity = Parity.Even;
}
serialportcom.ReadTimeout = 100000;//设置超时读取时间
serialportcom.RtsEnable = true;
serialportcom.DataReceived += new SerialDataReceivedEventHandler(serialportcom_DataReceived);//接受数据事件监听
if (rbnHex.Checked)
{
isHex = true;
}
else
{
isHex = false;
}
}
private void btnOpenCom_Click(object sender, EventArgs e)
{
if (isOpen == false)
{
if (!checkPortSetting())//检测串口设置
{
MessageBox.Show("串口未设置", "错误提示");
return;
}
if (!isSetProperty)
{
SetPortProperty();
isSetProperty = true;
}
try
{
serialportcom.Open();
isOpen = true;
btnOpenCom.Text = "关闭串口";
//串口打开后,相关的串口设置按钮不再可用
cbxCOMPort.Enabled = false;
cbxBaudRate.Enabled = false;
cbxDataBits.Enabled = false;
cbxStopBits.Enabled = false;
cbxParity.Enabled = false;
rbnChar.Enabled = false;
rbnHex.Enabled = false;
btnCheckCom.Enabled = false;
}
catch (Exception)
{
isSetProperty = false;//串口设置标志位设置为false
isOpen = false; //串口打开标志位设置为false
MessageBox.Show("串口无效或被占用", "错误提示");//打开失败提示消息框
}
}
else//之前串口是打开的,则执行else语句块
{
try
{
serialportcom.Close();//关闭串口
isOpen = false; //串口打开标志位设置为false
btnOpenCom.Text = "打开串口"; //btnOpenCom的文本设置为“打开串口”
cbxCOMPort.Enabled = true; //串口号使能
cbxBaudRate.Enabled = true; //波特率
cbxDataBits.Enabled = true; //数据位
cbxStopBits.Enabled = true; //停止位
cbxParity.Enabled = true; //校验
rbnChar.Enabled = true; //字符型
rbnHex.Enabled = true; //Hex型
btnCheckCom.Enabled = true;//检测串口
}
catch (Exception)
{
MessageBox.Show("关闭串口时发生错误", "错误提示"); //关闭失败提示消息框
}
}
}
private void button2_Click(object sender, EventArgs e)//选择文件时间监听
{
//新建一个文件对话框
OpenFileDialog pOpen = new OpenFileDialog();//创建文件变量
//设置对话框标题
pOpen.Title = "打开想要传输的文件";
//设置打开文件类型
pOpen.Filter = "所有文件(*.*)|*.*";
//监测文件是否存在
pOpen.CheckFileExists = true;
//文件打开后执行以下程序
if (pOpen.ShowDialog() == DialogResult.OK)
{
filename_test_box.Text = pOpen.FileName;
isfiletranfers = true;
}
}
private void button1_Click(object sender, EventArgs e)//发送文件
{
if (isOpen)
{
try
{
string filenameee = filename_test_box.Text;//获取文件名
FileStream fs = File.OpenRead(@filenameee);//新建文件流
byte[] filedata = new byte[fs.Length];//创建文件内容大小的字节空间
fs.Read(filedata, 0, filedata.Length);//将文件内容写入字节空间
string writest = Encoding.Default.GetString(filedata);
filedata = Encoding.Default.GetBytes(writest);
serialportcom.Write(filedata, 0, filedata.Length);//传输字节数组
//判断文件传输完毕,文件传输标志位变为false
if (serialportcom.BytesToRead == 0)
{
isfiletranfers = false;
}
}
catch
{
MessageBox.Show("发送数据时发生错误!", "错误提示");
return;
}
}
else
{
MessageBox.Show("串口未打开", "错误提示");
}
if (!CheckFileSendData())
{
MessageBox.Show("请输入要发送的数据", "错误提示");
}
}
private void btnSendData_Click(object sender, EventArgs e)
{
if (isOpen) //串口打开状态
{
try
{
Encoding sendData = System.Text.Encoding.GetEncoding(936);//使用合适字符编码,936表示GB2312
byte[] bytesSD = Encoding.Default.GetBytes(tbxSendData.Text+"\r\n");//创建字节空间,并写入待传输数据
tbxRecvData.Text += tbxSendData.Text + "\r\n";
serialportcom.Write(bytesSD, 0, bytesSD.Length); //串口发送数据
tbxRecvData.Text += "发送成功" + "\r\n";
}
catch
{
MessageBox.Show("发送数据时发生错误!", "错误提示");
return;
}
}
else
{
MessageBox.Show("串口未打开", "错误提示");
}
if (!CheckSendData())
{
MessageBox.Show("请输入要发送的数据", "错误提示");
}
}
private void serialportcom_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
System.Threading.Thread.Sleep(100); //延时100ms,等待接收完数据
//MessageBox.Show("收到数据");
this.Invoke((EventHandler)(delegate //this.Invoke是跨线程访问ui的方法,也是文本的范例
{
try
{
if (isHex == false)
{
tbxRecvData.Text += "正在接收数据...." + "\r\n";
byte[] a = new byte[serialportcom.BytesToRead];//创建一个缓冲区数据大小的字节空间
serialportcom.Read(a, 0, a.Length); //读取缓冲区的数据,并将其写入a的空间中
string recvstring = Encoding.Default.GetString(a);//解码出a中的字符信息
tbxRecvData.Text += recvstring + "\r\n";
}
else
{
Byte[] ReceivedData = new Byte[serialportcom.BytesToRead]; //定义并初始化字符数组,sp.ByteToRead串口读字符串长度
serialportcom.Read(ReceivedData, 0, ReceivedData.Length); //字符数组读取串口数据
String RecvDataText = null; //定义字符串
for (int i = 0; i < ReceivedData.Length; i++)
{
RecvDataText += ("0X" + ReceivedData[i].ToString("X2") + " "); //串口接收字符数组,字符依次转换为字符串,0Xxx
RecvDataText +="\r\n"; //X2:X是十六进制,2是两位。(A X2--0X0A,A X---0XA)
}
tbxRecvData.Text += RecvDataText; //转换后的字符串显示到tbxRecvData上面
}
}
catch (Exception)
{
MessageBox.Show("数据接受失败");
}
serialportcom.DiscardInBuffer(); //清除串口接收缓冲区数据
}));
}
private void btnClearData_Click_1(object sender, EventArgs e)//清空数据
{
tbxRecvData.Text = "";
tbxSendData.Text = "";
filename_test_box.Text = "";
}
private void btnAT1_Click(object sender, EventArgs e)
{
Encoding sendData = System.Text.Encoding.GetEncoding(936);//使用合适字符编码,936表示GB2312
byte[] bytesSD = Encoding.Default.GetBytes("AT" + "\r\n");//创建字节空间,并写入待传输数据
tbxRecvData.Text += btnAT1.Text + "\r\n";
serialportcom.Write(bytesSD, 0, bytesSD.Length); //串口发送数据
tbxRecvData.Text += "发送成功" + "\r\n";
}
private void btnAT2_Click(object sender, EventArgs e)
{
Encoding sendData = System.Text.Encoding.GetEncoding(936);//使用合适字符编码,936表示GB2312
byte[] bytesSD = Encoding.Default.GetBytes("ATI8" + "\r\n");//创建字节空间,并写入待传输数据
tbxRecvData.Text += btnAT2.Text + "\r\n";
serialportcom.Write(bytesSD, 0, bytesSD.Length); //串口发送数据
tbxRecvData.Text += "发送成功" + "\r\n";
}
}
}