ASCII에서 고급 직렬 프로토콜로 전환해야하는시기는 언제입니까?


28

UART를 통해 PC와 통신하는 모든 마이크로 컨트롤러 장치는 ASCII 문자열을 사용하여 명령을 보내고 데이터를 수신합니다 (Arduino에서 구현 됨). 그것이 내가 전자 제품을 파고 들었을 때 배운 것입니다. 나는 항상 맨 손으로 줄을 보내는 것이 충분하다는 것을 알았습니다. 그러나 필자가 접한 대부분의 장치는 기능 코드, 주소 및 CRC 오류 검사를 포함하는 정교한 이진 프로토콜을 사용하는 것으로 나타났습니다.

기본 ASCII 통신은 언제 가능하며 Modbus와 같은 고급 기능을 고려해야 할 때는 언제입니까? 상용 장치는 이러한 ASCII를 사용합니까? 산업?


3
짧은 대답 : 응용 프로그램에 필요할 때. 예, 상용 장치는 ASCII를 사용합니다. GPS NMEA를 예로 들어 보겠습니다. (그리고 다시, 나는 여기서 내 자신의 질문 을 참조 할 것이다 )
Eugene Sh.

1
Modbus에는 ASCII 모드가 있습니다. 참조 디콘 모드 버스 프로토콜 참조 설명서
혀를

@EugeneSh .: NMEA에 체크섬 필드가 있다는 점은 주목할 가치가 있으며 체크섬 실패 (생각보다 더 자주 발생)로 인해 단일 샘플 버스트를 삭제하는 것은 일반적으로 치명적인 실패가 아닙니다. 그건 아주 잘 다른 프로토콜의 경우하지 않을 수 있습니다 ... 그리고 사용 바이너리 GPS 프로토콜 (예 : 가민)의 많음은 참으로 중요 할 수있는 응용 프로그램 (또는이보다 높은 1Hz의 샘플 속도는에 대한가 NMEA가 너무 자세한 경우 필수). 이것은 실제로 당신의 요점을 확고히합니다.
Monica와의 가벼움 경주

답변:


28
  1. ASCII와 CRC는 상호 배타적이지 않습니다. ASCII는 인코딩이고 CRC는 오류 검사를위한 것입니다.

  2. 모든 것을 ASCII로 보낼 수 있습니다. 우리 노인들은 확실히 UUEncoding을 기억하여 ASCII 문자열로 변환합니다.

  3. A) 나를 위해, 그것은 일반적으로 속도와 효율성의 문제입니다. ASCII로 큰 32 비트 숫자를 보내는 데 시간이 오래 걸릴 수 있지만 직렬 프로토콜을 통해 이진수로 보내려면 4 바이트 만 걸립니다.

    B) ASCII를 통해 NUMBERS를 전송한다는 것은 숫자를 ASCII로 변환해야한다는 것을 의미합니다. 이는 분명한 추가 단계입니다 ( "printf"의 일부입니다).

  4. 당신이 어떻게 든 당신의 자리를 잃고, 조이고, 형식을 잃고, 잘못된 엔디안을 얻는다면, 바이너리 통신 프로토콜은 확실히 망칠 수 있습니다. ASCII를 전송하는 경우 데이터 스트림에서 들어가서 찾기 만하면 스크류 업에서 쉽게 복구 할 수 있습니다.


12
"ASCII는 인코딩"에 +1입니다. 프로토콜이 아닙니다. 프로토콜은 ASCII 위에 구축 될 수 있습니다.
Pete Becker

8
스크류 업으로부터 자동 복구하는 것은 본질적으로 텍스트 기반 프로토콜에서 이진 프로토콜로 쉽게 수행 할 수는 없지만 검사하고 디버깅하는 것은 매우 쉬운 일입니다.
닉 존슨

1
@NickJohnson-절대적으로. 당신은 복구 할 수 있는지 확인하기 위해 16 진수 편집기에서 파일을 여는 시점에 들어가면 SOP이가는대로, 당신은 지금까지 FUBAR 이미있어
스콧 Seidman

1
@nickjohnson 그것은 사실이 아닙니다. ASCII는 동기화 및 복구에 도움이되는 많은 대역 외 프레이밍 / 구분 기호 옵션을 제공하며, 채널이 전체 너비 이진 데이터에 사용되는 경우 추가 이스케이프, 비트 스터핑, 시간 간격 또는 기타 트릭이 필요합니다.
Chris Stratton

2
모든 명백한 이점 (가독성, 로그 가능성 등)을 위해 프로토콜을 작성할 때 항상 ASCII를 선호합니다. 바이너리가 더 의미 가있는 경우 에는 두 가지 경우 가 있습니다 . 첫째, 속도가 문제이고 가능한 많은 데이터를 스트림에 크램 핑하기 위해 바이너리가 필요하고, 둘째, 의도적으로 데이터를 난독 화하거나 암호화하려는 경우에는 한계가 있습니다. 리버스 엔지니어링을 방해하거나 방지하기 위해 스트리밍합니다. 그 시점에서 나는 이진 프로토콜을 리버스 엔지니어링했으며 실제로 실제로 그 행위를 막는 것보다 더 자극적이었습니다.
J ...

