串口助手|上位机软件-串口助手-带登陆界面

前言: 这是我在大三的时候写的一个串口助手,觉得挺好用的就分享给大家。如果有什么bug的话,希望大家多多包涵,毕竟对于C#语言我只是新手。
制作串口助手 串口助手选用Visual C#开发语言和Visual Studio 2012开发平台进行开发,实现的主要功能如下:

  1. 需要用户名和密码才能登录软件——可以保障用户的隐私
  2. 可用串口扫描——精确且快速的找到可以打开的串口号
  3. 保存和读取数据——可以对数据进行保存和读取,方便后期查看
  4. 显示接收数据的时间——用户可以知道数据到来的时间
  5. 定时发送——用户可以设定在几秒甚至几小时后发送控制命令
成品图如下:
串口助手|上位机软件-串口助手-带登陆界面
文章图片

登陆界面的源码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace SerialCommunicate {public partial class login : Form {public login() {InitializeComponent(); }private void button1_Click(object sender, EventArgs e) {if (textBox1.Text == "刘小纯" && textBox2.Text == "3118003167") {MessageBox.Show("欢迎登录系统!", "提示"); this.Hide(); Form1 form1 = new Form1(); form1.Show(); } else if(textBox1.Text == "刘小纯" && textBox2.Text != "3118003167") {MessageBox.Show("密码错误!", "提示"); } else if (textBox1.Text != "刘小纯") {MessageBox.Show("该用户不存在!", "提示"); } }private void label3_Click(object sender, EventArgs e) {} } }

