안녕하세요. C# SerialPort 클래스를 이용해요 DataReceived 이벤트에 데이터를 읽을 때, 데이터 수신을 한 번에 못하는 경우가 있습니다. 예를 들어 MCU와 C#으로 UART 통신을 하는 경우, MCU에서 C#으로 12bytes를 보냅니다. 그러면 DataReceived에서 12bytes를 한 번에 수신하는 경우가 있고, 여러번에 나눠서 수신하는 경우가 있습니다.
이러한 이유는 RX에 신호가들어오면 Receive 이벤트가 발생합니다. 이벤트가 발생하고 처리를할때 수신버퍼에 데이터가 있는만큼 처리를 합니다.(BytesToRead()가 수신버퍼에 있는 바이트수를 보는 함수입니다) 그렇기 때문에 코드는 같더라도 BaudRate에 따라서 이벤트가발생했을때 12bytes가 모두 수신되는 경우도 있고 아닌경우도 있는겁니다.
이런경우 처리할수있는 몇가지 방법이 있습니다.
첫번째) Received함수에 delay 주기
DataReceived 이벤트에 Thread.Sleep 함수를 사용하여 데이터를 수신한 경우, 약간의 딜레이를 주면 데이터가 잘리지 않고 들어오게 됩니다.
예시)
SerialPort Port;
Port.DataReceived += Port_DataReceived;
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(10); // 10ms
}
이런 식으로 Thread.Sleep을 사용하면 됩니다. 그리고 다른 예시로 MCU에서 UART 통신으로 0.1초마다 1바이트씩 데이터를 계속 보낸다고 했을 때, C# 코드에서 Thread.Sleep(1000)을 하면 Port_DataReceived 함수에서 10바이트의 데이터가 수신됩니다. 그리고 Thread.Sleep(2000)을 하면 20바이트의 데이터가 수신됩니다. Thread.Sleep 동안에 데이터 수신 버퍼에 데이터를 쌓아놨다가 읽기 때문에 한 번에 수신되는 것입니다
두번째) 수신문자열 개수가 일정할 경우 ReceivedBytesThreshold 사용하기
정해둔 Bytes가 들어오면 DataReceived 함수를 호출합니다. 기본적으로 ReceivedBytesThreshold는 1로 설정되어 있습니다. 근데 여기서 중요한게 만약 ReceivedBytesThreshold 값을 10으로해놓은 상태에서 송신 측에서 20bytes를 보낸 경우가 있다고 가정해보겠습니다. 그러면 DataReceived함수는 수신버퍼에 10bytes가 채워지면 호출되는데 이때 수신버퍼에 10bytes이상이 들어있다면 10bytes이상으로 DataReceived함수가 진행됩니다.
세번째) 수신문자열 끝을 알 수 있는 문자가 포함해있는경우
수신 문자열 끝에 알수있는 문자가 포함해있으면 몇 bytes가 들어오던 한곳에 저장만해두다가 특정문자가 들어왔을때 처리를 하면 됩니다. 예를들어 문자열 저장 => 특정문자열 들어있나 확인 => 없으면 pass => 있으면 이벤트 처리
가장 손쉽게 사용할 수 있는 방법은 첫 번째 방법입니다. 일반적으로 9600bps/stop bit 1/ 8bit 세팅으로 봤을 때 1바이트 데이터를 수신하기 위해서는 10bit 포맷입니다. (start bit + data 8bit + stop bit) 10bit 면 1.041 ms입니다. 딜레이를 100ms만 줘도 기본 딜레이+100ms 한다면 한 번에 약 100bytes 이상 수신이 가능할 것입니다. 단점은 프로그램이 멈춰있는 시간이 생긴다는 것입니다.
이 세 가지 방법 외에도 상황에 따라 여러 가지 방법이 있을 것입니다. 수신하는 데이터의 포맷과 목적에 맞게 선택하면 됩니다.
'프로그래밍 언어 > C#' 카테고리의 다른 글
C# winform에서 exe파일로 디버깅 쉽게하기 (1) | 2024.10.27 |
---|---|
C# 스레드 사용하기 (0) | 2022.04.25 |
C# 예외처리 try,catch,finally (0) | 2021.11.14 |
C# this키워드 (0) | 2021.10.23 |
C# 생성자 (0) | 2021.10.18 |