10

여기에 대한 몇 가지 생각이 있습니다.

  • 직렬 모니터를 사용하여 전송 내용을 수동으로 볼 수 있기 때문에 ASCII가 좋습니다.
  • 연결이 안정적이지 않으면 전송 오류를 예상해야하며 CRC를 사용하여 수신 된 각 메시지의 무결성을 확인해야합니다. ASCII 메시지에서도 수행 할 수 있습니다.
  • 연결 속도가 너무 느린 경우 이진 형식으로 전환하여 메시지 크기를 줄일 수 있습니다
  • 특수 바이너리 형식은 ASCII보다 수신기 측에서 디코딩하기가 더 쉽습니다.

7

가장 간단한 수준에서 간단한 통신 프로토콜에는 물리적, 전송 및 응용 프로그램의 세 가지 계층이 있다고 말할 수 있습니다. ( OSI 7 또는 TCP / IP 와 같은 모델이 더 있습니다 4의 와 있습니다.이 질문의 맥락에서 레이어 수는별로 중요하지 않습니다.)

응용 프로그램 계층은 코드에서 직접 처리하는 계층이며 질문의 초점입니다. 전송 계층과 관련하여 send_data에 전달한 바이트는 이진 패턴이지만 응용 프로그램 코드에서는 문자 'A'로 해석 할 수 있습니다. 바이트를 'A', 0x41 또는 0b01000001로 간주하는지 여부에 관계없이 CRC 또는 체크섬 계산은 동일합니다.

전송 계층은 CRC이든 기본 체크섬이든 메시지 헤더와 오류 검사가있는 패킷 수준입니다. 펌웨어와 관련하여 send_data와 같은 함수가있을 수 있습니다. 이 함수 안에 "이것은 정상적인 메시지이고, 확인이 필요하고, 체크섬은 0x47이고, 현재 시간은 X입니다." 이 패킷은 물리 계층을 통해 수신 노드로 전송됩니다.

물리적 계층은 커넥터, 전압 레벨, 타이밍 등 전자 장치 및 인터페이스가 정의되는 곳입니다.이 계층은 PCB의 기본 UART에 대한 TTL 신호를 실행하는 몇 가지 트레이스부터 일부 절연 회로와 같이 완전히 분리 된 차동 쌍에 이르기까지 다양합니다. 양철통 구현.

수신 노드에서 패킷은 물리 계층으로 들어오고 전송 계층에서 압축이 풀린 다음 응용 프로그램 계층에서 이진 패턴을 사용할 수 있습니다. 해당 패턴을 'A', 0x41 또는 0b01000001로 해석해야하는지 여부와 해당 처리 방법을 아는 것은 수신 노드 애플리케이션 계층에 달려 있습니다.

결론적으로 응용 프로그램에 필요한 ASCII 문자를 보내는 것이 항상 허용됩니다. 중요한 것은 통신 체계를 이해하고 오류 검사 메커니즘을 포함시키는 것입니다.


Ascii 프로토콜은 체크섬도 통합 할 수 있습니다. 숫자의 ASCII 표현을 사용하여 Hex-as-ascii 변형을 발견했습니다.
유진 Sh.

@EugeneSh. 그 요점을 명확하게 함
Matt Young

nitpick은 아니지만 TCP는 4 개의 계층이 아닙니다. OSI 모델의 계층 4에 맞는 것으로 보입니다. 직렬 통신은 OSI 모델에 잘 맞지 않습니다.
batsplatsterson

@batsplatsterson 그것은 nitpicking이며, 내가 만들고있는 지점과 관련이 없습니다.
매트 영

5

아직 언급되지 않은 요점은 ASCII를 사용하든 이진 프로토콜을 사용하든 각 패킷 전에 문지르 기 문자를 보내면 패킷 시작 전에 라인 노이즈 또는 프레이밍 오류가 발생하더라도 문지르 기 뒤의 모든 문자가 보장됩니다. 더 이상 노이즈가 없으면 out이 올바르게 프레임됩니다. 그렇지 않으면, 지속적으로 패킷을 전송하고 재 동기화를 보장하는 문자를 포함하지 않으면, 하나의 글리치가 다음 번 전송 일시 정지까지 후속하는 모든 것을 손상시킬 수 있습니다. 0xFF 문자는 모든 수신자가 다음 문자에서 재 동기화 할 수 있기 때문에 좋습니다.

