串口通讯导致System.Threading.Timer不正常工作的问题!

心云意水 2011-03-11 08:46:29
RT,程序运行于wince5.0,用vs2005-c#编写。
经过精简后,核心代码如下:

//串口接收数据,接收到的东西显示到文本框t1种,以备查看
String memo = "",tmpmemo="";
private void sp_DataReceived(object sender,SerialDataReceivedEventArgs e)
{
String readMsg = (sp.ReadExisting()).ToString();//串口获得的数据
//将收到的数据合并入缓存
tmpmemo += readMsg;
//永久缓存
memo += readMsg;
//数据正确,显示数据
this.Invoke(new EventHandler(delegate
{
t1.Text += tmpmemo + "\r\n";
t1.SelectionStart = t1.TextLength;
t1.ScrollToCaret();
tmpmemo = "";
}));
}

System.Threading.Timer T;
private void button5_Click(object sender,EventArgs e)
{
T = new System.Threading.Timer(tt,null,0,100);
}
//这里本来是要对字符串memo进行分析,将数据显示到窗体上的,为了测试程序是否正常工作,只是简单的显示累加数字
private void tt(object state)
{
Invoke(( ThreadStart ) delegate
{
l1.Text = (errCount++).ToString();
});
}


目前情况是:pc机端间隔100ms不停的往程序这端发送一次64字节长的数据包,如果不开启定时器,那么串口部分工作正常,可以正常接收数据。如果单独测试定时器部分,即串口不接收数据,则工作也正常。但是两者同时运行,串口接收数据会变慢,导致丢包,而定时器这部分代码则根本不运行!

不是Threading.Timer是独立线程运行的么?为什么会相互影响???
...全文
302 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
lizhibin11 2011-03-13
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 xinyunyishui 的回复:]
非常感谢楼上的朋友,这几天打扰了您很多!
程序变慢的原因,正是因为把数据不断写入那个名为t1的textbox,本想着通过这个看看是否会丢包,结果这个存储太多文字后,程序运行变得异常缓慢。。。。
同时,我也转变了下思路,取消了串口的DataReceived事件绑定函数,改为定时器定时抓取。。。。
目前效果还算可以,只是可能还有部分算法不够优化,效率距离目标还有一些距离,但是大方向已经ok了!
……
[/Quote]
不用了,别发了,呵呵。
心云意水 2011-03-13
  • 打赏
  • 举报
回复
非常感谢楼上的朋友,这几天打扰了您很多!
程序变慢的原因,正是因为把数据不断写入那个名为t1的textbox,本想着通过这个看看是否会丢包,结果这个存储太多文字后,程序运行变得异常缓慢。。。。
同时,我也转变了下思路,取消了串口的DataReceived事件绑定函数,改为定时器定时抓取。。。。
目前效果还算可以,只是可能还有部分算法不够优化,效率距离目标还有一些距离,但是大方向已经ok了!

感谢各位的帮助。
我在上一个帖子http://topic.csdn.net/u/20110310/23/6e561223-f016-4e13-b63a-c47cc2e31653.html里说过,如果问题解决,另外开帖100分感谢,立刻就去,请lizhibin11移步接分。

再次感谢各位的帮助!
心云意水 2011-03-12
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 lizhibin11 的回复:]

呵呵,肯定会滞后的,因为你的界面操作已经到了极限,改为begininvoke是为了不影响数据接收。
实际处理中不会有这么高频率的界面操作的对吧?
[/Quote]

实际处理时,就是这个频率。。。。
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
另外begininvoke中只需要保留这四句,其他的都放到外面
t1.Text += str + "\r\n";
t1.SelectionStart = t1.TextLength;
t1.ScrollToCaret();
l1.Text = str;
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
呵呵,肯定会滞后的,因为你的界面操作已经到了极限,改为begininvoke是为了不影响数据接收。
实际处理中不会有这么高频率的界面操作的对吧?
心云意水 2011-03-12
  • 打赏
  • 举报
回复
测试完毕,测试代码如下:

String memo = "";
private void sp_DataReceived(object sender,SerialDataReceivedEventArgs e)
{
String readMsg = (sp.ReadExisting()).ToString();//串口获得的数据
//将收到的数据合并入缓存
memo += readMsg;
}


Boolean show = false;
Regex reg = new Regex(@"ABCD\d+EFGH");//数据包格式为:以ABCD开始,EFGH结尾,共计64个字符。具体报文为0-9的数字
private void tt(object state)
{ if (show)
return;
MatchCollection info = reg.Matches(memo);
int l = info.Count;
//当收到的数据中没有完整数据包时,退出,继续等待新的数据
if (l == 0)
{
return;
}

BeginInvoke((ThreadStart)delegate
{
try
{
show = true;
String str = info[0].Value;
memo = memo.Replace(str, "");//将抓取的数据从缓存中移除
t1.Text += str + "\r\n";
t1.SelectionStart = t1.TextLength;
t1.ScrollToCaret();
str = str.Substring(59, 3);
l1.Text = str;
if (!Timers)
T.Dispose();
GC.Collect();
}
finally
{
show = false;
}
});

}

private void button1_Click(object sender,EventArgs e)
{

T = new System.Threading.Timer(tt,null,0,20);
}