主页面源码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO.Ports; //导入串口的命名空间 using System.IO; //using System.Text.RegularExpressions; //using System.Threading.Tasks; //using System.Collections; namespace SerialCommunicate {public partial class Form1 : Form {public Form1() {InitializeComponent(); serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); //串口数据接收事件 serialPort1.Encoding = Encoding.GetEncoding("GB2312"); //串口接收编码 System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; // } //List receivedDatas = new List(); //接收数据泛型数据/*窗体创建初始化函数*/ private void Form1_Load(object sender, EventArgs e)//窗口弹出触发 {ovalShape1.FillColor = Color.Gray; //小圆圈状态为灰色 SearchAndAddSerialToComboBox(serialPort1, comboBox1); //可用串口扫描 comboBox2.Text = "115200"; //默认波特率选择 comboBox4.Text = "8"; //默认数据位 comboBox5.Text = "无"; //默认校验位 comboBox3.Text = "1"; //默认停止位 }/*点击打开串口按键触发*/ private void button1_Click(object sender, EventArgs e) {try {serialPort1.PortName = comboBox1.Text; //端口号 serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text); //波特率 serialPort1.DataBits = Convert.ToInt32(comboBox4.Text.Trim()); //设置数据位,默认为8 switch (comboBox5.Text.Trim())//设置奇偶校验位,默认为无 {case "无": serialPort1.Parity = Parity.None; break; case "奇校验": serialPort1.Parity = Parity.Odd; break; case "偶校验": serialPort1.Parity = Parity.Even; break; default: serialPort1.Parity = Parity.None; break; } switch(comboBox3.Text .Trim () )//设置停止位,默认为1 {case "1": serialPort1.StopBits = StopBits .One ; break ; case "1.5": serialPort1.StopBits = StopBits .OnePointFive ; break ; case "2": serialPort1.StopBits= StopBits .Two ; break; default: serialPort1.StopBits= StopBits .None ; break; }serialPort1.ReadTimeout = 5000; //设置超时时间为5S Control.CheckForIllegalCrossThreadCalls = false; // 这个类中我们不检查跨线程的调用是否合法 //定义.DataReceived事件的委托,当串口收到数据后触发事件, //serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); //加了会使自动换行和显示时间出BugserialPort1.Open(); //打开串口 button1.Enabled = false; //打开串口的按键不能使用 button2.Enabled = true; //关闭串口的按键可以使用 ovalShape1.FillColor = Color.Red; //串口状态指示灯为红色 } catch//出错处理 {MessageBox.Show("串口打开错误或波特率设置有误", "小纯提示"); //弹出系统提示框 } }/*点击关闭串口触发*/ private void button2_Click(object sender, EventArgs e) {try {serialPort1.Close(); //关闭串口 button1.Enabled = true; //打开串口按键可用 button2.Enabled = false; //关闭串口按键不可用 ovalShape1.FillColor = Color.Gray; //串口状态指示灯变为灰色 comboBox2.DropDownStyle = ComboBoxStyle.DropDownList; //当点击关闭串口时,将波特率下拉列表设置为不可编辑 } catch {MessageBox.Show("关闭串口错误!", "小纯提示"); } }/*定义一个扫描可用串口的函数*/ private void SearchAndAddSerialToComboBox(SerialPort MyPort, ComboBox MyBox) { //将可用端口号添加到ComboBox string Buffer; //缓存 MyBox.Items.Clear(); //清空ComboBox内容 for (int i = 1; i < 20; i++)//循环 {try//核心原理是依靠try和catch完成遍历,即是从COM1到COM19逐个打开试试, //如果能打开,就把这个串口号添加到串口的下拉列表中,后关闭串口,让用户打开 {Buffer = "COM" + i.ToString(); MyPort.PortName = Buffer; MyPort.Open(); //如果失败,后面的代码不会执行 MyBox.Items.Add(Buffer); //打开成功,添加至下拉列表 MyPort.Close(); //关闭串口} catch {//不添加出错处理,因为这个程序就是为了试错 } } }/*串口接收事件*/ private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) {if (!radioButton3.Checked)//接收模式为ASCII(字符) {if (checkBox3.Checked)//显示时间的校验框被选中 {textBox1.AppendText(System.DateTime.Now.ToString("HH:mm:ss")+"\r\n"); //在接收数据的前面一行追加显示时间} textBox1.AppendText(serialPort1.ReadExisting()); //串口类会自动处理汉字,所以不需要特别转换,textBox1是输出框if (checkBox2.Checked)//自动换行的校验框被选中 try {textBox1.AppendText(Environment.NewLine); //接收自动换行 } catch {} }else//接收模式为Hex(数值) {byte[] data = https://www.it610.com/article/new byte[serialPort1.BytesToRead]; //定义缓冲区,大小为:serialPort1.BytesToRead,因为串口事件触发时有可能收到不止一个字节 serialPort1.Read(data, 0, data.Length); //从串口中读取数据/*函数原型:foreach(Type t in arry); Type:需要遍历每一的对象的类型,t:每一个对象,arry:需要遍历的数组*/foreach (byte Member in data)//遍历用法 {string str = Convert.ToString(Member, 16).ToUpper(); //将Member这个数转化为字符串,并且大写 textBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " "); //如果str的长度为1的就在其前面添加0如0x0A } if (checkBox3.Checked)//显示时间的校验框被选中 {textBox1.AppendText("\r\n"+System.DateTime.Now.ToString("HH:mm:ss")); }if (checkBox2.Checked)//自动换行的校验框被选中 try {textBox1.AppendText(Environment.NewLine); } catch { } } }/*发送按键触发*/ private void button3_Click(object sender, EventArgs e) {byte[] Data = https://www.it610.com/article/new byte[1]; //定义一个单字节的数组,用来发数据 if (serialPort1.IsOpen)//判断串口是否打开 {if (textBox2.Text !="")//判断输入框的内容是否为空 {if (!radioButton1.Checked)//发送模式为ASCII(字符) {try {serialPort1.Write(textBox2.Text); //将指定的字符串写入串口 //serialPort1.WriteLine(); //字符串写入 } catch {MessageBox.Show("串口数据写入错误", "小纯提示"); } }else//发送模式为HEX(数值) {try//如果此时用户输入字符串中含有非法字符(字母,汉字,符号等等,try,catch块可以捕捉并提示) {/*将用户输入的数字比如1234,转化为0x12,0x34*/ for (int i = 0; i < (textBox2.Text.Length - textBox2.Text.Length % 2) / 2; i++)//转换偶数个 {Data[0] = Convert.ToByte(textBox2.Text.Substring(i * 2, 2), 16); //转换(一次处理两个数字?) serialPort1.Write(Data, 0, 1); //将转化好的一个字节写入串口 } if (textBox2.Text.Length % 2 != 0)//如果数据的长度为奇数,需要单独处理最后一位 {Data[0] = Convert.ToByte(textBox2.Text.Substring(textBox2.Text.Length - 1, 1), 16); //单独处理最后一个字符 serialPort1.Write(Data, 0, 1); //写入 } } catch {MessageBox.Show("数据转换错误,请输入数字。", "小纯提示"); } } } } }/*扫描按键触发*/ private void button5_Click(object sender, EventArgs e) {SearchAndAddSerialToComboBox(serialPort1, comboBox1); //扫描并将可用串口添加至下拉列表 }/*清空按键触发*/ private void button4_Click(object sender, EventArgs e) {textBox1.Text = ""; }/*定时发送校验框被选中*/ private void checkBox1_CheckedChanged(object sender, EventArgs e) {if (checkBox1.Checked)//定时发送校验框被选中 {try {//选择自动发送 numericUpDown1.Enabled = false; //启动定时发送后不能修改定时时间 timer1.Interval = (int)numericUpDown1.Value; // * 1000; //设置定时器中断时间,*1000将单位转化为秒 timer1.Start(); //启动定时器 } catch { }} else//定时发送校验框不被选中 {try {//选择不自动发送 numericUpDown1.Enabled = true; ////停止定时发送后能修改定时时间 timer1.Stop(); //停止定时 } catch {timer1.Stop(); //出错的话再次停止定时 MessageBox.Show("停止自动发送错误", "小纯提示"); } }}/*定时时间到,定时发送数据*/ private void timer1_Tick(object sender, EventArgs e) {button3_Click(button3, new EventArgs()); //调用发送按钮的回调函数 }/*清空发送框*/ private void button6_Click_1(object sender, EventArgs e) {textBox2.Clear(); }/*点击波特率设置下列表*/ private void comboBox2_SelectedIndexChanged(object sender, EventArgs e) {if (comboBox2.Text.Equals("custom"))//当选择custom项时列表属性发生改变 {try {// comboBox2.DropDownStyle = ComboBoxStyle.DropDown; comboBox2.DropDownStyle = ComboBoxStyle.Simple; //将属性更改为可以编辑} catch {MessageBox.Show("设置波特率时错误!", "小纯提示"); } } }/*点击保存数据按钮*/ private void button7_Click(object sender, EventArgs e) {/*saveFileDialog1 为保存文件的对话框,StreamWriter是专门用来处理文本文化的类,可以方便的向文本文件中写入字符串*/ saveFileDialog1 = new SaveFileDialog(); //初始化此类的新实例 saveFileDialog1.Filter = "(*.txt)|*.txt"; //只允许保存为TXT文本 // try //{if (saveFileDialog1.ShowDialog() == DialogResult.OK)//页面弹出判断框是否点击确定按钮 {StreamWriter streamWriter = new StreamWriter(saveFileDialog1.FileName, false); streamWriter.Write(this.textBox1.Text); //将输出框的字符串写入TXT文本 streamWriter.Close(); //关闭流 } // }// catch { MessageBox.Show("先打开串口!", "小纯提示"); } }/*点击读入文件按钮*/ private void button8_Click(object sender, EventArgs e) {OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Filter = "All files(*.*)|*.*|txt file (*.txt)|*.txt"; if (openFileDialog1.ShowDialog() == DialogResult.OK) {string logpath = openFileDialog1.FileName; using (StreamReader sr = new StreamReader(logpath, Encoding.GetEncoding("gb2312"))) {string oneLineInfo = string.Empty; //读取到的每行内容 while (sr.EndOfStream != true) {oneLineInfo = oneLineInfo + "\r\n" + sr.ReadLine(); //按行读取 } sr.Close(); textBox1.Text = oneLineInfo; } } } } }

【串口助手|上位机软件-串口助手-带登陆界面】登陆界面与主页面的切换:
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace SerialCommunicate {static class Program {/// /// 应用程序的主入口点。 /// [STAThread] static void Main() {Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new Form1()); Application.Run(new login()); //若不需要登陆界面就把这个注释掉,取消上面的注释 } } }

    推荐阅读