软件功能:
使用C#实现PC串口通讯
支持定时发送
支持16进制(hex) ASCII UTF-8 Unicode 四种编码格式
支持配置文件的保存和读取
可以可以显示发送历史
可以统计总的发送字节数和接受字节数
软件界面:
C#源码:
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; using System.IO.Ports; using System.Threading; using System.IO; using System.Xml.Serialization; namespace 串口调试工具 { public partial class Form1 : Form { private SerialPort sp = new SerialPort();//链接对象 Config config = new Config();//配置文件 public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //获取串口列表 string[] comList = SerialPort.GetPortNames(); if (comList.Length == 0) { MessageBox.Show("无可用串口"); return; } foreach (var com in comList) { cmbComList.Items.Add(com); } //添加波特率 int[] baudRate = { 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 43000, 56000, 57600, 115200 }; foreach (var br in baudRate) { cmbBautRade.Items.Add(br); } //添加数据位 int[] dataBits = { 8, 7, 6, 5 }; foreach (var db in dataBits) { cmbDataBits.Items.Add(db); } //添加停止位 int[] stopBits = { 1, 2, 3 }; foreach (var sb in stopBits) { cmbStopBits.Items.Add(sb); } //添加检验方式 string[] parity = { "None", "Even", "Mark", "Odd", "Space" }; foreach (var p in parity) { cmbParity.Items.Add(p); } //添加常用编码 string[] encode = { "ASCII","UTF-8","Unicode","Hex"}; foreach (var en in encode) { cmbEncodeSend.Items.Add(en); cmbEncodeRec.Items.Add(en); } //加载配置文件 LoadConfig(); } private void LoadConfig() { //把配置信息赋值给控件默认值 cmbComList.SelectedItem = config.PortName; if (cmbComList.SelectedIndex == -1) cmbComList.SelectedIndex = 0; cmbBautRade.SelectedItem = config.BautRade; cmbDataBits.SelectedItem = config.DataBits; cmbStopBits.SelectedItem = config.StopBits; cmbParity.SelectedItem = config.Parity; cmbEncodeRec.SelectedItem = config.EncodeRec; cmbEncodeSend.SelectedItem = config.EncodeSend; //激活打开按钮 this.btnOpen.Enabled = true; } private void btnOpen_Click(object sender, EventArgs e) { if (((Button)sender).Text == "打开串口") { //赋值给串口 sp.PortName = cmbComList.SelectedItem.ToString(); sp.Parity=(Parity)Enum.Parse(typeof(Parity),cmbParity.SelectedItem.ToString()); sp.BaudRate = Convert.ToInt32(cmbBautRade.SelectedItem.ToString()); sp.StopBits = (StopBits)Convert.ToInt32(cmbStopBits.SelectedItem.ToString()); sp.DataBits = Convert.ToInt32(cmbDataBits.SelectedItem.ToString()); try { sp.Open(); //修改控件状态 this.btnOpen.Text = "关闭串口"; foreach (Control ctr in groupBox1.Controls) { //把下拉框全部禁用 ctr.Enabled = false; } //开启新线程,监听收取内容 Thread thread = new Thread(receive); thread.Start(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } else { if (this.btnAutoSend.Text == "停止发送") { MessageBox.Show("当前定时发送中,请先停止定时发送任务."); return; } sp.Close(); //修改控件状态 this.btnOpen.Text = "打开串口"; foreach (Control ctr in this.groupBox1.Controls) { ctr.Enabled = true; } } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { //窗体关闭时关闭端口 sp.Close(); } private void btnSend_Click(object sender, EventArgs e) { Send(); } private void btnAutoSend_Click(object sender, EventArgs e) { if (this.btnAutoSend.Text == "定时发送") { //根据打开按钮状态初步检查端口是否已经打开 if (this.btnOpen.Text == "打开串口") return; System.Text.RegularExpressions.Regex reg1 = new System.Text.RegularExpressions.Regex(@"^[0-9]\d*$"); if (reg1.IsMatch(txtTime.Text.ToString())) { //激活Timer定时器 this.timer1.Interval = Convert.ToInt32(txtTime.Text.ToString()); this.timer1.Start(); //修改控件状态 this.btnAutoSend.Text = "停止发送"; this.btnSend.Enabled = false; } else { MessageBox.Show("发送间隔应为正整数"); txtTime.Text = "1000"; } } else { this.btnAutoSend.Text = "定时发送"; this.btnSend.Enabled = true; this.timer1.Stop(); } } private void Send() { if (sp.IsOpen) { //获取字节 byte[] buffer = Encode(); if (buffer.Length == 0) return; try { sp.Write(buffer, 0, buffer.Length); } catch (Exception ex) { MessageBox.Show(ex.Message); } //添加发送历史 this.txtHistory.AppendText(string.Format("[{0}] {1} \r\n", DateTime.Now.ToString("HH:mm:ss.ff"), txtSend.Text)); //统计发送字节 this.labSendCount.Text = (Convert.ToInt32(labSendCount.Text) + buffer.Length).ToString(); } else { this.timer1.Stop(); MessageBox.Show("串口尚未打开"); this.btnAutoSend.Text = "定时发送"; } } private void timer1_Tick(object sender, EventArgs e) { //定时发送 Send(); } //字节反编码 private byte[] Encode() { byte[] buffer = null; switch (this.cmbEncodeSend.SelectedItem.ToString()) { case "Unicode": buffer = Encoding.Unicode.GetBytes(txtSend.Text); break; case "UTF-8": buffer = Encoding.UTF8.GetBytes(txtSend.Text); break; case "ASCII": buffer = Encoding.ASCII.GetBytes(txtSend.Text); break; case "Hex": buffer = strToToHexByte(txtSend.Text); break; } return buffer; } //编码 private string UnEncode(byte[] buffer) { string str = string.Empty; switch (this.cmbEncodeSend.SelectedItem.ToString()) { case "Unicode": str = new UnicodeEncoding().GetString(buffer); break; case "UTF-8": str = new UTF8Encoding().GetString(buffer); break; case "ASCII": str = new ASCIIEncoding().GetString(buffer); break; case "Hex": str = byteToHexStr(buffer); break; } return str; } /// <summary> /// 字节数组转16进制字符串 /// </summary> /// <param name="bytes"></param> /// <returns></returns> public static string byteToHexStr(byte[] bytes) { string returnStr = ""; if (bytes != null) { for (int i = 0; i < bytes.Length; i++) { returnStr += bytes[i].ToString("X2"); } } return returnStr; } /// <summary> /// 字符串转16进制字节数组 /// </summary> /// <param name="hexString"></param> /// <returns></returns> private static byte[] strToToHexByte(string hexString) { hexString = hexString.Replace(" ", ""); if ((hexString.Length % 2) != 0) hexString += " "; byte[] returnBytes = new byte[hexString.Length / 2]; for (int i = 0; i < returnBytes.Length; i++) returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); return returnBytes; } private void receive() { //接收信息 先判断是否为打开状态 while (sp.IsOpen) { if (sp.BytesToRead == 0) continue; //准备接收 byte[] buffer = new byte[sp.BytesToRead]; try { //接受动作 sp.Read(buffer, 0, buffer.Length); } catch (Exception ex) { MessageBox.Show(ex.Message); } //更新UI信息 this.Invoke((Action)delegate { this.txtRec.AppendText(UnEncode(buffer)); //是否自动换行 if(cbLine.Checked) this.txtRec.AppendText("\r\n"); //接收统计信息 this.labRecCount.Text = (Convert.ToInt32(this.labRecCount.Text) + buffer.Length).ToString(); }); } } private void button1_Click(object sender, EventArgs e) { //清空发送历史 this.txtHistory.Clear(); } private void button2_Click(object sender, EventArgs e) { //清空接收 this.txtRec.Clear(); } private void btnLoad_Click(object sender, EventArgs e) { //读取xml文件 序列化对象 OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "XML(*.xml)|"; if (ofd.ShowDialog() == DialogResult.OK) { string filePath = ofd.FileName; if (File.Exists(filePath)) { try { var mySerializer = new XmlSerializer(typeof(Config)); using (var sr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read))) { config = (Config)mySerializer.Deserialize(sr); } LoadConfig(); } catch (Exception ee) { MessageBox.Show(ee.Message); } } else { MessageBox.Show("文件不存在"); } } } private void btnSave_Click(object sender, EventArgs e) { FolderBrowserDialog fbd = new FolderBrowserDialog(); if (fbd.ShowDialog() == DialogResult.OK) { //给对象赋值并序列化保存 config.PortName = cmbComList.SelectedItem.ToString(); config.Parity = cmbParity.SelectedItem.ToString(); config.BautRade = Convert.ToInt32(cmbBautRade.SelectedItem.ToString()); config.StopBits = Convert.ToInt32(cmbStopBits.SelectedItem.ToString()); config.DataBits = Convert.ToInt32(cmbDataBits.SelectedItem.ToString()); XmlSerializer xmlFormat=new XmlSerializer(typeof(Config)); string filePath = fbd.SelectedPath + "\\PortConfig.xml"; using (Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) { xmlFormat.Serialize(stream, config); } MessageBox.Show("成功保存到路径:"+filePath); } } private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { System.Diagnostics.Process.Start("http://www.chengchenxu.com"); } } }
软件下载:
源码工程文件:
虚拟端口软件下载:
未实现的功能:
16进制校验功能,即发送16进制格式的时候检查输入值是否为正确的16进制数字
接受文件的完整性校验功能,有时候一条信息会分两次接受完整
本文为博主原创,转载请保留出处:
http://www.chengchenxu.com/Article/30/