Wave Sensor 시리얼 통신 데이터 출력 오류 관련

안녕하세요, C# 독학 중인 개발자입니다.

Serial 통신을 활용하여 데이터 수신 프로그램을 개발하고 있는데 막히는 부분이 있어 질문 올립니다.

우선 제가 가진 센서는 Wave Sensor로 Serial 통신을 활용하여 188개의 데이터를 수신합니다.

저는 우선 WinForms에서 Serial 통신 데이터를 전부 읽은 후, Array.Copy 함수를 통하여 원하는 데이터 위치에 index를 잡고 복사하여 TextBox로 출력하는 프로그램을 작성했습니다.

그런데 어떤 연유에선지 데이터가 안정적으로 출력 되지 않고, 앞 배열 혹은 뒤 배열의 데이터가 번갈아 출력 되는 현상이 있습니다.

이를 어떻게 해결해야 할지, 관련하여 조언을 부탁드립니다.
아래 코드 일부 공유드리니 참고해 주세요!

private void MySerialReceived(object s, EventArgs e)  
{
   if (serialPort1.IsOpen)
   {
       int bytes = 188;
       byte[] recv = new byte[bytes];
       serialPort1.Read(recv, 0, bytes);                

       byte[] GPSWSTime = new byte[4];
       byte[] UTCHour = new byte[1];
       byte[] UTCMinutes = new byte[1];
       byte[] UTCSeconds = new byte[1];
       byte[] UTCDecimalSeconds = new byte[2];

       Array.Copy(recv, 21, GPSWSTime, 0, 4);
       Array.Copy(recv, 25, UTCHour, 0, 1);
       Array.Copy(recv, 26, UTCMinutes, 0, 1);
       Array.Copy(recv, 27, UTCSeconds, 0, 1);
       Array.Copy(recv, 28, UTCDecimalSeconds, 0, 2);

       string GPSWSTime1 = GPSWSTime[3].ToString() 
           + GPSWSTime[2].ToString() 
           + GPSWSTime[1].ToString() 
           + GPSWSTime[0].ToString();
       textBox2.Text = GPSWSTime1.ToString();

       string UTCHour1 = UTCHour[0].ToString();
       textBox3.Text = UTCHour1.ToString();

       string UTCMinutes1 = UTCMinutes[0].ToString();
       textBox4.Text = UTCMinutes1.ToString();

       string UTCSeconds1 = UTCSeconds[0].ToString();
       textBox5.Text = UTCSeconds1.ToString();

       string UTCDecimalSeconds1 = UTCDecimalSeconds[1].ToString() 
           + UTCDecimalSeconds[0].ToString();
       textBox6.Text = UTCDecimalSeconds1.ToString();             
   }
}
2개의 좋아요

Stackoverflow를 살펴보니 시리얼 포트 관련해서는 정확한 설정을 넣어주는 것이 좋다는 답변이 있네요. 지금 연결하시는 장치의 속성과 일치하는 구성 (송수신 버퍼크기, Baud Rate, Paritiy Bit 사용 여부, Stop Bit 사용 여부 등)을 대입해보셔야 할 것 같습니다.

그리고 GUI 애플리케이션에서 이벤트 핸들러 안에서 IO 작업을 하거나 실행 시간이 오래 걸릴 수 있는 작업을 하는 것은 안티패턴입니다. 이 때문에 애플리케이션에 hang이 걸려서 응답 없음 상태로 빠지기 쉽고, 혹은 비 UI 스레드에서 UI를 제어하려고 하다가 역시 문제가 발생할 수 있어서 그런데, 잘 고민해보시고 별도 스레드로 리팩토링하시는 것도 추천드립니다.

4개의 좋아요

먼저 정현님이 말씀하신 것 처럼 별도의 스레드에서 수집 활동을 하는것이 좋습니다. 센서 정보이므로 실시간 성이 있는 것 같은데 별도의 스레드에서 수집된 정보를 큐로 저장해 두시면 좋습니다. (이때 큐당 저장하는 데이터는 시각정보도 같이 있으면 좋아요)

이와는 별개로 일반적으로 시리얼을 통해 데이터를 수신할 때 (특히 요청-수신이 아닌 수신-수신의 형태) 일반적으로 발생할 수 있는 문제는 데이터가 밀리는 경우 입니다.

질문주신 내용중에서 패킷에 대한 구체적인 정보는 없기 때문에 예단할 수는 없지만 일반적으로 STX-ETX 형태로 하나의 패킷을 규정합니다. STX를 시작 패킷으로 해서 ETX까지를 하나의 패킷으로 처리해야 하는데 중간에서 데이터를 수집할 경우 ETX까지 데이터를 무시한 뒤 STX부터 데이터를 다시 수집해야 합니다. 이렇게 처리해야 하는 이유는 시리얼통신은 데이터가 누락되거나 왜곡될 수 있기 때문입니다. 마찬가지로 CRC체크나 체크섬 처리를 반드시 해야 하는데 그래서 일반적으로 패킷 중 CRC또는 체크섬 정보가 있습니다. (아마 체크섬일 가능성이 큽니다) 그래서 체크섬도 마찬가지로 계산해줘서 동일하지 않으면 패킷을 버려야합니다.

센서 패킷 정보를 확인하셔서 STX, ETX를 확인하시고 체크섬 정보도 확인하셔서 관련 처리를 반드시 해줘야 합니다.

4개의 좋아요
  1. 설정값 확인
    SerialPort sp = new SerialPort();
    sp.PortName = “COM6”;
    sp.BaudRate = 9600;
    sp.DataBits = 8;
    sp.Parity = Parity.None;
    sp.StopBits = StopBits.One;

BaudRate를 특히 한번 더 확인해보시면 좋을거같습니다.

  1. 함수 사용 변경
    시리얼포트에서 Read함수뿐만아니라
    ReadLine, ReadExisting으로 읽어올수도 있을거같습니다. (저는 ReadExisting을 사용했던 기억이…)
    해당 내용 읽어온 후 데이터 길이나 시작,종료 (STX, ETX)를 확인해보셔도 좋을거같습니다.

위에 답글주신분의 내용을 한번 더 쓴거같네요.

확인해보시고 안되거나 문제있으면 또 답글주십시요!

3개의 좋아요

지금껏 눈팅만 하다가 몇자 적어 봅니다.
아마도 수신 이벤트를 이용하여 데이터를 받으시는 것 같습니다.
시리얼 포트 수신 이벤트는 수신 버퍼에 데이터가 수신되면 이벤트가 발생합니다.
보여주신 코드에서는 dimohy님 말씀 처럼 데이터의 선두(header)를 확인 하는 부분 없이
무조건 정해진 수의 바이트를 읽고 있습니다.
그렇기때문에 발행하는 문제인 것 같습니다.

데이터의 헤드는 정해진 것이 없고, 제조사에 따라 다양합니다.
STX, ETX 일 수도 있고, 아닐 수도 있습니다.

코드로 보면 데이터가 바이너리 형태 인 것 같은데, 이를 경우에는 선두에 데이터 길이가 올 수도 있습니다.
제조사의 통신 관련 문서를 잘 확인 해보셔야 할 것 같습니다.

5개의 좋아요

아 갑자기 생각난건데
야매 방법이지만 Read()하기 전에 Thread.Sleep(1000) 정도 줘서 받았던 경우도 있었습니다.
바로 받으면 데이터가 덜들어와서 누락이 된다나 어쩐다나;;;

혹 이 방법이 비논리적이면 정정하도록 하겠습니다

2개의 좋아요