![]()
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 = "发送";
}
}
}
}