关于spcomm的缓冲管理问题(头快咋了,工期吃紧) (80分)

  • 主题发起人 主题发起人 windcolor
  • 开始时间 开始时间
W

windcolor

Unregistered / Unconfirmed
GUEST, unregistred user!
用过spcomm的朋友们好,我现在用spcomm做一串口数据采集程序,发现spcomm的onDataReceive
事件中,如果处理的时间过长,会引起后来的数据将串口中原本的数据冲掉,从而引起数据
丢失,大家有知道如何解决吗(最好还用spcomm)
 
可以先设一个变量,将缓冲区的数据放在变量里再处理,避免直接处理控件的缓冲区
然后,加大缓冲,以防溢出
还有问题吗?呵呵
 
to Rope:
我就是这样做的,但头儿说不行的,我的数据采集是多线程的,接受到后,分析字符串,
然后入后段数据库,我想问的是,OnDataReceive是怎样工作的,是真正的多线程吗??
 
你在ondatareceive事件里接收完数据以后,必须立刻清除spcomm的接收缓冲区,
然后再处理接收到的数据。
spcomm是通过你在控件里设置的参数去操作串口,具体的操作由windows完成,
windows收到数据后给spcomm发消息,spcomm把它收到的数据处理一下后放到它自己的缓冲区里,
spcomm只开一个线程就足够了。串口通讯的关键不是开几个线程,而是缓冲区的使用。
 
开一个队列, 接收喝发送用不同的线程, 注意线程间的同步. 在OnDataReceive中只
向队列增加, 这样处理速度一般会满足要求. spcomm是多线程, 但他是发送和接收
用不同的线程, 对你的应用不会用影响, 关键看你的处理代码.
 
to Rope:
我想,当我如您所说的做时,晴空spcomm的buffer,处理传来的数据,再处理期间如果又有
数据传来,那么spcomm::OnDataReceive事件能被及时激发吗??如果不能(我做的测试结果
的确如此),那么当buffer满了以后,数据的采集还是不完备的。

我是一接触com口编程的新手,另外工作压力极大,请各位多多赐教
 
to Tseug:
愿闻其祥,我会加分给大家的
 
如同rope所说, 你只要把缓冲区开大了就可以. 你所说的在处理期间有数据到达
其实应该不会发生. 理由是这样的. 如果你的接收处理程序只负责些缓冲区的话
那么应该不会有几行代码的, 以计算机的处理速度来说应该远远快于串口通讯的
速度. 我想你在设计通讯程序的时候应该计算过串口的通讯速度是否满足你的要
求. 如果采集速度过快的话, 用串口可能满足不了要求. 另外如果发送段支持流
控制, 你可以考虑用流控制来同步数据.
 
to tseug:
是这样的,我做的是一个克服中心的pbx数据采集工作,将话单纪录从com中读出来,在
ondatareceive中分成一条条单话单,作为一个参数,生成一线程,实现分析话单并入库功能,我的同事说以够用了,但
头说春在掉数据的可能,要我重做,既写出的程序应“包含“spcomm的ondatareceive事件
处理,我对底层了解也不多,能帮我分析一下吗??
 
如果spcomm::OnDataReceive不能被触发,那你可以定期去读spcomm的当前缓冲区数据长度,
如果socomm的缓冲区长度大于零,就表示接收到数据。至于隔多久去检测一次,需要你根据
通讯速度和缓冲区的大小来决定,如果对数据的处理不包括网络操作的话,如tseug所说,
不需要考虑数据处理的时间。如果要写数据库,可以把缓冲区放大,就算设成spcomm的
上限也没什么。
如果传送丢数据,那是Windows的问题,唯一可行的方法是数据包加校验,出错后请求对方重发。
只要缓冲区够大,硬件不出故障,就不可能丢数据。
 
