2012-05-11 7 views
1

아직 TComPort 컴포넌트에 문제가 있지만 이번에는 컴포넌트 자체가 로직이 아닙니다. 장치 마녀 직렬 포트를 통해 일부 아스키 문자열을 보냅니다 그 문자열을 prase 필요가 문제는 컴퓨터가 너무 빨리 사건의 이벤트를 문자열의 나머지 부분 만 캡처 나중에 문자열의 나머지 부분은 ... 그것이 암시 될 때 그것을 파싱하는 것은 불가능하게 만듭니다.델파이의 시리얼 포트 동기화

10 미터 이상의 연속적인 활동이 없는지 확인하고 버퍼에 저장하고있는 문자열을 초기화하십시오. 하지만이 방법은 전문가가 아닙니다. 유휴 이벤트 마녀가 아니에요. 내 문제를 해결하기 위해 최선의 해결책을 기다리고 있습니다. 감사. OnRXChar 이벤트

+2

이 알려진 문제입니다 : 예 문자의 4 한 금액을 초과 할 수 없습니다. 더 많은 환경에서 사용했습니다. 데이터 이벤트 트리거는 실제로 다음 데이터보다 빠릅니다. 독서하기 전에 잠깐 기다리는 것 외에 다른 것이 있다는 것을 확신하지 못합니다. – pritaeas

+0

이것은 매우 정상적이며, 버퍼에 문자를 저장하고 타이머를 재설정해야합니다. 그런 다음 타이머를 사용하여 실제 활동을 트리거하십시오. 타이머가 꽤 빡빡 할 수 있습니다. "상태 머신"으로 끝내고 이벤트에 대한 트리거를 원합니다. – mj2008

+0

Djean Crnila의 TComport (여러 구성 요소를 'TComport'라고 함)를 사용한다고 가정합니다. 이 문제는 데이터 이벤트 트리거와 관련이있을 수 있지만 직렬 장치의 전송 속도가 사용자의 comport 제어 속도와 다른 속도로 설정 될 수도 있습니다. 장치가 몇 밀리 초마다 패킷을 보내는 경우 패킷이 적당한 길이이면 전체 데이터 패킷을 쉽게 캡처하고 파싱 할 수 있어야합니다. 장치가 패킷 제어 문자의 끝을 보냅니 까? - 더 쉬워진다.기기에 대한 더 많은 정보를 제공하면 수신 된 패킷 등 누군가가 도움을 줄 수 있습니다. – SteveJG

답변

3

는 직렬 포트 구성 요소의 수를 사용한 후, 나는이 THandleStream 인스턴스에 처리 전달 CreateFile('\\?\COM1',GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0)을 사용하고 그것에서 읽을 수있는 전용 스레드를 시작하여, 지금까지 가장 좋은 결과를 가지고있다. 스레드가 이벤트 핸들러를 작성하는 것보다 조금 더 많은 작업을한다는 것을 알고 있지만 직렬 포트를 사용하여 발생하는 모든 동기화 문제를 처리하는 가장 좋은 방법입니다.

3

일반 핸들러 :

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; 
+0

문자열에 # 0과 같은 문자가 포함되어 있으므로 readstr 메서드 사용은 defenetly입니다 the.question – opc0de

+1

파스칼 문자열에 대해서는 중요하지 않습니다 (OS 함수에 의한 출력까지) – MBo

+0

@ opc0de, 파스칼에서 # 0 문자는 다른 문자와 같습니다. 바이트 작업을 선호하는 경우 AnsiChars/AnsiStrings를 Bytes/TBytes로 바꿉니다. 이것은 D2009 및 유니 코드 이후 선호되는 방법입니다. –

2

참고. 대부분의 컴 포트 구성 요소는 소유자에게 다시보고 할 때 단서가 없습니다. 일반적으로 포트에서 바이트를 수집하는 스레드는 OS에서 하나 이상의 바이트를 처리 할 준비가되었음을 알립니다. 이 정보는 귀하의 레벨까지 간단히 나타납니다. 따라서 메시지가 전송되기를 기대할 때 OS가 제공하는 것을 얻을 수 있습니다.

들어오는 모든 문자를 글로벌 버퍼에 버퍼링해야합니다. 메시지 문자열에서 마지막 문자를 얻으면 메시지를 처리하십시오.

다음은 메시지 시작이 특수 문자로 식별되고 메시지의 끝이 다른 문자로 식별되는 예입니다.

메시지를 다른 방법으로 작성한 경우 코드를 적용하는 방법을 알 수 있습니다.

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

프로토콜에 시작/끝 표시자가있는 경우 사용할 수있는 경우 TComDataPacket을 사용하여 전체 패킷을 제공 할 수 있습니다.

+0

Delphi 7에서 TComDataPacket을 사용할 때마다 액세스 위반이 발생하지만 항상 패킷이 큰 경우 – opc0de

+0

OK, 워렌이 다른 질문에서 반대하는 것을 보았습니다. 우리는 Delphi XE2에서 성공으로 사용했습니다. –

+0

크기가 1024 바이트 인 고정 버퍼를 정의하는 것으로 보입니다. 생성자에서 값을 늘려 더 큰 패킷을 얻는 지 확인하십시오. –

-2

문자의 양에 따라 ReadStr보다 몇 밀리 초 지연을 사용하여 데이터가 완전히 전송되도록 할 수 있습니다.

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

...