通过t1这个文本框中的内容,可以发现,目的是达到了,但是有个很严重的问题:严重滞后!
pc机端发送数据的间隔是100ms一次,但是当发送到第200包的时候,t1这里才显示处理到第几十包(50以下)。这个是什么原因?
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
另外begininvoke那里也别用匿名写法了,我觉得这个也是降低效率的原因,可改为如下

public delegate DisPlay(string s)
DisPlay display;
private void Form1_Load(object sender, EventArgs e)
{
display = ShowText;
}
void ShowText(string str)
{
t1.Text += str + "\r\n";
t1.SelectionStart = t1.TextLength;
t1.ScrollToCaret();
str = str.Substring(59, 3);
l1.Text = str;
show = false;
}
private void tt(object state)
{
if (show)
return;
MatchCollection info = reg.Matches(memo);
int l = info.Count;
//当收到的数据中没有完整数据包时,退出,继续等待新的数据
if (l == 0)
{
return;
}
show = true;
String str = info[0].Value;
memo = memo.Replace(str, "");//将抓取的数据从缓存中移除
BeginInvoke(display, str);
if (!Timers)
T.Dispose();
//GC.Collect();
}
心云意水 2011-03-12
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 lizhibin11 的回复:]
补充一个,datareceived事件如果没有设置字节数,每个字节都会触发一次,而实际运行中应该是读到一个数组才进行一次界面操作,所以直接在这个事件中处理,频率太快了。
这个事件触发后,修改一个全局标识,然后下次触发后,检查该标识,不进行任何操作。第一次触发后,进入一个线程循环接收,接收完毕后,修改标识让datareceived事件触发后可以再次进行处理。
[/Quote]
多谢提醒!
其实我的datareceived事件中存在如下交验:

memo += readMsg;
//分析缓存数据中是否有完整数据包
MatchCollection info = reg.Matches(memo);
int l = info.Count;
//当收到的数据中没有完整数据包时,退出,继续等待新的数据
if(l == 0)
{
return;
}

不过为了提问时候尽量简化代码,我给简化掉了。
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
那你先把两个invoke改为begininvoke试一下,这样会立即返回,不太会耽误数据接收。
心云意水 2011-03-12
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 lizhibin11 的回复:]
sp_DataReceived中对界面是耗时操作,定时器频率也快,接收数据慢和丢包(缓冲区溢出)是很有可能发生的.把两个invoke都改为begininvoke试试看。
最好别在sp_DataReceived中进行处理,这个时间起一个提示作用,然后在循环中读取较好。
[/Quote]
根据设计要求,我的思路是这样的:
串口这部分,只负责接受数据,即:sp_DataReceived事件中,仅执行
String readMsg = (sp.ReadExisting()).ToString();//串口获得的数据
//将收到的数据合并入缓存
memo += readMsg;
然后开启定时器,去定时分析memo,并通过invoke跟新界面显示。
目前sp_DataReceived中的invoke显示,只是想保存串口接受记录,以便查证。我现在怀疑是两个地方跟新界面显示冲突了。。。

不知道这个思路是否正确?我先去掉串口部分跟新界面的功能测试下。
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
补充一个,datareceived事件如果没有设置字节数,每个字节都会触发一次,而实际运行中应该是读到一个数组才进行一次界面操作,所以直接在这个事件中处理,频率太快了。
这个事件触发后,修改一个全局标识,然后下次触发后,检查该标识,不进行任何操作。第一次触发后,进入一个线程循环接收,接收完毕后,修改标识让datareceived事件触发后可以再次进行处理。
_三皮_ 2011-03-12
  • 打赏
  • 举报
回复
串口和定时器从硬件角度说是两个中断,理论上是没有影响的,没环境我也不好试试,只有你再找找原因了
explife 2011-03-12
  • 打赏
  • 举报
回复
1.用Thread线程
2.加大串口缓冲区和超时时间
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
这个时间起一个提示作用
改为让这个事件起一个提示作用。
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
sp_DataReceived中对界面是耗时操作,定时器频率也快,接收数据慢和丢包(缓冲区溢出)是很有可能发生的.把两个invoke都改为begininvoke试试看。
最好别在sp_DataReceived中进行处理,这个时间起一个提示作用,然后在循环中读取较好。
心云意水 2011-03-12
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 yalan 的回复:]
没写过wince程序,不过你为什么不直接用Thread呢?设置线程的IsBackground=true应该就行了。

个人感觉这里用Threading.Timer不合适
[/Quote]

使用timer是因为设计的要求。

请问您让我使用Thread,是针对哪部分呢?
lizhibin11 2011-03-12
  • 打赏
  • 举报
回复
这个可以改进,第一个,t1达到某个数量,添加一条后要清除一条,否则越来越庞大的字符串相加很麻烦.这样还有一个好处就是t1.SelectionStart = t1.TextLength;t1.ScrollToCaret();也没必要了.
第二个,GC.Collect();是没必要的.
第三个,正则如果能够不用的话最好.
第四个,实在不行,还可以用GDI来画字符.
yalan 2011-03-11
  • 打赏
  • 举报
回复
没写过wince程序,不过你为什么不直接用Thread呢?设置线程的IsBackground=true应该就行了。

个人感觉这里用Threading.Timer不合适

110,502

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