Khi nào nên chuyển từ ASCII sang các giao thức nối tiếp nâng cao?


28

Tất cả các thiết bị vi điều khiển của tôi giao tiếp với PC thông qua UART đều sử dụng chuỗi ASCII để gửi lệnh và nhận dữ liệu (như được thực hiện trong Arduino). Đó là những gì tôi học được khi tôi bắt đầu đào sâu vào thiết bị điện tử và tôi luôn thấy gửi dây trần là đủ. Tuy nhiên, tôi nhận thấy rằng hầu hết các thiết bị tôi gặp đều sử dụng các giao thức nhị phân tinh vi bao gồm mã chức năng, địa chỉ và kiểm tra lỗi CRC.

Khi nào thì giao tiếp ASCII cơ bản được chấp nhận và khi nào tôi nên xem xét một thứ gì đó tiên tiến hơn, như Modbus? Các thiết bị thương mại có sử dụng ASCII như vậy không? Công nghiệp?


3
Câu trả lời ngắn: Khi ứng dụng của bạn cần nó. Có, các thiết bị thương mại sử dụng ASCII. Lấy GPS NMEA làm ví dụ. (Và một lần nữa, tôi sẽ giới thiệu câu hỏi của riêng tôi ở đây )
Eugene Sh.

1
Modbus có chế độ ASCII. Xem Hướng dẫn tham khảo giao thức Modicon Modbus
Tut

@EugeneSh.: Đáng chú ý là NMEA có trường tổng kiểm tra và giảm một vụ nổ mẫu do lỗi tổng kiểm tra (xảy ra thường xuyên hơn bạn nghĩ) nói chung không phải là một thất bại nghiêm trọng. Điều đó rất có thể không xảy ra đối với các giao thức khác ... có rất nhiều giao thức GPS nhị phân được sử dụng (ví dụ: Garmin) cho các ứng dụng thực sự có thể rất quan trọng (hoặc trong đó tốc độ mẫu cao hơn 1Hz bắt buộc, mà NMEA quá dài dòng). Mặc dù điều này thực sự chỉ củng cố quan điểm của bạn.
Cuộc đua nhẹ nhàng với Monica

Câu trả lời:


28
  1. ASCII và CRC không loại trừ lẫn nhau. ASCII là một mã hóa và CRC là để kiểm tra lỗi.

  2. MỌI THỨ có thể được gửi dưới dạng ASCII. Những người già của chúng tôi chắc chắn nhớ UUEncoding, biến mọi thứ thành chuỗi ASCII.

  3. A) Đối với tôi, đó thường là một câu hỏi về tốc độ và hiệu quả. Gửi một số lượng lớn 32 bit bằng ASCII có thể mất nhiều thời gian, nhưng chỉ mất 4 byte để gửi nó dưới dạng nhị phân thông qua giao thức nối tiếp.

    B) Gửi SỐ TIỀN qua ASCII có nghĩa là bạn phải chuyển đổi số sang ASCII, đây là một bước bổ sung rõ ràng (đây là một phần của "printf" làm gì).

  4. Nếu bạn bằng cách nào đó mất vị trí của bạn, làm hỏng, mất định dạng, nhận được endian sai, vv, một giao thức truyền thông nhị phân chắc chắn có thể làm hỏng. Nếu bạn đang gửi ASCII, có thể dễ dàng phục hồi hơn từ các cuộc tấn công bằng cách chỉ cần truy cập và TÌM KIẾM tại luồng dữ liệu.


12
+1 cho "ASCII là mã hóa". Nó không phải là một giao thức; các giao thức có thể được xây dựng trên đỉnh ASCII.
Pete Becker

8
Tự động phục hồi từ một bản sao không thực sự dễ dàng hơn đối với giao thức dựa trên văn bản dưới dạng nhị phân, nhưng việc kiểm tra và gỡ lỗi nó chắc chắn sẽ xảy ra.
Nick Johnson

