Delphi 字符串操作太慢了

Delphi 字符串操作太慢了,delphi,serial-port,arduino,delphi-7,Delphi,Serial Port,Arduino,Delphi 7,我使用Delphi7制作了一个接口软件,从arduino获取数据。Arduino有3个传感器。Arduino将发送16个字符的传感器值。例如: m 0 0 . 0 1 0 0 . 0 2 0 0 . 0 3 [1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16] [1] Flag for Start value [2],[7],[12] are sensors status (0=disconn

我使用Delphi7制作了一个接口软件,从arduino获取数据。Arduino有3个传感器。Arduino将发送16个字符的传感器值。例如:

 m  0  0  .  0  1  0  0  .  0   2   0   0   .   0   3
[1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16]

[1] Flag for Start value
[2],[7],[12] are sensors status (0=disconnected, 1=connected)
[3][4][5][6] first sensor value
[8][9][10][11] second sensor value
[13][14][15][16] third sensor value
我将arduino中的字符串值分配给名为Edit1的editText。之后,我使用字符串“Copy”逐个获取传感器值。然后,传感器值将在标签中逐一显示。但标签更改值需要很长时间。第一次,我认为这是由于标签更新速度太慢造成的。然后我用editText更改标签,但工作方式相同(更新值仍然需要很长时间)。那么,有没有办法让这一切变得更快?或者字符串操作有问题

这是我的代码:

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
  Str,Buffer,Rstatus,Sstatus,Tstatus: String;
  arus : real;
  i : integer;
begin
  DecimalSeparator:='.';   
  ComPort1.ReadStr(Str, 1);
  begin
    Buffer:=Buffer + Str;
    Edit1.Text:=Edit1.Text+Str;
    if Str='m' then
    edit1.Text:='';
      if Length(Edit1.Text) >=15 then
      begin
        Rstatus:=copy(Edit1.Text,1,1);
        Sstatus:=copy(Edit1.Text,6,1);
        Tstatus:=copy(Edit1.Text,11,1);
        if Rstatus='0' then
          begin
          Label1.Caption:='0 A';
          Label1.Update
          end
        else
          begin
          Label1.Caption:=copy(Edit1.Text,2,4)+' A';
          Label1.Update
          end;
        if Sstatus='0' then
          begin
          Label2.Caption:='0 A';
          Label2.Update
          end
        else
          begin
          Label2.Caption:=copy(Edit1.Text,7,4)+' A';
          Label2.Update;
          end;
        if Tstatus='0' then
          begin
          Label3.Caption:='0 A';
          Label3.Update
          end
        else
          begin
          Label3.Caption:=copy(Edit1.Text,12,4)+' A';
          Label3.Update;
          end;
      end;
    end;
end;

您只从comport读取了一个字节,并且对可视化组件做了很多不必要的工作。简图:

 ComPort1.ReadStr(Str); // read out all data
 Buffer:=Buffer + Str;

 //ensure that buffer starts with right value
 pm := Pos('m', Buffer);
 if pm > 1 then
   Delete(Buffer, 1, pm - 1);  
 if pm < 0 then
   Buffer := '';

 if Length(Buffer) >= 16 then begin
    if Buffer[2] = '0' then begin
       //do something for zero rstatus
    end else begin
       //do something for nonzero rstatus
    end;

   //and so on

   Delete(Buffer, 1, 16);//erase treated data
 end;
ComPort1.ReadStr(Str);//读出所有数据
缓冲区:=Buffer+Str;
//确保缓冲区以正确的值开始
pm:=位置('m',缓冲器);
如果pm>1,则
删除(缓冲区,1,pm-1);
如果pm<0,则
缓冲区:='';
如果长度(缓冲区)>=16,则开始
如果缓冲区[2]=“0”,则开始
//为零状态做点什么
结束,否则开始
//为非零状态做点什么
终止
//等等
删除(缓冲区,1,16)//擦除处理过的数据
终止

过程的标题有一个重要参数,
Count

  procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
它告诉您收到了多少个字符并准备好供您阅读。通常,在通信速度较低的情况下,只有一个,但有时可能有两个或更多。如果只读取1个字符,如中所示

  ComPort1.ReadStr(Str, 1);
在下一个
OnRxChar
出现之前,其余字符将丢失或无法读取。对于消息中的最后一个字符,在下一条消息触发事件之前不会发生这种情况。这也许可以解释为什么你觉得这个过程如此缓慢。解决方法是读取
计数
字符,而不是只读取一个字符

但似乎有一个错误,你根本无法收到完整的测量结果。让我们看看代码:

Edit1.text := Edit1.text + Str;
if Str = 'm' then
  Edit1.text := '';
if Length(Edit1.text) >= 15 then
您的目的是等待
m
标志,并在收到它时清除Edit1.Text。那很好。然后接收并收集消息的其余部分,直到Edit1.Text中有15个字符,这也是可以的。但是,您会用
'2'
覆盖收到的消息吗

begin
  Edit1.text := '2';
当然,消息解析的其余部分将失败

如果您纠正了以上两个错误,我相信您的代码实际上可能会工作

评论后编辑

更换这些线路

Edit1.text := Edit1.text + Str;
if Str = 'm' then
  Edit1.text := '';


然后,您还可以删除
缓冲区,因为您不使用它以及多余的
开始。。结束配对。

我相信问题中对字符串进行操作的代码可以有所改进。然而,即使如此,它仍将在很短的时间内执行,肯定比您能够检测到的速度要快。所以我猜实际的延迟是在通信中。如果您不同意,请显示您的计时,以证明字符串操作是一个瓶颈。改进代码的明显方法是使用
char
而不是字符串作为单字符值。并在提取单个值时使用索引运算符
[]
而不是
Copy
。另外,您不需要初始化
缓冲区
。我看到Edit1的变化如此之快。但不能使用标签标题。设置标签标题很快。我看不到任何时间。一个免通信的复制程序会很有用。你也应该删除不必要的更新调用。如果我是你,我会将数据处理与GUI分离。它将使您的代码更易于编写、阅读、调整和重用。我认为串行通信很好,因为我看到Edit1的变化如此之快。更改标签标题的问题太晚了。即使我断开了串行端口,标签标题仍然在更改值,因为太晚了。对不起,Edit2.text:=“2”;这只是我的实验。我忘了删除那个。我已经编辑了列表。在我再次观看之后,我认为你是对的。Edit1在接收数据时非常慢。所以我用Count替换readStr中的1。但是现在。如何读取m作为开始标志?
for i := 1 to Length(Str) do
if Str[i] = 'm' then
  Edit1.text := ''
else
  Edit1.Text := Edit1.Text + Str[i];