在delphi中拆分串行数据

时间:2015-03-10 09:53:09

标签: delphi serial-port delphi-7 delimiter arduino-uno

我是Delphi编程的新手,我需要一些帮助。我在分割我的串行数据时遇到问题。这是我的代码:

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer); 
var 
  DataByte : string;  
  x, i: integer;   
  save_data : TStringList;  
begin 
  save_data := TStringList.create;

  for x := 0 to Count-1 do begin
    ComPort1.ReadStr(DataByte,1);
    if DataByte = 'n' then
    begin
      memo1.Text := '';
    end
    else
    begin
      memo1.Text := memo1.Text + DataByte;
      Split(' ', DataByte, save_data);
    end; 
  end;   
  save_gyroX := save_data[0];   
  save_gyroY := save_data[1];   
  save_gyroZ := save_data[2];   
  save_accelX := save_data[3];   
  save_accelY := save_data[4];   
  save_accelZ := save_data[5];   
  SerialProcess();
  save_data.Free; 
end;

我的Split(' ', DataByte, save_data);无效。我不明白,因为我只是将String数据从串口中取出。这是我的Split()程序:

procedure TForm1.Split(const Delimiter: Char; Input: string; const Strings: TStrings) ; 
begin
  Assert(Assigned(Strings));
  Strings.Clear;
  Strings.Delimiter := Delimiter;
  Strings.DelimitedText := Input;
end;

我不知道为什么我的程序给了EStringListError错误。

2 个答案:

答案 0 :(得分:2)

您正在调用ReadStr()来读取单个字节,并在每个字节上调用Split()'n'除外)。所以TStringList一次只能容纳1个字符串。就像MBo所说,你需要修复你的循环以避免这种情况,例如:

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer); 
var 
  DataByte : string;  
  x: integer;   
  save_data : TStringList;  
begin 
  ComPort1.ReadStr(DataByte, Count);

  for x := 1 to Length(DataByte) do
  begin
    if DataByte[x] = 'n' then
    begin
      Memo1.Text := '';
    end
    else
    begin
      Memo1.Text := Memo1.Text + DataByte[x];
    end; 
  end;   

  save_data := TStringList.create;
  try
    Split(' ', DataByte, save_data);

    save_gyroX := save_data[0];   
    save_gyroY := save_data[1];   
    save_gyroZ := save_data[2];   
    save_accelX := save_data[3];   
    save_accelY := save_data[4];   
    save_accelZ := save_data[5];   
    SerialProcess();
  finally
    save_data.Free; 
  end;
end;

话虽如此,您没有考虑到任何给定OnRxChar事件调用的字节数是任意。它是在那个确切时刻读取的原始字节。您假设一个包含至少6个分隔子串的完整字符串,这根本不能保证。您需要在收到原始数据时对其进行缓冲,然后根据需要从缓冲区中解析并删除已完成的字符串。

尝试更像这样的事情:

var
  DataBuffer: string;

// consider using the OnRxBuf event instead...
procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer); 
var 
  DataByte : string;  
  x: integer;   
  save_data : TStringList;  
begin 
  ComPort1.ReadStr(DataByte, Count);
  DataBuffer := DataBuffer + DataByte;

  x := Pos('n', DataBuffer);
  if x = 0 then Exit;

  save_data := TStringList.Create;
  try
    repeat
      DataByte := Copy(DataBuffer, 1, x-1);
      Delete(DataBuffer, 1, x);

      Memo1.Text := DataByte;

      Split(' ', DataByte, save_data);
      if save_data.Count >= 6 then
      begin
        save_gyroX := save_data[0];   
        save_gyroY := save_data[1];   
        save_gyroZ := save_data[2];   
        save_accelX := save_data[3];   
        save_accelY := save_data[4];   
        save_accelZ := save_data[5];   
        SerialProcess();
      end;

      x := Pos('n', DataBuffer);
    until x = 0;
  finally
    save_data.Free; 
  end;
end;

答案 1 :(得分:1)

如果Comport是Dejan Crnila CPort类,那么这一行

 ComPort1.ReadStr(DataByte,1);

每次都替换Databyte内容,此字符串的长度始终为1个字节。

只需通过一次调用

读取缓冲区中的所有字节
ComPort1.ReadStr(DataByte, Count);

并使用字符串