码迷,mamicode.com
首页 > Windows程序 > 详细

Delphi TCOM控件串口通信调试寻找文件传输速度慢的原因

时间:2016-07-11 18:51:46      阅读:483      评论:0      收藏:0      [点我收藏+]

标签:

PC工具: IC util

手持设备:Dynasty ARM嵌入式设备

通信设备: TTL-USB串口传输器

 

问题:IC_Util向dynasty传输所需的配置文件,传输速度慢。

传输10k大小的文件

顺利时耗时大约10s,文件分块传输,1k/block or 2k/block。

波特率115200

传输时对于接受和发送的函数需要做适当的延时处理,同时需要对传输时的block大小做一定规定,BLOCK为2k时传输正常,BLOCK为1k时IC_Util将会不时的出现接收超时的问题。

Delphi串口模块使用的是TCOM模块

以下为TCOM模块的配置:

object DtmdComm: TDtmdComm
  OldCreateOrder = False
  OnCreate = DataModuleCreate
  OnDestroy = DataModuleDestroy
  Left = 415
  Top = 275
  Height = 225
  Width = 314
  object cmmMain: TComm
    CommName = COM1
    BaudRate = 9600
    ParityCheck = False
    Outx_CtsFlow = False
    Outx_DsrFlow = False
    DtrControl = DtrDisable
    DsrSensitivity = False
    TxContinueOnXoff = True
    Outx_XonXoffFlow = False
    Inx_XonXoffFlow = False
    ReplaceWhenParityError = False
    IgnoreNullChar = False
    RtsControl = RtsDisable
    XonLimit = 500
    XoffLimit = 500
    ByteSize = _8
    Parity = None
    StopBits = _1
    XonChar = #17
    XoffChar = #19
    ReplacedChar = #0
    ReadIntervalTimeout = 500
    ReadTotalTimeoutMultiplier = 0
    ReadTotalTimeoutConstant = 0
    WriteTotalTimeoutMultiplier = 0
    WriteTotalTimeoutConstant = 0
    OnReceiveData = cmmMainReceiveData
    Left = 48
    Top = 16
  end
  object tmrPack: TTimer
    Tag = 20
    Enabled = False
    OnTimer = tmrPackTimer
    Left = 136
    Top = 56
  end
end

接收函数的对应实现接口为cmmMainReceiveData()

以下为cmmMainReceiveData()的实现:

procedure TDtmdComm.cmmMainReceiveData(Sender: TObject; Buffer: Pointer;
  BufferLength: Word);
var
  tmpArray:array[1..8096] of Byte;
 i,DataCount: Integer;
 tmpRecvStr:string;
 OneCommand:string;
begin
  //Delay(100);
  tmpRecvStr := ‘‘;
  Move(Buffer^,PChar(@tmpArray)^,BufferLength);
  for   i:=1   to   BufferLength   do
    tmpRecvStr:=tmpRecvStr+inttohex(tmpArray[i],2);
  RecvPOSStr := RecvPOSStr +tmpRecvStr;
  OutputMemo.Lines.Add(FormatDateTime(hh:nn:ss-zzz,now)+---->[Receive]:);
  OutputMemo.Lines.Add(GetBinStrWithSpace(tmpRecvStr));
  if Copy(RecvPOSStr,1,2) = 02 then
  begin
    CommandType := Copy(RecvPOSStr,3,2);
    try
      DataCount := StrToInt($+Copy(RecvPOSStr,5,2))*256;
      DataCount := DataCount +StrToInt($+Copy(RecvPOSStr,7,2));
      DataCount := DataCount * 2;
      if Copy(RecvPOSStr,11+DataCount,2) <> 03 then //03开头的数据
      begin
        MoniterMemoAppend(FormatDateTime(yy-mm-dd hh:nn:ss,now)+---->Data format error,(02,03)。+Copy(RecvPOSStr,11+DataCount,2),0,0,0);
        RecvPOSStr := ‘‘;
        POSCommand := ‘‘;
        Exit;
      end;

      if ((CommandType <> 40) and (CommandType <> 41) and
          (CommandType <> 42) and (CommandType <> 43) and
          (CommandType <> 44) and (CommandType <> 45) and
          (CommandType <> 46) and (CommandType <> 47) and
          (CommandType <> 48) and (CommandType <> 49) and
          (CommandType <> 50) and (CommandType <> 51) and
          (CommandType <> 52) and (CommandType <> 53) and
          (CommandType <> 54) and (CommandType <> 55) and 
          (CommandType <> 60) and (CommandType <> 61) and
          (CommandType <> 70) and (CommandType <> 71)) then
      begin
        RecvPOSStr := Copy(RecvPOSStr,9,DataCount);
        if CommandType <> 03 then
        begin
          LogOutputMemoAppend(FormatDateTime(yy-mm-dd hh:nn:ss,now)+-------------------------------->[Transaction Log]:);
          OperPackageMessage(RecvPOSStr,tmpRecvStr);
          LogOutputMemoAppend(FormatDateTime(yy-mm-dd hh:nn:ss,now)+-------------------------------->[End Log]);

          CommandType := IntToHex(StrToInt($+Copy(CommandType,1,2)) + 1 ,2);
          SendHostScript(CommandType);
        end;
      end
      else
      begin
        OneCommand := Copy(RecvPOSStr,9,DataCount);
        POSCommand := OneCommand;
        RecvPOSStr := ‘‘;
        if (CommandType = 46) then    //请求输入密码
        begin
          SendStringByCom(CommandType,StrToHex(ACK));//响应ACK
          ExecInputPin(OneCommand);
          POSCommand := ‘‘;
        end
        else if (CommandType = 47) or (CommandType = 48)
             or (CommandType = 49) or (CommandType = 50)   then
        begin
          SendStringByCom(CommandType,StrToHex(ACK)); //响应ACK
          tmpRecvStr := ‘‘;
          OperSimulatorMessage(CommandType ,OneCommand, tmpRecvStr );
          POSCommand := ‘‘;
        end
        else if (CommandType = 51) or (CommandType = 52)
             or (CommandType = 60) or (CommandType = 61)  then
        begin
          SendStringByCom(CommandType,StrToHex(ACK)); //响应ACK
          tmpRecvStr := ‘‘;
          OperSimulatorMessage(CommandType ,OneCommand, tmpRecvStr );
          SendStringByCom(CommandType,tmpRecvStr);
          POSCommand := ‘‘;
        end
        else if(CommandType = 70) then
        begin
          //START TEST
          frmMain.ChangeLedColor(PosCommand);
          //EMD TEST
        end
        else if(CommandType = 71) then
        begin
          //START TEST
          frmMain.BeepSound(PosCommand);
          //EMD TEST
        end
      end;
      RecvPOSStr := ‘‘;
    except
      RecvPOSStr := ‘‘;
      POSCommand := ‘‘;
      MoniterMemoAppend(FormatDateTime(yy-mm-dd hh:nn:ss,now)+---->Data length is not hex,0,0,0);
      Exit;
    end;
  end
  else  if (Copy(RecvPOSStr,1,2) = 0D) or (Copy(RecvPOSStr,1,2) = 0A) then
  begin
    MoniterMemoAppend(FormatDateTime(yy-mm-dd hh:nn:ss,now)+---->Log:+HexToStr(RecvPOSStr),0,0,0);
    RecvPOSStr := ‘‘;
    POSCommand := ‘‘;
  end
  else
  begin
    MoniterMemoAppend(FormatDateTime(yy-mm-dd hh:nn:ss,now)+---->Log:+HexToStr(RecvPOSStr),0,0,0);
    RecvPOSStr := ‘‘;
    POSCommand := ‘‘;
  end;
