2009-10-20 7 views
2

나는 SerialPort 응용 프로그램에서 일하고 있는데 그 중 하나는 아주 간단한 부분으로 나에게 문제가되고있다. 나는 항구에서 일정한 데이터 스트림을 읽고 그것이 들어올 때 바이너리 파일에 쓰기를 원한다. 문제는 속도가 빠른 것 같다 : 나의 코드는 나의 9600 보드 테스트 장치에서 잘 작동했지만, 115200bps 라이브 장치, 나는 데이터를 잃어 가고있는 것 같습니다. 가변적 인 시간이 지나면 데이터의 나머지 부분을 버리는 1 바이트를 놓친다.SerialPort 데이터 손실 - C#

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    bwLogger.Write((byte)serialPort1.ReadByte()); 
} 

또는

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    byte[] inc = new byte[serialPort1.BytesToRead]; 
    serialPort1.Read(inc, 0, inc.Length); 

    bwLogger.Write(inc); 
} 

과 몇 가지 변화 : 나는 몇 가지를 시도했습니다. 나는 일정한 데이터 스트림으로 작업 할 때 ReadLine()을 사용할 수 없다. 버퍼 크기 (serialPort1.ReadBufferSize 및 하드웨어 FIFO 버퍼 모두)를 사용하여 보았습니다. 이상적으로는 유용성을 위해 소프트웨어 측면에서이를 처리하고 사용자가 Windows 드라이버 설정을 변경하지 못하게하는 것이 좋습니다.

아이디어가 있으십니까?

+2

이것은 통신 프로토콜에 규칙과 체크섬이있는 이유입니다. 그러한 이벤트를 감지하고 이벤트를 복구 할 수있는 유연성을 제공하는 프로토콜을 코딩해야합니다. 시간 초과를 사용하여 버퍼를 지우고 필요에 따라 다시 보낼 수 있습니다. 때때로 데이터가 손실됩니다. 기간. 이야기의 끝. 이러한 상황을 정상적으로 복구하려면 각 최종 장치를 가져와야합니다 (즉, 나머지 데이터를 버리지 않아야 함). –

+0

이것은 훌륭한 조언입니다. 내 특정 장치의 고유 한 기능으로 인해 데이터를 선형 적으로 보간하여 누락되거나 "나쁜"패킷을 채울 수 있습니다. 대부분의 통신 상황에서,이 유형의 이벤트 처리는 언급 한 것처럼 적절한 프로토콜에 대해 개발함으로써 가장 확실하게 강력 해집니다. 어떤 형태의 의사 소통으로도 일하는 사람에게 좋은 충고. – Slim

+0

사과드립니다. 다시 읽은 후 하드 리얼 타임 요구 사항을 언급하고 있으며 누락 된 데이터가 누락되었다는 것을 알게되었습니다. 다가오는 스레드에 관한 답변을 참조하십시오. 이미 답변을 수락 했더라도 조사 할 가치가있을 수 있습니다. –

답변

4

SerialPort 객체의 핸드 셰이크 속성을 사용하여 핸드 셰이 킹을 활성화 해보십시오.

발신자 또는 수신자 모두에서 설정해야합니다. 그러나 : 만약 당신이 수신기의 UART의 버퍼 (아주 작은, 16 바이트 IIRC)를 오버플로한다면, 아마 다른 방법이 없을 것입니다. 발신자 측에서 핸드 쉐이킹을 활성화 할 수없는 경우 9600 이하로 머물러 있어야합니다.

+0

올바른 아이디어로 보입니다. 나는 핸드 셰이크 설정을 엉망으로 만들었지 만 항상 소프트웨어로 제어했다. 드라이버 설정을 하드웨어 흐름 제어로 변경하면 * 짧은 테스트에서 문제가 해결 된 것으로 보입니다. 12 시간 이상의 테스트를 거쳐야하는지 확인해야합니다.이 경우에는 내가 알려주고 그 중 하나에 체크 표시를 할 것입니다. 좋은 전화와 내가 들여다 봤어야했던 것이 었습니다. – Slim

