各位大侠朋友,我的工控软件使用了6个Spcomm,用户操作了某个部件后,需要显示该部件的状态,如果使用定时器扫描的话,好像很卡,这时是不是要用线程扫描?在窗体里创建线程,直接可以使用本窗体的Spcomm控件进行收发吗?有没有例子看看?
解决方案 »
- 一串ASCII字符串转换问题
- 开发一个基于数据库的聊天程序.
- 马上要去公司了,总要带点东西给同事们意思一下, 不知道大家去公司都会带些什么东西,参考以下! 多谢了!~
- 简繁转换的另一种思维,请帮助
- ScrollBoX的问题
- 如何使用C#生成的COM中的事件
- 国庆了,却在外出差,不能和女友,朋友们一起玩,散分!
- 如何把正在浏览的网页用图片的形式保存下来
- 我要读大专,大家帮忙提点意见了@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- 如何在Application最小化的情况下,在屏幕上显示一个窗口?
- 关于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,串口通信方面的可以留言哟,咱们交流学习