end;

procedure TDtmdComm.DataModuleCreate(Sender: TObject);
begin
  bOperPackBusy := False;
  PosMaxCommLen := 2000;
  RecvPOSStr := ‘‘;
end;

以下为文件下载中判断Poscommand是否有数据的函数

function TDtmdComm.ReceACKByComm(SendCommandType:string;TimeOut:Integer): Boolean;
var
  RecvStr:string;
begin
  Result := False;
  tmrPack.Tag := TimeOut;
  tmrPack.Enabled := True;
  while True do
  begin
    if POSCommand <> ‘‘ then
    begin
      RecvStr := POSCommand;
      tmrPack.Enabled := False;
      Break;
    end;
    if not tmrPack.Enabled then  //连接超时
    begin
      Exit;
    end;
    if not bComOpened then
    begin
      tmrPack.Enabled := False;
      Exit;
    end;
    Application.ProcessMessages;
  end;

  if SendCommandType <> CommandType then Exit;
  
  UnpackTLV(RecvStr);
  FindTLV($0,RecvStr);
  if RecvStr <> ACK then
  begin
    Exit;
  end
  else
  begin
    Result := True;
  end;
end;

超时间为5s

文件传输函数将会对Poscommand的数据进行判断,传输过程中经常出现Poscommand数据为NULL,也就是没有成功获取从ARM设备端获取到数据从而超时的情况。

 

经过测试发现,在发送和接收之间增加适当的延时或者修改配置文件中ReadIntervalTimeout值对于传输超时现象有很大的改善。(最上面配置文件中红字部分)

1.当将ReadIntervalTimeout从原始的100ms增加为500ms时,无论对于Block为1k或Block为2k的传输单位都不会出现PC接收超时的情况。

2.在PC向ARM设备发送Block数据之间增加500ms的延时,也可以有效的改善PC接收超时的情况。

for j := 0 to 3 do
     begin
       Delay(500);//ms
       SendStringByCom(41,SendStr);//发送连接相应
       if not ReceACKByComm(41,5) then//5s超时等待接收数据
       begin
         MoniterMemoAppend(FormatDateTime(yy-mm-dd hh:nn:ss,now)+------>Download file error[+IntToStr(j+1)+],0,0,0);
         Continue;
       end;
       Break;
     end;

 但当Delay的时间少于500ms时,每次传输超时现象出现概率大大增加。

注:以上两种方法采用任意一种均可达到消除超时的效果。

 

================================  我是分割线 ======================================

分析为什么这两种操作可以改善超时?

尤其是为什么增加ReadIntervalTimeout参数可以改善超时现象?

因为根据ReadInervalTimeout的定义:

来确定所接收到的数据是否属子同一帧数据,其默认值是100ms,也就是说,只要任何两个字节到达的时间间隔小于1OOms,都被认为是属于同一帧数据。

想了半天脑袋都快炸了!!还是没有明白~哪天脑洞一开解决了这个问题再补上,先挖个坑...

 

就这样,祝您身体健康~

 

Delphi TCOM控件串口通信调试寻找文件传输速度慢的原因

标签:

原文地址:http://www.cnblogs.com/simon-code/p/5661102.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!