这种情况是不是要用线程,SPCOMM如何在线程中使用? 各位大侠朋友,我的工控软件使用了6个Spcomm,用户操作了某个部件后,需要显示该部件的状态,如果使用定时器扫描的话,好像很卡,这时是不是要用线程扫描?在窗体里创建线程,直接可以使用本窗体的Spcomm控件进行收发吗?有没有例子看看? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 SPCOMM 本身就是线程类,消息触发的。在收到消息反馈后,给主进程发送一个消息,就可以了,比如说,收到1号串口,状态值是多少。就可以了。 如果操作才触发数据刷新的话,不应该会卡顿啊,每包数据都很大?也可以定时器时间间隔放大一点。6个SPCOMM也不多。分配好每个SPCOMM的收发内存空间就行。除非你的PC本来配置就不高,CPU对一次过多缓存数据处理不过来可能会卡。 我如果在窗体里创建线程,那线程函数就可以直接使用窗体里的Spcomm控件吗?如果不用线程,多加Application.processMessage是否可以改善? unearth 说的挺清楚的啊。另外 你的定时器是接收还是发送还是两者都有? SPCOMM对串口的读写是分别放在读、写线程中的。我们的写操作,实际上是向写线程post一条消息,这费不了多少时间而我们定义的读函数,实际是在接收线程中被调用,这也不会引起主线程的阻赛,当然对UI的操作可能略有影响我觉得unearth 说的挺清楚的啊。或者把你的定时器 和 读取设备某个参数的函数,用一段伪代码发布上来? 收发数据很快的,用SPCOMM,根本不需要自己写线程,我现在是这么做的,我96个串口都处理的过来。private Comm:array of TComm; SRData:array[1..6,0..1]of string; //【1-6,0】此列存储发送数据,【1..6,1】此列存储接收到的数据如需要6个串口初始化函数里写SetLength(Comm,6)for循环创建6个对象并且写Comm[i].OnReceiveData=CommReceiveData; 共用一个接收函数接收函数里写Str_CommName:=(Sender as TComm).CommName;比如你6个串口设置的串口名称列表为COM1,COM2,COM3,COM4,COM5,COM6根据Str_CommName就可以等到是第X个串口发的数据.然后存到SRData[X,1]里面去。发送数据流程1、for i:=1 to 6 do 发数据2、 延时(此处可以判定比如你用全局变量计数你发送了6条,判断是否接收了6条,如果是,就结束延时)处理数据我现在在家,没办法发代码。我现在用的一点都不卡。 procedure Delay(i_Msc:integer);var 初始时间,现在时间。begin 初始时间=GetTickCount; repeat 现在时间=GetTickCount; Application.ProcessMessage; until(B_Receive) or (现在时间 减去 初始时间)>=I_Mscend;在接收函数里判断是否接收到6条( 可以根据数据帧结束字符判断),如果是就B_Receive:=True; 更正: 根据Str_CommName就可以得到是第X个串口收到的数据 你的问题感觉描述的不是太清楚大概是串口收发处理的不利索导致界面卡了吧。SPCOMM这个控件基本没用过,用的最多的是CPort,不过应该都差不多的吧,都有接收事件的吧,或者说在串口收到数的时候主线程应该是知道的吧。我的想法就是6个串口用一个接受事件,然后再接收事件里通过判断是哪个串口收到数了,加上标记然后存入缓冲区,然后就不用管了。再用一个定时器定时扫描缓冲区,如果有数据就处理,然后清除缓冲区,如果没有就不管。原则是串口接受事件里做的事情最好不要太多,把解析数据的工作放到定时器里面去做。当然这里最好加一个临界区,这样就更保险了。我做工控,再大的数据量都不出错 首先感谢大家的帮助!我有22个温控模块;22个流量计模块;13个松下伺服;13个分子泵;7台特种电源,我在定时器里实现对他们的状态扫描。我是窗体里拖了6个SPcomm控件,每个设置好接收函数。对于每个Spcomm控件,写好发送函数。卡得很厉害。 我对DMC这种部件使用了一个定时器,定时间隔是2秒。每次扫描一个。procedure TSamMonitor.timDMCTimer(Sender: TObject);beginif DMCmonitorEnable = False then exit; Application.ProcessMessages; intDMCmonTim := intDMCmonTim + 1; case intDMCmonTim of 1: ScanDMC10(1,'D8009','D8020','D8031','D8042'); 2: ScanDMC10(2,'D8053','D8064','D8075','D8086'); 3: ScanDMC10(3,'D10009','D10020','D10031','D10042'); 4: ScanDMC10(4,'D8209','D8220','D8231','D8242'); 5: ScanDMC10(5,'D8253','D8264','D8275','D8286'); 6: ScanDMC10(6,'D10209','D10220','D10231','D10242'); 7: ScanDMC10(7,'D8409','D8420','D8431','D8442'); 8: ScanDMC10(8,'D8453','D8464','D8475','D8486'); 9: ScanDMC10(9,'D8609','D8620','D8631','D8642'); 10: ScanDMC10(10,'D8653','D8664','D8675','D8686'); 11: ScanDMC10(11,'D8809','D8820','D8831','D8842'); 12: ScanDMC10(12,'D8853','D8864','D8875','D8886'); 13: ScanDMC10(13,'D9009','D9020','D9031','D9042'); 14: ScanDMC10(14,'D9053','D9064','D9075','D9086'); 15: ScanDMC10New(1,'D9209','D9220','D9231','D9242'); 16: ScanDMC10New(2,'D9253','D9264','D9275','D9286'); 17: ScanDMC10New(3,'D9409','D9420','D9431','D9442'); 18: ScanDMC10New(4,'D9453','D9464','D9475','D9486'); 19: ScanDMC10New(5,'D9609','D9620','D9631','D9642'); 20: ScanDMC10New(6,'D9653','D9664','D9675','D9686'); 21: ScanDMC10New(7,'D9809','D9820','D9831','D9842'); 22: ScanDMC10New(8,'D9853','D9864','D9875','D9886'); end; if intDMCmonTim > 22 then intDMCmonTim := 0;end;在我的工程里,目前使用了四个这种定时器。我想如果动态扫描做成线程的话,线程函数只管不停地扫描设备状态,结果送到我的PLC通道中。这种会最好,但是自己没有深入用过线程,所以至今没下决心。监控的过程有发有收,我一般做成一个函数。然后在定时器里循环调用。SPcomm自带接收、发送线程,但对于扫描监控怎么用线程还是没想清楚。 在窗体里已经有Spcomm对象的情况下,再创建线程,可以使用这些Spcomm的实例对象吗? ScanDMC10 和 ScanDMC10New 是如何实现的?感觉你程序卡是设计问题 而不是实现问题 SPCOMM 本身就是线程类,消息触发的。在收到消息反馈后,给主进程发送一个消息,就可以了,比如说,收到1号串口,状态值是多少。就可以了 http://download.csdn.net/detail/a295281315/7162601我上传的一个使用SPCOMM并发的Demo,自编程序部分没有使用多线程。 七个RS485通讯回路,每个都有20多个站点,通讯参数基本在19200,E,8,1,这样扫描起来很费时间,整个程序跑起来后,有“死机”现象,不能响应键盘、鼠标消息,但是通讯仍在进行。苦恼中 串口控件本身单开线程进行接收,如果有的话,只要做好协议中自己这边的发送部分就OK了我们前段做的一个工程,用MOXA的8串口卡进行通讯,8个SPCOMM同时工作,不卡啊 hongss,你好!会不会是我的接收程序中使用了VCL控件,导致了系统不稳定?我想把接收到的数据放到状态栏中的面盘中显示,以便观察来往的数据是否正确。这样7个Spcomm控件都会收到数据后访问Statusbar,这算不算线程中修改了VCL?会不会是这里导致了系统的卡死?我的接收函数类似下面:procedure TsamMonitor.commSDC46ReceiveData(Sender: TObject; Buffer: Pointer; BufferLength: Word);var str : String;begin SetLength(Str,BufferLength); move(buffer^,pchar(@Str[1])^,bufferlength); sbarDMCMQV.Panels.Items[3].Text := sbarDMCMQV.Panels.Items[3].Text + Str;end;我想接收函数中直接用一个字符串全局变量来接收,不用StatusBar中的panel了,这样会不会好一些? 还有,Spcomm本身是支持线程的,在我这种情况下如何使用它的线程?我要轮询很多的现场设备,可以说不停地轮询扫描,发一个命令,等待其返回结果,再发下一个,再等待反馈结果。那么Spcomm的线程是怎样用?准备好发送数据,然后给发送线程发送消息?接收到数据怎么处理?Spcomm收到数据后也会发送消息给主线程?我希望将这个很费时间的监控扫描过程做在一个或几个线程里面,每个线程驱动一个Spcomm,完成征询命令1,征询命令2.依次下去,这样可以实现吗? unearth 说的挺清楚的啊。另外 你的定时器是接收还是发送还是两者都有?我的定时器发送、接收都有 串口控件本身的线程不是这样理解的,你不用管它本身用不用线程,它的内部线程和你也没关系。前面说过了,你可以在自己的主线程里创建好Spcomm,并配置好各个参数,然后你的线程就可以用这个在主线程里创建的SPCOMM了。为了简单,一个线程单独用一个SPCOMM,这样就不用考虑各个线程间的冲突了。要发送的消息可以预先设置好一个列表传入通信子线程,通信子线程收到数据后给主线程发消息,可以这样发消息:var aDataRec:TMyRec; .................PostMessage(MainFormHandle,WM_MESSAGE001,Integer(@aDataRec),0);................//这个aDataRec可以是临时变量,这样就可以传递大数据了,也不要用全局变量了如果上位机和下位要交互的信息是有限和预知的,可以在通信线程里设置好。如果是要人参与交互,那就得临时挂起通信线程了,控件通信流程。我记得LZ是个和我一样的大龄DELPHIER,串口通信方面的可以留言哟,咱们交流学习 你的串口操作是发完就等待收数据的?如果是这样的话,效率感觉不是很高,自己定义一个管理SPCOMM的类,定义一个回调函数接口这个接口可能是(串口ID(标识你所使用的是哪个串口,长度,数据)在SPCOMM的接收中调用回调函数来告诉你哪个串口有数据来了,发送就相对简单了,数据发完就往下一个走不要等,有数据来回调会告诉你,没有数据来肯定就是没有回的,回调函数里面可能要做同步处理。如果回调是你的线程函数你可能还要考虑VCL线程安全的问题。 SPCOMM我记得是收发是两条单独的线程,感觉你的应用像是串口矩阵一样,如果要提高效率可能要把6个发整合在一个线程中处理,这个是你打开了串口就可以拿到句柄发数据就不是问题了,收数据可以参考SPCOMM,发数据要你改了。祝你好运。 全局Tlist输出结构体错误 干了一件蠢事 动态创建过程 老公获奖了,开心!! 【劲暴】CSDN自动接分助手发布了! 重分求DLL技术。 delphi怎样用IE浏览器浏览? 我的fastReport未注册,打印出来有FastReport-unregistered,各位有什么办法消除它!! 远程服务器上的IIS上有个MDB,如何用ADO远程连接上去?(72分) 哪里有数据库存取jpg图片的控件? 关于ADOQuery的UpdateBatch的一个问题 Delphi编程技巧总汇--------[持续更新]
如果不用线程,多加Application.processMessage是否可以改善?
我们的写操作,实际上是向写线程post一条消息,这费不了多少时间
而我们定义的读函数,实际是在接收线程中被调用,这也不会引起主线程的阻赛,当然对UI的操作可能略有影响
我觉得unearth 说的挺清楚的啊。
或者把你的定时器 和 读取设备某个参数的函数,用一段伪代码发布上来?
Comm:array of TComm;
SRData:array[1..6,0..1]of string; //【1-6,0】此列存储发送数据,【1..6,1】此列存储接收到的数据如需要6个串口初始化函数里写
SetLength(Comm,6)for循环创建6个对象
并且写Comm[i].OnReceiveData=CommReceiveData; 共用一个接收函数接收函数里写
Str_CommName:=(Sender as TComm).CommName;
比如你6个串口设置的串口名称列表为COM1,COM2,COM3,COM4,COM5,COM6
根据Str_CommName就可以等到是第X个串口发的数据.
然后存到SRData[X,1]里面去。发送数据流程
1、for i:=1 to 6 do
发数据
2、 延时(此处可以判定比如你用全局变量计数你发送了6条,判断是否接收了6条,如果是,就结束延时)
处理数据我现在在家,没办法发代码。
我现在用的一点都不卡。
var
初始时间,现在时间。
begin
初始时间=GetTickCount;
repeat
现在时间=GetTickCount;
Application.ProcessMessage;
until(B_Receive) or (现在时间 减去 初始时间)>=I_Msc
end;在接收函数里判断是否接收到6条( 可以根据数据帧结束字符判断),如果是就B_Receive:=True;
根据Str_CommName就可以得到是第X个串口收到的数据
大概是串口收发处理的不利索导致界面卡了吧。
SPCOMM这个控件基本没用过,用的最多的是CPort,不过应该都差不多的吧,都有接收事件的吧,或者说在串口收到数的时候主线程应该是知道的吧。
我的想法就是6个串口用一个接受事件,然后再接收事件里通过判断是哪个串口收到数了,加上标记然后存入缓冲区,然后就不用管了。再用一个定时器定时扫描缓冲区,如果有数据就处理,然后清除缓冲区,如果没有就不管。原则是串口接受事件里做的事情最好不要太多,把解析数据的工作放到定时器里面去做。当然这里最好加一个临界区,这样就更保险了。
我做工控,再大的数据量都不出错
我有22个温控模块;
22个流量计模块;
13个松下伺服;
13个分子泵;
7台特种电源,我在定时器里实现对他们的状态扫描。
我是窗体里拖了6个SPcomm控件,每个设置好接收函数。
对于每个Spcomm控件,写好发送函数。
卡得很厉害。
procedure TSamMonitor.timDMCTimer(Sender: TObject);
begin
if DMCmonitorEnable = False then exit; Application.ProcessMessages;
intDMCmonTim := intDMCmonTim + 1;
case intDMCmonTim of
1: ScanDMC10(1,'D8009','D8020','D8031','D8042');
2: ScanDMC10(2,'D8053','D8064','D8075','D8086');
3: ScanDMC10(3,'D10009','D10020','D10031','D10042');
4: ScanDMC10(4,'D8209','D8220','D8231','D8242');
5: ScanDMC10(5,'D8253','D8264','D8275','D8286');
6: ScanDMC10(6,'D10209','D10220','D10231','D10242');
7: ScanDMC10(7,'D8409','D8420','D8431','D8442');
8: ScanDMC10(8,'D8453','D8464','D8475','D8486');
9: ScanDMC10(9,'D8609','D8620','D8631','D8642');
10: ScanDMC10(10,'D8653','D8664','D8675','D8686');
11: ScanDMC10(11,'D8809','D8820','D8831','D8842');
12: ScanDMC10(12,'D8853','D8864','D8875','D8886');
13: ScanDMC10(13,'D9009','D9020','D9031','D9042');
14: ScanDMC10(14,'D9053','D9064','D9075','D9086');
15: ScanDMC10New(1,'D9209','D9220','D9231','D9242');
16: ScanDMC10New(2,'D9253','D9264','D9275','D9286');
17: ScanDMC10New(3,'D9409','D9420','D9431','D9442');
18: ScanDMC10New(4,'D9453','D9464','D9475','D9486');
19: ScanDMC10New(5,'D9609','D9620','D9631','D9642');
20: ScanDMC10New(6,'D9653','D9664','D9675','D9686');
21: ScanDMC10New(7,'D9809','D9820','D9831','D9842');
22: ScanDMC10New(8,'D9853','D9864','D9875','D9886');
end;
if intDMCmonTim > 22 then intDMCmonTim := 0;
end;
在我的工程里,目前使用了四个这种定时器。
我想如果动态扫描做成线程的话,线程函数只管不停地扫描设备状态,结果送到我的PLC通道中。
这种会最好,但是自己没有深入用过线程,所以至今没下决心。
监控的过程有发有收,我一般做成一个函数。然后在定时器里循环调用。
SPcomm自带接收、发送线程,但对于扫描监控怎么用线程还是没想清楚。
感觉你程序卡是设计问题 而不是实现问题
我上传的一个使用SPCOMM并发的Demo,自编程序部分没有使用多线程。
我的接收函数类似下面:
procedure TsamMonitor.commSDC46ReceiveData(Sender: TObject;
Buffer: Pointer; BufferLength: Word);
var
str : String;
begin
SetLength(Str,BufferLength);
move(buffer^,pchar(@Str[1])^,bufferlength);
sbarDMCMQV.Panels.Items[3].Text := sbarDMCMQV.Panels.Items[3].Text + Str;
end;
我想接收函数中直接用一个字符串全局变量来接收,不用StatusBar中的panel了,这样会不会好一些?
我要轮询很多的现场设备,可以说不停地轮询扫描,发一个命令,等待其返回结果,再发下一个,再等待反馈结果。
那么Spcomm的线程是怎样用?准备好发送数据,然后给发送线程发送消息?接收到数据怎么处理?Spcomm收到数据后也会发送消息给主线程?我希望将这个很费时间的监控扫描过程做在一个或几个线程里面,每个线程驱动一个Spcomm,完成征询命令1,征询命令2.依次下去,这样可以实现吗?
aDataRec:TMyRec; .................
PostMessage(MainFormHandle,WM_MESSAGE001,Integer(@aDataRec),0);
................
//这个aDataRec可以是临时变量,这样就可以传递大数据了,也不要用全局变量了如果上位机和下位要交互的信息是有限和预知的,可以在通信线程里设置好。如果是要人参与交互,那就得临时挂起通信线程了,控件通信流程。我记得LZ是个和我一样的大龄DELPHIER,串口通信方面的可以留言哟,咱们交流学习