请教:WPF中定时器的应用

zhoucs21 2018-11-09 02:57:17
最近用WPF做项目,要做与PLC的通讯,涉及到数据的实时采集,于是用定时器定时读取。
1、用了System.Timers.Timer,可是运行一段时间(大概5分钟)后,对PLC的下发命令明显响应迟钝,有时甚至把整个界面卡死。
2、又改用System.Threading.Timer,效果是一样的。
3、再改用DispatcherTimer,这时响应迟钝、卡死的现象没有了,不过原定时1秒的刷新速度会变成在1-2秒间。
注:
1、执行读取PLC数据的代码运行时间,大概需要200-900ms。
2、PLC为西门子的S7-300(一种工控上用到的设备,与电脑间通过MPI电缆通讯)
...全文
289 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
mk_lucifer 2018-11-10
  • 打赏
  • 举报
回复
写程序要分前后台现成的,尤其是IO操作是必须的,前台通讯多长时间,界面就会卡多长时间,前台不是让你来做这些事情的。。。
两种做法:
1. 用定时器,但定时器只作为定时唤醒通讯线程的作用(不推荐,麻烦),如果不知道什么叫唤醒线程,学一下AutoResetEvent这个对象。
2. 不要定时器, 通讯线程读取系统时间,根据上一次通信的时间,自行决定休息多少ms,也就是Sleep函数(推荐)。。
当然这些都是粗浅的解决办法,实际上你可以模仿下组态软件的实现逻辑,需要完成一个通信调度器这个对象,他的用途就是觉得一个变量是否要更新,什么时候更新(更新规则条件太多了,定时只是一种,除此之外常见的还有, 事件触发(某事件发生则更新),优先等级,变量可见(界面上看不见则不更新,好的组态软件都有该规则,因为大多数工控变量只是为了浏览))。。。调度器是不直接通讯的,只是调度,通讯都是后台完成,以IO任务包的形式发给执行线程,执行线程才是通讯驱动的直接使用者。。。

E次奥 2018-11-09
  • 打赏
  • 举报
回复
在ReadData中另起线程运行代码;
ManBOyyy 2018-11-09
  • 打赏
  • 举报
回复
private void ReadData(object source, System.Timers.ElapsedEventArgs e) { ti.stop(); ti.Enabled = false; Scp.Instance.ReadAI(); //压变数据 for(int i=0;i<Var.numP;i++) { Var._dataP[i] = (Scp.Instance._AI[i] - 27648 / 5) * (Var._maxPE[i] - Var._minPE[i]) / (27648 * 4 / 5) + Var._minPE[i]; } //温变数据 for (int i = 0; i < Var.numT; i++) { Var._dataT[i] = (Scp.Instance._AI[i + Var.numP] - 27648 / 5) * (Var._maxTE[i] - Var._minTE[i]) / (27648 * 4 / 5) + Var._minTE[i]; } ti.start(); ti.Enabled = true; } 试试这样子行不行
sdfgrtyu 2018-11-09
  • 打赏
  • 举报
回复
你可以把时间改成5s看看还卡不卡,就知道了
zhoucs21 2018-11-09
  • 打赏
  • 举报
回复
没有操作UI的代码,执行时间我用Stopwatch显示出来,确实在900ms之内
ManBOyyy 2018-11-09
  • 打赏
  • 举报
回复
执行读取PLC数据的代码运行时间,大概需要200-900ms。 有可能和PLC通讯不上呢?也是这个200-900ms?,你试试ReadData这个方法里一开始停止定时器System.Timers.Timer,执行完了再开启定时器这个System.Timers.Timer
sdfgrtyu 2018-11-09
  • 打赏
  • 举报
回复
估计是你那个方法根本没执行完,又进入了
sdfgrtyu 2018-11-09
  • 打赏
  • 举报
回复
readdata这个里面有操作Ui界面的代码?还有你能确定1s中之内你这个方法能执行完?
zhoucs21 2018-11-09
  • 打赏
  • 举报
回复
这个就是卡的啊,点按钮,对PLC下发命令就卡。如果关了这个定时器,或者把readdata中的内容屏蔽掉就一点不卡了。
sdfgrtyu 2018-11-09
  • 打赏
  • 举报
回复
我的意思是你说卡的那个是怎么写的,肯定是你写的有问题
zhoucs21 2018-11-09
  • 打赏
  • 举报
回复
System.Timers.Timer ti = new System.Timers.Timer(1000);//定时器(1000ms),用于设备数据的读取。

ti.Elapsed += new System.Timers.ElapsedEventHandler(ReadData);
ti.AutoReset = true;
ti.Enabled = true;

private void ReadData(object source, System.Timers.ElapsedEventArgs e)
{
Scp.Instance.ReadAI();
//压变数据
for(int i=0;i<Var.numP;i++)
{
Var._dataP[i] = (Scp.Instance._AI[i] - 27648 / 5) * (Var._maxPE[i] - Var._minPE[i]) / (27648 * 4 / 5) + Var._minPE[i];
}
//温变数据
for (int i = 0; i < Var.numT; i++)
{
Var._dataT[i] = (Scp.Instance._AI[i + Var.numP] - 27648 / 5) * (Var._maxTE[i] - Var._minTE[i]) / (27648 * 4 / 5) + Var._minTE[i];
}
}
基本上是这样的,Var._dataT这些数据又传到了WPF中绑定的数据上
zhoucs21 2018-11-09
  • 打赏
  • 举报
回复
DispatcherTimer是UI里的线程,但我想把通讯部分独立开来,怕这部分内容多了影响UI的刷新和响应。请教有没有什么好的办法,或是我对timer的用法有问题
sdfgrtyu 2018-11-09
  • 打赏
  • 举报
回复
怎么写的,肯定是你写的有问题,我一直再用定时器,并不卡啊

110,533

社区成员

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

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

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