超级串口调试工具设计及实现(C#源码)
工具业务说明
编写此工具是因为物联网设备调试及批量出厂需要,硬件开发,肯定少不了串口工具,但网上找过几个,都不如意,如是产生了自己编写的想法,并且,因为物联网设备批量出货时,量很大,经常需要采集设备信息,如:模组IMEI号、ICCID、IMSI等信息,如是,在串口工具的基础上,本人添加了“出厂设备”按钮,实现了程序自动采集,只需要人工将设备从串口线另一端进行更换,设备的信息就会采集在列表中,采保证列表不会重复,并可以导出为Excel表文件,文档后面提供全部源码,源码采用Vs.Net2017开发,.NET4.6.2的框架。C#
工具界面
源码
3.1、FormMain
using INIFILE;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SuperSerialTools
{
public partial class FormMain : Form
{
SerialPort sp1 = new SerialPort();//sp1.ReceivedBytesThreshold = 1;//只要有1个字符送达端口时便触发DataReceived事件
int InterValTotal = 0;//间隔时间总秒数
public FormMain()
{
InitializeComponent();
}
/// <summary>
/// 程序启动时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FormMain_Load(object sender, EventArgs e)
{
INIFILE.Profile.LoadProfile();//加载所有
SetControlValue();
string strPath = AppDomain.CurrentDomain.BaseDirectory;
cbAutoSave.Text = strPath + "log.txt";
}
/// <summary>
/// 初始化窗体
/// </summary>
private void SetControlValue()
{
// 预置波特率
switch (Profile.G_BAUDRATE)
{
case "300":
cbBaudRate.SelectedIndex = 0;
break;
case "600":
cbBaudRate.SelectedIndex = 1;
break;
case "1200":
cbBaudRate.SelectedIndex = 2;
break;
case "2400":
cbBaudRate.SelectedIndex = 3;
break;
case "4800":
cbBaudRate.SelectedIndex = 4;
break;
case "9600":
cbBaudRate.SelectedIndex = 5;
break;
case "19200":
cbBaudRate.SelectedIndex = 6;
break;
case "38400":
cbBaudRate.SelectedIndex = 7;
break;
case "115200":
cbBaudRate.SelectedIndex = 8;
break;
default:
{
MessageBox.Show("波特率预置参数错误!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
//预置数据位
switch (Profile.G_DATABITS)
{
case "5":
cbDataBits.SelectedIndex = 0;
break;
case "6":
cbDataBits.SelectedIndex = 1;
break;
case "7":
cbDataBits.SelectedIndex = 2;
break;
case "8":
cbDataBits.SelectedIndex = 3;
break;
default:
{
MessageBox.Show("数据位预置参数错误!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
//预置停止位
switch (Profile.G_STOP)
{
case "1":
cbStop.SelectedIndex = 0;
break;
case "1.5":
cbStop.SelectedIndex = 1;
break;
case "2":
cbStop.SelectedIndex = 2;
break;
default:
{
MessageBox.Show("停止位预置参数错误!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
//预置校验位
switch (Profile.G_PARITY)
{
case "NONE":
cbParity.SelectedIndex = 0;
break;
case "ODD":
cbParity.SelectedIndex = 1;
break;
case "EVEN":
cbParity.SelectedIndex = 2;
break;
default:
{
MessageBox.Show("校验位预置参数错误!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
txtCommand1.Text = Profile.txtCmd1;
txtCommand2.Text = Profile.txtCmd2;
txtCommand3.Text = Profile.txtCmd3;
txtCommand4.Text = Profile.txtCmd4;
txtCommand5.Text = Profile.txtCmd5;
txtCommand6.Text = Profile.txtCmd6;
txtCommand7.Text = Profile.txtCmd7;
txtCommand8.Text = Profile.txtCmd8;
txtCommand9.Text = Profile.txtCmd9;
txtCommand10.Text = Profile.txtCmd10;
txtCommand11.Text = Profile.txtCmd11;
txtCommand12.Text = Profile.txtCmd12;
txtCommand13.Text = Profile.txtCmd13;
txtCommand14.Text = Profile.txtCmd14;
txtCommand15.Text = Profile.txtCmd15;
txtCommand16.Text = Profile.txtCmd16;
txtCommand17.Text = Profile.txtCmd17;
txtCommand18.Text = Profile.txtCmd18;
txtCommand19.Text = Profile.txtCmd19;
txtCommand20.Text = Profile.txtCmd20;
txtMsg1.Text = Profile.txtDesc1;
txtMsg2.Text = Profile.txtDesc2;
txtMsg3.Text = Profile.txtDesc3;
txtMsg4.Text = Profile.txtDesc4;
txtMsg5.Text = Profile.txtDesc5;
txtMsg6.Text = Profile.txtDesc6;
txtMsg7.Text = Profile.txtDesc7;
txtMsg8.Text = Profile.txtDesc8;
txtMsg9.Text = Profile.txtDesc9;
txtMsg10.Text = Profile.txtDesc10;
txtMsg11.Text = Profile.txtDesc11;
txtMsg12.Text = Profile.txtDesc12;
txtMsg13.Text = Profile.txtDesc13;
txtMsg14.Text = Profile.txtDesc14;
txtMsg15.Text = Profile.txtDesc15;
txtMsg16.Text = Profile.txtDesc16;
txtMsg17.Text = Profile.txtDesc17;
txtMsg18.Text = Profile.txtDesc18;
txtMsg19.Text = Profile.txtDesc19;
txtMsg20.Text = Profile.txtDesc20;
//检查是否含有串口
string[] str = SerialPort.GetPortNames();
if (str == null)
{
MessageBox.Show("本机没有串口!", "Error");
return;
}
//添加串口项目
foreach (string s in System.IO.Ports.SerialPort.GetPortNames())
{//获取有多少个COM口
//System.Diagnostics.Debug.WriteLine(s);
cbSerial.Items.Add(s);
}
//串口设置默认选择项
if (cbSerial.Items.Count > 0)
{
cbSerial.SelectedIndex = 0;
}
sp1.BaudRate = 9600;
Control.CheckForIllegalCrossThreadCalls = false; //这个类中我们不检查跨线程的调用是否合法(因为.net 2.0以后加强了安全机制,,不允许在winform中直接跨线程访问控件的属性)
sp1.DataReceived += new SerialDataReceivedEventHandler(sp1_DataReceived);
//sp1.ReceivedBytesThreshold = 1;
//准备就绪
sp1.DtrEnable = true;
sp1.RtsEnable = true;
//设置数据读取超时为1秒
sp1.ReadTimeout = 1000;
sp1.Close();
}
/// <summary>
/// 串口接收入口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
Thread.Sleep(300);
this.Invoke((EventHandler)(delegate
{
string receivStr = sp1.ReadExisting();
string[] receivSplit = receivStr.Split(Environment.NewLine.ToArray(), StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < receivSplit.Length; i++)
{
if (!string.IsNullOrEmpty(receivSplit[i]))
{
receivSplit[i] = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss fff]") + receivSplit[i];
}
}
receivStr = string.Join(System.Environment.NewLine, receivSplit);
if (txtReceive.Text.Trim() == "")
{
txtReceive.Text = receivStr;
}
else
{
txtReceive.Text = txtReceive.Text + System.Environment.NewLine + System.Environment.NewLine + receivStr;
}
txtReceive.Focus();
txtReceive.SelectionStart = txtReceive.TextLength;
sp1.DiscardInBuffer();//清空SerialPort控件的Buffer
txtSend.Focus();
}));
}
catch
{ }
}
/// <summary>
/// 发送按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnSend_Click(object sender, EventArgs e)
{
if (!sp1.IsOpen) //如果没打开
{
MessageBox.Show("请先打开串口!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
sp1.WriteLine(txtSend.Text); //写入数据
if (cbAutoSave.Checked)
{
string strPath = AppDomain.CurrentDomain.BaseDirectory;
txtReceive.SaveFile(strPath + "log.txt", RichTextBoxStreamType.PlainText);
}
}
/// <summary>
/// 打开串口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnOpen_Click(object sender, EventArgs e)
{
if (cbSerial.Items.Count == 0)
{
MessageBox.Show("Error:没有检测到可用的串口!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (!sp1.IsOpen)
{
try
{
//设置串口号
string serialName = cbSerial.SelectedItem.ToString();
sp1.PortName = serialName;
//设置各“串口设置”
string strBaudRate = cbBaudRate.Text;
string strDateBits = cbDataBits.Text;
string strStopBits = cbStop.Text;
Int32 iBaudRate = Convert.ToInt32(strBaudRate);
Int32 iDateBits = Convert.ToInt32(strDateBits);
sp1.BaudRate = iBaudRate; //波特率
sp1.DataBits = iDateBits; //数据位
switch (cbStop.Text) //停止位
{
case "1":
sp1.StopBits = StopBits.One;
break;
case "1.5":
sp1.StopBits = StopBits.OnePointFive;
break;
case "2":
sp1.StopBits = StopBits.Two;
break;
default:
MessageBox.Show("Error:参数不正确!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
switch (cbParity.Text) //校验位
{
case "无":
sp1.Parity = Parity.None;
break;
case "奇校验":
sp1.Parity = Parity.Odd;
break;
case "偶校验":
sp1.Parity = Parity.Even;
break;
default:
MessageBox.Show("Error:参数不正确!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
if (sp1.IsOpen == true)//如果打开状态,则先关闭一下
{
sp1.Close();
}
//状态栏设置
tsSpNum.Text = "串口号:" + sp1.PortName + "|";
tsBaudRate.Text = "波特率:" + sp1.BaudRate + "|";
tsDataBits.Text = "数据位:" + sp1.DataBits + "|";
tsStopBits.Text = "停止位:" + sp1.StopBits + "|";
tsParity.Text = "校验位:" + sp1.Parity + "|";
//设置必要控件不可用
cbSerial.Enabled = false;
cbBaudRate.Enabled = false;
cbDataBits.Enabled = false;
cbStop.Enabled = false;
cbParity.Enabled = false;
sp1.Open(); //打开串口
btnOpen.Text = "关闭串口";
}
catch (System.Exception ex)
{
MessageBox.Show("Error:" + ex.Message, "Error");
//状态栏设置
tsSpNum.Text = "串口号:未指定|";
tsBaudRate.Text = "波特率:未指定|";
tsDataBits.Text = "数据位:未指定|";
tsStopBits.Text = "停止位:未指定|";
tsParity.Text = "校验位:未指定|";
//恢复控件功能
//设置必要控件不可用
cbSerial.Enabled = true;
cbBaudRate.Enabled = true;
cbDataBits.Enabled = true;
cbStop.Enabled = true;
//cbParity.Enabled = true;
tmSend.Enabled = false;
tmSend.Stop();
cbTimeSend.Checked = false;
return;
}
}
else
{
//状态栏设置
tsSpNum.Text = "串口号:未指定|";
tsBaudRate.Text = "波特率:未指定|";
tsDataBits.Text = "数据位:未指定|";
tsStopBits.Text = "停止位:未指定|";
tsParity.Text = "校验位:未指定|";
//恢复控件功能
//设置必要控件不可用
cbSerial.Enabled = true;
cbBaudRate.Enabled = true;
cbDataBits.Enabled = true;
cbStop.Enabled = true;
cbParity.Enabled = true;
sp1.Close(); //关闭串口
btnOpen.Text = "打开串口";
tmSend.Enabled = false; //关闭计时器
tmSend.Stop();
cbTimeSend.Checked = false;
}
}
/// <summary>
/// 关闭窗体时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
Profile.txtCmd1 = txtCommand1.Text;
Profile.txtCmd2 = txtCommand2.Text;
Profile.txtCmd3 = txtCommand3.Text;
Profile.txtCmd4 = txtCommand4.Text;
Profile.txtCmd5 = txtCommand5.Text;
Profile.txtCmd6 = txtCommand6.Text;
Profile.txtCmd7 = txtCommand7.Text;
Profile.txtCmd8 = txtCommand8.Text;
Profile.txtCmd9 = txtCommand9.Text;
Profile.txtCmd10 = txtCommand10.Text;
Profile.txtCmd11 = txtCommand11.Text;
Profile.txtCmd12 = txtCommand12.Text;
Profile.txtCmd13 = txtCommand13.Text;
Profile.txtCmd14 = txtCommand14.Text;
Profile.txtCmd15 = txtCommand15.Text;
Profile.txtCmd16 = txtCommand16.Text;
Profile.txtCmd17 = txtCommand17.Text;
Profile.txtCmd18 = txtCommand18.Text;
Profile.txtCmd19 = txtCommand19.Text;
Profile.txtCmd20 = txtCommand20.Text;
Profile.txtDesc1 = txtMsg1.Text;
Profile.txtDesc2 = txtMsg2.Text;
Profile.txtDesc3 = txtMsg3.Text;
Profile.txtDesc4 = txtMsg4.Text;
Profile.txtDesc5 = txtMsg5.Text;
Profile.txtDesc6 = txtMsg6.Text;
Profile.txtDesc7 = txtMsg7.Text;
Profile.txtDesc8 = txtMsg8.Text;
Profile.txtDesc9 = txtMsg9.Text;
Profile.txtDesc10 = txtMsg10.Text;
Profile.txtDesc11 = txtMsg11.Text;
Profile.txtDesc12 = txtMsg12.Text;
Profile.txtDesc13 = txtMsg13.Text;
Profile.txtDesc14 = txtMsg14.Text;
Profile.txtDesc15 = txtMsg15.Text;
Profile.txtDesc16 = txtMsg16.Text;
Profile.txtDesc17 = txtMsg17.Text;
Profile.txtDesc18 = txtMsg18.Text;
Profile.txtDesc19 = txtMsg19.Text;
Profile.txtDesc20 = txtMsg20.Text;
INIFILE.Profile.SaveProfile();
sp1.Close();
}
catch
{ }
}
private void CheckPort()
{ //状态栏设置
tsSpNum.Text = "串口号:未指定|";
tsBaudRate.Text = "波特率:未指定|";
tsDataBits.Text = "数据位:未指定|";
tsStopBits.Text = "停止位:未指定|";
tsParity.Text = "校验位:未指定|";
//恢复控件功能
//设置必要控件不可用
cbSerial.Enabled = true;
cbBaudRate.Enabled = true;
cbDataBits.Enabled = true;
cbStop.Enabled = true;
cbParity.Enabled = true;
sp1.Close(); //关闭串口
btnOpen.Text = "打开串口";
tmSend.Enabled = false; //关闭计时器
tmSend.Stop();
cbTimeSend.Checked = false;
try
{
//设置串口号
string serialName = cbSerial.SelectedItem.ToString();
sp1.PortName = serialName;
//设置各“串口设置”
string strBaudRate = cbBaudRate.Text;
string strDateBits = cbDataBits.Text;
string strStopBits = cbStop.Text;
Int32 iBaudRate = Convert.ToInt32(strBaudRate);
Int32 iDateBits = Convert.ToInt32(strDateBits);
sp1.BaudRate = iBaudRate; //波特率
sp1.DataBits = iDateBits; //数据位
switch (cbStop.Text) //停止位
{
case "1":
sp1.StopBits = StopBits.One;
break;
case "1.5":
sp1.StopBits = StopBits.OnePointFive;
break;
case "2":
sp1.StopBits = StopBits.Two;
break;
default:
MessageBox.Show("Error:参数不正确!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
switch (cbParity.Text) //校验位
{
case "无":
sp1.Parity = Parity.None;
break;
case "奇校验":
sp1.Parity = Parity.Odd;
break;
case "偶校验":
sp1.Parity = Parity.Even;
break;
default:
MessageBox.Show("Error:参数不正确!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
if (sp1.IsOpen == true)//如果打开状态,则先关闭一下
{
sp1.Close();
}
//状态栏设置
tsSpNum.Text = "串口号:" + sp1.PortName + "|";
tsBaudRate.Text = "波特率:" + sp1.BaudRate + "|";
tsDataBits.Text = "数据位:" + sp1.DataBits + "|";
tsStopBits.Text = "停止位:" + sp1.StopBits + "|";
tsParity.Text = "校验位:" + sp1.Parity + "|";
//设置必要控件不可用
cbSerial.Enabled = false;
cbBaudRate.Enabled = false;
cbDataBits.Enabled = false;
cbStop.Enabled = false;
cbParity.Enabled = false;
sp1.Open(); //打开串口
btnOpen.Text = "关闭串口";
}
catch (System.Exception ex)
{
MessageBox.Show("Error:" + ex.Message, "Error");
tmSend.Enabled = false;
tmSend.Stop();
cbTimeSend.Checked = false;
return;
}
}
/// <summary>
/// 时间控件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TmSend_Tick(object sender, EventArgs e)
{
tmSend.Interval = InterValTotal;
if (!sp1.IsOpen)
{
// MessageBox.Show("请先打开串口!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
tmSend.Interval = 10;
CheckPort();
return;
}
SendCommandList();
if (cbAutoSave.Checked)
{
string strPath = AppDomain.CurrentDomain.BaseDirectory;
txtReceive.SaveFile(strPath + "log.txt", RichTextBoxStreamType.PlainText);
}
}
/// <summary>
/// 发送批量命令
/// </summary>
private void SendCommandList()
{
try
{
for (int i = 1; i < 21; i++)
{
if (((CheckBox)groupBox7.Controls.Find("checkBox" + i.ToString(), true)[0]).Checked)
{
if (((TextBox)groupBox7.Controls.Find("txtCommand" + i.ToString(), true)[0]).Text.Trim() != "")
{
string interval = ((TextBox)groupBox7.Controls.Find("txtTime" + i.ToString(), true)[0]).Text.Trim();
int.TryParse(interval, out int SleepInterVal);
string txtCommand = ((TextBox)groupBox7.Controls.Find("txtCommand" + i.ToString(), true)[0]).Text;
sp1.WriteLine(txtCommand);
Application.DoEvents();
Delay(SleepInterVal * 1000);
Application.DoEvents();
}
}
}
}
catch
{ }
}
/// <summary>
/// 延时不卡界面
/// </summary>
/// <param name="milliSecond"></param>
public void Delay(int milliSecond)
{
int start = Environment.TickCount;
while (Math.Abs(Environment.TickCount - start) < milliSecond)
{
Application.DoEvents();
}
}
/// <summary>
/// 发送命令文本
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TxtSend_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
BtnSend_Click(sender, e);
}
}
/// <summary>
/// 全选择
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CheckBox_CheckedChanged(object sender, EventArgs e)
{
foreach (Control item in groupBox7.Controls)
{
if (item.Name.IndexOf("checkBox") > -1)
{
((CheckBox)item).Checked = cbSelectAll.Checked;
}
}
}
/// <summary>
/// 统一设定时间间隔文本框
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TxtTime_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
foreach (Control item in groupBox7.Controls)
{
if (item.Name.IndexOf("txtTime") > -1)
{
((TextBox)item).Text = txtSetTime.Text;
}
}
}
}
/// <summary>
/// 20个发送命令按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button20_Click(object sender, EventArgs e)
{
string controlIndex = ((Button)sender).Text;
string txtCommand = ((TextBox)groupBox7.Controls.Find("txtCommand" + controlIndex, true)[0]).Text;
if (!sp1.IsOpen) //如果没打开
{
MessageBox.Show("请先打开串口!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
sp1.WriteLine(txtCommand);//写入数据
if (cbAutoSave.Checked)
{
string strPath = AppDomain.CurrentDomain.BaseDirectory;
txtReceive.SaveFile(strPath + "log.txt", RichTextBoxStreamType.PlainText);
}
}
/// <summary>
/// 定时发送数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CbTimeSend_CheckedChanged(object sender, EventArgs e)
{
if (cbTimeSend.Checked)
{
if (!sp1.IsOpen)
{
MessageBox.Show("请先打开串口!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
cbTimeSend.Checked = false;
return;
}
InterValTotal = 0;
foreach (Control item in groupBox7.Controls)
{
if (item.Name.IndexOf("checkBox") > -1)
{
CheckBox cb = (CheckBox)item;
if (cb.Checked)
{
string interval = ((TextBox)groupBox7.Controls.Find(cb.Name.Replace("checkBox", "txtTime"), true)[0]).Text.Trim();
if (int.TryParse(interval, out int intTime) == false)
{
MessageBox.Show("检测到设定的时间间隔有误!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
else
{
InterValTotal = InterValTotal + 310 + intTime * 1000;
}
}
}
}
foreach (Control item in groupBox7.Controls)
{
if (item.Name != "cbTimeSend")
{
item.Enabled = false;
}
}
tmSend.Interval = 10;
tmSend.Enabled = true;
tmSend.Start();
}
else
{
tmSend.Stop();
tmSend.Enabled = false;
foreach (Control item in groupBox7.Controls)
{
item.Enabled = true;
}
}
}
private void BtnDevice_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Title = "请输入要保存的文件日志文件路径";
sfd.Filter = "文本文件|*.txt";
if (sfd.ShowDialog() == DialogResult.OK)
{
FormDevice frm = new FormDevice();
frm.Tag = sfd.FileName;
frm.Text = "出厂设备信息采集[" + sfd.FileName + "]";
frm.ShowDialog();
}
}
}
}
更多的源码请前往下载