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.Text.RegularExpressions; using System.Threading; namespace Serial_T { public partial class Form1 : Form { private SerialPort comm = new SerialPort(); private StringBuilder builder = new StringBuilder();//避免在事件处理方法中反复的创建,定义到外面。 private long received_count = 0;//接收计数 private long send_count = 0;//发送计数 private System.Timers.Timer timer = new System.Timers.Timer(); public Form1() { InitializeComponent(); Init(); //添加事件注册 comm.DataReceived += comm_DataReceived; } /// <summary> /// 打开/关闭当前串口 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonOpenClose_Click(object sender, EventArgs e) { //根据当前串口对象,来判断操作 if (comm.IsOpen) { //打开时点击,则关闭串口 comm.Close(); } else { OpenPort(); } //设置按钮的状态 BthStatus(); } /// <summary> /// 初始化系统 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnInit_Click(object sender, EventArgs e) { Init(); } /// <summary> /// 应用端口配置 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSetPort_Click(object sender, EventArgs e) { SetPort(); } /// <summary> /// 发送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonSend_Click(object sender, EventArgs e) { string sendData = txSend.Text; // 循环发送 if (cirSend.Checked) { int _interval = 0; if (int.TryParse(txInterval.Text.Trim(), out _interval)) { buttonSend.Invoke(new MethodInvoker(delegate { if (buttonSend.Text.Trim() == "发送") { buttonSend.Text = "停止"; } else { buttonSend.Text = "发送"; } })); timer.Enabled = true; timer.Interval = _interval; timer.AutoReset = true; timer.Elapsed += new System.Timers.ElapsedEventHandler((s, erg) => comm_DataSend(s, erg, sendData)); timer.Start(); } else { MessageBox.Show("请填入正确间隔时间!"); } } else { comm_DataSend(sendData); } } /// <summary> /// 清空 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void clearData_Click(object sender, EventArgs e) { //复位接受和发送的字节数计数器并更新界面。 send_count = received_count = 0; NumReceive.Text = "接收量:0"; NumSend.Text = "发送量:0"; txReceive.Text = ""; txSend.Text = ""; } /// <summary> /// 接收文本换行状态改变 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void checkBoxNewlineGet_CheckedChanged(object sender, EventArgs e) { txReceive.WordWrap = checkBoxNewlineGet.Checked; } /// <summary> /// 十六进制发送状态改变 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void checkBoxHexSend_CheckedChanged(object sender, EventArgs e) { if (checkBoxHexSend.Checked) { checkBoxNewlineSend.Checked = false; checkBoxNewlineSend.Enabled = false; } else { checkBoxNewlineSend.Enabled = true; } } /// <summary> /// 初始化系统 /// </summary> private void Init() { //关闭当前串口 if (comm.IsOpen) { comm.Close(); } //初始化下拉串口名称列表框 string[] ports = SerialPort.GetPortNames(); Array.Sort(ports); comboPortName.Items.Clear(); comboPortName.Items.AddRange(ports); comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1; comboBaudrate.SelectedIndex = comboBaudrate.Items.IndexOf("9600"); dataBits.SelectedIndex = dataBits.Items.IndexOf("8"); StopBits.SelectedIndex = StopBits.Items.IndexOf("1"); ParityBits.SelectedIndex = ParityBits.Items.IndexOf("None"); //初始化SerialPort对象 comm.NewLine = "/r/n"; comm.RtsEnable = true;//根据实际情况吧。 //复位接受和发送的字节数计数器并更新界面。 checkBoxNewlineGet.Checked = false; hexReceive.Checked = false; cirSend.Checked = false; checkBoxHexSend.Checked = false; checkBoxNewlineSend.Checked = false; txReceive.Text = ""; txSend.Text = ""; send_count = received_count = 0; NumReceive.Text = "接收量:0"; NumSend.Text = "发送量:0"; BthStatus(); } /// <summary> /// 串口数据接收事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void comm_DataReceived(object sender, SerialDataReceivedEventArgs e) { int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致 byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据 received_count += n;//增加接收计数 comm.Read(buf, 0, n);//读取缓冲数据 builder.Clear();//清除字符串构造器的内容 //因为要访问ui资源,所以需要使用invoke方式同步ui。 this.Invoke((EventHandler)(delegate { //判断是否是显示为16禁止 if (hexReceive.Checked) { //依次的拼接出16进制字符串 foreach (byte b in buf) { builder.Append(b.ToString("X2") + " "); } } else { //直接按ASCII规则转换成字符串 builder.Append(Encoding.ASCII.GetString(buf)); } //追加的形式添加到文本框末端,并滚动到最后。 this.txReceive.AppendText(builder.ToString()); //修改接收计数 NumReceive.Text = "接收量:" + received_count.ToString(); })); } /// <summary> /// 串口发送数据 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void comm_DataSend(string str) { str =localName.Text.Trim() + str; //定义一个变量,记录发送了几个字节 int n = 0; //16进制发送 if (checkBoxHexSend.Checked) { //我们不管规则了。如果写错了一些,我们允许的,只用正则得到有效的十六进制数 MatchCollection mc = Regex.Matches(str, @"[0-9a-fA-F]{2}"); List<byte> buf = new List<byte>();//填充到这个临时列表中 //依次添加到列表中 foreach (Match m in mc) { buf.Add(Convert.ToByte(m.ToString(), 16)); } //转换列表为数组后发送 comm.Write(buf.ToArray(), 0, buf.Count); //记录发送的字节数 n = buf.Count; } else//ascii编码直接发送 { //包含换行符 if (checkBoxNewlineSend.Checked) { comm.WriteLine(str); n = txSend.Text.Length + 2; } else//不包含换行符 { comm.Write(str); n = txSend.Text.Length; } } send_count += n;//累加发送字节数 NumSend.Text = "发送量:" + send_count.ToString();//更新界面 } /// <summary> /// 串口发送数据(定时) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void comm_DataSend(object sender, System.Timers.ElapsedEventArgs e, string str) { if (cirSend.Checked && comm.IsOpen && (buttonSend.Text == "停止")) { //定义一个变量,记录发送了几个字节 int n = 0; //16进制发送 if (checkBoxHexSend.Checked) { //我们不管规则了。如果写错了一些,我们允许的,只用正则得到有效的十六进制数 MatchCollection mc = Regex.Matches(str, @"[0-9a-fA-F]{2}"); List<byte> buf = new List<byte>();//填充到这个临时列表中 //依次添加到列表中 foreach (Match m in mc) { buf.Add(Convert.ToByte(m.ToString(), 16)); } //转换列表为数组后发送 comm.Write(buf.ToArray(), 0, buf.Count); //记录发送的字节数 n = buf.Count; } else//ascii编码直接发送 { //包含换行符 if (checkBoxNewlineSend.Checked) { comm.WriteLine(str); n = txSend.Text.Length + 2; } else//不包含换行符 { comm.Write(str); n = txSend.Text.Length; } } send_count += n;//累加发送字节数 NumSend.Invoke(new MethodInvoker(delegate { NumSend.Text = "发送量:" + send_count.ToString(); })); //NumSend.Text = "发送量:" + send_count.ToString();//更新界面 } else { timer.Stop(); } } /// <summary> /// 同步按钮状态 /// </summary> private void BthStatus() { //设置按钮的状态 buttonOpenClose.Text = comm.IsOpen ? "关闭串口" : "启动串口"; buttonSend.Enabled = comm.IsOpen; } /// <summary> /// 打开串口 /// </summary> /// <returns>返回BOOL型,True为成功,False为失败</returns> public void OpenPort() { if (!comm.IsOpen) { SetPort(); try { comm.Open(); } catch (Exception ex) { //捕获到异常信息,创建一个新的comm对象,之前的不能用了。 comm = new SerialPort(); //添加事件注册 comm.DataReceived += comm_DataReceived; //现实异常信息给客户。 MessageBox.Show(ex.Message); } } } /// <summary> /// 应用串口配置 /// </summary> /// <returns>返回BOOL型,True为成功,False为失败</returns> public void SetPort() { if (string.IsNullOrEmpty(comboPortName.Text.Trim())) { MessageBox.Show("串口号不能为空!"); } else { //关闭当前串口 if (comm.IsOpen) { comm.Close(); } comm.PortName = comboPortName.Text; comm.BaudRate = int.Parse(comboBaudrate.Text); comm.DataBits = int.Parse(dataBits.Text); //comm.Parity = Parity.None; //comm.StopBits = new StopBits(); BthStatus(); } } private void cirSend_CheckedChanged(object sender, EventArgs e) { if (!cirSend.Checked && buttonSend.Text.Trim() == "停止") { buttonSend.Text = "发送"; } } } }