从字节序列中提取数据

时间:2012-03-12 15:56:36

标签: delphi header serial-port

假设我们有一个标题为'807F'的字节序列,它通过RS232输入到PC。例如“...... 80 7F 4B 97 80 7F 21 3A 80 7F ......”其中“21 3A”是我们的粗体包装数据,21是MSB,3A是LSB。我们如何从DELPHI中的序列中提取数据?

2 个答案:

答案 0 :(得分:4)

您的数据存储方式有点不清楚,但假设它存储在TBytes数组中,下面是一些解包数据的代码:

procedure ExtractWordFromRS232Data( a : TBytes);
var
  i: integer;
  myWord: word;
begin
  // a is a TBytes buffer from reading the RS232 port
  i := 0;
  while (i < Length(a)-3) do 
  begin
    if (a[i] = $80) and (a[i+1] = $7F) then 
    begin
      myWord := (a[i+2] shl 8) + a[i+3];
      // Do something with myWord
      Inc(i,4);
    end
    else
      Inc(i);
  end;
end;

它将搜索标头$ 80 $ 7F的第一个输出并将以下两个字节解压缩到word。用这个词做你想做的事。然后搜索继续,直到输入数据数组结束。

更新: 目前还不清楚你真正想要什么,但这里有一些代码,数据通过一个事件进入程序。

var
  gData : array[1..4] of byte;
  gIX : integer;

gIx := 1; // initialized at start

procedure InterpretIndataEvent( b : byte);
var
  i : integer;
  myWord : word;
begin
  gData[gIx] := b;
  if (gIx = 4) then
  begin
    if (gData[1] = $80) and (gData[2] = $7f) then
    begin
      myWord := (gData[3] shl 8) + gData[4];
      // do something with myWord
      gIx := 1;
    end
    else
    begin
      for i := 1 to 3 do gData[i] := gData[i+1];
    end;
  end
  else
    Inc(gIx);
end;

更新2:

从评论的角度来看,似乎数据就像ascii字符一样。

然后解码过程看起来像这样(包括一个小测试):

uses
  System.SysUtils;

var
  gData : string[8] = '12345678'; // Old fixed size ansistring type
  gIX : integer = 1;

procedure InterpretIndataEvent( a : AnsiChar);
var
  i : integer;
  myWord : word;
begin
  gData[gIx] := a;
  if (gIx = 8) then
  begin
    if (Copy(gData,1,4) = '807F') then
    begin
      myWord := StrToInt('$'+Copy(gData,5,4));
      // do something with myWord
      WriteLn(IntToHex(myWord,4));
      gIx := 1;
    end
    else
    begin
      for i := 1 to 7 do gData[i] := gData[i+1];
      // During startup or if a character is missed we end up here.
      // These events can be logged from here.
    end;
  end
  else
    Inc(gIx);
end;

const
  testBuf : string[8] = '807F213A';
var
  i : integer;

begin
  for i := 1 to 8 do
    InterpretIndataEvent(testBuf[i]);
  ReadLn;

end.

答案 1 :(得分:0)

从你的评论中我假设......

program project;

{$mode objfpc}{$H+}

const
  DATA_HEADER = Word(Swap($807F));

type
  TData = Word;
  TDataCallback = procedure(const aData: TData);

  PDataStruct = ^TDataStruct;
  TDataStruct = packed record
    Header: Word;
    Data: TData
  end;

procedure DecodeData(const aData: Pointer; const aDataSize: Integer;
  const aCallback: TDataCallback);
type
  PDataBuffer = ^TDataBuffer;
  TDataBuffer = packed array[0..High(Integer)-1] of Byte;
var
  Ix: Integer;
  Data: PDataStruct;
begin
  if not Assigned(aCallback) then
     Exit; // WARRNING: program flow disorder

  Ix := 0;
  while (Ix <= aDataSize - SizeOf(TDataStruct)) do
  begin

    Data:= @PDataBuffer(aData)^[Ix];
    if Data^.Header = DATA_HEADER then
    begin

      aCallback(Swap(Data^.Data));
      Inc(Ix, SizeOf(Data^));

    end
    else
      Inc(Ix)

  end
end;

var
  W: TData = 0;

procedure ProcessData(const aData: TData);
begin
  Inc(W, aData)
end;

var
  InputIx: Integer = 0;

// youre serial input
function ReadByte(): Byte;
const
  DATA: packed array[0..11] of Byte = (
    $80, $7F, $4B, $97, $80, $7F, $21, $3A, $80, $7F, $AB, $CD);
begin
  Result:= DATA[InputIx];
  InputIx:= (InputIx + 1) mod SizeOf(DATA);
end;

var
  Buffer: packed record
    case Byte of
      0: (
        Data: TDataStruct);
      1: (
        Raw: array[0..Pred(SizeOf(TDataStruct))] of Byte)
  end;

var
  Ix: Integer;
begin
  while true do
  begin

    for Ix := Low(Buffer.Raw) to High(Buffer.Raw) do
    begin

      Buffer.Raw[Ix]:= ReadByte()

    end;
    DecodeData(
      @Buffer,
      SizeOf(Buffer),
      @ProcessData)

  end
end.

但是阅读Byte输入的内容可能有点无效。