我将onreceivedata事件的代码贴上来了,请帮我分析一下,是否存在掉数据的现象?是否
需要修改?如何改??
procedure TfrmMain.CommReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var i:Integer;
single_hd:String;
athread:TDealLogThread;
cond1,cond2:Boolean;
begin
i:=1;
SetLength(Hds,BufferLength);
Move(Buffer^, PChar(Hds)^, BufferLength);
if Copy(HDs,1,Start_flag_len)<>Start_flag then
HDs:=start_flag+HDs;
//deal with the tele-records...
while (Length(HDs)>=TeleReco_len) do
begin
//if the next string is no more than a sole telereco len,
//the skip out of the loop
if Length(HDs)<TeleReco_len then Exit;

cond1:=Copy(HDs,1,Start_flag_len)=Start_flag ;
cond2:=Copy(HDs,1+Start_flag_len,start_flag_len)=Start_flag;

if (cond1) and (not cond2) then
begin
//得到单条电话话单
single_hd:=ExtractQuotedStr(Start_flag,End_flag,HDs);
if Start_flag=end_flag then
Delete(HDs,1,Start_flag_len+TeleReco_len)
else
Delete(HDs,1,Start_flag_len+TeleReco_len+End_flag_len);
//启动数据分析及入库线程
athread:=TDealLogThread.Create(single_hd,Database,Session,qrInsLog);

end
else
Delete(HDs,1,1);
end;
 
在这句之后
Move(Buffer^, PChar(Hds)^, BufferLength);
立刻清 spcomm 缓冲,hds是你自己的数组吧,要清 spcomm 的缓冲,切记。
 
to rope:
大虾有礼了:"windows收到数据后给spcomm发消息,spcomm把它收到的数据处理一下后
放到它自己的缓冲区里,",我想知道,这时onreceivedata会发生吗?(我测试是不行),
不发生,buffer就存在overflow的可能,可能我的事件里还在做我程序的那些事
(说老实话,只有我头儿一个人说),我现在可以试试你的做法先

spcomm的ondatareceive事件何时能触发呢??看了source后,也不得要领阿

 
由于我碰到的问题和这位朋友类似。
TO WINDCOLOR:我这里发现ONRECEIVEDATA中掉数据。

TO ROPE:
来自:rope, 时间:2001-11-5 13:19:00, ID:707548
在这句之后
Move(Buffer^, PChar(Hds)^, BufferLength);
立刻清 spcomm 缓冲,hds是你自己的数组吧,要清 spcomm 的缓冲,切记。

是不是加句NEW(BUFFER);缓冲区在SPCOMM.pas中在SETCOMM中,我看4096,4096应该够大了
我的波特率是9600.
可是我还是碰到数据掉的情况,导致出现和这位朋友一样的情况
http://www.delphibbs.com/delphibbs/dispq.asp?lid=700817

我的个人问题在http://www.delphibbs.com/delphibbs/dispq.asp?lid=678999
期间有我的部分代码
 
to lp414:
您的意思是spcomm已经无法胜任这种工作了??有好建议马??
to all:
我有该了一下程序,在ondatareceive中,将穿过来的整个数据包给现程,完成话单的
解析及入库,虽然还不合头儿的要求,但效率已经高多了

看了看大家的各种建议,受益匪浅,但是,我还是想说一句:难道诸位经常
和spcomm打交道的大虾们,对spcomm的接受过程了解的都是这样模糊马?
聊发狂言,请见谅
 
也许我们的处理思路和你不一样, 像你所说的问题我没有到过. 按照我的设计思路,
我是不允许编程人员在OnDataReceive中直接处理数据的, 一定要把所有数据送到程
序内部的队列中, 至于对于数据的处理, 另开一个线程用阻塞的方式读取内部队列进
行处理. 这样, 一来接口清晰, 二来可以避免因为OnDataReceive事件处理时间过长
导致数据丢失的现象.
 
to tseug:
多谢
 
多人接受答案了。
 
to windcolor:my msn is lp414@hotmail.com.晚上我一直在的。

TO TSEUG:如果有空的话,加我MSN。

我的EMAIL也是这个
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
549
import
I
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
后退
顶部