1
@NickJohnson - hoàn toàn. Khi bạn đang ở thời điểm mở tệp trong trình chỉnh sửa hex để xem những gì bạn có thể khôi phục, bạn đã ở FUBAR cho đến khi SOP đi
Scott Seidman

1
@nickjohnson điều đó không thực sự đúng. ASCII cung cấp cho bạn rất nhiều tùy chọn đóng khung / phân định băng tần để hỗ trợ đồng bộ hóa và khôi phục, điều này sẽ yêu cầu thoát bổ sung, nhồi bit, khoảng thời gian hoặc các thủ thuật khác nếu kênh được sử dụng cho dữ liệu nhị phân toàn chiều rộng.
Chris Stratton

2
Tôi luôn ưu tiên ASCII khi viết các giao thức cho tất cả các lợi ích rõ ràng (khả năng đọc, khả năng đăng nhập, v.v.). Có hai trường hợp khi nhị phân có ý nghĩa hơn: thứ nhất, nếu tốc độ là một vấn đề và bạn cần nhị phân để nhồi nhét càng nhiều dữ liệu vào luồng và thứ hai, ngoài lề, nếu bạn cố tình làm xáo trộn hoặc thậm chí mã hóa dữ liệu dòng để cản trở hoặc ngăn chặn kỹ thuật đảo ngược. Tại đó, tôi đã đảo ngược các giao thức nhị phân và nó phần lớn chỉ khiến tôi khó chịu hơn là thực sự ngăn chặn hành động này.
J ...

10

Dưới đây là một số suy nghĩ về nó:

  • ASCII rất hay vì bạn có thể sử dụng màn hình nối tiếp để có giao diện thủ công trong nội dung được gửi.
  • nếu kết nối của bạn không đáng tin cậy, bạn phải mong đợi các lỗi truyền và nên sử dụng CRC để kiểm tra tính toàn vẹn của từng tin nhắn nhận được. Điều này cũng có thể được thực hiện trên các thông điệp ASCII.
  • nếu kết nối của bạn quá chậm, bạn có thể giảm kích thước tin nhắn bằng cách chuyển sang định dạng nhị phân
  • Một định dạng nhị phân chuyên dụng có thể dễ dàng giải mã ở phía người nhận hơn ASCII

7

Ở cấp độ đơn giản nhất, bạn có thể nói một giao thức giao tiếp đơn giản có ba lớp: vật lý, vận chuyển và ứng dụng. (Có những mô hình có nhiều hơn như OSI với 7 hoặc TCP / IP với 4. Số lớp không quá quan trọng trong bối cảnh của câu hỏi này.)

Lớp ứng dụng là lớp bạn xử lý trực tiếp trong mã của bạn và là trọng tâm của câu hỏi. Đối với lớp vận chuyển có liên quan, byte bạn truyền cho nó trong send_data chỉ là một mẫu nhị phân, nhưng bạn có thể hiểu nó trong mã ứng dụng của bạn là chữ 'A'. Tính toán CRC hoặc tổng kiểm tra sẽ giống nhau bất kể bạn coi byte là 'A,' 0x41 hay 0b01000001.

Tầng giao vận là cấp gói, nơi bạn có các tiêu đề thư và kiểm tra lỗi, cho dù đó là CRC hay tổng kiểm tra cơ bản. Trong ngữ cảnh của phần sụn, bạn có thể có một hàm như send_data, nơi bạn truyền cho nó một byte để gửi. Bên trong chức năng đó, nó đặt vào một gói có nội dung: "Này đây là một tin nhắn bình thường, yêu cầu xác nhận và tổng kiểm tra là 0x47, thời gian hiện tại là X." Gói này được gửi qua lớp vật lý đến nút nhận.

Lớp vật lý là nơi xác định giao diện và thiết bị điện tử: đầu nối, cấp điện áp, thời gian, v.v ... Lớp này có thể bao gồm từ một vài dấu vết chạy tín hiệu TTL cho UART cơ bản trên PCB, đến cặp vi sai cách ly hoàn toàn như trong một số CÓ THỂ thực hiện.

