目前碰上个问题:我要操作两个串口,串口的返回数据是通过事件获得的。
但是我要在一个操作中连续向串口写数据,然后查看返回数据,以实现操作。这样就存在线程问题。头一次处理类似问题,大家看看在现在的代码情况下如何处理。代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;namespace Termie
{
public partial class frmMain : Form
{
string RevInto, RevMag; /// <summary>
/// If character 0-9 a-f A-F, then return hex digit value ?
/// </summary>
private static int GetHexDigit(char c)
{
if ('0' <= c && c <= '9') return (c - '0');
if ('a' <= c && c <= 'f') return (c - 'a') + 10;
if ('A' <= c && c <= 'F') return (c - 'A') + 10;
return 0;
}
/// <summary>
/// Parse states for ConvertEscapeSequences()
/// </summary>
public enum Expecting : byte
{
ANY = 1,
ESCAPED_CHAR,
HEX_1ST_DIGIT,
HEX_2ND_DIGIT
}; public frmMain()
{
InitializeComponent(); Settings.Read();
TopMost = Settings.Option.StayOnTop; // let form use multiple fonts PortInto comInto = PortInto.Instance;
comInto.StatusChanged += OnIntoStatusChanged;
comInto.DataReceived += OnIntoDataReceived; PortMag comMag = PortMag.Instance;
comMag.StatusChanged += OnMagStatusChanged;
comMag.DataReceived += OnMagDataReceived; RevInto ="";
RevMag = "";
} internal delegate void StringDelegate(string data); //传入值转码
private string ConvertEscapeSequences(string s)
{
Expecting expecting = Expecting.ANY; int hexNum = 0;
string outs = "";
foreach (char c in s)
{
switch (expecting)
{
case Expecting.ANY:
if (c == '\\')
expecting = Expecting.ESCAPED_CHAR;
else
outs += c;
break;
case Expecting.ESCAPED_CHAR:
if (c == 'x')
{
expecting = Expecting.HEX_1ST_DIGIT;
}
else
{
char c2 = c;
switch (c)
{
case 'n': c2 = '\n'; break;
case 'r': c2 = '\r'; break;
case 't': c2 = '\t'; break;
}
outs += c2;
expecting = Expecting.ANY;
}
break;
case Expecting.HEX_1ST_DIGIT:
hexNum = GetHexDigit(c) * 16;
expecting = Expecting.HEX_2ND_DIGIT;
break;
case Expecting.HEX_2ND_DIGIT:
hexNum += GetHexDigit(c);
outs += (char)hexNum;
expecting = Expecting.ANY;
break;
}
}
return outs;
} /// <summary>
/// Update the connection status
/// </summary>
public void OnIntoStatusChanged(string status)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnIntoStatusChanged), new object[] { status });
return;
} txtInfo.AppendText("端口A状态:" + status + "\r\n");
txtInfo.ScrollToCaret();
} /// <summary>
/// Update the connection status
/// </summary>
public void OnMagStatusChanged(string status)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnMagStatusChanged), new object[] { status });
return;
} txtInfo.AppendText("端口B状态:" + status + "\r\n");
txtInfo.ScrollToCaret();
} public void OnIntoDataReceived(string dataIn)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnIntoDataReceived), new object[] { dataIn });
return;
} if (dataIn.EndsWith("D"))
{
if (dataIn.StartsWith("C"))
{
RevInto = dataIn;
}
else
{
RevInto += dataIn;
} txtInfo.AppendText("端口A接收数据:" + RevInto + "\r\n");
txtInfo.ScrollToCaret();
}
else if (dataIn.StartsWith("C"))
{
RevInto = dataIn;
}
else
{
RevInto += dataIn;
}
} public void OnMagDataReceived(string dataIn)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnMagDataReceived), new object[] { dataIn });
return;
}
txtInfo.AppendText("端口B接收数据:" + dataIn + "\r\n");
} private void btPortConn_Click(object sender, EventArgs e)
{
PortInto comInto = PortInto.Instance;
PortMag comMag = PortMag.Instance; if (!comInto.IsOpen)
comInto.Open(); if (!comMag.IsOpen)
comMag.Open(); string command = "AK" + (char)0 + "B";
command = ConvertEscapeSequences(command);
comInto.Send(command); //这里发送了端口数据,需要等待返回OnIntoDataReceived事件返回数据,请问如何切换线程
if (RevInto == "CE1D")
{
MessageBox.Show(RevInto + "端口A联机成功!");
}
else
{
MessageBox.Show(RevInto + "端口A联机失败!");
return;
} command = (char)2 + "C0132400000000" + (char)3;
command = ConvertEscapeSequences(command);
comMag.Send(command);
} private void btSetting_Click(object sender, EventArgs e)
{
frmSetting nowFrmSetting = new frmSetting(); nowFrmSetting.ShowDialog();
} private void btExit_Click(object sender, EventArgs e)
{
PortInto comInto = PortInto.Instance;
PortMag comMag = PortMag.Instance; comInto.Close();
comMag.Close();
} private void btReset_Click(object sender, EventArgs e)
{ }
}
}
但是我要在一个操作中连续向串口写数据,然后查看返回数据,以实现操作。这样就存在线程问题。头一次处理类似问题,大家看看在现在的代码情况下如何处理。代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;namespace Termie
{
public partial class frmMain : Form
{
string RevInto, RevMag; /// <summary>
/// If character 0-9 a-f A-F, then return hex digit value ?
/// </summary>
private static int GetHexDigit(char c)
{
if ('0' <= c && c <= '9') return (c - '0');
if ('a' <= c && c <= 'f') return (c - 'a') + 10;
if ('A' <= c && c <= 'F') return (c - 'A') + 10;
return 0;
}
/// <summary>
/// Parse states for ConvertEscapeSequences()
/// </summary>
public enum Expecting : byte
{
ANY = 1,
ESCAPED_CHAR,
HEX_1ST_DIGIT,
HEX_2ND_DIGIT
}; public frmMain()
{
InitializeComponent(); Settings.Read();
TopMost = Settings.Option.StayOnTop; // let form use multiple fonts PortInto comInto = PortInto.Instance;
comInto.StatusChanged += OnIntoStatusChanged;
comInto.DataReceived += OnIntoDataReceived; PortMag comMag = PortMag.Instance;
comMag.StatusChanged += OnMagStatusChanged;
comMag.DataReceived += OnMagDataReceived; RevInto ="";
RevMag = "";
} internal delegate void StringDelegate(string data); //传入值转码
private string ConvertEscapeSequences(string s)
{
Expecting expecting = Expecting.ANY; int hexNum = 0;
string outs = "";
foreach (char c in s)
{
switch (expecting)
{
case Expecting.ANY:
if (c == '\\')
expecting = Expecting.ESCAPED_CHAR;
else
outs += c;
break;
case Expecting.ESCAPED_CHAR:
if (c == 'x')
{
expecting = Expecting.HEX_1ST_DIGIT;
}
else
{
char c2 = c;
switch (c)
{
case 'n': c2 = '\n'; break;
case 'r': c2 = '\r'; break;
case 't': c2 = '\t'; break;
}
outs += c2;
expecting = Expecting.ANY;
}
break;
case Expecting.HEX_1ST_DIGIT:
hexNum = GetHexDigit(c) * 16;
expecting = Expecting.HEX_2ND_DIGIT;
break;
case Expecting.HEX_2ND_DIGIT:
hexNum += GetHexDigit(c);
outs += (char)hexNum;
expecting = Expecting.ANY;
break;
}
}
return outs;
} /// <summary>
/// Update the connection status
/// </summary>
public void OnIntoStatusChanged(string status)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnIntoStatusChanged), new object[] { status });
return;
} txtInfo.AppendText("端口A状态:" + status + "\r\n");
txtInfo.ScrollToCaret();
} /// <summary>
/// Update the connection status
/// </summary>
public void OnMagStatusChanged(string status)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnMagStatusChanged), new object[] { status });
return;
} txtInfo.AppendText("端口B状态:" + status + "\r\n");
txtInfo.ScrollToCaret();
} public void OnIntoDataReceived(string dataIn)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnIntoDataReceived), new object[] { dataIn });
return;
} if (dataIn.EndsWith("D"))
{
if (dataIn.StartsWith("C"))
{
RevInto = dataIn;
}
else
{
RevInto += dataIn;
} txtInfo.AppendText("端口A接收数据:" + RevInto + "\r\n");
txtInfo.ScrollToCaret();
}
else if (dataIn.StartsWith("C"))
{
RevInto = dataIn;
}
else
{
RevInto += dataIn;
}
} public void OnMagDataReceived(string dataIn)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnMagDataReceived), new object[] { dataIn });
return;
}
txtInfo.AppendText("端口B接收数据:" + dataIn + "\r\n");
} private void btPortConn_Click(object sender, EventArgs e)
{
PortInto comInto = PortInto.Instance;
PortMag comMag = PortMag.Instance; if (!comInto.IsOpen)
comInto.Open(); if (!comMag.IsOpen)
comMag.Open(); string command = "AK" + (char)0 + "B";
command = ConvertEscapeSequences(command);
comInto.Send(command); //这里发送了端口数据,需要等待返回OnIntoDataReceived事件返回数据,请问如何切换线程
if (RevInto == "CE1D")
{
MessageBox.Show(RevInto + "端口A联机成功!");
}
else
{
MessageBox.Show(RevInto + "端口A联机失败!");
return;
} command = (char)2 + "C0132400000000" + (char)3;
command = ConvertEscapeSequences(command);
comMag.Send(command);
} private void btSetting_Click(object sender, EventArgs e)
{
frmSetting nowFrmSetting = new frmSetting(); nowFrmSetting.ShowDialog();
} private void btExit_Click(object sender, EventArgs e)
{
PortInto comInto = PortInto.Instance;
PortMag comMag = PortMag.Instance; comInto.Close();
comMag.Close();
} private void btReset_Click(object sender, EventArgs e)
{ }
}
}
串口通讯中,如果不确定数据是否完整有效。不要用字符串方式搜索,这样效率比较低,当然如果你只找一个,系统的IndexOf比你写的高,但协议往往不止一个字符,或一个单词,有连续的规则,看上去很像正则是不是?很遗憾,字符串操作都不推荐用了,正则就更不推荐用了。虽然正则实现了复杂规则。但是正则的回溯机制导致了你搜索的可逆,效率不稳定,极限情况可能导致引擎崩溃而让程序瘫痪。协议分析,尤其是字符串协议分析。你可以考虑自己循环一次来搜索关键字,这样时间复杂度能总是O(n)。