(*) 0xFF-종이 테이프에 데이터를 입력하는 동안 잘못된 문자를 입력하는 사람이 "스텝 테이프 뒤로"버튼을 누르고 문지르기를 눌러 잘못 펀칭 된 문자를 0xFF로 바꿀 수 있기 때문에 0xFF-쓰레기 제거라고 함 대부분의 수신자에게는 무시됩니다).


2

ASCII 문자열 전송의 한 가지 장점은 제어 코드를 사용하여 메시지 시작 / 종료 신호를 보낼 수 있다는 것입니다. 예를 들어 STX (char 2) 및 ETX (char 3)는 시작 전송 및 종료 전송을 시그널링 할 수 있습니다. 또는 간단한 라인 피드를 추가하여 전송 끝을 표시 할 수 있습니다.

이진 데이터를 전송할 때, 유효한 데이터 바이트가 동일한 패턴을 가질 수 있기 때문에 (일부 오버 헤드 나 복잡성없이) 제어 코드를 위해 특정 비트 패턴을 예약 할 수 없으므로 더 복잡해진다.


3
많은 이진 프로토콜은 하나 이상의 비트 패턴을 제어 코드로 예약하지만 데이터에 나타날 때 해당 코드를 처리하는 이스케이프 메커니즘도 포함합니다.
Dave Tweed

바이너리로 원하는 것을 표시하기 위해 패턴을 예약 할 수 있습니다. 예를 들어, 나는 빠른 데이터 스트림과 느린 데이터 스트림이 동일한 uart를 가진 프로젝트에 있습니다. 나는 느린 데이터에 대한 플래그로 가장 큰 네거티브 int32를 예약하고 가장 큰 네거티브 + 1로 내 네거티브 데이터를 포화시킵니다.
Scott Seidman

동의했다. 편집 된 답변에서 이것을 명확히했으면 좋겠습니다.
트랜지스터

2

ASCII는 괜찮습니다. 거의 모든 프로젝트에서 사용합니다. 포트 모니터링을 훨씬 쉽게 디버깅 할 수 있으며 전송할 데이터가 많은 경우에만 문제가됩니다.

또 다른 보너스, 나는 직렬 라디오 장치를 사용하여 arduino 사이에 메시지를 가져오고 랩톱에 연결된 직렬 모니터를 사용하여 메시지를 주입하여 특정 일이 발생할 수 있습니다. 테스트에 좋습니다.

또한 바이너리로 파일을 보내는 것은 디버깅이 불가능하지 않으며 도구에 따라 바이너리를 추출하여 사람이 읽을 수있는 것으로 변환 할 수 있습니다. 또는 찾고있는 것을 알고 있다면 데이터 스트림을 시각적으로 검사하여 값을 인식 할 수 있으며 오류는 쉽게 찾을 수는 없지만 쉽게 찾을 수 있습니다. 즉, 바이트 패턴을 인식하고 예상 값을 인식합니다.


2

Modbus 대신 HDLC를 고려하십시오 . 오류가 감지됩니다 (시끄러운 직렬 회선에서 중요 함). 동기화가 강력하고 이스케이프가 강력합니다.

RS-485 네트워크에서 HDLC를 문제없이 사용했으며 PPP에서도이를 사용합니다.


2
Modbus를 통해 제안하는 이유를 지적하면 좋을 것입니다.
오전

1

UART를 통한 ASCII는 다음과 같은 이유로 가장 인기가 있습니다.

  • 디버깅 할 때 사람이 읽을 수 있습니다 (아스키를 해독하지 않는 로직 분석기는 아직 보지 못했습니다).

  • 구현하기가 매우 쉽습니다. 표준화 된 빠른 Google을 통해 ASCII 테이블이 있습니다.

  • 시작 / 정지 비트와 동기화되어 있습니다.

  • 거의 모든 취미 세계가 직렬을 통해 ASCII로 설정되었으므로 새로운 방법으로 처리해야 할 것이므로 결코 쉬운 일이 아닙니다.

그런 다음 float를 ASCII로 변환하는 것과 비교하여 float의 메모리 내 표현을 보내는 것과 같은 특정 인코딩을 보내거나 직렬로 전송하여 4 바이트 이상이 될 수있는 상황으로 전환합니다. 호스트의 메모리 내 표현에. 대신 매번 4 바이트 표현 만 보냅니다. 물론 인코딩을 직접 처리 할 수는 있지만 시작 / 종료 태그, 순서 등을 설정해야합니다.

대신 Protobuf 와 같은 것을 사용할 수 있습니다. 이것은 실제로 내가 작업 한 프로젝트에서 사용되었으며 매우 유익했으며 가변 길이 메시지를 처리하고 엔디안을 처리하며 몇 가지 멋진 기능을 제공합니다. 또한 코드 크기가 크지 않으므로 시작할 때 정적으로 할당 할 모든 것을 지정할 수 있습니다. 필요하다면 체크섬을 직접 던져야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.