Tại nút nhận, gói đến trong lớp vật lý, được giải nén ở lớp vận chuyển và sau đó mẫu nhị phân của bạn có sẵn cho lớp ứng dụng. Tùy thuộc vào lớp ứng dụng nút nhận để biết liệu mẫu đó nên được hiểu là 'A,' 0x41 hay 0b01000001 và phải làm gì với nó.

Tóm lại, việc gửi các ký tự ASCII khá dễ chấp nhận nếu đó là những gì ứng dụng yêu cầu. Điều quan trọng là phải hiểu sơ đồ liên lạc của bạn và bao gồm cơ chế kiểm tra lỗi.


Giao thức Ascii có thể kết hợp kiểm tra là tốt. Tôi đã gặp các biến thể Hex-as-ascii, sử dụng đại diện số ascii.
Eugene Sh.

@EugeneSh. Làm rõ điểm đó
Matt Young

Không phải nitpick, nhưng TCP không phải là bốn lớp; nó được coi là phù hợp trong lớp bốn của mô hình OSI. Truyền thông nối tiếp không thực sự phù hợp với mô hình OSI.
batsplatsterson

@batsplatsterson Đó là nitpicking, và khá không liên quan đến điểm tôi đang làm.
Matt Young

5

Một điểm chưa được đề cập là dù người ta đang sử dụng ASCII hay giao thức nhị phân, việc gửi một ký tự xóa trước mỗi gói sẽ đảm bảo rằng ngay cả khi lỗi dòng hoặc lỗi khung xuất hiện trước khi bắt đầu gói, tất cả các ký tự sau khi xóa sẽ được đóng khung chính xác trong trường hợp không có tiếng ồn hơn. Mặt khác, nếu một người gửi các gói liên tục và không bao gồm bất kỳ ký tự nào được đảm bảo để đạt được đồng bộ hóa, có thể một trục trặc có thể làm hỏng mọi thứ tiếp theo cho đến khi tạm dừng tiếp theo trong quá trình truyền. Ký tự 0xFF là tốt vì nó đảm bảo rằng bất kỳ người nhận nào cũng có thể đồng bộ hóa lại ký tự sau.

(*) 0xFF - được gọi là rub-out vì ai đó gõ một ký tự sai trong khi nhập dữ liệu vào băng giấy có thể ấn nút "bước băng từ lùi" và nhấn rub-out để thay thế ký tự bị bấm nhầm bằng 0xFF, sẽ bị bỏ qua bởi hầu hết người nhận).


2

Một lợi thế của việc gửi các chuỗi ASCII là các mã điều khiển sau đó có thể được sử dụng để báo hiệu bắt đầu / kết thúc tin nhắn. ví dụ STX (char 2) và ETX (char 3) có thể báo hiệu bắt đầu truyền và kết thúc truyền. Ngoài ra, bạn có thể thêm một nguồn cấp dữ liệu đơn giản để đánh dấu kết thúc truyền.

Khi gửi dữ liệu nhị phân, điều này trở nên phức tạp hơn vì không có mẫu bit cụ thể nào có thể được dành riêng cho mã điều khiển (không có thêm chi phí hoặc độ phức tạp) vì một byte dữ liệu hợp lệ có thể có cùng một mẫu.


3
Nhiều giao thức nhị phân DO dự trữ một hoặc nhiều mẫu bit làm mã kiểm soát, nhưng chúng cũng bao gồm một cơ chế thoát để xử lý các mã đó khi chúng xuất hiện trong dữ liệu.
Dave Tweed

Bạn có thể dự trữ bất kỳ mẫu nào để gắn cờ mọi thứ bạn muốn trong hệ nhị phân. Ví dụ: tôi đang tham gia một dự án có luồng dữ liệu nhanh và luồng dữ liệu chậm đi cùng một uart. Tôi đã đặt int32 âm lớn nhất làm cờ cho dữ liệu chậm của mình và chỉ bão hòa dữ liệu âm của tôi ở mức âm lớn nhất + 1.
Scott Seidman

