2013-09-26 2 views
1

저는 C#에서 데이터 로깅 응용 프로그램을 만들었습니다. SerialPort 클래스가있는 4 개의 USB 센서에 연결됩니다. 모든 바이트에서 데이터 수신 이벤트 임계 값을 트리거했습니다. 데이터가 수신되면 프로그램은 해당 바이트가 라인의 끝인지 여부를 확인합니다. 그렇지 않은 경우 입력이 버퍼에 추가됩니다. 행 끝인 경우 프로그램은 시간 소인을 추가하고 데이터와 시간 소인을 파일에 씁니다 (각 입력 소스는 전용 파일을 가져옵니다).복수의 SerialPort가 실시간으로 반환됩니다.

하나 이상의 COM 포트 입력을 사용할 때 문제가 발생합니다. 내가 출력 파일에서 볼 것은 :

4 파일의 모든 :

... 
timestamp1 value1 
timestamp2 value2 
timestamp3 value3 
value4 
value5 
value6 
timestamp7 value7 
... 

그래서, 그것이 무엇처럼 보이는 것은 컴퓨터가 다음 값 전에 4 개 인터럽트에 도착하는 빠른 것만으로는 충분하지 않습니다이다 태어나다.

... 
timestamp value 
timestamp value 
value 
val 
timestamp ue 
timestamp value 
... 

그것은 수 있습니다 때문에 난 단지 코어 2. 내가 한 실행하는 프로세서 선호도를 변경한다는 사실에 : 나는 가끔이 같은 출력을 볼 수 있기 때문에이 범인이라고 생각하는 이유가 이것은 내가 사용하고있는 타임 스탬프가 프로세서 사이클 수로 계산되기 때문에 어떤 코어가 실행 중인지에 따라 여러 시간 참조를 가질 수 없습니다. 아래에 코드 스 니펫 중 일부를 넣었습니다. 누락 된 타임 스탬프를 도울 수있는 제안 사항은 크게 감사하겠습니다!

public mainLoggerIO() 
    { 
     //bind to one cpu 
     Process proc = Process.GetCurrentProcess(); 
     long AffinityMask = (long)proc.ProcessorAffinity; 
     AffinityMask &= 0x0002; //use only the 2nd processor 
     proc.ProcessorAffinity = (IntPtr)AffinityMask; 

     //prevent any other threads from using core 2 
     Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; 
     Thread.CurrentThread.Priority = ThreadPriority.Highest; 

     long frequency = Stopwatch.Frequency; 
     Console.WriteLine(" Timer frequency in ticks per second = {0}", 
      frequency); 
     long nanosecPerTick = (1000L * 1000L * 1000L)/frequency; 
     Console.WriteLine(" Timer is accurate within {0} nanoseconds", 
      nanosecPerTick); 

     if (Stopwatch.IsHighResolution) 
      MessageBox.Show("High Resolution Timer Available"); 
     else 
      MessageBox.Show("No High Resolution Timer Available on this Machine"); 

     InitializeComponent(); 
    } 

등등. 임)

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 
    { 
     //serialPort1.DataReceived = serialPort1_DataReceived; 
     rawPort1Data = ""; 
     rawPort1Data = serialPort1.ReadExisting(); 
     this.Invoke((MethodInvoker)delegate { returnTextPort1(); }); 
    } 

메소드 returnTextPort 번호 (: 각 데이터 귀환 인터럽트는 다음과 같다

private void returnTextPort1() 
    { 
     if (string.Compare(saveFileName, "") == 0)//no savefile specified 
      return; 
     bufferedString += rawPort1Data; 
     if(bufferedString.Contains('\r')){ 
      long timeStamp = DateTime.Now.Ticks; 
      textBox2.AppendText(nicknames[0] + " " + timeStamp/10000 + ", " + rawPort1Data); 
      //write to file 
      using (System.IO.StreamWriter file = new System.IO.StreamWriter(@saveFileName, true)) 
      { 
       file.WriteLine(nicknames[0] + " " + timeStamp/10000 + ", " + rawPort1Data);//in Ms 
      } 
      bufferedString = ""; 
     } 

    } 
+0

사용중인 용어에주의하십시오. 프로그래밍에서 COM은 직렬 포트와 완전히 다른 것입니다. –

+0

사실입니다. 직렬 통신을 의미하므로 COM을 의미했습니다. –

+0

저는 Ghz 범위에서 작동하는 직렬 포트를 아직 보지 못했습니다. 그래서 PC가 입력보다 느릴지 의심 스럽습니다.모든 이벤트가 동일한 스레드 (주 스레드)에서 트리거되어 데이터 블리딩으로 나타날 수있는 식별 가능한 이벤트가 발생할 가능성이 큽니다. 다른 스레드 또는 자식 프로세스로 처리 부하를 줄이면 COM 활동을 분리 할 수 ​​있습니까? –

답변

1

청소기 방법은 수신 된 데이터 이벤트 핸들러와 별도의 스레드 사이 ConcurrentQueue<T>를 사용하는 것이라고 결과 데이터를 처리합니다. 그렇게하면 이벤트 핸들러는 즉시 스레드 안전 모드로 rawPort1 데이터를 수정하는 대신 리턴하여 스레드 안전 솔루션으로 이동할 수 있습니다.

동시 대기열에서 읽고 파일에 쓰고 UI 변경 사항을 호출하는 스레드를 만듭니다. 파일 쓰기는 UI 스레드에 있어서는 안됩니다.

ConcurrentQueue<T>T 클래스에서 포트 번호, 수신 된 데이터 및 수신 된 타임 스탬프를 캡처 할 수 있습니다.

대부분의 위치에서 DateTime.Now은 거의 올바른 대답이 아니며, 일광 절약 시간이 시작되거나 끝날 때마다 1 시간에 두 번 점프합니다 (DateTime.UtcNow 대신). 그러나 두 코드 모두 StopWatch 코드로 얻으려는 정확성을 가지고 있지 않습니다.

직렬 포트에 버퍼가있는 프로세스 나 스레드 우선 순위를 조작 할 필요가 없습니다. 효율적으로 처리하는 데이터는 놓치지 마십시오.

+0

+1 좋은 답변이지만 OP의 "실시간"의미 및 그가 다루는 데이터의 양에 따라 적용 할 수 있습니다. –

+0

제안 해 주셔서 감사합니다. 나는 그것을 시도 할 것이다. 타임 스탬프의 경우 사용하기 가장 좋은 것에 대한 온라인 답변을 찾을 수 없었습니다. 나는 첫 수신 스탬프와 관련하여 최대한 정확한 타이밍을 얻으려고 노력하고 있습니다. 이 일에 가장 적합한 것이 무엇인지, 그리고 얼마나 좋은지 알 수 있습니까? –

+0

네 개의 소스는 각각 10, 3, 3 및 6 Hz에서 데이터를 보냅니다. 로깅은 2-3 시간 동안 계속되어야합니다. –