博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Delphi TCOM控件串口通信调试寻找文件传输速度慢的原因
阅读量:5359 次
发布时间:2019-06-15

本文共 7424 字,大约阅读时间需要 24 分钟。

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  endend

接收函数的对应实现接口为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,都被认为是属于同一帧数据。

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

 

就这样,祝您身体健康~

 

转载于:https://www.cnblogs.com/simon-code/p/5661102.html

你可能感兴趣的文章
第一阶段测试题
查看>>
第二轮冲刺第五天
查看>>
图片压缩
查看>>
Hadoop-2.6.5安装
查看>>
[poj-2985]The k-th Largest Group_Treap+并查集
查看>>
2018年移动用户界面的三种最潮趋势
查看>>
小甲鱼python视频第三讲(课堂笔记)
查看>>
JMeter压力测试及并发量计算-2
查看>>
Eclipse调试Bug的七种常用技巧
查看>>
go 语言如何跨平台编译
查看>>
重构大数据统计
查看>>
Fortran学习笔记2(变量声明)
查看>>
Trie树
查看>>
A/B test
查看>>
Ad Hoc网络概念、特点和比较
查看>>
2018牛客多校第四场 J.Hash Function
查看>>
ZOJ 解题报告索引
查看>>
vim命令
查看>>
运行在 tomcat7.0.88 的应用在Safari浏览器上无法识别回车键、下拉框数据无法加载出来...
查看>>
Java后端进阶教程
查看>>