在 stackoverflow 上阅读了这个非常有趣的主题后 --> How to wait for COM port receive event before sending more data in a loop
我遇到了很多问题,并且尝试了很多解决方案......不幸的是,没有什么效果很好!
许多串行端口库都是事件驱动的,我很难理解它们。
我尝试过 Asyncpro、Synaser 和 TComport。
是否可以有这样的功能:
SerialSendandReply(tx string here,timeout) 返回 rx 字符串,如果超时则发送错误字符串
设备的响应都在几毫秒内,采用阻塞方式会更好吗?
像这样:
Dosomething here
showmessage(SerialSendandReply('test',100 )); //100 ms timeout
dosomething else
使用此代码
TForm1 = class(TForm)
...
private
IOEvent : THandle; // used for IO events
IORx : string;
Comport : TapdComport;
...
procedure TForm1.ComportTriggerAvail(CP: TObject; Count: Word);
var i : integer;
begin
for i:=1 to Count do
IORx:=IORx+Comport.GetChar;
SetEvent(IOEvent);
end;
function TForm1.SerialSAWR(tx : string; TimeOut : integer) : boolean;
begin
Result := False;
try
IORx := ''; // your global var
ResetEvent(IOEvent);
Comport.PutString(tx);
Result := WaitForSingleObject(IOEvent, TimeOut) = WAIT_OBJECT_0;
except
on E : Exception do
// dosomething with exception
end;
end;
// constructor part
IOEvent := CreateEvent(nil, True, False, nil);
// destructor part
if IOEvent <> 0 then
CloseHandle(IOEvent);
然后我尝试调用这个函数:
if SerialSAWR('test'; 5000) then showmessage(IORx);
发送工作正常,但不会返回字符串中的任何内容。
有什么建议吗?
非常感谢!
问候, 洛朗
最佳答案
我使用 TComPort 并创建了以下例程来执行您所要求的操作。 TComPort 监视其监视线程中接收到的字符,并且我的例程等待字符而不调用 Application.ProcessMessages。它可能不是最优雅的代码,但它工作得很好。
function TArtTComPort.SerialPort_AwaitChars(AMinLength: integer;
ATerminator: char; AQtyAfterTerm: integer; ARaise: boolean): string;
var
fDueBy : TDateTime;
function IsEndOfReplyOrTimeout( var AStr : string ) : boolean;
var
I : integer;
begin
Result := False;
If ATerminator <> #0 then
begin
I := Length( AStr ) - AQtyAfterTerm;
If I > 0 then
Result := AStr[I] = ATerminator;
end;
If not Result then
Result := Length(AStr) >= AMinLength;
// Un-comment this next line to disable the timeout.
//Exit;
If not Result then
begin
Result := Now > fDueBy;
If Result then
If ARaise then
raise EArtTComPort.Create( 'Serial port reply timeout' )
else
AStr := '';
end;
end;
var
Events : TComEvents;
iCount : integer;
S : string;
begin
Assert( AMinLength > 0, 'Invalid minimum length' );
If not FComPort.Connected then
begin
Result := '';
Exit;
end;
fDueBy := Now + (FTimeoutMS * TDMSec );
Result := '';
Repeat
// Setup events to wait for:
Events := [evRxChar, evTxEmpty, evRxFlag, evRing, evBreak,
evCTS, evDSR, evError, evRLSD, evRx80Full];
// Wait until at least one event happens.
FComPort.WaitForEvent(
Events,
FStopEvent.Handle,
FTimeOutMS);
If Events = [] then // timeout
begin
If ARaise then
raise EArtTComPort.Create( 'Serial port reply timeout' )
end
else
begin
If evRxChar in Events then
begin
iCount := FComport.InputCount;
FComPort.ReadStr( S, iCount );
Result := Result + S;
end;
end;
until IsEndOfReplyOrTimeout( Result );
end;
关于multithreading - 如何发送字符串(串口),等待(超时)并捕获回复字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13868851/