前言
上一篇文章《ISP 串口调试工具的开发(一)》介绍了如何实现一个简单具有读写功能的串口调试工具,这篇文章会介绍进阶版的串口调试工具。
因为上一篇文章的所有读写操作都是在主线程中进行的,但是这样存在一个弊端,因为在 Windows 的桌面开发中,由于界面编程中的 “Windows 消息队列” 机制,当在主线程(UI 线程)中有耗时较长的操作的话,就会造成界面卡、不流畅、反应慢等现象。如果界面出现长时间静止,会造成使用者觉得软件卡死的错觉。可以查看《.net开发笔记(十三)Winform 常用开发模式第一篇》了解更多。
数据接收
在接收数据时,可以使用 SerialPort.DataRecevied 事件来接收,也可以为数据接收新开启一个新线程。
使用事件接收
使用 SerialPort.DataRecevied 事件接收数据,需要注册接收事件创建 SerialDataReceivedEventHandler 委托,即把接收数据的事件关联到相应的事件去,否则接收事件发生时无法触发对应的方法, DataRecevied 只做数据接收,数据处理则是交给了委托进行。
private void Demo_Load(object sender, EventArgs e)
{
Init_Port_Confs();
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived);
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if(serialPort.IsOpen)
{
byte[] receviedData = new byte[serialPort.BytesToRead];
serialPort.Read(receviedData, 0, receivedData.Length);
//数据处理操作
}
}
使用线程接收
本文采用的是开启新的监听线程方式,当点击读取参数的按钮后,开启一个新线程 loadThread 关联委托方法 LoadData,将数据的处理放在委托中:
/// <summary>
/// 读取参数按钮事件
/// </summary>
private void BtnGetData_Click(object sender, EventArgs e)
{
if (!serialPort.IsOpen)
{
MessageBox.Show("串口未连接!", "传输错误");
return;
}
BtnSendParams.Enabled = false;
BtnGetParams.Enabled = false;
Thread loadThread = new Thread(LoadData);
try
{
loadThread.Start();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
loadThread.Abort();
}
}
在 LoadData 中,读取了缓冲区中的数据后将参数渲染到对应的 TextBox:
/// <summary>
/// 加载参数
/// </summary>
private void LoadData()
{
// 清空缓冲区
serialPort.DiscardInBuffer();
int byteCount = 0;
while (byteCount < 3)
{
byteCount = serialPort.BytesToRead;
}
// 获取数据并检查响应数据
byte[] data = new byte[byteCount];
serialPort.Read(data, 0, byteCount);
//展示数据
int index, value;
string controlName;
// 循环读取参数
for (int i = 0; i < data.Length; i += 3)
{
index = (int)data[i];
// 获取参数名
controlName = "param" + index;
// 获取参数值
value = data[i + 1] * 256 + data[i + 2];
TextBox textbox = (TextBox)Controls.Find(controlName, true)[0];
textbox.Text = value.ToString();
}
CourseRecord("读取参数完成!");
BtnSendParams.Enabled = true;
BtnGetParams.Enabled = true;
}
数据发送
同样的,在数据发送中,也是开启一个新线程 sendThread 关联委托方法 SendData,数据处理交给委托方法:
/// <summary>
/// 发送参数按钮事件
/// </summary>
private void BtnSendParams_Click(object sender, EventArgs e)
{
if (!serialPort.IsOpen)
{
MessageBox.Show("串口未连接!", "传输错误");
return;
}
BtnSendParams.Enabled = false;
BtnGetParams.Enabled = false;
Thread sendThread = new Thread(SendData);
try
{
sendThread.Start();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
sendThread.Abort();
}
}
在 SendData 中,先清空发送缓冲区的数据,然后读取非空的参数发送出去:
/// <summary>
/// 发送数据
/// </summary>
private void SendData()
{
// 清空缓冲区
serialPort.DiscardOutBuffer();
ushort length = 0;
// 计算参数个数
foreach (Control control in groupParams.Controls)
{
if (control is TextBox && control.Text.Length != 0