RS485를 통해 작성된 메시지의 두 문자 사이의 간격

RS485를 통해 작성된 메시지의 두 문자 사이의 간격

저는 ATMEL 임베디드 컨트롤러(at91sam9x25e)와 해당 직렬 포트를 사용하여 RS485 Modbus RTU를 통해 전송/수신하고 있습니다. 일반적인 통신은 잘 작동하지만 때로는 (쓰기 시) 일부 패킷이 약 3.5ms의 지연으로 메시지의 두 문자 사이에 분할되어 새 메시지로 감지됩니다.

설정:

  • 모노 3.2.8
  • Modbus RTU 19.2kBaud
  • RS485
  • 자동RTS

전체 패키지를 즉시 보냅니다.

try  
{
  Thread.Sleep(_timePreSend);
  _serialPort.Write(buffer, offset, count);
} catch(Exception err)
{
   log.Error(err.Message);
} finally
{
   Thread.Sleep(2);
}

버퍼(UART 또는 FIFO)의 마지막 비트를 전송하기 위해 RTS를 수동으로 활성화/비활성화하기 전에 2밀리초를 사용했습니다.

오실로스코프에서 캡처:

120318000100020032000403200000001C000500000000000000003D <- 갭-> B6

Modbus 메시지

stty의 출력:

stty -F /dev/ttyS4 -a
speed 19200 baud; rows 0; columns 0; line = 0;    
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl    -ixon  -ixoff
-iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
 echoctl echoke

이 격차의 이유는 무엇입니까? 그것을 방지하려면 어떻게 해야 합니까?

답변1

원인이 무엇인지 정확히 말하기는 어렵습니다. 불행하게도 Linux 직렬 포트는 타이밍 보장을 제공하지 않으며 일반 UART 프로토콜에는 그렇게 엄격한 타이밍 요구 사항이 있어서는 안 됩니다. 프로토콜에 이런 종류의 타이밍 보장이 필요한 경우 커널 드라이버를 자세히 살펴보고, 공백 없이 모든 바이트의 원자적 전송을 보장하기 위해 자체 드라이버를 작성해야 할 수도 있고, UART 버퍼가 항상 적시인지 확인하기 위해 인터럽트를 사용할 수도 있습니다. 보충. 커널의 도움 없이는 사용자 공간에서 이러한 보장을 할 수 없습니다.

즉, 분할의 원인을 파악하고 수정하고 실제로 목적에 맞게 충분히 신뢰할 수 있는지 경험적으로 판단할 수 있습니다. 지연은 항상 마지막 바이트 이전입니까? 그렇다면 스택의 무언가가 여러 바이트를 하드웨어에 동시에 전달하고 짧은 시간 초과 후에 단일 바이트만 전달하여 처리량을 최적화하기 위해 어떤 이유로 문자를 버퍼링하는 것처럼 들립니다. 먼저 사용자 공간 애플리케이션이 제대로 실행되고 있는지 확인해야 합니다. 이를 실행하여 시스템 호출을 확인하고 strace단일 시스템 호출에서 패킷이 커널에 기록되는지 확인하세요. write그렇다면 UART 드라이버의 커널 소스 코드를 읽고 이상한 버퍼링이 포함되어 있는지 확인해야 합니다.

또 다른 가능성은 커널 드라이버가 단지 커널 스레드(또는 프로세스 컨텍스트에서 직접)에서 데이터를 처리하고 있으며, 여러분이 보고 있는 공백은 예약 중인 다른 프로세스라는 것입니다. 그렇다면 이 문제를 해결하는 유일한 방법은 다른 프로세스가 우선권을 갖도록 허용하지 않고(예: 인터럽트 컨텍스트에서 모든 작업을 수행) 엄격하게 실시간 방식으로 전송을 처리하도록 커널 드라이버를 수정하거나 자체 드라이버를 작성하는 것입니다.

답변2

나는 마침내 이 행동의 문제점이 무엇인지 알아냈습니다. 통신 루프에서 일부 바쁜 대기를 사용하고 있었는데, 이로 인해 CPU에 과도한 부하가 발생했습니다. 그런 다음 다음과 같은 SerialPort 명령을 사용하여 읽었습니다.BytesToRead 및 읽기전혀 이상적이지 않음: .NET System.IO.Port.Serialport를 사용해야 하는 경우

그래서 ByteStream의 비동기 기능을 사용해 보았습니다.ReadAsync 및 WriteAsync내 새로운 질문에 명시된 바와 같이직렬 포트 및 ReadAsync 시간 초과를 사용하는 올바른 방법그리고 CPU 사용량도 훨씬 적고 더 이상 공백이 없습니다.

관련 정보