Delphi中的串口同步
我仍然对TComPort组件存在问题,但这次不是因为组件本身,而是因为它背后的逻辑。我有一个设备,它通过串口发送一些ascii字符串,我需要使用这些字符串问题是计算机反应非常快,所以在事件中,它只捕获字符串的一部分,其余的字符串稍后返回。。。因此,当它被接收时解析它就不可能了Delphi中的串口同步,delphi,serial-port,Delphi,Serial Port,我仍然对TComPort组件存在问题,但这次不是因为组件本身,而是因为它背后的逻辑。我有一个设备,它通过串口发送一些ascii字符串,我需要使用这些字符串问题是计算机反应非常快,所以在事件中,它只捕获字符串的一部分,其余的字符串稍后返回。。。因此,当它被接收时解析它就不可能了 我在想写一个计时器,验证10秒或更长时间内是否没有串行活动,然后将保存的字符串放入缓冲区。但是,这种方法是不专业的,难道没有一个空闲的事件,我可以听…等待我的问题的最佳解决方案。谢谢。OnRXChar事件的典型处理程序:
我在想写一个计时器,验证10秒或更长时间内是否没有串行活动,然后将保存的字符串放入缓冲区。但是,这种方法是不专业的,难道没有一个空闲的事件,我可以听…等待我的问题的最佳解决方案。谢谢。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;
注意。
大多数com端口组件不知道何时向所有者报告。通常,操作系统会通知负责从端口收集字节的线程一个或多个字节已准备好进行处理。然后,这些信息就会弹出到您的级别。因此,当您期望消息被传输时,您将得到操作系统所提供的信息
必须在全局缓冲区中缓冲所有传入字符。当您获得消息字符串中的最后一个字符时,处理消息
下面是一个示例,其中消息的开头用一个特殊字符标识,而消息的结尾用另一个字符标识
如果您的消息是以另一种方式构造的,我相信您可以找到如何修改代码的方法
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;
var
最终用途:翻译;
{正在检查消息}
函数ParseAndCheckMessage(const-parseS:AnsiString):整数;
开始
结果:=0;//假设可以
{-进行测试以确认有效消息}
...
结束;
过程tmaninform.ComPortRxChar(发送方:TObject;计数:整数);
变量
i、 err:整数;
strBuf:AnsiString;
开始
组件ReadStr(strBuf,Count);
对于i:=1到长度(strBuf)do
strBuf[i]案
'$' :
finalBuf:=“$”;//包装开始
#10 :
开始
如果(finalBuf“”)和(finalBuf[1]=“$”),则//简单验证检查
开始
设置长度(finalBuf,长度(finalBuf)-1);//条状铬
错误:=ParseAndCheckMessage(finalBuf);
如果(err=0),则
{Handle-validated string}
其他的
{Handle error}
结束;
finalBuf:='';
结束;
其他的
finalBuf:=finalBuf+strBuf[i];
结束;
结束;
在使用了大量串行端口组件之后,我得到了迄今为止最好的结果,方法是使用CreateFile('\?\COM1',GENERIC\u READ或GENERIC\u WRITE,0,nil,OPEN\u EXISTING,FILE\u ATTRIBUTE\u NORMAL,0)
,将该句柄传递给一个THandleStream实例,并启动一个专用线程从中读取。我知道线程比编写事件处理程序要花费更多的工作,但它仍然是处理因使用串行端口而产生的任何同步问题的最佳方法。如果您的协议有开始/结束标记,您可以使用TComDataPacket来提供完整的数据包,当它们可用时。对于一定数量的字符,我们可以在ReadStr之前使用延迟数毫秒来确保数据完全发送。4个字符数量的示例:
procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
Str: String;
tegangan : real;
begin
sleep(100); //delay for 100ms
ComPort1.ReadStr(Str, 4);
这是一个众所周知的问题。在更多的环境中使用它。数据事件触发器确实比后面的数据更快。我不确定除了阅读前的一小段等待之外还有什么。这很正常,你应该简单地将字符存储在缓冲区中,然后重置计时器。然后使用计时器来触发实际活动-计时器可能会很紧。您希望最终得到一个“状态机”并具有事件触发器。假设您使用Djean Crnila等人的TComport(有几个组件称为“TComport”)。此问题可能与数据事件触发器有关,但也可能是串行设备的波特率设置为与comport控件的速率不同的速率。如果您的设备每隔几毫秒发送一次数据包,那么如果数据包的长度合理,您应该能够轻松捕获和解析整个数据包。设备是否发送数据包结束控制字符-使它更容易。如果您提供有关设备、收到的数据包等的更多信息,可能有人能够提供帮助。编写数据包组件并不难。事件中的所有数据都进入缓冲区,数据包分析缓冲区,根据您的需要,您可以有一个startcondition、endcondition等…字符串包含诸如#0之类的字符,因此readstr方法的使用是防御性的。这对于pascal字符串并不重要(直到OS函数输出)@opc0de,在pascal中#0字符与任何其他字符一样。如果您喜欢使用字节,请将ansichar/ansistring交换为bytes/TBytes。这是自D2009和unicode以来的首选方式。请参见示例,但正如MBo所说,
TComPort.Read(var buffer;Count:Integer)
和TComPort.ReadStr(var Str:AnsiStr;Count:Integer)之间没有根本区别
。当我在Delphi 7中使用TComDataPacket时,我收到了一个访问冲突。并非所有时间都是这样,但当数据包较大时,我看到Warren在你的另一个问题中反对它。不过,我们刚刚在DelphiXe2中成功地使用了它,它似乎定义了一个大小为1024字节的固定缓冲区。尝试在构造函数中增加它,看看这是否有助于处理更大的数据包。