2

stackoverflow に関するこの非常に興味深いトピックを読んだ後 -->ループでさらにデータを送信する前に COM ポートの受信イベントを待機する方法

私は多くの問題に遭遇し、多くの解決策を試しました...残念ながらうまくいきません!

多くのシリアル ポート ライブラリはイベント ドリブンであり、それらを理解するのに苦労しています。

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);

送信はうまく機能していますが、文字列には何も返されません。

何かアドバイスはありますか?

どうもありがとうございました!

よろしく、ローラン

4

3 に答える 3

1

nrComm Lib (v9.31) に切り替えました...非常に使いやすく、十分にサポートされています。

唯一の欠点は、無料でオープン ソースではないことですが、それだけの価値はあります。

また、スレッドセーフでもあります:)。

返信ありがとうございます!

于 2012-12-15T15:30:42.150 に答える
1

私は 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;
于 2012-12-14T08:40:19.893 に答える
0

メインスレッドから非同期I/Oを実行しようとしています。これはGUIではうまく機能しません。

複雑な非同期I/Oを実行することは、別のスレッドに適しています。ブロッキングシリアル通信パッケージ(Synaserにもブロッキングモードがあると思います)と次のような機能があります。

function TransmitReceive(const msg: AnsiString; var reply: AnsiString; 
  timeOut: Integer): Boolean;

複雑なコードロジックをa内にthread.execute配置し、イベント信号でロジックの開始をトリガーします。

PostMessageたとえば、呼び出しを介して結果などをメインスレッドに伝達します。

于 2012-12-13T22:45:55.760 に答える