using System.IO.Ports;
SerialPort comm = new SerialPort();
public partial class SerialportSampleForm : Form
{
private SerialPort comm = new SerialPort();
private StringBuilder builder = new StringBuilder();//避免在事件处理方法中反复的创建,定义到外面。
private long received_count = 0;//接收计数
private long send_count = 0;//发送计数
private bool Listening = false;//是否没有执行完invoke相关操作
private bool Closing = false;//是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke
public SerialportSampleForm()
{
InitializeComponent();
}
//窗体初始化
private void Form1_Load(object sender, EventArgs e)
{
//初始化串口名称列表,波特率列表
string[] ports = SerialPort.GetPortNames();
Array.Sort(ports);
comboPortName.Items.AddRange(ports);
comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1;
comboBaudrate.SelectedIndex = comboBaudrate.Items.IndexOf("9600");
DropCRC.SelectedIndex = DropCRC.Items.IndexOf("16 CRC ,低字节在前");
//初始化SerialPort对象
comm.NewLine = "\r\n";//回车换行
comm.RtsEnable = true;//根据实际情况吧。
//添加事件注册(串口监听线程)
comm.DataReceived += comm_DataReceived;
}
/// <summary>
/// 接受数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (Closing) return;//如果正在关闭端口,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
try
{
Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。
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 (checkBoxHexView.Checked)
{
//依次的拼接出16进制字符串
foreach (byte b in buf)
{
builder.Append(b.ToString("X2") + " ");
}
}
else
{
//直接按ASCII规则转换成字符串
builder.Append(Encoding.ASCII.GetString(buf));
}
//追加的形式添加到文本框末端,并滚动到最后。
this.txGet.AppendText(builder.ToString());
//修改接收计数
labelGetCount.Text = "Get:" + received_count.ToString();
}));
}
finally
{
Listening = false;//我用完了,ui可以关闭串口了。
}
}
/// <summary>
/// 打开串口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonOpenClose_Click(object sender, EventArgs e)
{
if (comm.IsOpen)
{
Closing = true;
while (Listening) Application.DoEvents();//处理当前队列的window消息
comm.Close();//关闭串口
Closing = false;
}
else
{
comm.PortName = comboPortName.Text;//设置通讯端口
comm.BaudRate = int.Parse(comboBaudrate.Text);//设置串口波特率
try
{
comm.Open();//打开串口
}
catch(Exception ex)
{
comm = new SerialPort();//捕获到异常信息,创建一个新的comm对象,之前的不能用了
MessageBox.Show(ex.Message);//现实异常信息给客户。
}
}
//设置按钮的状态
buttonOpenClose.Text = comm.IsOpen ? "关闭端口" : "打开端口";
buttonSend.Enabled = comm.IsOpen;
}
//动态的修改获取文本框是否支持自动换行。
private void checkBoxNewlineGet_CheckedChanged(object sender, EventArgs e)
{
txGet.WordWrap = checkBoxNewlineGet.Checked;
}
/// <summary>
/// 发送
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonSend_Click(object sender, EventArgs e)
{
if (comm.IsOpen==false)
{
MessageBox.Show("请打开串口!");
return;
}
//定义一个变量,记录发送了几个字节
int n = 0;
//16进制发送
if (checkBoxHexSend.Checked)
{
//我们不管规则了。如果写错了一些,我们允许的,只用正则得到有效的十六进制数
MatchCollection mc = Regex.Matches(txSend.Text, @"(?i)[\da-f]{2}");
List<byte> buf = new List<byte>();//填充到这个临时列表中
//依次添加到列表中
foreach (Match m in mc)
{
//buf.Add(byte.Parse(m.Value));
buf.Add(byte.Parse(m.Value, System.Glob