背景:有些下位机通过串口显示交互信息(可能是一次性,可能开机自动触发),上位机需要从中查找指定定关键字。这个时候就需要有一个能够实时接收并显示,并能够实时“等待”某个关键字,TerminalWaiter就是为此而来。
软件界面如下:
下面不会直接贴全部源代码,只贴关键部分.
实时被动接收比较好实现:(初始化的时候添加DataReceived事件)
public SerialPort ComPort = new SerialPort();
ComPort.DataReceived += new SerialDataReceivedEventHandler(DebugUI.ComPort_DataReceived);
下面的DeviceUI是自定义控件
public SerialPort ComPort = new SerialPort();
public EMoudle()
{
DeviceUI = new Dev_UI();
DeviceUI.EMoudleInstance = this;
DebugUI = new Dbg_UI();
DebugUI.EMoudleInstance = this;
ComPort.BaudRate = 115200;
ComPort.ReadTimeout = 500;
ComPort.NewLine = "\r\n";
try
{
ComPort.PortName = DeviceUI.drpComList.Text;
ComPort.Open();
}
catch (Exception ex)
{
Console.WriteLine(MoudleConnString+ " Exception: " + ex.Message);
}
ComPort.DataReceived += new SerialDataReceivedEventHandler(DebugUI.ComPort_DataReceived);
}
ComPort_DataReceived方法写在DebugUI(另外一个自定义控件)里面,用的是判断缓存里的bytesToRead 大于0 的方法,好处是可以一个一个字符的动态显示,实时效果很好,EmoudleInstace就是上面EModule的实例。然后MyLib.COMMFunc.AppendText 是我自己写的一个委托显示。(效果和richTextBox.Append()一样,只不过非UI线程要实时显示控件需要用委托。)
internal void ComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (IsStoppingDataReceive) return;
int n = EMoudleInstance.ComPort.BytesToRead;
string rst = "";
if (n > 0)
{
byte[] buf = new byte[n];
EMoudleInstance.ComPort.Read(buf, 0, n);
rst = Encoding.ASCII.GetString(buf);
MyLib.COMMFunc.AppendText(richTextBox1, rst);
}
等待关键字的方法在自定义控件DebugUI里面:
private void button1_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBox1.Text))
{
richTextBox1.AppendText("Textbox content can not be null!\r\n");
textBox1.Focus();
return;
}
Thread thd = new Thread(new ThreadStart(Test));
thd.Start();
}
private void Test()
{
IsStoppingDataReceive = true;
bool rst = COMWaitStr(textBox1.Text, (int)(numericUpDown1.Value * 1000));
IsStoppingDataReceive = false;
Console.WriteLine("rst: " + rst);
}
public bool COMWaitStr(string WaitStr, int ms_TimeOut)
{
MyLib.COMMFunc.AppendText(richTextBox1, "\r\nWAIT " + WaitStr + " ...\r\n\r\n");
int i = 0;
while (i < ms_TimeOut / 200)
{
string Readrst = "";
if (CHKComPortRead(WaitStr, out Readrst)) return true;
Thread.Sleep(100);
i++;
}
MyLib.COMMFunc.AppendText(richTextBox1, "\r\nWAIT " + WaitStr + " TimeOut=" + ms_TimeOut + " ms\r\n\r\n");
return false;
}
internal bool CHKComPortRead(string CHKStr,out string Readrst )
{
Readrst = ""; string temp = "";
if (!EMoudleInstance.CHKComPortOpen()) return false;
while (true)
{
int i = 0;
int n = 0;
while ((n = EMoudleInstance.ComPort.BytesToRead) == 0)
{
Thread.Sleep(50);
i++;
if (i >= 3) break;
}
if ((n = EMoudleInstance.ComPort.BytesToRead) == 0) break;
byte[] buf = new byte[n];
EMoudleInstance.ComPort.Read(buf, 0, n);
temp = Encoding.ASCII.GetString(buf);
MyLib.COMMFunc.AppendText(richTextBox1, temp);
Readrst += temp;
if (temp.Contains(CHKStr))
{
MyLib.COMMFunc.AppendText(richTextBox1, "\r\nWAIT " + CHKStr + " OK\r\n\r\n");
return true;
}
}
if (Readrst.Contains(CHKStr))
{
MyLib.COMMFunc.AppendText(richTextBox1, "\r\nWAIT " + CHKStr + " OK\r\n\r\n");
return true;
}else
{
return false;
}
}
最关键的函数是 CHKComPortRead() 调用它前面需要设置 IsStoppingDataReceive = true;(在Test()函数里面)这样被动接收和主动接收就可以实时切换。为什么要切换到主动接收,因为点击WAIT String 按钮是主动点击事件,可以实现任意时刻触发WAIT方法。
以上,如果还是不明白的可以评论留言。
有兴趣的可以下载示例程序实验一下。如果示例程序好用,我再教大家怎么把示例程序引用到自己程序中。
如果有人需要全部源代码,我再上传。