izzuddin
izzuddin

Reputation: 13

String Operation so Slow

I made an interface software using Delphi 7 to fetch data from arduino. Arduino has 3 sensors. Arduino will send 16 characters for sensor value. The example is :

 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

I assign the string value from arduino to an editText called Edit1. After that I use string "Copy" to get the sensor value one by one. The sensor value then will be displayed one by one in a label. But it takes long time for label to change the value. First time, I think it caused by label that slow on update. Then I change the label with editText, but work the same way (still takes long time to update the value). So is there a way to make this things faster? or there's something wrong with string operation?

This is my code:

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;

Upvotes: 0

Views: 593

Answers (2)

Tom Brunberg
Tom Brunberg

Reputation: 21033

The header of the procedure has an important parameter, Count:

  procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);

It tells you how many characters are received and ready for you to read. Mostly, with low comm speed there will be only one, but sometimes there could be two or more. If you only read 1 character as in

  ComPort1.ReadStr(Str, 1);

the remaining characters will be lost or they will not be read before the next OnRxChar occurs. For the last characters in a message, that will not take place before the next message triggers the event. That may explain why you percieve the process to be so slow. The cure is to read Count characters instead of only one.

But there seems to be an error and you were not at all able to receive complete measurements. Let's look at the code:

Edit1.text := Edit1.text + Str;
if Str = 'm' then
  Edit1.text := '';
if Length(Edit1.text) >= 15 then

Your intention is to wait for the m flag, and clear Edit1.Text when you do receive it. That's fine. Then you receive and collect the rest of the message until you have 15 characters in Edit1.Text, which is also ok. But then, you overwrite the received message with a '2' ?

begin
  Edit1.text := '2';

Of course the rest of the message parsing will then fail.

If you correct above two errors, I believe that your code might actually work.

Edit after comment

Replace these lines

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

with

for i := 1 to Length(Str) do
if Str[i] = 'm' then
  Edit1.text := ''
else
  Edit1.Text := Edit1.Text + Str[i];

And then you could also remove Buffer as you are not using it as well as the superfluous begin .. end; pair.

Upvotes: 5

MBo
MBo

Reputation: 80107

You read only one byte from comport and do a lot of unnecessary work with visual components. Short sketch:

 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;

Upvotes: 3

Related Questions