2

我仍然对 TComPort 组件有问题,但这次不是组件本身,而是它背后的逻辑。我有一个设备女巫通过串行端口发送一些 ascii 字符串我需要 prase 这些字符串问题是计算机反应非常快,所以在事件 char 它只捕获字符串的一部分,其余的字符串稍后会回来......所以当它被接收时解析它是不可能的。

我正在考虑编写一个计时器来验证是否在 10 秒或更长时间内没有串行活动,然后将我保存到缓冲区中的字符串 prase。但是这种方法是不专业的,不是有一个空闲的事件女巫我可以听...等待我的问题的最佳解决方案。谢谢。

4

5 回答 5

4

在使用了许多串行端口组件之后,到目前为止,我已经获得了最好的结果,通过使用CreateFile('\\?\COM1',GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0),将该句柄传递给一个 THandleStream 实例,并启动一个专用线程来读取它。我知道线程比编写事件处理程序需要更多的工作,但它仍然是处理使用串行端口引起的任何同步问题的最佳方法。

于 2012-05-11T15:28:02.613 回答
3

OnRXChar 事件的典型处理程序:

procedure XXX.RXChar(Sender: TObject; Count: Integer);
begin
  ComPort.ReadStr(s, Count);
  Accumulator := Accumulator + s;
  if not AccumContainsPacketStart then
    Accumulator := ''
  else if AccumContainsPacketEndAfterStart then begin
    ExtractFullStringFromAccum;
    ParseIt;
  end;
end;
于 2012-05-11T14:09:27.023 回答
2

笔记。 大多数通信端口组件都不知道何时向所有者报告。通常,负责从端口收集字节的线程会被操作系统通知一个或多个字节已准备好进行处理。然后,此信息会简单地弹出到您的级别。因此,当您期望消息被传输时,您会得到操作系统给您的信息。

您必须在全局缓冲区中缓冲所有传入的字符。当您获得消息字符串中的最后一个字符时,处理该消息。

下面是一个示例,其中消息开头用特殊字符标识,消息结尾用另一个字符标识。

如果您的消息是以另一种方式构建的,我相信您可以弄清楚如何调整代码。

var
  finalBuf: AnsiString;

{- Checking message }
Function ParseAndCheckMessage(const parseS: AnsiString) : Integer;
begin
  Result := 0; // Assume ok
  {- Make tests to confirm a valid message }
  ...
end;


procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer);
var
  i,err: Integer;
  strBuf: AnsiString;
begin
  ComPort.ReadStr(strBuf, Count);
  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 := ParseAndCheckMessage(finalBuf);
              if (err = 0) then 
                {- Handle validated string }
              else
                {- Handle error } 
            end;
          finalBuf := '';
        end; 
    else
      finalBuf := finalBuf + strBuf[i];  
    end;
end;
于 2012-05-11T14:09:53.310 回答
1

如果您的协议有开始/结束标记,您可以使用 TComDataPacket 为您提供完整的数据包(当它们可用时)。

于 2012-05-11T20:06:09.240 回答
-2

对于一定数量的字符,我们可以在 ReadStr 之前使用延迟几毫秒来确保数据完全发送。4个字符的示例:

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
  Str: String;
  tegangan : real;
begin
  sleep(100); //delay for 100ms
  ComPort1.ReadStr(Str, 4);

...

于 2014-08-22T06:57:14.203 回答