我已经下载并安装了comport库.我有一个模拟器通过串口RS232发送数据到Selphi程序.这是以下代码段.
procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer); begin ComPort.ReadStr(CPort.Str,Count); Memo.Text := Memo.Text + CPort.Str; end;
至于CPort库部分,我补充说:
var Str: String; here is the problem.
正在经历的数据示例大致相同
$HEHDT,288.45,T*1D $HEHDT,288.46,T*18 $HEHDT,288.47,T*1A
等等.每行每秒发送一次.因此,使用上面的代码,备忘录将显示所有这些数据.
但是,如果我将代码更改为:
procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer); begin ComPort.ReadStr(CPort.Str,Count); Memo.Text := Memo.Text + CPort.Str + 'haha'; end;
这是备忘录上的内容:
$HEHDT,2haha88.45,T*haha1Dhaha $HEHDT,2haha88.46,T*haha18haha $HEHDT,2haha88.47,T*haha1Ahaha
8个ASCII字符后出现“haha”.这在CPort.pas中意味着什么呢?
库,在异步/同步部分下,最多只有8ASCII字符
分配给变量Str?
我如何改变代码,使整个数据字符串,无论如何
它的大小,将分配给变量Str而不是仅8个字节.
更新**我意识到这部分CPort库包含以下代码.任何人都可以启发我如何编辑代码?或者它是否是我采购的正确块.谢谢!
// split buffer in packets procedure TComDataPacket.HandleBuffer; procedure DiscardPacketToPos(Pos: Integer); var Str: string; begin FInPacket := True; if Pos > 1 then begin Str := Copy(Buffer,1,Pos - 1); // some discarded data Buffer := Copy(Buffer,Pos,Length(Buffer) - Pos + 1); DoDiscard(Str); end; end; procedure FormPacket(CutSize: Integer); var Str: string; begin Str := Copy(Buffer,CutSize); Buffer := Copy(Buffer,CutSize + 1,Length(Buffer) - CutSize); CheckIncludeStrings(Str); DoPacket(Str); end; procedure StartPacket; var Found: Integer; begin // check for custom start condition Found := -1; DoCustomStart(Buffer,Found); if Found > 0 then DiscardPacketToPos(Found); if Found = -1 then begin if Length(FStartString) > 0 then // start string valid begin Found := Pos(Upper(FStartString),Upper(Buffer)); if Found > 0 then DiscardPacketToPos(Found); end else FInPacket := True; end; end; procedure EndPacket; var Found,CutSize,Len: Integer; begin // check for custom stop condition Found := -1; DoCustomStop(Buffer,Found); if Found > 0 then begin // custom stop condition detected CutSize := Found; FInPacket := False; end else if Found = -1 then begin Len := Length(Buffer); if (FSize > 0) and (Len >= FSize) then begin // size stop condition detected FInPacket := False; CutSize := FSize; end else begin Len := Length(FStartString); Found := Pos(Upper(FStopString),Upper(Copy(Buffer,Len + 1,Length(Buffer) - Len))); if Found > 0 then begin // stop string stop condition detected CutSize := Found + Length(FStopString) + Len - 1; FInPacket := False; end; end; end; if not FInPacket then FormPacket(CutSize); // create packet end;
解决方法
完整错误检查的简约解决方案是:
更新:
(假设接收到的字符串以CRLF组合结束,并且数据包长度不是常量.这是NMEA 0183数据包)
var finalBuf: AnsiString; // Example packet: $HEHDT,10.17,T*28 + CRLF // This is a NMEA 0183 protocol (Marine and GPS standard) // Subset for reading the heading. // HDT Heading – True // 1 2 3 // | | | //$--HDT,x.x,T*hh //1) Heading Degrees,true //2) T = True //3) Checksum // HE stands for: Heading – North Seeking Gyro {- Checking packet and checksum,calculating heading } Function ParseAndCheckNMEA_HDT(const parseS: AnsiString; var heading: Double): Integer; // Example packet: $HEHDT,T*28 + CRLF var i,p,err: Integer; xorSum: Byte; xorStr: AnsiString; headingStr: AnsiString; begin Result := 0; // Assume ok if (Pos('$HEHDT',parseS) = 1) then // Start header ok ? begin p := Pos('*',parseS); if (p <> 0) and (Length(parseS) >= p + 2) then // Assumes a checksum in packet begin xorSum := Ord(parseS[2]); for i := 3 to p - 1 do // Calculate checksum xorSum := xorSum xor Ord(parseS[i]); xorStr := IntToHex(xorSum,2); if (UpperCase(xorStr) = Copy(parseS,p + 1,2)) then // Checksum ok ? begin // Validate heading headingStr := Copy(parseS,8,p - 10); Val(headingStr,heading,err); if (err <> 0) then Result := 4; // Not a valid float end else Result := 3; // Wrong checksum end else Result := 2; // No checksum end else Result := 1; // Wrong header end; procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer); var i,err: Integer; strBuf: AnsiString; heading: Double; begin ComPort.ReadStr(CPort.Str,Count); strBuf := CPort.str; for i := 1 to Length(strBuf) do case strBuf[i] of '$' : finalBuf := '$'; // Start of package #10 : begin if (finalBuf <> '') and (finalBuf[1] = '$') then // Simple validate check begin SetLength( finalBuf,Length(finalBuf) - 1); // Strips CR err := ParseAndCheckNMEA_HDT(finalBuf,heading); if (err = 0) then Memo.Lines.Add(finalBuf); // Add validated string //else // Memo.Lines.Add('Error:' + IntToStr(err)); end; finalBuf := ''; end; else finalBuf := finalBuf + strBuf[i]; end; end;
知道开始字符和数据包结束,这应该是相当安全的使用.
标记包结束的#13和#10(CR LF)字符被剥离,并检查包的有效校验和,并计算得到的标题值.
然后将经过验证的字符串添加到备忘录中.
更新2
要回答直接问题,为什么接收方法可以在数据字符串的中间添加“haha”字符串:
comport例程按照自己的节奏传递一个或多个字符的数据.您无法控制何时获取数据或将有多少个字符.在我的回答中使用该方案,数据被缓冲,直到交付完整的包.通过TComPort的数据包支持,可以执行相同的操作.
从您的评论看,似乎有几个NMEA 0183传感器类型连接到串行端口. (给出其他长度的包,但都以$字符开头).
用以下函数替换ParseAndCheckNMEA_HDT以在这种情况下验证字符串:
Function ParseAndCheckNMEA(const parseS: AnsiString): Integer; // Example packet: $HEHDT,p: Integer; xorSum: Byte; xorStr: AnsiString; begin Result := 0; // Assume ok if (Pos('$',2); if (UpperCase(xorStr) <> Copy(parseS,2)) then // Checksum ok ? Result := 3; // Wrong checksum end else Result := 2; // No checksum end else Result := 1; // Wrong header end;