Đã đồng ý. Tôi hy vọng điều này trong câu trả lời được chỉnh sửa, tôi hy vọng.
Transitor

2

ASCII là tốt, tôi sử dụng nó trong tất cả các dự án. Nó giúp việc gỡ lỗi dễ dàng hơn nhiều cho việc giám sát cổng và nó sẽ chỉ trở thành vấn đề nếu có nhiều dữ liệu cần gửi.

Một phần thưởng khác, tôi sử dụng các thiết bị vô tuyến nối tiếp để nhận tin nhắn giữa các arduinos và tôi có thể sử dụng một màn hình nối tiếp được kết nối với máy tính xách tay của mình và gửi tin nhắn để thực hiện một số điều nhất định. Tuyệt vời để thử nghiệm.

Ngoài ra, gửi mọi thứ dưới dạng nhị phân không phải là không thể gỡ lỗi và tùy thuộc vào công cụ của bạn, bạn có thể trích xuất và chuyển đổi thành nhị phân thành thứ mà con người có thể đọc được. Hoặc nếu bạn biết những gì bạn đang tìm kiếm, bạn có thể kiểm tra trực quan kho dữ liệu và nhận ra các giá trị nơi chúng nên và lỗi tìm theo cách đó, mặc dù, không dễ dàng như vậy. tức là, bạn sẽ nhận ra các mẫu byte và nhận ra các giá trị mong đợi


2

Thay vì Modbus xem xét HDLC . Bạn nhận được phát hiện lỗi (điều này rất quan trọng đối với các dòng nối tiếp ồn ào). Đồng bộ hóa là mạnh mẽ, thoát là mạnh mẽ.

Tôi đã sử dụng HDLC trong các mạng RS-485 mà không gặp vấn đề gì và PPP cũng sử dụng nó.


2
Sẽ thật tuyệt nếu bạn chỉ ra lý do tại sao bạn đề xuất nó qua Modbus.
Tôi không biết tôi đang làm gì vào

1

ASCII trên UART là phần phổ biến nhất vì:

  • Nó có thể đọc được khi con người gỡ lỗi (Tôi vẫn chưa thấy bộ phân tích logic không giải mã ASCII).

  • Rất dễ thực hiện, bạn đã có một bảng ASCII thông qua google nhanh được chuẩn hóa tốt.

  • Nó đã được xây dựng đồng bộ hóa với các bit start / stop.

  • Gần như toàn bộ thế giới hobbyst đã tự thiết lập với ASCII qua nối tiếp, do đó, bất kỳ phương pháp mới nào cũng sẽ phải đối phó với điều đó, và điều đó không dễ dàng bằng bất kỳ phương tiện nào.

Sau đó, bạn gặp phải tình huống khi bạn bắt đầu gửi mã hóa cụ thể, chẳng hạn như gửi biểu diễn trong bộ nhớ của float so với chuyển đổi float sang ASCII, gửi qua serial đó có thể hơn 4 byte, sau đó chuyển đổi trở lại đến một đại diện trong bộ nhớ trên máy chủ. Thay vào đó, bạn chỉ cần gửi đại diện 4 byte mỗi lần. Chắc chắn, bạn có thể tự mình bắt đầu xử lý mã hóa, nhưng sau đó bạn cần thiết lập thẻ bắt đầu / kết thúc, đặt hàng, v.v.

Thay vào đó, những thứ như Protobuf có thể được sử dụng. Điều này thực sự được sử dụng trong một dự án tôi đang thực hiện và nó cực kỳ có lợi, nó có các thông điệp có độ dài thay đổi, xử lý endian cho bạn và một vài tính năng thú vị khác. Nó cũng không lớn về kích thước mã và bạn có thể chỉ định mọi thứ sẽ được phân bổ tĩnh khi khởi động. Bạn sẽ phải ném vào tổng kiểm tra mặc dù, nếu bạn cần nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.