+0

희망이 있습니다. :-) – XXXXX

0

내가 최근에 작업 한 기계는 모두 내 경우 ASCII 코드 3 또는 4로 중지 코드를 보냅니다. 이 기능이있는 경우 SerialPort 객체에서 ReadTo(string)을 사용할 수 있습니다.

+0

불행히도 나는 그 사치품을 가지고 있지 않다 : \ 단순한 상수 스트림의 이진 데이터. ReadTo 메서드는 유틸리티의 다른 곳에 확실히 적용 할 수 있습니다. 머리를 가져 주셔서 감사합니다. – Slim

2

나는 다음과 같은 시도를하려는 : 설정

  • 버퍼 크기 적어도 230K 바이트
  • 설정 16K, 32K 또는 65K
  • 쓰기로 들어오는 임계 값 데이터의 고정 블록 파일

이 방법이 도움이 될지 잘 모르겠지만 적어도 자주 발생하는 프레임 워크의 압력을 받아야합니다.

+0

논리적으로 생각했지만 문제를 해결하는 데 도움이되지 않는 것 같습니다. 그럼에도 불구하고 발생하는 이벤트가 줄어들어 내 메모리 사용량을 줄여야하는 좋은 조언이됩니다. 감사. – Slim

1
  1. Read (Byte> [], Int32, Int32) 메서드가 반환하는 읽은 바이트 수를 확인하고 예상 한 값과 일치하는지 확인합니다.

  2. 포트 객체에서 SerialErrorReceivedEventHandler ErrorReceived 이벤트를 수신하고 있는지 확인하십시오. RXOver 오류는 버퍼가 꽉 찼음을 나타냅니다.

  3. 출력 버퍼의 스레드 안전성을 확인하십시오. 출력 버퍼에 대한 쓰기가 스레드로부터 안전하지 않으면 두 번째 쓰기가 첫 번째 쓰기를 손상시킬 수 있습니다.

1

bwLogger는 BinaryWriter 클래스입니까? BufferedStream과 함께 사용하여 디스크 I/O를 비 차단으로 만들 수도 있습니다.

또한 패킷에 알려진 종료 문자가있는 경우 성능 차이를 많이 줄 것이라고 생각하지 않지만 SerialPort.NewLine 속성을 설정하여 ReadLine/WriteLine을 사용할 수 있습니다.

5

데이터를 충분히 빠르게 처리 할 수 ​​없다는 문제가있는 경우 데이터를 이중 버퍼링하는 것이 좋습니다.

1) 한 스레드가 직렬 포트를 하나의 버퍼로 읽을 수있게하십시오. 이것은 데이터를 포트에서 버퍼로 복사하는 것을 포함 할 수 있습니다 (.NET에 익숙하지 않습니다).

2) 들어오는 데이터를 처리 할 준비가되면 (다른 스레드에서) 프로그램을 2 차 버퍼로 읽게되고이 상황이 발생하는 동안 디스크에 첫 번째 버퍼를 작성해야합니다.

3) 첫 번째 버퍼가 디스크에 쓰여지면 다시 직렬 포트 버퍼로 스왑하고 두 번째 버퍼를 디스크에 씁니다. 버퍼링을 계속 반복하면서 프로세스를 반복하십시오.

+1

실제로 문제를 해결하지 못했던 여러 문제를 해결 한 후에 이중 버퍼를 구현해야했습니다. 나는이 질문을 재검토하여 기쁘다. 그리고 당신이 또 다른 훌륭한 제안을 다시 전하기 위해 시간을 들여서 더욱 그렇다. 감사! 고맙게도 .NET은 표준 FileStream (자체 내부 버퍼가 있음)을 중심으로 BufferedStream을 단순히 래핑하여 모든 것을 처리했습니다. 나는 이것을 * 확신 할 수 있기 전에 몇 가지 테스트를 더 거쳤지 만,이 버퍼링 로직은 약간의 꼬임을 없애 버린 것처럼 보입니다. – Slim