我在使用SPCOMM的时候无意间发现一个问题,我写了一个Demo程序,代码很简单,我只是接收的地方写了一句代码,
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
  BufferLength: Word);
var
  receivebuf:array[1..255] of byte;
begin
  move(buffer^,pchar(@rbuf)^,bufferlength);
end;电脑和另外一台机器的串口是连着的,我在另外一台机器用串口调试程序手动发送,如果一下下点,差不多间隔1000ms,是没问题的,如果鼠标连续快速点发送的话,这个程序是出错:access violation at 0x01b1d2b7: read of address 0x01b1d2b7.
我想应该是内存溢出了,但是为什么会出现这种情况呢,难道SPCOMM内部机制没有对种情况作相应的处理吗?我又用了COMPORT,代码也很简单:
procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer);
var
  Str: String;
begin
  ComPort.ReadStr(Str, Count);
  Memo.Text := Memo.Text + Str;
end;
我用串口调试程序发送,无论我鼠标怎么快的点都没问题,我想这样应该是正常的。因为人工鼠标点才多快啊!!!请教各位,如果知道的话,请告诉我一声好吗?谢谢

解决方案 »

  1.   

    首先呢,用Spcomm绝对没有问题的。是你的程序处理有问题。目前看来应该在你的发送部分有问题,因为接收部分没有问题。你最好断点调式以下你的发送端。顺便给你看看我刚才写的DEMO,随便点,多块都没问题哦。而且多种方式发送和接收.
    procedure TForm1.Button1Click(Sender: TObject);
    begin
     Comm.CommName:=ComboBox1.Text;
     Comm.BaudRate:=StrToInt(Edit2.Text);
     try
       Comm.StartComm;
       except
         raise Exception.Create('打开串口错误');
       end;
     StatusBar1.Panels[0].Text :=Comm.CommName+'已打开';
     StatusBar1.Refresh;
    end;procedure TForm1.Button3Click(Sender: TObject);
    begin
    Comm.StopComm;
     StatusBar1.Panels[0].Text :=Comm.CommName+'已关闭';
     StatusBar1.Refresh;
    end;procedure TForm1.Button2Click(Sender: TObject);
    var
      str:PChar ;
      count:Integer ;
      i:Integer;
      sbuf:array[1..6] of byte;
      viewstr:string ;
    begin
      //以HEX发送
      sbuf[1]:=byte($5B);
      sbuf[2]:=byte($53);
      sbuf[3]:=byte($00);
      sbuf[4]:=byte($43);
      sbuf[5]:=byte($01);
      sbuf[6]:=byte($5D);
      viewstr:='';
      for i:=1 to 6 do
      begin
        if not Comm.WriteCommData(@sbuf[i],1) then
          break;
        sleep(2);
        viewstr:=viewstr+inttohex(sbuf[i],2)+'';
      end;
      //Memo1.Lines.Add('已发送字符'+'-->'+viewstr);
      {
      //以ASCII发送
      str:=PChar(Edit1.Text);
      count :=Length(str);
      //if Comm.WriteCommData(str,count) then
      if Comm.WriteCommData(PChar('[RS]'),4) then
      Memo1.Lines.Add('已发送'+inttostr(count)+'个字符'+'-->'+Edit1.Text)
      else
      raise Exception.Create('发送错误'); }
    end;
    procedure TForm1.CommReceiveData(Sender: TObject; Buffer: Pointer;
      BufferLength: Word);
    var
      strRecv:string;
      
      i:Integer ;
      rbuf:array[1..6] of byte;
      viewstr1:string ;  Channel:array[1..4] of string ;
    begin
      {//1-ASC接收
      SetLength(strRecv,BufferLength);
      Move(Buffer^,PChar(strRecv)^,BufferLength);
      Memo1.Lines.Add('已收到:'+IntToStr(BufferLength)+'字节的数据');
      Memo1.Lines.Add(strRecv);
      Memo1.Invalidate; }
      //2-HEX接收
      viewstr1:='';
      Move(Buffer^,PChar(@rbuf)^,BufferLength);
      for i:=1 to bufferlength do
      viewstr1:=viewstr1+inttohex(rbuf[i],2)+'';
      Memo1.Lines.Add(viewstr1);  if Copy(viewstr1,1,12)='5B530043015D' then
      begin
      Channel[1]:=Copy(viewstr1,13,4);
      Channel[2]:=Copy(viewstr1,17,4);
      Channel[3]:=Copy(viewstr1,21,4);
      Channel[4]:=Copy(viewstr1,25,4);
      //ShowMessage(Channel[1]+' '+Channel[2]+' '+Channel[3]+' '+Channel[4]);  ShowMessage(IntToStr(StrToInt('$'+Channel[1])));
      end;
    end;
      

  2.   

    to xjjrocker(了无痕) 
    谢谢你的回答因为我不了解SPCOMM所以才怀疑是不是他内部机制问题,但是我知道这种可能性很小。我的发送端是用“串口调试助手V2.2”,不知道是不是这个调试程序的问题,接收端的代码我已经给出了,很简单,因为我只是做测试,但是鼠标快速发送还会有同样的问题,不知道为什么
      

  3.   

    哦,可能是你接收的内存空间有问题,receivebuf:array[1..255] of byte;,我用的是我知道的大小,你的可能太大了,一次用不完,当你快速点击的时候一个数组接受不了两次的数据,也就是接收不完数据,所以报错,你不要用255,用小点空间接收应该没问题,最多丢失数据而已,或者你知道是多大的数据就好了.你可以调试看看报错的是哪里!
      

  4.   

    各位,请帮忙看看,我这个问题还没解决,还是老样子,我是用两台机器串口连接起来做测试的,问题还是老样子,不知道是不是spcomm控件要做什么设置,我在一抬机器一下下点发送是没有问题的,接收也是正常的,显示也的数据也是对的,但是我快速点发送,感觉还没来得及显示,程序就出错了,难道你们都没碰到过类似的问题吗?
      

  5.   

    的确没有遇到,你不要用串口调试,自己写个发送端试验,就直接用网上的DEMO写出来,单机两个串口测试。如果没有问题,那么两台机器也没有问题.
      

  6.   

    快速点击的时候,串口buf的数据有堆集!
    bufferlength肯定是大于255了,会出现越界写的情况,就会报错。 move(buffer^,pchar(@rbuf)^,bufferlength);
    这里面的rbuf,不要用静态数组,要根据bufferlength动态申请内存(处理完后记得释放,不然就是内存泄露了)。
      

  7.   

    to erhan可能是你说的情况,因为我做了很多种测试,发送时间太短是会出问题的,可能是越界了.我写一个动态的Demo试试
      

  8.   

    to erhan
       是你说的原因,我给写一下,结果发现连续快速发送的话,接收到的数据有些是两条数据一起发送的,有些甚至是3条,我想就是这么情况造成的错误。   但是我还有个问题,为什么SPCOMM会有这么问题呢?是发送端的问题吗?为什么我用COMPORT来做就没这么问题了,无论发送多快都没问题的。是不是SPCOMM对发送端有要求?
      

  9.   

    我用是SPCOMM没有出现问题,也许是因为我的move(buffer^,pchar(@rbuf)^,bufferlength);中的rbuf本身就是根据bufferlength动态申请的原因吧。
    COMPORT没有问题么?
      

  10.   

    怎么说呢,Cport是收到一个回传一个而Spcomm则是等缓冲满了才回传,所以你用Cport就不用管这个问题,但是用Spcomm就要控制你的缓存了。所以有些人认为Cport是死读,spcomm灵活,另外还有Mscomm容易出错。
      

  11.   

    to xjjrocker
       我目前测试下来好象COMPORT没有问题,起码我测试的时候没问题,现在我把rbuf改为动态申请了,出现的问题也解决了,汗一下。
       不过既然有这个问题,那么对发送端就有要求了,不是只管发送就可以了,如果时间没控制好,那么会出现这种情况,原来发送两条指令,结果由于时间太短,两条指令一起发送了
      

  12.   

    发送两条指令,结果由于时间太短,两条指令一起发送了--->
    会么?自己写的发送端?不会吧,一条就是条,还会出现一起发送两条?应该不至于这样,是不是参数设置的问题,我想Spcomm还不至于这样吧!
      

  13.   

    是啊,我想这样一个大家都在用的控件应该不会这样,我没有修改设置啊,都是默认的,就是Inx_XonXoffFlow 和 Out_XonXoffFlow设置成了False
      

  14.   

    move(buffer^,pchar(@rbuf)^,bufferlength);
    bufferLength的大小你根本不知道,你怎么能够保证他不出问题。
    bufferlength是word类型的,那么最大长度可以是2^16-1的。
    SPCOMM好像可以设置事件触发条件的,你可以选择数据到了多少的时候触发OnRecieve不就行了?
    一般这种情况,如果你知道发送端数据量和本地处理速度的情况下,选择一个足够大的缓冲区做接受,或者就动态申请缓冲区好了。
      

  15.   

    你要是真不想用动态申请内存,就把spcomm的接收缓存改小,改到255以内,这样应该不会出现你说的问题了。
    这个根本就不是spcomm的问题,是个基本的内存使用问题!!!!
      

  16.   

    其实控制的方法很多,一种,你控制buffer大小,确认到多少的时候触发事件;另外一种,就是自己处理,如果数据是规律的,比如一条是5个字节,那么10条就一定是2条,这样就在接收到的数据用一个算法来分离数据就可以了;我个人编码的时候采用的是第二种方法。