在 delphi 中拆分串行数据

Split up serial data in delphi

我是 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 错误。

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

 ComPort1.ReadStr(DataByte,1);

每次都替换Databyte的内容,这个字符串总是1个字节的长度。

只需一次调用即可从缓冲区中读取所有字节

ComPort1.ReadStr(DataByte, Count);

并使用字符串

您正在调用 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;